Clock Management

Time is a very important concept. Going out with friends requires an appointment, and completing tasks also requires time. Life is inseparable from time. The same is true for operating systems, which need to use time to regulate the execution of their tasks. The smallest unit of time in an operating system is the clock tick (OS Tick). This chapter mainly introduces the clock tick and the timer based on the clock tick. After reading this chapter, we will understand how the clock tick is generated and how to use the timer of RT-Thread.

Any operating system needs to provide a clock tick for the system to handle all time-related events, such as thread delays, thread time slice round-robin scheduling, and timer timeouts. The clock tick is a specific periodic interrupt, which can be regarded as the heartbeat of the system. The time interval between interrupts depends on different applications, usually 1ms-100ms. The faster the clock tick rate, the faster the real-time response of the system, but the greater the system overhead. The number of clock ticks counted from the start of the system is called the system time.

In RT-Thread, the length of the clock tick can be adjusted according to the definition of RT_TICK_PER_SECOND, which is equal to 1/RT_TICK_PER_SECOND seconds.

The clock beat is generated by a hardware timer configured in interrupt trigger mode. When an interrupt arrives, it will call once: void rt_tick_increase(void) to notify the operating system that a system clock has passed. Different hardware timer interrupt implementations are different. The following interrupt function takes the STM32 timer as an example.

void SysTick_Handler(void)
{
    /* 进入中断 */
    rt_interrupt_enter();
    ……
    rt_tick_increase();
    /* 退出中断 */
    rt_interrupt_leave();
}copymistakeCopy Success

Call rt_tick_increase() in the interrupt function to increment the global variable rt_tick. The code is as follows:

void rt_tick_increase(void)
{
    struct rt_thread *thread;

    /* 全局变量 rt_tick 自加 */
    ++ rt_tick;

    /* 检查时间片 */
    thread = rt_thread_self();

    -- thread->remaining_tick;
    if (thread->remaining_tick == 0)
    {
        /* 重新赋初值 */
        thread->remaining_tick = thread->init_tick;

        /* 线程挂起 */
        rt_thread_yield();
    }

    /* 检查定时器 */
    rt_timer_check();
}copymistakeCopy Success

It can be seen that the value of the global variable rt_tick increases by 1 every time a clock tick passes. The value of rt_tick represents the total number of clock ticks that have passed since the system was started, that is, the system time. In addition, every time a clock tick passes, it checks whether the time slice of the current thread has been used up and whether any timer has timed out.

Note

Note: rt_timer_check() in the interrupt is used to check the system hardware timer list. If a timer times out, the corresponding timeout function will be called. All timers will be removed from the timer list after the timer times out, and the periodic timer will be added to the timer list when it is started again.

Since the value of the global variable rt_tick increases by 1 every time a clock tick passes, calling rt_tick_get will return the current value of rt_tick, that is, the current clock tick value can be obtained. This interface can be used to record the running time of the system or measure the running time of a task. The interface function is as follows:

rt_tick_t rt_tick_get(void);copymistakeCopy Success

The following table describes the return values ​​of the rt_tick_get() function:

return

describe

rt_tick

Current clock tick value

A timer is a device that triggers an event after a specified period of time, such as setting a time to remind you to get up on time the next day. There are two types of timers: hardware timers and software timers:

1) The hardware timer is a timing function provided by the chip itself. Generally, an external crystal oscillator provides the chip with input clock. The chip provides a set of configuration registers to the software module, accepts control input, and the chip interrupt controller generates a clock interrupt after reaching the set time value. The accuracy of the hardware timer is generally very high, reaching the nanosecond level, and it is an interrupt trigger mode.

2) Software timer is a type of system interface provided by the operating system. It is built on the basis of hardware timer, enabling the system to provide unlimited number of timer services.

The RT-Thread operating system provides a software-implemented timer that uses the length of the clock tick (OS Tick) as the unit, that is, the timing value must be an integer multiple of the OS Tick. For example, if an OS Tick is 10ms, then the upper-level software timer can only be 10ms, 20ms, 100ms, etc., and cannot be timed to 15ms. The RT-Thread timer is also based on the system tick, providing a timing capability based on integer multiples of the tick.

RT-Thread's timer provides two types of timer mechanisms: the first type is a single-trigger timer, which will only trigger a timer event once after it is started, and then the timer will stop automatically. The second type is a periodic trigger timer, which will periodically trigger a timer event until the user manually stops it, otherwise it will continue to execute forever.

In addition, according to the context in which the timeout function is executed, the RT-Thread timer can be divided into HARD_TIMER mode and SOFT_TIMER mode, as shown in the following figure.

HARD_TIMER mode

The timer timeout function in HARD_TIMER mode is executed in the interrupt context and can be specified using the parameter RT_TIMER_FLAG_HARD_TIMER when initializing/creating the timer.

When executed in the interrupt context, the requirements for the timeout function are the same as those for the interrupt service routine: the execution time should be as short as possible, and the execution should not cause the current context to suspend or wait. For example, a timeout function executed in the interrupt context should not attempt to apply for dynamic memory or release dynamic memory.

The default mode of RT-Thread timer is HARD_TIMER mode, that is, after the timer times out, the timeout function is executed in the context of the system clock interrupt. The execution mode in the interrupt context determines that the timer timeout function should not call any system function that will suspend the current context; it cannot be executed for a very long time, otherwise it will cause the response time of other interrupts to be prolonged or preempt the execution time of other threads.

SOFT_TIMER mode

The SOFT_TIMER mode is configurable. The macro definition RT_USING_TIMER_SOFT determines whether to enable this mode. When this mode is enabled, the system will create a timer thread during initialization, and then the timer timeout function of the SOFT_TIMER mode will be executed in the context of the timer thread. The parameter RT_TIMER_FLAG_SOFT_TIMER can be used to specify the setting of SOFT_TIMER mode when initializing/creating the timer.

The following example illustrates the working mechanism of the RT-Thread timer. Two important global variables are maintained in the RT-Thread timer module:

(1) The current system tick time rt_tick (when the hardware timer interrupt comes, it will be increased by 1);

(2) Timer linked list rt_timer_list. Newly created and activated timers in the system are inserted into the rt_timer_list linked list in the order of timeout time.

As shown in the figure below, the current tick value of the system is 20. Three timers have been created and started in the current system, namely Timer1 with a timing time of 50 ticks, Timer2 with a timing time of 100 ticks, and Timer3 with a timing time of 500 ticks. These three timers are added with the current system time rt_tick=20, and are linked in the rt_timer_list linked list in ascending order, forming the timer linked list structure shown in the figure.

As the hardware timer is triggered, rt_tick keeps increasing (each time the hardware timer interrupt comes, the rt_tick variable will increase by 1). After 50 ticks, rt_tick increases from 20 to 70, which is equal to the timeout value of Timer1. At this time, the timeout function associated with Timer1 timer will be triggered, and Timer1 will be deleted from the rt_timer_list linked list. Similarly, after 100 ticks and 500 ticks have passed, the timeout function associated with Timer2 and Timer3 timers will be triggered, and then Timer2 and Timer3 timers will be deleted from the rt_timer_list linked list.

If the current timer state of the system is after 10 ticks (rt_tick=30), a task creates a new Timer4 timer with a tick value of 300. Since the timeout of Timer4 timer=rt_tick+300=330, it will be inserted between Timer2 and Timer3 timers, forming a linked list structure as shown in the following figure:

Timer control block

In the RT-Thread operating system, the timer control block is defined by the structure struct rt_timer and forms a timer kernel object, which is then linked to the kernel object container for management. It is a data structure used by the operating system to manage timers, which stores some information about the timer, such as the initial beat number, the beat number when the timeout occurs, and also includes the linked list structure used to connect timers, timeout callback functions, etc.

struct rt_timer
{
    struct rt_object parent;
    rt_list_t row[RT_TIMER_SKIP_LIST_LEVEL];  /* 定时器链表节点 */

    void (*timeout_func)(void *parameter);    /* 定时器超时调用的函数 */
    void      *parameter;                         /* 超时函数的参数 */
    rt_tick_t init_tick;                         /* 定时器初始超时节拍数 */
    rt_tick_t timeout_tick;                     /* 定时器实际超时时的节拍数 */
};
typedef struct rt_timer *rt_timer_t;copymistakeCopy Success

The timer control block is defined by the struct rt_timer structure and forms a timer kernel object, which is then linked to the kernel object container for management. The list member is used to link an activated (already started) timer to the rt_timer_list linked list.

Timer Skip List Algorithm

When introducing the working method of timers, we mentioned that newly created and activated timers in the system will be inserted into the rt_timer_list linked list in the order of timeout time. That is to say, the t_timer_list linked list is an ordered linked list. The skip list algorithm is used in RT-Thread to speed up the search of linked list elements.

A skip list is a data structure based on a parallel linked list. It is simple to implement, and the time complexity of insertion, deletion, and search is O(log n). A skip list is a type of linked list, but it adds a "jump" function on the basis of the linked list. It is this function that enables the skip list to provide a time complexity of O(log n) when searching for elements. For example:

An ordered linked list, as shown in the figure below, searches for the element {13, 39} from the ordered linked list. The number of comparisons required is {3, 5}, and the total number of comparisons is 3 + 5 = 8.

After using the skip list algorithm, you can use a method similar to the binary search tree to extract some nodes as indexes, and get the structure shown in the following figure:

In this structure, {3, 18, 77} is extracted as the primary index, so that the number of comparisons can be reduced when searching. For example, when searching for 39, only 3 comparisons are made (by comparing 3, 18, 39). Of course, we can also extract some elements from the primary index as the secondary index, which can speed up the element search.

Therefore, the timer skip list can reduce the number of comparisons during the search through the upper-level index, thereby improving the efficiency of the search. This is an algorithm that "trades space for time". In RT-Thread, the number of levels of the skip list is configured through the macro definition RT_TIMER_SKIP_LIST_LEVEL. The default value is 1, which means that an ordered linked list algorithm with a first-level ordered linked list graph is used. Each increase by one means that a level of index is added on the basis of the original linked list.

The previous section introduced the RT-Thread timer and gave a conceptual explanation of the working mechanism of the timer. This section will go into the various interfaces of the timer to help readers understand the RT-Thread timer at the code level.

The timer management system needs to be initialized when the system starts. This can be done through the following function interface:

void rt_system_timer_init(void);copymistakeCopy Success

If you need to use SOFT_TIMER, you should call the following function interface when the system is initialized:

void rt_system_timer_thread_init(void);copymistakeCopy Success

The timer control block contains important parameters related to the timer, and acts as a link between the various states of the timer. The relevant operations of the timer are shown in the figure below. The operations on the timer include: creating/initializing the timer, starting the timer, running the timer, and deleting/leaving the timer. All timers will be removed from the timer list after the timer times out, and the periodic timer will be added to the timer list when it is started again, which is related to the timer parameter setting. Every time the operating system clock interrupt occurs, the state parameters of the timer that has timed out will be changed.

Creating and Deleting Timers

When dynamically creating a timer, you can use the following function interface:

rt_timer_t rt_timer_create(const char* name,
                           void (*timeout)(void* parameter),
                           void* parameter,
                           rt_tick_t time,
                           rt_uint8_t flag);copymistakeCopy Success

After calling this function interface, the kernel first allocates a timer control block from the dynamic memory heap, and then performs basic initialization on the control block. The parameters and return values ​​are described in the following table:

Input parameters and return values ​​of rt_timer_create()

parameter

describe

name

Timer name

void (timeout) (void parameter)

Timer timeout function pointer (when the timer times out, the system will call this function)

parameter

The entry parameter of the timer timeout function (when the timer times out, the timeout callback function is called and this parameter is passed to the timeout function as the entry parameter)

time

The timer timeout period, in clock ticks

flag

Parameters when creating a timer. Supported values ​​include single timer, periodic timer, hardware timer, software timer, etc. (You can use the "or" relationship to take multiple values)

return

——

RT_NULL

Creation failed (usually returns RT_NULL due to insufficient system memory)

The timer handle

Timer created successfully

Some timer-related macros are defined in include/rtdef.h, as follows:

#define RT_TIMER_FLAG_ONE_SHOT      0x0     /* 单次定时     */
#define RT_TIMER_FLAG_PERIODIC      0x2     /* 周期定时     */

#define RT_TIMER_FLAG_HARD_TIMER    0x0     /* 硬件定时器   */
#define RT_TIMER_FLAG_SOFT_TIMER    0x4     /* 软件定时器   */copymistakeCopy Success

The above two sets of values ​​can be assigned to flags in an "OR" logic manner. When the specified flag is RT_TIMER_FLAG_HARD_TIMER, if the timer times out, the timer callback function will be called in the context of the clock interrupt service routine; when the specified flag is RT_TIMER_FLAG_SOFT_TIMER, if the timer times out, the timer callback function will be called in the context of the system clock timer thread.

When the system no longer uses dynamic timers, the following function interface can be used:

rt_err_t rt_timer_delete(rt_timer_t timer);copymistakeCopy Success

After calling this function interface, the system will delete this timer from the rt_timer_list linked list, and then release the memory occupied by the corresponding timer control block. The parameters and return values ​​are described in the following table:

Input parameters and return value of rt_timer_delete()

parameter

describe

timer

Timer handle, pointing to the timer to be deleted

return

——

RT_EOK

Deletion is successful (if the parameter timer handle is a RT_NULL, it will cause an ASSERT assertion)

Initialization and exit timer

When you choose to create a timer statically, you can use the rt_timer_init interface to initialize the timer. The function interface is as follows:

void rt_timer_init(rt_timer_t timer,
                   const char* name,
                   void (*timeout)(void* parameter),
                   void* parameter,
                   rt_tick_t time, rt_uint8_t flag);copymistakeCopy Success

When using this function interface, the corresponding timer control block will be initialized, the corresponding timer name, timer timeout function, etc. The parameters and return values ​​are described in the following table:

Input parameters and return values ​​of rt_timer_init()

parameter

describe

timer

Timer handle, pointing to the timer control block to be initialized

name

Timer name

void (timeout) (void parameter)

Timer timeout function pointer (when the timer times out, the system will call this function)

parameter

The entry parameter of the timer timeout function (when the timer times out, the timeout callback function is called and this parameter is passed to the timeout function as the entry parameter)

time

The timer timeout period, in clock ticks

flag

Parameters for creating a timer. Supported values ​​include single timer, periodic timer, hardware timer, and software timer (you can use the "or" relationship to take multiple values). For details, see the section Creating a Timer.

When a static timer is no longer needed, the following function interface can be used:

rt_err_t rt_timer_detach(rt_timer_t timer);copymistakeCopy Success

When detaching from a timer, the system will detach the timer object from the kernel object container, but the memory occupied by the timer object will not be released. For details on the parameters and return values, see the table below:

rt_timer_detach() Input Parameters and Return Values

parameter

describe

timer

Timer handle, pointing to the timer control block to be detached

return

——

RT_EOK

Breakaway success

Starting and stopping the timer

After a timer is created or initialized, it will not be started immediately. It must start working after calling the start timer function interface. The start timer function interface is as follows:

rt_err_t rt_timer_start(rt_timer_t timer);copymistakeCopy Success

After calling the timer start function interface, the timer status will be changed to the activated status (RT_TIMER_FLAG_ACTIVATED) and inserted into the rt_timer_list queue list in the order of timeout. The parameters and return values ​​are described in the following table:

Input parameters and return value of rt_timer_start()

parameter

describe

timer

Timer handle, pointing to the timer control block to be started

return

——

RT_EOK

Startup Success

For an example of starting a timer, please refer to the sample code below.

After starting the timer, if you want to stop it, you can use the following function interface:

rt_err_t rt_timer_stop(rt_timer_t timer);copymistakeCopy Success

After calling the timer stop function interface, the timer state will change to the stop state, and it will be separated from the rt_timer_list list and will not participate in the timer timeout check. When a (periodic) timer times out, this function interface can also be called to stop the (periodic) timer itself. The parameters and return values ​​are described in the following table:

Input parameters and return value of rt_timer_stop()

parameter

describe

timer

Timer handle, pointing to the timer control block to be stopped

return

——

RT_EOK

Successfully stopped the timer

- RT_ERROR

The timer is already in the stopped state

Control timer

In addition to the programming interfaces provided above, RT-Thread also provides additional timer control function interfaces to obtain or set more timer information. The control timer function interface is as follows:

rt_err_t rt_timer_control(rt_timer_t timer, rt_uint8_t cmd, void* arg);copymistakeCopy Success

The control timer function interface can view or change the timer settings according to the command type parameters. The parameters and return values ​​are described in the following table:

rt_timer_control() Input Parameters and Return Values

parameter

describe

timer

Timer handle, pointing to the timer control block to be controlled

cmd

Commands used to control the timer. Currently, four commands are supported: set timing time, view timing time, set single trigger, and set periodic trigger.

arg

The control command parameters corresponding to cmd. For example, when cmd is used to set the timeout, the timeout parameter can be set through arg.

return

——

RT_EOK

success

Function parameter cmd supports the following commands:

#define RT_TIMER_CTRL_SET_TIME      0x0     /* 设置定时器超时时间       */
#define RT_TIMER_CTRL_GET_TIME      0x1     /* 获得定时器超时时间       */
#define RT_TIMER_CTRL_SET_ONESHOT   0x2     /* 设置定时器为单次定时器   */
#define RT_TIMER_CTRL_SET_PERIODIC  0x3     /* 设置定时器为周期型定时器 */copymistakeCopy Success

For code using the timer control interface, see the dynamic timer example.

This is an example of creating a timer. This routine will create two dynamic timers, one is a one-time timer and the other is a periodic timer and let the periodic timer run for a period of time and then stop running, as shown below:

#include <rtthread.h>

/* 定时器的控制块 */
static rt_timer_t timer1;
static rt_timer_t timer2;
static rt_uint8_t cnt = 0;

/* 定时器 1 超时函数 */
static void timeout1(void *parameter)
{
    rt_kprintf("periodic timer is timeout %d\n", cnt);

    /* 运行第 10 次,停止周期定时器 */
    if (cnt++>= 9)
    {
        /* 清除计数值 */
        cnt = 0;
        rt_timer_stop(timer1);
        rt_kprintf("periodic timer was stopped! \n");
    }
}

/* 定时器 2 超时函数 */
static void timeout2(void *parameter)
{
    rt_kprintf("one shot timer is timeout\n");
}

/* 检查,清理上次的定时器 */
static void check_timer_exist(void)
{
    if (timer1 != RT_NULL)
    {
        rt_timer_delete(timer1);
        timer1 = RT_NULL;
    }
    if (timer2 != RT_NULL)
    {
        rt_timer_delete(timer2);
        timer2 = RT_NULL;
    }
}

int timer_sample(void)
{
    /* 检查,清理上次的定时器 */
    check_timer_exist();

    /* 创建定时器 1  周期定时器 */
    timer1 = rt_timer_create("timer1", timeout1,
                             RT_NULL, 10,
                             RT_TIMER_FLAG_PERIODIC);

    /* 启动定时器 1 */
    if (timer1 != RT_NULL) rt_timer_start(timer1);

    /* 创建定时器 2 单次定时器 */
    timer2 = rt_timer_create("timer2", timeout2,
                             RT_NULL,  30,
                             RT_TIMER_FLAG_ONE_SHOT);

    /* 启动定时器 2 */
    if (timer2 != RT_NULL) rt_timer_start(timer2);
    return 0;
}

/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(timer_sample, timer sample);copymistakeCopy Success

The simulation results are as follows:

 \ | /
- RT -     Thread Operating System
 / | \     3.1.0 build Aug 24 2018
 2006 - 2018 Copyright by rt-thread team
msh >timer_sample
msh >periodic timer is timeout 0
periodic timer is timeout 1
one shot timer is timeout
periodic timer is timeout 2
periodic timer is timeout 3
periodic timer is timeout 4
periodic timer is timeout 5
periodic timer is timeout 6
periodic timer is timeout 7
periodic timer is timeout 8
periodic timer is timeout 9
periodic timer was stopped!copymistakeCopy Success

The timeout function of periodic timer 1 runs once every 10 OS ticks, for a total of 10 times (call rt_timer_stop after 10 times to stop timer 1); the timeout function of one-shot timer 2 runs once at the 30th OS tick.

The example of initializing a timer is similar to the example of creating a timer. This program will initialize two static timers, one for a single timer and one for a periodic timer, as shown in the following code:

Initialize static timer routine

#include <rtthread.h>

/* 定时器的控制块 */
static struct rt_timer timer1;
static struct rt_timer timer2;
static int cnt = 0;

/* 定时器 1 超时函数 */
static void timeout1(void* parameter)
{
    rt_kprintf("periodic timer is timeout\n");
    /* 运行 10 次 */
    if (cnt++>= 9)
    {
        cnt = 0;
        rt_timer_stop(&timer1);
    }
}

/* 定时器 2 超时函数 */
static void timeout2(void* parameter)
{
    rt_kprintf("one shot timer is timeout\n");
}

/* 检查,清理上次的定时器 */
static void check_timer_exist(void)
{
   if (rt_object_find("timer1", RT_Object_Class_Timer) != RT_NULL)
   {
       rt_timer_detach(&timer1);
   }
   if (rt_object_find("timer2", RT_Object_Class_Timer) != RT_NULL)
   {
       rt_timer_detach(&timer2);
   }
}

int timer_static_sample(void)
{
    /* 检查,清理上次的定时器 */
    check_timer_exist();
    /* 初始化定时器 */
    rt_timer_init(&timer1, "timer1",  /* 定时器名字是 timer1 */
                    timeout1, /* 超时时回调的处理函数 */
                    RT_NULL, /* 超时函数的入口参数 */
                    10, /* 定时长度,以 OS Tick 为单位,即 10 个 OS Tick */
                    RT_TIMER_FLAG_PERIODIC); /* 周期性定时器 */
    rt_timer_init(&timer2, "timer2",   /* 定时器名字是 timer2 */
                    timeout2, /* 超时时回调的处理函数 */
                      RT_NULL, /* 超时函数的入口参数 */
                      30, /* 定时长度为 30 个 OS Tick */
                    RT_TIMER_FLAG_ONE_SHOT); /* 单次定时器 */

    /* 启动定时器 */
    rt_timer_start(&timer1);
    rt_timer_start(&timer2);
    return 0;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(timer_static_sample, timer_static sample);copymistakeCopy Success

The simulation results are as follows:

\ | /
- RT -     Thread Operating System
 / | \     3.1.0 build Aug 24 2018
 2006 - 2018 Copyright by rt-thread team
msh >timer_static_sample
msh >periodic timer is timeout
periodic timer is timeout
one shot timer is timeout
periodic timer is timeout
periodic timer is timeout
periodic timer is timeout
periodic timer is timeout
periodic timer is timeout
periodic timer is timeout
periodic timer is timeout
periodic timer is timeoutcopymistakeCopy Success

The timeout function of periodic timer 1 runs once every 10 OS ticks, for a total of 10 times (call rt_timer_stop after 10 times to stop timer 1); the timeout function of one-shot timer 2 runs once at the 30th OS tick.

The minimum precision of the RT-Thread timer is determined by the system clock tick (1 OS Tick = 1/RT_TICK_PER_SECOND seconds, RT_TICK_PER_SECOND value is defined in the rtconfig.h file), and the time set by the timer must be an integer multiple of the OS Tick. When a shorter system timing is required, for example, the OS Tick is 10ms, and the program needs to implement 1ms timing or delay, the operating system timer will not be able to meet the requirements, and can only be read by reading the counter of a hardware timer in the system or directly using the hardware timer.

In the Cortex-M series, SysTick has been used by RT-Thread as OS Tick. It is configured to trigger an interrupt after 1/RT_TICK_PER_SECOND seconds. The interrupt handler uses the default SysTick_Handler name of Cortex-M3. The CMSIS (Cortex Microcontroller Software Interface Standard) specification of Cortex-M3 stipulates that SystemCoreClock represents the main frequency of the chip, so based on SysTick and SystemCoreClock, we can use SysTick to obtain an accurate delay function, as shown in the following example, the precise delay based on SysTick on Cortex-M3 (needs to be used after the system enables SysTick):

The high-precision delay routine is as follows:

#include <board.h>
void rt_hw_us_delay(rt_uint32_t us)
{
    rt_uint32_t ticks;
    rt_uint32_t told, tnow, tcnt = 0;
    rt_uint32_t reload = SysTick->LOAD;

    /* 获得延时经过的 tick 数 */
    ticks = us * reload / (1000000 / RT_TICK_PER_SECOND);
    /* 获得当前时间 */
    told = SysTick->VAL;
    while (1)
    {
        /* 循环获得当前时间,直到达到指定的时间后退出循环 */
        tnow = SysTick->VAL;
        if (tnow != told)
        {
            if (tnow < told)
            {
                tcnt += told - tnow;
            }
            else
            {
                tcnt += reload - tnow + told;
            }
            told = tnow;
            if (tcnt >= ticks)
            {
                break;
            }
        }
    }
}copymistakeCopy Success

The entry parameter us indicates the number of microseconds required for delay. This function can only support delays less than 1 OS Tick.

Note: This interface should be implemented by the BSP maker according to the specific chip characteristics. The above code is for reference only!

Last updated

Assoc. Prof. Wiroon Sriborrirux, Founder of Advance Innovation Center (AIC) and Bangsaen Design House (BDH), Electrical Engineering Department, Faculty of Engineering, Burapha University