Concepts First
- Watchdog (WDG): like a supervisor — the program must periodically "feed" it (reset the counter); if the program hangs, the watchdog resets the system.
- Counter/compare value: the watchdog clock keeps counting; if it reaches
comp_valwithout a feed, an interrupt or reset fires. - Clock source: the watchdog can use BCLK/32K/1K/XTAL; the example iterates over them to verify the actual timing.
Example Overview
This page is based on the wdg_clksource_check example in the official Bouffalo SDK (examples/peripherals/wdg/wdg_clksource_check), which demonstrates the watchdog timer and clock-source verification:
- Watchdog clock = clock source / (divider + 1); the example iterates over BCLK, 32K, 1K, XTAL;
- For each source: configure → reset the counter → start → delay 200 ms → read the counter → stop, repeated 10 times;
- Comparing the counts verifies whether the watchdog timing matches the theoretical frequency.
- Sibling examples (
examples/peripherals/wdg/):wdg_int(interrupt mode),wdg_reset(reset mode).
Operation Steps
No external wiring is needed for this page. Open a terminal and enter the watchdog example directory (prerequisite: set up the environment as in Quick Start (Linux) or Windows):
cd examples/peripherals/wdg/wdg_clksource_checkRun the build command. The Ai-M62 (BL616) and Ai-M61 (BL618) belong to the same series, so both use bl616:
make CHIP=bl616 BOARD=bl616dkConnect the board with a USB cable, hold the BOOT button (IO2 on the Ai-M61-32S-Kit), briefly press EN/RST to enter download mode, then flash (replace the serial port with the one on your computer):
make flash CHIP=bl616 COMX=/dev/ttyUSB0Open a serial tool (baud rate 2000000). The example starts the watchdog with BCLK/32K/1K/XTAL clock sources in turn; each time it delays 200 ms, reads the counter, and prints Delay 200ms, div = x, test x times, cnt: xxx, ending with case success.
Code Execution Flow
The complete execution flow from startup to running is shown below (loop arrows mean repeated execution):
APIs Used by the Example
bflb_device_get_by_name("watchdog0")
Gets the watchdog device handle; "watchdog0" on BL616/BL618.
Parameters:
name: device name, always"watchdog0"
Return: struct bflb_device_s * device handle (NULL on failure)
bflb_wdg_init(wdt, config)
Initializes the watchdog. In struct bflb_wdg_config_s:
clock_source:WDG_CLKSRC_BCLK/WDG_CLKSRC_32K/WDG_CLKSRC_1K/WDG_CLKSRC_XTALclock_div: divider; counting clock = source / (div + 1)comp_val: compare value,0xffffin the examplemode:WDG_MODE_INTERRUPT
Parameters:
wdt: watchdog device handleconfig: pointer to the config struct
Return: 0 on success; negative error code on failure
bflb_wdg_reset_countervalue(wdt)
Resets the watchdog counter (i.e. "feed the dog").
Parameters:
wdt: watchdog device handle
Return: none
bflb_wdg_start / bflb_wdg_stop(wdt)
Starts/stops the watchdog. Once started, the counter must be reset before the compare value expires, or the system resets/interrupts.
Parameters:
wdt: watchdog device handle
Return: none
bflb_wdg_get_countervalue(wdt)
Reads the current counter value to verify timing.
Parameters:
wdt: watchdog device handle
Return: counter value
Complete Code
The complete source below matches the effect described on this page. It is based on the official example (examples/peripherals/wdg/wdg_clksource_check); the LED pins are adapted to the Ai-M61/62-32S-Kit onboard RGB LED. Collapsed by default, click to expand:
📜 Click to expand wdg_clksource_check/main.c full code
#include "bflb_mtimer.h"
#include "bflb_wdg.h"
#include "board.h"
#include <assert.h>
#if !defined(BL702L)
uint8_t wdg_clk_src_type[] = {
WDG_CLKSRC_BCLK,
WDG_CLKSRC_32K,
WDG_CLKSRC_1K,
WDG_CLKSRC_XTAL,
};
#else
uint8_t wdg_clk_src_type[] = {
WDG_CLKSRC_32K,
WDG_CLKSRC_1K,
WDG_CLKSRC_XTAL,
};
#endif
int main(void)
{
uint32_t i = 0;
uint32_t j = 0;
uint32_t cnt = 0;
board_init();
printf("Timer clksource check\n");
struct bflb_device_s *wdt;
wdt = bflb_device_get_by_name("watchdog0");
assert(wdt != NULL);
/* watchdog clk = clock_source/(div + 1)*/
struct bflb_wdg_config_s cfg;
cfg.clock_source = WDG_CLKSRC_32K;
cfg.clock_div = 0;
cfg.comp_val = 0xffff;
cfg.mode = WDG_MODE_INTERRUPT;
for (i = 0; i < sizeof(wdg_clk_src_type) / sizeof(wdg_clk_src_type[0]); i++) {
cnt = 0;
if (wdg_clk_src_type[i] == WDG_CLKSRC_XTAL) {
printf("Watchdog Src Clk is XTAL\r\n");
cfg.clock_div = 199;
} else if (wdg_clk_src_type[i] == WDG_CLKSRC_32K) {
printf("Watchdog Src Clk is 32K\r\n");
cfg.clock_div = 1;
} else if (wdg_clk_src_type[i] == WDG_CLKSRC_1K) {
printf("Watchdog Src Clk is 1K\r\n");
cfg.clock_div = 1;
}
#if !defined(BL702L)
else if (wdg_clk_src_type[i] == WDG_CLKSRC_BCLK) {
printf("Watchdog Src Clk is BCLK\r\n");
cfg.clock_div = 249;
}
#endif
else {
printf("Other clock, not test.\r\n");
continue;
}
cfg.clock_source = wdg_clk_src_type[i];
bflb_wdg_init(wdt, &cfg);
for (j = 0; j < 10; j++) {
bflb_wdg_reset_countervalue(wdt);
bflb_wdg_start(wdt);
bflb_mtimer_delay_ms(200);
cnt = bflb_wdg_get_countervalue(wdt);
bflb_wdg_stop(wdt);
bflb_mtimer_delay_ms(10);
printf("Delay 200ms, div = %lu, test %lu times, cnt: %lu\r\n", cfg.clock_div + 1, j, cnt);
}
}
printf("case success.\r\n");
while (1) {
bflb_mtimer_delay_ms(1500);
}
}FAQ
The program keeps resetting
The watchdog resets the system if it is not fed in time. This example is a verification (start/stop) demo; in a real project, call bflb_wdg_reset_countervalue periodically in the main loop or idle task.
The counter does not match the theory
Count = source frequency / (div + 1) × time. Confirm the actual frequency of the source (XTAL = 40 MHz, 32K = 32768 Hz) and the clock_div value.
How to make the watchdog truly reset the system
Set mode to a reset mode (e.g. WDG_MODE_RESET, see bflb_wdg.h) and configure a suitable comp_val timeout.
Have questions?
For any other questions, visit the unified Q&A and discussion board: Ai-Thinker Discussions

