A record of the SysTick timer of STM32

CSDN Blog Homepage
ID: Eterlove
, one stroke at a time, recording my study life! Standing on Shoulders
of Giants!

This article is original, please indicate the source and author for reprinting!

foreword

       We often use delay to complete some project requirements, often using the software delay achieved by the CPU idle loop to achieve, the method has the advantages of simple, but there will be a problem of low time accuracy , and this is a method with obvious disadvantages, because When the delay function is in progress, the system cannot perform other operations, which greatly reduces the efficiency of the system.
       The second method is to use the timer TIM to achieve precise delay, but it seems that the resources are very wasteful. At this time, the SysTick timer of STM32 comes in handy, but the introduction of the SysTick timer, ST does not describe much in the STM32Reference manual. , so record the experience in the blog.

//空循环达到的软件延时
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 value from the Load register.
The original text of the STM32Reference manual is that
       RCC is used as the external clock of the Cortex system timer (SysTick) after dividing the AHB clock (HCLK) by 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.

英文版为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.

insert image description here

As shown in the above figure and text, there are two clock sources for the SysTick timer, one is the clock after HCLK divided by 8 –> HCLK/8 (actually 72MHZ/8 = 9MHZ), and the other is the undivided HCLK Clock —> HCLK (72MHZ)

There is a macro definition of the SysTick_clock_source clock source in the P172 line of the misc.h file!

//misc.h文件P172行处
/** @defgroup SysTick_cl
ock_source 
  * @{
  */
#define SysTick_CLKSource_HCLK_Div8    ((uint32_t)0xFFFFFFFB)
#define SysTick_CLKSource_HCLK         ((uint32_t)0x00000004)

2. SysTick register

First look at the definition in the ST library function, in the core_cm3.h file P365 line ~ P371 line

//core_cm3.h 文件P365行~P371行
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 introductionCTRL
----->SysTick Control and Status Register
LOAD----->SysTick Reload Value Register
VAL------->SysTick Current Value RegisterCurrent Value Register
CALIB----->SysTick Calibration Value Register

insert image description here
SysTick Control and Status Register
insert image description here
insert image description here

For more detailed description of registers, please refer to the document Cortex™-M3 r1p1 Technical Reference Manual (TRM) , which is not listed here.

The SysTick_Config() function is a CMSIS function that configures the SysTick Reload register whose value is passed as a function parameter.

//core_cm3.h P1694行~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 the SysTick timer

1. Configure the clock source
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)

//在misc.c文件
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
Reload Value Reload Value = SysTick Counter Clock (Hz) x Desired Time base (s)
3. Enable SysTick Interrupt
4. Enable SysTick Counter

4. Program code (detailed comments)

#include "stm32f10x.h"    //包含需要的头文件
#include "delay.h"
/*-------------------------------------------------*/
/*函数名:初始化延迟计数器函数                     */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void Delay_Init(void)
{
    
    
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
	//SysTick_CLKSource_HCLK_Div8 = 8 表示分频系数
	//因为分频系数我们设置为8,所以SysTick(滴答时钟)的频率是主频率的1/8
	//通常主频率为最大的72M,那么SysTick的频率是9M
	//那么SysTick计数器的1个数,代表(1/9)us
}

/*-------------------------------------------------*/
/*函数名:延迟微秒函数                             */
/*参  数:us:延时多少微秒                         */
/*返回值:无                                       */
/*-------------------------------------------------*/
void delay_us(unsigned int us)
{
    
    		
	unsigned int temp;	                      //定义一个变量待用    	 
	
	SysTick->LOAD=us*9;                       //计数器的重载值,要注意SysTick是倒数计数的
	                                          //SysTick计数器每倒数一个数是1/9微秒,所以我们用us*9,就是计数器的重载值
	SysTick->VAL=0x00;                        //清空当前计数器的值
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;  //使能SysTick计数器,重载值加载到计数器中,开始倒数计数
	do{
    
    
		temp=SysTick->CTRL;                   //循环读取SysTick状态寄存器,用于判断计时结束与否
	}while(temp&0x01&&!(temp&(1<<16)));       //等待时间到达
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;  //关闭计数器 
}

/*-------------------------------------------------*/
/*函数名:延迟毫秒函数                             */
/*参  数:ms:延时多少毫秒                         */
/*返回值:无                                       */
/*-------------------------------------------------*/
void delay_ms(unsigned int ms)
{
    
    
	//我们首先注意一个问题SysTick时钟计数器是24位的,9M频率下,总共能延时1864.135ms
	//所有我们以1800为界限,小于1800的延时一次计数就行,大于1800的多次计数	
	
	unsigned char i;      //定义一个变量待用  
	unsigned int temp;    //定义一个变量待用  
	
	/*-----------if判断,小于1800ms延时的情况,执行if分支------------------*/
	if(ms<1800){
    
                                       
		SysTick->LOAD=(unsigned int)ms*9*1000;     //计数器的重载值,要注意SysTick是倒数计数的        
		                                           //SysTick计1个数是1/9微秒,换算成ms的话,乘以9再乘以1000,就是计数器的重载值
		SysTick->VAL=0x00;                         //清空当前计数器的值
		SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;   //使能SysTick计数器,重载值加载到计数器中,开始倒数
		do{
    
    
			temp=SysTick->CTRL;                    //循环读取SysTick状态寄存器,判断计时结束与否
		}while(temp&0x01&&!(temp&(1<<16)));        //等待时间到达
		SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;}  //关闭计数器 
	
	/*--------------大于1800ms延时的情况,执行else分支-------------------*/
	else{
    
     
		for(i=0;i<(ms/1800);i++){
    
                         //除以1800,整数部分,用for循环,每次延时1800ms
			SysTick->LOAD=(unsigned int)1800*9*1000;  //计数器的重载值,要注意SysTick是倒数计数的        
													  //SysTick一个数是1/9微秒,1800ms就是 1800*9*1000
			SysTick->VAL=0x00;                        //清空当前计数器的值
			SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;  //使能SysTick计数器,重载值加载到计数器中,开始倒数
			do{
    
    
				temp=SysTick->CTRL;                   //循环读取SysTick状态寄存器,判断计时结束与否
			}while(temp&0x01&&!(temp&(1<<16)));       //等待时间到达
			SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;} //关闭计数器 
		
		//接下来余数部分的延时
		SysTick->LOAD=(unsigned int)(ms%1800)*9*1000; //计数器的重载值,要注意SysTick是倒数计数的  
		                                              //SysTick一个数是1/9微秒,余数部分就是(ms%1800)*9*1000
		SysTick->VAL =0x00;                           //清空当前计数器的值
		SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;      //使能SysTick计数器,重载值加载到计数器中,开始倒数  
		do{
    
    
			temp=SysTick->CTRL;                       //循环读取SysTick状态寄存器,判断计时结束与否
		}while(temp&0x01&&!(temp&(1<<16)));           //等待时间到达
		SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;      //关闭计数器
	}
} 

For a detailed description of the 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"

Guess you like

Origin blog.csdn.net/Eterlove/article/details/122722298