Stm32 systick tick timer - delay function

Posted by tasistro on Tue, 14 Sep 2021 05:54:02 +0200

1. STM32 systick ticking timer

  • Systick timer is a simple timer. For ST cm3, CM4 and CM7 core chips, systick timer is available.

  • Systick timer is often used as delay or heartbeat clock of real-time system. This can save MCU resources without wasting a timer. For example, in UCOS, time-sharing multiplexing requires a minimum timestamp. Generally, systick is used as UCOS heartbeat clock in STM32+UCOS system.

  • SysTick timer is the system tick timer, a 24 bit countdown timer. When it counts to 0, it will automatically RELOAD the initial value of timing from the RELOAD register. As long as its enable bit in SysTick control and status register is not cleared, it will never stop and can work even in sleep mode.

  • Systick timer is bundled in NVIC to generate systick exception (exception No.: 15).

  • The priority of Systick interrupt can also be set.

  • 4 Systick registers

    CTRL             SysTick Control and status registers  
    LOAD             SysTick Automatic reload division value register 
    VAL              SysTick Current value register  
    CALIB            SysTick Calibration value register
    

Available in core core_ Found in CM7. H file

typedef struct
{
  __IOM uint32_t CTRL;                   /*!< Offset: 0x000 (R/W)  SysTick Control and Status Register */
  __IOM uint32_t LOAD;                   /*!< Offset: 0x004 (R/W)  SysTick Reload Value Register */
  __IOM uint32_t VAL;                    /*!< Offset: 0x008 (R/W)  SysTick Current Value Register */
  __IM  uint32_t CALIB;                  /*!< Offset: 0x00C (R/ )  SysTick Calibration Register */
} SysTick_Type;

SysTick control and status register - CTRL:

For STM32, the external clock source is 1 / 8 of HCLK(AHB bus clock). The kernel clock is HCLK clock. Configuration function: HAL_SYSTICK_CLKSourceConfig();

SysTick reload value register - LOAD

SysTick current value register - VAL

Systick related functions in HAL Library:

stm32f7xx_hal_cortex.c file: hal_systick_clksourceconfig(); / / systick clock source selection

If SysTick's clock originates from HCLK, assuming that the external crystal oscillator is 25M and frequency doubled to 216MHZ, SysTick's clock is 216MHZ, that is, every time SysTick's counter VAL decreases by 1, it means that the time has passed 1/216us.

void HAL_SYSTICK_CLKSourceConfig(uint32_t CLKSource)
{
  /* Check the parameters */
  assert_param(IS_SYSTICK_CLK_SOURCE(CLKSource));
  if (CLKSource == SYSTICK_CLKSOURCE_HCLK)
  {
    SysTick->CTRL |= SYSTICK_CLKSOURCE_HCLK;
  }
  else
  {
    SysTick->CTRL &= ~SYSTICK_CLKSOURCE_HCLK;
  }
}

You can look at the types of CLKSource: find the definition of IS_SYSTICK_CLK_SOURCE and find that it can be SYSTICK_CLKSOURCE_HCLK and SYSTICK_CLKSOURCE_HCLK_DIV8, that is, no frequency division or 8 frequency division.

#define IS_SYSTICK_CLK_SOURCE(SOURCE) (((SOURCE) == SYSTICK_CLKSOURCE_HCLK) || \
                                       ((SOURCE) == SYSTICK_CLKSOURCE_HCLK_DIV8))

In the core_cm7.h file: SysTick_Config (uint32_t ticks) / / initialize systick, set the clock to HCLK, and start the interrupt.

Ticks: how many systick cycles an interrupt occurs. It is used to configure the systick timer how many ticks an interrupt occurs.

__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
  {
    return (1UL);                                                   /* Reload value impossible */
  }

  SysTick->LOAD  = (uint32_t)(ticks - 1UL);                         /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
  SysTick->VAL   = 0UL;                                             /* 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 (0UL);                                                     /* Function successful */
}

First, you can see SysTick_LOAD_RELOAD_Msk. Since Systick is a 24 bit countdown timer, the value cannot be too large.

#define SysTick_LOAD_RELOAD_Msk            (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/)

Systick interrupt service function: void SysTick_Handler (void);

2.delay function

//Initialization delay function
//When using ucos, this function initializes the clock beat of ucos
//SYSTICK's clock is fixed to 1 / 8 of AHB's clock
//SYSCLK: system clock frequency
void delay_init(u8 SYSCLK)
{
#if SYSTEM_SUPPORT_OS  						// If necessary, support OS
	u32 reload;
#endif
    HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);//SysTick frequency is HCLK
	fac_us=SYSCLK;						    //Whether OS is used or not, fac_us needs to be used
#if SYSTEM_SUPPORT_OS  						// If necessary, support OS
	reload=SYSCLK;					        //The number of counts per second is in K	   
	reload*=1000000/delay_ostickspersec;	//Set the overflow time according to delay_ostickspersec
											//reload is a 24 bit register. The maximum value is 16777216. At 216M, it is about 77.7ms	
	fac_ms=1000/delay_ostickspersec;		//Represents the minimum unit that the OS can delay	   
	SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;//Enable SYSTICK interrupt
	SysTick->LOAD=reload; 					//Interrupt every 1 / os_tips_per_sec seconds	
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //Turn on SYSTICK
#endif 
}				

Call delay_init(216) in main; / / delay initialization. 1 microsecond equals 10 minus 6 second seconds, 1MHZ equals 10^6 Hz.

fac_us=SYSCLK; the system clock is 216MHZ, fac_us=216, which means: how many systick cycles does it take for systick to run 1us? Since systick is 216MHZ, it takes 216 cycles. If you need to delay n microseconds later, you only need n*fac_us. Since the set systick frequency is HCLK, the parameter SYSCLK in the delay_init function is 216.

Idea of delay_us function:

Detect the current value in the loop. If the current value is less than the previous value, it indicates that it has not been reduced to 0. You can know how many cycles it has run through told tnow. Otherwise, it indicates that it has overflowed, that is, it has run reload tnow + told cycles. Finally, if the time exceeds / equals the time to be delayed, exit.

//Delay nus
//nus: the number of us to delay	
//NUS: 0 ~ 204522252 (max. 2 ^ 32 / FAC)_ us@fac_us =21)	    								   
void delay_us(u32 nus)
{		
	u32 ticks;
	u32 told,tnow,tcnt=0;
	u32 reload=SysTick->LOAD;				//Value of LOAD	    	 
	ticks=nus*fac_us; 						//Number of beats required 
	delay_osschedlock();					//Prevent OS scheduling and interrupt us delay
	told=SysTick->VAL;        				//Counter value when entering
	while(1)
	{
		tnow=SysTick->VAL;	
		if(tnow!=told)
		{	    
			if(tnow<told)tcnt+=told-tnow;	//Note that SYSTICK is a decrement counter
			else tcnt+=reload-tnow+told;	    
			told=tnow;
			if(tcnt>=ticks)break;			//If the time exceeds / equals the time to be delayed, exit
		}  
	};
	delay_osschedunlock();					//Resume OS scheduling											    
}  

Topics: stm32