stm32 system tick timer use

Publisher:紫菜包饭Latest update time:2018-12-21 Source: eefocusKeywords:stm32 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

1. Systick Introduction

     Systick is just a timer, but it is placed in NVIC. Its main purpose is to provide a hardware interrupt (called tick interrupt) to the operating system . Tick interrupt? Here is a brief explanation. When the operating system is running, it will also have a "heartbeat". It will work according to the beat of the "heartbeat", dividing the entire time period into many small time slices. Each task can only run for the length of a "time slice" at a time and must exit to let other tasks run. This ensures that no task will occupy the entire system. Or a certain time range of each timer cycle is given to a specific task, etc., and the various timing functions provided by the operating system are all related to this tick timer. Therefore, a timer is needed to generate periodic interrupts, and it is best not to allow user programs to access its registers at will to maintain the rhythm of the operating system's "heartbeat". As long as its enable bit in the SysTick control and status register is not cleared, it will never stop.

     After knowing the position of systick in the system, let's learn about the implementation of systick. Here is just an example to illustrate the use of systick. It has four registers, which I list below:

    SysTick->CTRL, --control and status register

    SysTick->LOAD, --Reload register

    SysTick->VAL, --current value register

   SysTick->CALIB, --calibration value register    

The following figure has their respective descriptions: The following figure reference address: http://blog.csdn .NET /marike1314/article/details/5673684

2. Systick programming

    Now we want to use the Systick timer to make a precise delay function, such as making the LED flash once with a delay of exactly 1 second.

    Idea: Use the Systick timer as a down counter. After setting the initial value and enabling it, it will decrement the counter every 1 system clock cycle. When the count reaches 0, the SysTick counter automatically reloads the initial value and continues counting, triggering an interrupt at the same time.

Then each time the counter is reduced to 0, the time that has passed is: system clock cycle * counter initial value. We use 72M as the system clock, so the time it takes for the counter to be reduced by 1 each time is 1/72M. If the initial value of the counter is 72000, then each time the counter is reduced to 0, the time that has passed is (1/72M)*72000= 0.001, that is, 1ms. (Simple understanding: using a clock frequency of 72M, that is, 1s counts 72M=72000000 times, then 1ms counts 72000 times, so the count value is 72000) 

 

First, we need a 72M systick system clock, so just use the following clock!

    SystemInit();

    This function can make the main frequency run to 72M. It can be used as the clock source of systick.

    Then start configuring systick. In fact, the strict process of configuring systick is as follows:

    1. Call SysTick_CounterCmd() -- disable SysTick counter

    2. Call SysTick_ITConfig() -- disable SysTick interrupt

    3. Call SysTick_CLKSourceConfig() -- set the SysTick clock source.

    4. Call SysTick_SetReload() -- sets the SysTick reload value.

    5. Call SysTick_ITConfig() -- Enable SysTick interrupt

    6. Call SysTick_CounterCmd() -- turn on the SysTick counter                                                      

    Here everyone must pay attention that the current register value VAL must be equal to 0!

    SysTick->VAL = (0x00); The counter is automatically reloaded RELOAD only when the VAL value is 0.

Next, you can directly call the Delay() function to delay. In the implementation of the delay function, it should be noted that the global variable TimingDelay must use volatile, otherwise it may be optimized by the compiler.

Let's do some program analysis:

(1) System clock configuration

First, we configured the system clock and the SetSysClock(void) function used 72M as the system clock;

In order to see the code clearly, I chose to take a screenshot:

(2) Let’s take a look at the main function first

  1. int main(void)  

  2.   

  3. {            unsigned char i=0;  

  4.   

  5.         unsigned char a[] = "abncdee";  

  6.   

  7.           

  8.   

  9.         SystemInit1(); //System initialization  

  10.   

  11.    

  12.   

  13.        if (SysTick_Config(72000)) //1ms response to an interrupt  

  14.   

  15.         {   

  16.   

  17.             /* Capture error */  

  18.   

  19.                  while (1);  

  20.   

  21.         }   

  22.   

  23.         /*Analysis: Because the requirement is to send data to the intermediate computer every 500ms, it is placed in the while statement.  

  24.   

  25. *Sending data + delay can achieve the effect equivalent to interruption;  

  26.   

  27.                *If one of the tasks in multi-tasking needs to be interrupted, call this task in the interrupt function;  

  28.   

  29.                */  

  30.   

  31.         while (1)  

  32.   

  33.         {  

  34.   

  35.              //Test code: Test the timer function by delaying the test  

  36.   

  37.    

  38.   

  39.              GPIO_SetBits(GPIOC, GPIO_Pin_6);      //V6  

  40.   

  41.              Delay(50);  

  42.   

  43.              GPIO_ResetBits(GPIOC, GPIO_Pin_6);         //V6  

  44.   

  45.              Delay(50);  

  46.   

  47.                         

  48.   

  49.             //Function 1 code: send data every 500ms  

  50.   

  51.                /*  

  52.   

  53.                       UART2_TX485_Puts("123450");  

  54.   

  55.                       Delay(500);  

  56.   

  57.            */  

  58.   

  59.             //Function 2 code: The upper computer sends a specific instruction, and the middle computer performs the corresponding operation  

  60.   

  61.               //     RS485_Test();  

  62.   

  63.               }       

  64.   

  65. }  

int main(void)


{            unsigned char i=0;


        unsigned char a[] = "abncdee";


        


        SystemInit1(); //System initialization


 


       if (SysTick_Config(72000)) //1ms response to an interrupt


        { 


            /* Capture error */


                 while (1);


        } 


        /*Analysis: Because the requirement is to send data to the intermediate computer every 500ms, it is placed in the while statement.


*Sending data + delay can achieve the effect equivalent to interruption;


               *If one of the tasks in multi-tasking needs to be interrupted, call this task in the interrupt function;


               */


        while (1)


        {


             //Test code: Test the timer function by delaying the test


 


             GPIO_SetBits(GPIOC, GPIO_Pin_6);      //V6


             Delay(50);


             GPIO_ResetBits(GPIOC, GPIO_Pin_6);         //V6


             Delay(50);


                      


            //Function 1 code: send data every 500ms


               /*


                      UART2_TX485_Puts("123450");


                      Delay(500);


           */


            //Function 2 code: The upper computer sends a specific instruction, and the middle computer performs the corresponding operation


              //     RS485_Test();


              }     


}

(3) Configuration of the system tick timer - the protagonist appears:

In the main function: SysTick_Config(72000); the parameter of the tick timer is 72000, which means the count is 72000

(Because we use a clock frequency of 72M, that is, 1s counts 72M=72000000 times, then 1ms counts 72000 times, so the count value is 72000) 

In the file Core_cm3.h

The specific implementation of the SysTick_Config function is as follows:

static __INLINE uint32_t SysTick_Config(uint32_t ticks)  

  

{   

  

    if (ticks>SYSTICK_MAXCOUNT)    

  

     return (1);      /* Reload value impossible */  

  

    SysTick->LOAD = (ticks & SYSTICK_MAXCOUNT) - 1; //systick reload value register /* set reload register */  

  

    NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */  

  

    SysTick->VAL = (0x00); //systick current value register                                

  

   /* Load the SysTick Counter Value */  

   SysTick->CTRL = (1 << SYSTICK_CLKSOURCE) | (1<

  

}     

           

static __INLINE uint32_t SysTick_Config(uint32_t ticks)

 

 

    if (ticks>SYSTICK_MAXCOUNT)  

 

     return (1);      /* Reload value impossible */

 

    SysTick->LOAD = (ticks & SYSTICK_MAXCOUNT) - 1; //systick reload value register /* set reload register */

 

    NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */

 

    SysTick->VAL = (0x00); //systick current value register                              

 

   /* Load the SysTick Counter Value */

   SysTick->CTRL = (1 << SYSTICK_CLKSOURCE) | (1<

}  

Let's take a look at this code: SysTick->CTRL = (1 << SYSTICK_CLKSOURCE) | (1<

Let's take a look at the stm32f10x_it.h file:

Find the tick timer interrupt function: SysTickHandler()

void SysTickHandler(void)

{

    TimingDelay_Decrement();

}

From the above, we know that an interrupt occurs every 1ms through the loaded count value 72000. In the interrupt function, a function TimingDelay_Decrement() is called; ----- that is, this function is called every 1ms when an interrupt occurs;

Let's take a look at what TimingDelay_Decrement(); is doing.

                                     

/*****************************************************************  

  

*Function name: TimingDelay_Decrement  

  

*Function description: This function is called in an interrupt, that is, no interrupt occurs, this function is called, in this function       

  

* The variable TimingDelay is equivalent to a subtraction counter  

  

*   

  

*Input parameters: None  

  

*Return value: None  

  

*Other Notes: None  

  

*Current version: v1.0  

  

*Author: Liang Yinxuan  

  

*Completion date: August 3, 2012  

  

*Modification date Version number Modifier Modification content  

  

*-----------------------------------------------------------------  

  

*  

  

******************************************************************/  

  

     

  

void TimingDelay_Decrement(void)    

  

{    

  

    

  

  if (TimingDelay != 0x00)    

  

  {     

  

    TimingDelay--;    

  

  }  

  

}    

  

We looked at the definition of TimingDelay and saw which other functions call this variable, as follows:  

  

/*****************************************************************  

  

* Global variables  

  

******************************************************************/  

  

   

  

static __IO uint32_t TimingDelay=0;  

  

           

  

/*****************************************************************  

  

*Function name: Delay  

  

*Function description: Use the system clock counter to decrement to achieve the delay function  

  

*   

  

*Input parameter: nTime: the number of milliseconds required to delay  

  

*Return value: None  

  

*Other Notes: None  

  

*Current version: v1.0  

  

*Author: Liang Yinxuan  

  

*Completion date: August 3, 2012  

  

*Modification date Version number Modifier Modification content  

  

*-----------------------------------------------------------------  

  

*  

  

******************************************************************/  

  

   

  

void Delay(__IO uint32_t nTime) //When delay is called, nTime=500  

  

{   

  

  TimingDelay = nTime;  

  

   

  

  while(TimingDelay != 0);  

  

}  

/*****************************************************************

 

*Function name: TimingDelay_Decrement

 

*Function description: This function is called in an interrupt, that is, no interrupt occurs, this function is called, in this function     

 

* The variable TimingDelay is equivalent to a subtraction counter

 

 

*Input parameters: None

 

*Return value: None

 

*Other Notes: None

 

*Current version: v1.0

 

*Author: Liang Yinxuan

 

*Completion date: August 3, 2012

 

*Modification date Version number Modifier Modification content

 

*-----------------------------------------------------------------

 

*

 

******************************************************************/

 

   

 

void TimingDelay_Decrement(void)  

 

{  

 

  

 

  if (TimingDelay != 0x00)  

 

  {   

 

    TimingDelay--;  

 

  }

 

}  

 

We looked at the definition of TimingDelay and saw which other functions call this variable, as follows:

 

/*****************************************************************

 

* Global variables

 

******************************************************************/

 

 

 

static __IO uint32_t TimingDelay=0;

 

         

 

/*****************************************************************

 

*Function name: Delay

 

*Function description: Use the system clock counter to decrement to achieve the delay function

 

 

*Input parameter: nTime: the number of milliseconds required to delay

 

*Return value: None

 

*Other Notes: None

 

*Current version: v1.0

 

*Author: Liang Yinxuan

 

*Completion date: August 3, 2012

 

*Modification date Version number Modifier Modification content

 

*-----------------------------------------------------------------

 

*

 

******************************************************************/

 

 

 

void Delay(__IO uint32_t nTime) //When delay is called, nTime=500

 

 

  TimingDelay = nTime;

 

 

 

  while(TimingDelay != 0);

 

}

Through the above functions, we know that when calling Delay(500), nTime=500; then in the Delay() function, TimingDelay =nTime; (that is, TimingDelay=500 is its initial value), and then the function of TimingDelay_Decrement(void) is to decrement TimingDelay- -; every millisecond until it reaches 0; this plays a role of delay;

Now the Delay(1) we created is 1 millisecond delay, and Delay(1000) is 1 second.

  Let's draw a picture to facilitate the understanding of the relationship between these functions:

Let's return to the main function main() and look at these statements:

while (1)  

  

        {  

  

             //Test code: Test the timer function by delaying the test  

  

             GPIO_SetBits(GPIOC, GPIO_Pin_6);      //V6   

  

             Delay(500);  

  

             GPIO_ResetBits(GPIOC, GPIO_Pin_6);         //V6   

  

             Delay(500);  

  

                        

  

            //Function 1 code: send data every 500ms  

  

               /*  

  

                      UART2_TX485_Puts("123450");  

  

                      Delay(500);  

  

           */  

  

            //Function 2 code: The upper computer sends a specific instruction, and the middle computer performs the corresponding operation  

  

              //     RS485_Test();  

  

              }       

while (1)

 

        {

 

             //Test code: Test the timer function by delaying the test

 

             GPIO_SetBits(GPIOC, GPIO_Pin_6);      //V6 

 

             Delay(500);

 

             GPIO_ResetBits(GPIOC, GPIO_Pin_6);         //V6 

 

             Delay(500);

 

                      

 

            //Function 1 code: send data every 500ms

 

               /*

 

                      UART2_TX485_Puts("123450");

 

                      Delay(500);

 

           */

 

            //Function 2 code: The upper computer sends a specific instruction, and the middle computer performs the corresponding operation

 

              //     RS485_Test();

 

              }     

After analyzing the system timer above, we know that Delay(500); means a delay of 500ms; then the LED flashes every 500ms;

The above explanation about the application of system tick timer is basically completed!

 Regarding the source code package compiled by SysTick, (in fact, if you are careful, you will find that the above code contains 485 communication code,

It's just temporarily blocked, which will be discussed in the next section) I put it in my resources: http://download.csdn.net/detail/yx_l128125/4511622

 

Let’s take a look at the reference material to get a deeper understanding of the blog I wrote above:

The Definitive Guide to Cortex-M3

《Cortex-M3 Technical Reference Manual》

Q: What is the SYSTick timer?

SysTick is a 24-bit countdown timer. When it reaches 0, it will automatically reload the initial value of the timer from the RELOAD register. As long as the enable bit in the SysTick control and status register is not cleared, it will never stop.

Q: Why do we need to set the SysTick timer?

(1) Generate the clock beat of the operating system

The SysTick timer is bundled in the NVIC and is used to generate the SYSTICK exception (exception number: 15). In the past, most operating systems required a hardware timer to generate the tick interrupt required by the operating system as the time base of the entire system. Therefore, a timer is needed to generate periodic interrupts, and it is best not to allow user programs to access its registers at will to maintain the rhythm of the operating system's "heartbeat".

(2) Facilitates program porting between different processors.

The Cortex-M3 processor contains a simple timer. Because all CM3 chips have this timer, software migration between different CM3 devices is simplified. The clock source of this timer can be an internal clock (FCLK, the free-running clock on CM3) or an external clock (STCLK signal on CM3 processors).

However, the specific source of STCLK is determined by the chip designer, so the clock frequency between different products may be very different. You need to check the device manual of the chip to decide what to choose as the clock source. The SysTick timer can generate an interrupt, and CM3 has a special exception type for it, and it has a place in the vector table. It makes it much easier to port the operating system and other system software between CM3 devices, because it is handled the same in all CM3 products.

(3) As an alarm to measure time.

In addition to serving the operating system, the SysTick timer can also be used for other purposes: as an alarm, for measuring time, etc. It should be noted that when the processor is halted during debugging, the SysTick timer will also be suspended.

Q: How does Systick work?

First, set the counter clock source, CTRL->CLKSOURCE (control register). Set the reload value (RELOAD register), clear the count register VAL (CURRENT in the figure below). Set CTRL->ENABLE to start timing.

If it is an interrupt, then Systick interrupt is enabled and processed in the interrupt routine. If the query mode is used, then the COUNTFLAG flag bit of the control register is continuously read to determine whether the timing has reached zero. Or, one of the following methods can be used:

When the SysTick timer counts from 1 to 0, it will set the COUNTFLAG bit; the following method can clear it:

1. Read the SysTick Control and Status Register (STCSR)

2. Write any data to the SysTick Current Value Register (STCVR)

The counter is automatically reloaded with RELOAD only when the VAL value is 0.

Q: How to use SysTicks as system clock?

The biggest mission of SysTick is to generate exception requests regularly as the system time base. The OS needs this "tick" to promote task and time management. To enable SysTick exceptions, set STCSR.TICKINT. In addition, if the vector table is relocated to SRAM, it is also necessary to create a vector for the SysTick exception and provide the entry address of its service routine.


Keywords:stm32 Reference address:stm32 system tick timer use

Previous article:STM32 Introduction - General Timer Configuration
Next article:Three methods of STM32 delay function - it is best to master the third one

Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号