Contributed by 爱笑, organized by Ai-Thinker
[Ai-WB2 Getting Started] Timer Usage
A general-purpose timer is used for timing. When the time reaches the timing value we set, a timer interrupt is generated, which can be used to complete timed tasks. This article describes in detail how to use the timer functions of the BL602. 1. Ai-WB2 Timer Introduction The Ai-WB2 has two built-in 32-bit counters, and each counter can independently control and configure its parameters and clock frequency. The functional block diagram of the timer is as follows:

The timers of the Ai-WB2 have the following features:
Click to expand full code
**·** 多种时钟来源,最高可支持160M时钟
**·** 8-bit 时钟分频器,分频系数为1-256
**·** 两组32-bit定时器
**·** 每个定时器包含三组报警值设定,可独立设定每组报警值溢出时报警
**·** 支持Free Run模式和Pre load模式
**·** 16-bit 看门狗定时器
**·** 支持写入密码保护,防止误设定造成系统异常
**·** 支持中断或复位两种看门狗溢出方式Each timer has four choices of clock source, as follows:
Click to expand full code
**·** Fclk-系统主时钟
**·** 32K-32K时钟
**·** 1K-1K时钟(32K的分频)
**·** Xtal-外部晶振Each counter has its own 8-bit divider. The selected clock can be divided by 1-256 through the APB. Specifically, setting it to 0 means no division, setting it to 1 means division by 2, and so on, with a maximum division factor of 256. The counter uses the divided clock as the counting cycle unit and increments by 1 every counting cycle. How the General-Purpose Timer Works Each general-purpose timer contains three sets of comparators, one counter and one preload register. After the clock source is configured and the timer is started, the counter starts counting up. When the counter value matches a comparator value, the compare flag is set and a compare interrupt can be generated. The initial value of the counter depends on the timing mode. In FreeRun mode, the initial value of the counter is 0, and then it counts up; after reaching the maximum count value, it restarts from 0 and counts again. In PreLoad mode, the initial value of the counter is the value of the PreLoad register, and then it counts up. When the PreLoad condition is met, the counter value is set to the value of the PreLoad register, and then the counter starts counting up again. During the counting process of the timer counter, once the counter value matches the value of one of the three comparators, the compare flag of that comparator is set and a corresponding compare interrupt can be generated. If the preload register value is 10, comparator 0 is 13, comparator 1 is 16 and comparator 2 is 19, the working sequence of the timer in PreLoad mode is shown in the figure below:

In FreeRun mode, the working sequence of the timer is basically the same as in PreLoad mode, except that the counter counts up from 0 to the maximum value. The mechanisms for generating compare flags and compare interrupts during this process are the same as in PreLoad mode. Alarm Configuration Each counter group has three compare values provided for software configuration, and it can be set whether each compare value triggers an alarm interrupt. When the counter matches a compare value and the alarm is enabled, the counter notifies the processor through an interrupt. Software can read via the APB whether an alarm has occurred and which compare value triggered the alarm interrupt. When the alarm interrupt is cleared, the alarm status is cleared synchronously. 2. Timer Driver API Introduction The HOSAL layer high-level driver API for the timer is defined in the file components/platform/hosal/include/hosal_timer.h. The commonly used API functions are as follows: · int hosal_timer_init(hosal_timer_dev_t *tim): initializes the timer. Its parameters are described as follows: · tim: the timer device, defined as follows:
Click to expand full code
typedef struct {
int8_t port; /**< 定时器端口 */
hosal_timer_config_t config; /**< 定时器配置 */
void *priv; /**< 用户自定义数据 */
} hosal_timer_dev_t;The timer configuration hosal_timer_config_t is defined as follows:
Click to expand full code
typedef struct {
uint32_t period; /**< 定时器周期以纳秒为单位 */
uint8_t reload_mode; /**< 是否自动重载 */
hosal_timer_cb_t cb; /**< 超时中断回调函数 */
void *arg; /**< 回调函数参数 */
} hosal_timer_config_t;hosal_timer_cb_t is the timer callback function, defined as follows:
- typedef void (*hosal_timer_cb_t)(void *arg);
Click to expand full code
**·** 返回值:成功时返回0;否则返回非零值
**·** int hosal_timer _start(hosal_timer_dev_t *tim):启动定时器。参数说明如下:
**·** tim:定时器设备对象
**·** 返回值:成功时返回0;否则返回非零值
**·** void hosal_timer_stop(hosal_timer_dev_t *tim):停止定时器。参数说明如下:
**·** tim:定时器设备对象
**·** 返回值:成功时返回0;否则返回非零值
**·** int hosal_timer_finalize(hosal_timer_dev_t *tim):定时器销毁。当不再使用定时器需要调用此函数。参数说明如下:
**·** tim:定时器设备对象
**·** 返回值:成功时返回0:否则返回非零值
**三:定时器使用实例**The general-purpose timers of the BL602 support two modes: one-shot timing and continuous timing.
- #define TIMER_RELOAD_PERIODIC 1 /**< 定时器自动重载 */
- #define TIMER_RELOAD_ONCE 2 /**< 定时器自动重载一次,需要手动重载 */
The following demonstrates how to use these two modes
Click to expand full code
单次计时
#include <stdio.h>
#include <string.h>
#include <FreeRTOS.h>
#include <task.h>
#include <stdio.h>
#include <stdbool.h>
#include <bl_gpio.h>
#include <hosal_gpio.h>
#include <hosal_timer.h>
#include <blog.h>
#define TAG "uart_demo"
#define LED_RED 14
#define LED_GREEN 17
#define LED_BLUE 3
static hosal_timer_dev_t timer;
void timer_callback(void *arg)
{
static int i = 0;
if (i % 3 == 0) {
bl_gpio_output_set(LED_RED,1);
bl_gpio_output_set(LED_GREEN,0);
bl_gpio_output_set(LED_BLUE,0);
} else if(i % 3 == 1) {
bl_gpio_output_set(LED_RED,0);
bl_gpio_output_set(LED_GREEN,1);
bl_gpio_output_set(LED_BLUE,0);
}else{
bl_gpio_output_set(LED_RED,0);
bl_gpio_output_set(LED_GREEN,0);
bl_gpio_output_set(LED_BLUE,1);
}
i++;
}
void timer_demo_init(void)
{
timer.port = 0;
timer.config.period = 2000 * 1000; /* 2000ms */
timer.config.reload_mode = TIMER_RELOAD_ONCE;
timer.config.cb =timer_callback;
timer.config.arg = NULL;
bl_gpio_enable_output(LED_RED, 1, 0);
bl_gpio_enable_output(LED_GREEN, 1, 0);
bl_gpio_enable_output(LED_BLUE, 1, 0);
// 初始化定时器
hosal_timer_init(&timer);
// 启动定时器
hosal_timer_start(&timer);
}
void main(void) {
timer_demo_init();
printf("timer demo start\r\n");
}
持续计时
#include <stdio.h>
#include <string.h>
#include <FreeRTOS.h>
#include <task.h>
#include <stdio.h>
#include <stdbool.h>
#include <bl_gpio.h>
#include <hosal_gpio.h>
#include <hosal_timer.h>
#include <blog.h>
#define TAG "uart_demo"
#define LED_RED 14
#define LED_GREEN 17
#define LED_BLUE 3
static hosal_timer_dev_t timer;
void timer_callback(void *arg)
{
static int i = 0;
if (i % 3 == 0) {
bl_gpio_output_set(LED_RED,1);
bl_gpio_output_set(LED_GREEN,0);
bl_gpio_output_set(LED_BLUE,0);
} else if(i % 3 == 1) {
bl_gpio_output_set(LED_RED,0);
bl_gpio_output_set(LED_GREEN,1);
bl_gpio_output_set(LED_BLUE,0);
}else{
bl_gpio_output_set(LED_RED,0);
bl_gpio_output_set(LED_GREEN,0);
bl_gpio_output_set(LED_BLUE,1);
}
i++;
}
void timer_demo_init(void)
{
timer.port = 0;
timer.config.period = 200 * 1000; /* 200ms */
timer.config.reload_mode = TIMER_RELOAD_PERIODIC;
timer.config.cb =timer_callback;
timer.config.arg = NULL;
bl_gpio_enable_output(LED_RED, 1, 0);
bl_gpio_enable_output(LED_GREEN, 1, 0);
bl_gpio_enable_output(LED_BLUE, 1, 0);
hosal_timer_init(&timer);
hosal_timer_start(&timer);
}
void main(void) {
timer_demo_init();
printf("timer demo start\r\n");
}
