While my roommate was playing the peak game, I quietly learned the SysTick timer of STM32

Posted by turtlefox on Sun, 30 Jan 2022 01:45:51 +0100

CSDN blog home page
ID : Eterlove
One by one, record my study and life! Standing on the shoulders of giants
of Giants!
This article is original, please indicate the source and author!

preface

We often use delay to complete some project requirements, and often use the software delay achieved by CPU empty cycle to realize it. Its method has the advantages of simple, but there will be the problem of low time accuracy. Moreover, this is an obvious disadvantage, because the system cannot carry out other operations when the delay function is in progress, which greatly reduces the efficiency of the system.
The second way is to use the timer TIM to achieve accurate delay, but it seems to be a waste of resources. At this time, the SysTick timer of STM32 comes in handy. However, ST does not describe much about the SysTick timer in STM32Reference manual, so it records its experience in the blog.

//Software delay reached by empty cycle
void Delay_ms(unsigned int ms)
{
  unsigned int i,j;
  
  for(i=0; i<ms; i++)
  {
    for(j=0; j<8450; j++)  ;
  }
}

1. Introduction to systick timer

There is a Systick timer in the ARM Cortex-M3 core, which is a 24 bit countdown timer. When the count reaches 0, it will automatically reload the initial timing value from the Load register.
STM32Reference manual
RCC is used as the external clock of Cortex system timer (SysTick) after frequency division by AHB clock (HCLK)8. By setting the SysTick control and status register, the above clock or Cortex(HCLK) clock can be selected as the SysTick clock. The ADC clock is obtained by dividing the high-speed APB2 clock by 2, 4, 6 or 8.

The English version is STM32Reference manual Rev 21
The RCC feeds the Cortex® System Timer (SysTick) external clock with the AHB clock (HCLK) divided by 8. The SysTick can work either with this clock or with the Cortex® clock (HCLK), configurable in the SysTick Control and Status register. The ADCs are clocked by the clock of the High Speed domain (APB2) divided by 2, 4, 6 or 8.

As shown in the above figure and text, SysTick timer has two clock sources, one is the clock of HCLK after 8 frequency division – > HCLK / 8 (actually 72MHZ/8 = 9MHZ), and the other is the clock of HCLK without frequency division – > HCLK (72MHZ)

In misc H file P172 line has SysTick_clock_source macro definition of clock source!

//misc.h at line P172 of the document
/** @defgroup SysTick_cl
ock_source 
  * @{
  */
#define SysTick_CLKSource_HCLK_Div8    ((uint32_t)0xFFFFFFFB)
#define SysTick_CLKSource_HCLK         ((uint32_t)0x00000004)

2. Register of systick

Let's first look at the definition in the ST library function, which is in the core_cm3.h file P365 ~ P371 lines

//core_cm3.h file P365 ~ P371 lines
typedef struct
{
  __IO uint32_t CTRL;                         /*!< Offset: 0x00  SysTick Control and Status Register */
  __IO uint32_t LOAD;                         /*!< Offset: 0x04  SysTick Reload Value Register       */
  __IO uint32_t VAL;                          /*!< Offset: 0x08  SysTick Current Value Register      */
  __I  uint32_t CALIB;                        /*!< Offset: 0x0C  SysTick Calibration Register        */
} SysTick_Type;

Register introduction
CTRL - > systick control and status register
Load - > systick reload value register reload value register
Val -------- > systick current value register
Calib - > systick calibration value register


SysTick Control and Status Register

For more details on registers, please refer to the documentation Cortex ™- M3 r1p1 technical reference manual (TRM) , not listed here.

SysTick_ The config() function is a CMSIS function. It configures the SysTick Reload register, and its value is passed as a function parameter.

//core_ cm3. H line p1694 ~ line P1705
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{ 
  if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            /* Reload value impossible */
                                                               
  SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Cortex-M0 System Interrupts */
  SysTick->VAL   = 0;                                          /* Load the SysTick Counter Value */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk | 
                   SysTick_CTRL_TICKINT_Msk   | 
                   SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */
  return (0);                                                  /* Function successful */
}

3. Steps to configure SysTick timer

1. Configure clock source
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)

//In misc C Documents
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)
{
  /* Check the parameters */
  assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));
  if (SysTick_CLKSource == SysTick_CLKSource_HCLK)
  {
    SysTick->CTRL |= SysTick_CLKSource_HCLK;
  }
  else
  {
    SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;
  }
}	

2. Calculate the overload value
Reload Value = SysTick Counter Clock (Hz) x Desired Time base (s)
3. Enable SysTick interrupt
4. Enable SysTick counter

4. Program code (detailed notes)

#include "stm32f10x.h" / / include the required header file
#include "delay.h"
/*-------------------------------------------------*/
/*Function name: initialize delay counter function                     */
/*Parameter: None                                       */
/*Return value: None                                       */
/*-------------------------------------------------*/
void Delay_Init(void)
{
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
	//SysTick_CLKSource_HCLK_Div8 = 8 indicates the frequency division coefficient
	//Because the frequency division coefficient is set to 8, the frequency of SysTick is 1 / 8 of the main frequency
	//Generally, the dominant frequency is 72M, so the frequency of SysTick is 9M
	//Then one number of SysTick counter represents (1/9)us
}

/*-------------------------------------------------*/
/*Function name: delay microsecond function                             */
/*Parameter: us: how many microseconds is the delay                         */
/*Return value: None                                       */
/*-------------------------------------------------*/
void delay_us(unsigned int us)
{		
	unsigned int temp;	                      //Define a variable to be used    	 
	
	SysTick->LOAD=us*9;                       //The overload value of the counter. Note that SysTick counts down
	                                          //Each countdown of SysTick counter is 1 / 9 microsecond, so we use us*9, which is the overload value of the counter
	SysTick->VAL=0x00;                        //Clear the value of the current counter
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;  //Enable the SysTick counter, load the overload value into the counter and start the countdown
	do{
		temp=SysTick->CTRL;                   //The SysTick status register is read circularly to judge whether the timing is over or not
	}while(temp&0x01&&!(temp&(1<<16)));       //Waiting time arrives
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;  //Turn off counter 
}

/*-------------------------------------------------*/
/*Function name: delay millisecond function                             */
/*Parameter: ms: how many milliseconds is the delay                         */
/*Return value: None                                       */
/*-------------------------------------------------*/
void delay_ms(unsigned int ms)
{
	//First of all, we should pay attention to a problem. The SysTick clock counter is 24 bits and can delay 1864.135ms in total at 9M frequency
	//All of us take 1800 as the boundary. The delay less than 1800 can be counted once, and the delay greater than 1800 can be counted many times	
	
	unsigned char i;      //Define a variable to be used  
	unsigned int temp;    //Define a variable to be used  
	
	/*-----------if Judge that if the delay is less than 1800ms, execute the if branch------------------*/
	if(ms<1800){                                   
		SysTick->LOAD=(unsigned int)ms*9*1000;     //The overload value of the counter. Note that SysTick counts down        
		                                           //The number of SysTick counts is 1 / 9 microsecond. If it is converted into ms, multiply by 9 and then multiply by 1000, which is the overload value of the counter
		SysTick->VAL=0x00;                         //Clear the value of the current counter
		SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;   //Enable the SysTick counter, load the overloaded value into the counter and start counting down
		do{
			temp=SysTick->CTRL;                    //Cycle to read SysTick status register and judge whether the timing is over or not
		}while(temp&0x01&&!(temp&(1<<16)));        //Waiting time arrives
		SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;}  //Turn off counter 
	
	/*--------------When the delay is greater than 1800ms, execute else branch-------------------*/
	else{ 
		for(i=0;i<(ms/1800);i++){                     //Divide by 1800, integer part, use for loop, delay 1800ms each time
			SysTick->LOAD=(unsigned int)1800*9*1000;  //The overload value of the counter. Note that SysTick counts down        
													  //SysTick is 1 / 9 microsecond, 1800 ms is 1800 * 9 * 1000
			SysTick->VAL=0x00;                        //Clear the value of the current counter
			SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;  //Enable the SysTick counter, load the overloaded value into the counter and start counting down
			do{
				temp=SysTick->CTRL;                   //Cycle to read SysTick status register and judge whether the timing is over or not
			}while(temp&0x01&&!(temp&(1<<16)));       //Waiting time arrives
			SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;} //Turn off counter 
		
		//Next, the delay of the remainder
		SysTick->LOAD=(unsigned int)(ms%1800)*9*1000; //The overload value of the counter. Note that SysTick counts down  
		                                              //SysTick has a number of 1 / 9 microseconds and the remainder is (ms%1800)*9*1000
		SysTick->VAL =0x00;                           //Clear the value of the current counter
		SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;      //Enable the SysTick counter, load the overloaded value into the counter and start counting down  
		do{
			temp=SysTick->CTRL;                       //Cycle to read SysTick status register and judge whether the timing is over or not
		}while(temp&0x01&&!(temp&(1<<16)));           //Waiting time arrives
		SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;      //Turn off counter
	}
} 

For detailed descriptions of Cortex-M3 core, SysTick timer and NVIC, please refer to another ST document and an ARM document: STM32F10xxx Cortex-M3 programming manual and cortex ™- M3 technical reference manual

Topics: Embedded system Single-Chip Microcomputer stm32 ARM