RT-Thread Timer Explained using STM32 – RT-Thread Tutorial Part 3

This article is a continuation of the  Series on RT-Thread STM32 Tutorials and carries the discussion on RT-Thread RTOS and implementation with STM32. The aim of this series is to provide easy and practical examples that anyone can understand. In our last post, we have seen Threads in the RT-Thread RTOS. In this post, we will see the RT-Thread RTOS Timer Management.

You can see the video explanation of Getting started with the RT-Thread RTOS.

Prerequisites

This is the continuation of the below tutorials. If you don’t read it, please read that also before this.

Tools and Components Required

  • STM32F411 Dev Board (You can use any STM32F4 controller)
  • RT-Thread Studio

Timer

A timer (sometimes referred to as a counter) is a special piece of hardware inside many microcontrollers. Timers play an essential role in embedded systems, and In any MCU timer is one of the most essential features. Without a timer all time critical operations won’t work.

Clock tick

The smallest time unit in the operating system is the clock tick (OS Tick).  It is simply 1 clock cycle. The microcontroller and all its peripherals run with respect to a continuous square wave. In every clock cycle, it increments the clock ticks by running one line of assembly code. A clock tick is a specific periodic interrupt. This interrupt can be regarded as the system heartbeat. In FreeRTOS, they call it as SysTicks.

Any operating system needs to provide a clock tick for the system to handle all time-related events, such as thread latency, thread time slice rotation scheduling, timer timeout, etc.

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

Timer operation modes

Timers can operate in 2 modes 

  • One-time mode (One Shot mode) and 
  • Periodic mode

One-time mode

In One-time mode, we can set the timer to go off after a particular time duration, say 10 ms. Once started, the timer counts down and once it runs out it notifies the core and the timer gets disabled. This action is very similar to using a stopwatch in countdown mode.

Periodic mode

In periodic mode, once the timer runs out, it notifies the core, then instead of getting disabled, it automatically reloads the initial value and starts counting down again. Basically, all this mode does extra compared to the One-time mode is just the auto-restart! 

Types of timers in RT-Thread

Two types of timers are available in the RT-Thread.

  • Hardware Timer
  • Software Timer

Hardware timer 

It is the timing function provided by the chip itself. The hardware timer can be used by configuring the timer module into timer mode and setting the time. The hardware timer is accurate to nanosecond precision and it executes in an interrupt context. So, the execution time should be as short as possible, and the execution should not cause the current context to suspend and wait.

Software timer 

It is a type of system interface provided by the operating system. It is built on the basis of the hardware timer to enable the system to provide a timer service with no constraint on numbers. This executes in thread context.

RT-Thread Timer APIs

Get Clock Tick

The below API is used to get the current clock tick in the RT-Thread.

rt_tick_t rt_tick_get(void);

The function returns the Current clock tick value.

Timer Management System Initialize

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

void rt_system_timer_init(void);

If you need to use the soft timer, then use the below function interface.

void rt_system_timer_thread_init(void);

Create the timer

There are two ways we can create the timer.

  • Dynamic creation
  • Static creation

You can use the below API to create the timer Dynamically.

rt_timer_t rt_timer_create(const char* name,
                           void (*timeout)(void* parameter),
                           void* parameter,
                           rt_tick_t time,
                           rt_uint8_t flag);
ParametersDescription
nameName of the timer
void (timeout) (void parameter)Timer timeout function pointer (this function is called when the timer expires)
parameterEntry parameter of the timer timeout function (when the timer expires, calling the timeout callback function will pass this parameter as the entry parameter to the timeout function)
timeTimeout of the timer, the unit is the clock tick
flagParameters when the timer is created. The supported values include one-shot timing, periodic timing, hardware timer, software timer, etc. (You can use multiple values with “OR”)
Return——
RT_NULLCreation failed (usually returning RT_NULL due to insufficient system memory)
Timer HandleTimer was created successfully.

You can use the below API for static timer creation.

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);
ParametersDescription
timerTimer handle, pointing to the to-be-initialized timer control block
nameName of the timer
void (timeout) (void parameter)Timer timeout function pointer (this function is called when the timer expires)
parameterEntry parameter of the timer timeout function (when the timer expires, the call timeout callback function will pass this parameter as the entry parameter to the timeout function)
timeTimeout of the timer, the unit is a clock tick
flagParameters of when the timer is created. The supported values include one-shot timing, periodic timing, hardware timer, and software timer (multiple values can be taken with OR). For details, see Creating a Timer.

Delete the timer

If you have created the timer using the dynamic method, then you can use the below function to delete the timer.

rt_err_t rt_timer_delete(rt_timer_t timer);

If you have created the timer using the static method, then you can use the below function to delete the timer.

rt_err_t rt_timer_detach(rt_timer_t timer);

Start and Stop Timer

Once you create and initialize the timer, it won’t start running immediately. We need to start it manually by using the below function.

rt_err_t rt_timer_start(rt_timer_t timer);

If you want to stop the timer, you can use the below function.

rt_err_t rt_timer_stop(rt_timer_t timer);

Control the Timer

You can control the timer when it is running. The below function is used to set the time, get the time, and change the mode to one-shot or periodic and many.

rt_err_t rt_timer_control(rt_timer_t timer, rt_uint8_t cmd, void* arg);
ParametersDescription
timerTimer handle
cmdThe command for controlling the timer currently supports four command interfaces, which are setting timing, viewing the timing time, setting a one-shot trigger, and setting the periodic trigger, etc.
argControl command parameters corresponding to cmd. For example, when cmd is the set timeout time, the timeout time parameter can be set by arg.
Return——
RT_EOKSuccessful

Commands supported by function parameters cmd:

#define RT_TIMER_CTRL_SET_TIME          0x0             /**< set timer control command */
#define RT_TIMER_CTRL_GET_TIME          0x1             /**< get timer control command */
#define RT_TIMER_CTRL_SET_ONESHOT       0x2             /**< change timer to one shot */
#define RT_TIMER_CTRL_SET_PERIODIC      0x3             /**< change timer to periodic */
#define RT_TIMER_CTRL_GET_STATE         0x4             /**< get timer run state active or deactive*/
#define RT_TIMER_CTRL_GET_REMAIN_TIME   0x5             /**< get the remaining hang time */

Example Source Code

In the below code, we have tried to explain all the possible scenarios in the RT-Thread Timer.

We have created 4 timers in the example.

Timer 1

Timer 1 is a Dynamic periodic timer that executes every 1 second.

Timer 2

Timer 2 is a Dynamic one-shot timer. The time of that timer is 2 seconds. So, it will call the callback after 2 seconds and it won’t call that callback again like the periodic timer.

Timer 3

Timer 3 is a Static periodic timer that executes every 3 seconds. Once the count reaches to 3, then we are getting the time of the timer 3 and stop that timer. So, the timer callback function won’t be called again as we stopped the timer.

Timer 4

Timer 4 is a Dynamic soft periodic timer that executes every 4 seconds.

You can also get the below entire project from GitHub.

/*
 * Copyright (c) 2006-2023, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2023-02-14     RT-Thread    first version
 */

#include <rtthread.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

/* Timer Control Block */
static rt_timer_t timer1;           //Dynamic Periodic timer
static rt_timer_t timer2;           //Dynamic One shot timer
static struct rt_timer timer3;      //Static Periodic timer
static rt_timer_t timer4;           //Dynamic Periodic soft timer

int32_t count = 0;

/* Timer 1 Function */
static void timer_1_callback(void *parameter)
{
    LOG_D("Timeout: Timer 1 Function!!!");
}

/* Timer 2 Function */
static void timer_2_callback(void *parameter)
{
    LOG_D("Timeout: Timer 2 Function!!!");
}

/* Timer 3 Function */
static void timer_3_callback(void *parameter)
{
    LOG_D("Timeout: Timer 3 Function!!!");

    if( count++ >= 2 )
    {
        rt_tick_t timeNow;

        //get time
        rt_timer_control( &timer3, RT_TIMER_CTRL_GET_TIME, &timeNow );

        //Stop timer
        rt_timer_stop(&timer3);

        LOG_D("Timer 3 Time is %dms, Stopping Timer 3", timeNow);
    }
}

/* Timer 4 Function */
static void timer_4_callback(void *parameter)
{
    LOG_D("Timeout: Timer 4 Function!!!");
}

int main(void)
{
    /* Create Timer 1 Periodic Timer */
    timer1 = rt_timer_create( "Timer1",
                              timer_1_callback,
                              RT_NULL,
                              1000,
                              RT_TIMER_FLAG_PERIODIC );

    /* Start Timer 1*/
    if (timer1 != RT_NULL)
    {
        rt_timer_start(timer1);
    }

    /* Create Timer 2 One Shot Timer */
    timer2 = rt_timer_create( "Timer2",
                              timer_2_callback,
                              RT_NULL,
                              2000,
                              RT_TIMER_FLAG_ONE_SHOT );

    /* Start Timer 2 */
    if (timer2 != RT_NULL)
    {
        rt_timer_start(timer2);
    }

    /* Create Timer 3 Static Periodic Timer */
     rt_timer_init(  &timer3,
                     "Timer3",
                     timer_3_callback,
                     RT_NULL,
                     3000,
                     RT_TIMER_FLAG_PERIODIC );

    /* Start Timer 3*/
    rt_timer_start(&timer3);

    /* Create Timer 4 Periodic Soft Timer */
    timer4 = rt_timer_create( "Timer4",
                              timer_4_callback,
                              RT_NULL,
                              4000,
                              RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER );

    /* Start Timer 4 */
    if (timer4 != RT_NULL)
    {
        rt_timer_start(timer4);
    }

    return RT_EOK;
}

Output

 \ | /
- RT -     Thread Operating System
 / | \     4.0.3 build Feb 14 2023
 2006 - 2020 Copyright by rt-thread team
msh >←[0m[D/main] Timeout: Timer 1 Function!!!←[0m
←[0m[D/main] Timeout: Timer 2 Function!!!←[0m
←[0m[D/main] Timeout: Timer 1 Function!!!←[0m
←[0m[D/main] Timeout: Timer 3 Function!!!←[0m
←[0m[D/main] Timeout: Timer 1 Function!!!←[0m
←[0m[D/main] Timeout: Timer 1 Function!!!←[0m
←[0m[D/main] Timeout: Timer 4 Function!!!←[0m
←[0m[D/main] Timeout: Timer 1 Function!!!←[0m
←[0m[D/main] Timeout: Timer 3 Function!!!←[0m
←[0m[D/main] Timeout: Timer 1 Function!!!←[0m
←[0m[D/main] Timeout: Timer 1 Function!!!←[0m
←[0m[D/main] Timeout: Timer 1 Function!!!←[0m
←[0m[D/main] Timeout: Timer 4 Function!!!←[0m
←[0m[D/main] Timeout: Timer 3 Function!!!←[0m
←[0m[D/main] Timer 3 Time is 3000ms, Stopping Timer 3←[0m
←[0m[D/main] Timeout: Timer 1 Function!!!←[0m
←[0m[D/main] Timeout: Timer 1 Function!!!←[0m
←[0m[D/main] Timeout: Timer 1 Function!!!←[0m
←[0m[D/main] Timeout: Timer 1 Function!!!←[0m
←[0m[D/main] Timeout: Timer 4 Function!!!←[0m
←[0m[D/main] Timeout: Timer 1 Function!!!←[0m
←[0m[D/main] Timeout: Timer 1 Function!!!←[0m
←[0m[D/main] Timeout: Timer 1 Function!!!←[0m
←[0m[D/main] Timeout: Timer 1 Function!!!←[0m
←[0m[D/main] Timeout: Timer 4 Function!!!←[0m
←[0m[D/main] Timeout: Timer 1 Function!!!←[0m

What’s Next

In our following tutorial, we will see the RT-Thread Synchronization (Semaphore).

You can also read the below tutorials.

Linux Device Driver TutorialsC Programming Tutorials
FreeRTOS TutorialsNuttX RTOS Tutorials
RTX RTOS TutorialsInterrupts Basics
I2C Protocol – Part 1 (Basics)I2C Protocol – Part 2 (Advanced Topics)
STM32 TutorialsLPC2148 (ARM7) Tutorials
PIC16F877A Tutorials8051 Tutorials
Unit Testing in C TutorialsESP32-IDF Tutorials
Raspberry Pi TutorialsEmbedded Interview Topics
Reset Sequence in ARM Cortex-M4BLE Basics
VIC and NVIC in ARMSPI – Serial Peripheral Interface Protocol
STM32F7 Bootloader TutorialsRaspberry PI Pico Tutorials
STM32F103 Bootloader TutorialsRT-Thread RTOS Tutorials
Zephyr RTOS Tutorials – STM32Zephyr RTOS Tutorials – ESP32
AUTOSAR TutorialsUDS Protocol Tutorials
Product ReviewsSTM32 MikroC Bootloader Tutorial
VHDL Tutorials
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Table of Contents