Article directory
- System timer SysTick
-
- Tick timer register
- STK_CTRL control register
- STK_LOAD reload register
- STK_VAL current value register
- STK_CALRB calibration value register
- Non-system initialization Systick timer
-
- SysTick_Init
-
- SysTick_CLKSourceConfig
- delay_us register
- delay_us library function
- delay_xms short time
- delay_ms long
- SysTick_Config
- System RTOS delay
System timer SysTick
The processing of the CM4 kernel is the same as that of CM3, and it contains a SysTick timer internally. There is no difference between the two. For its detailed introduction, please refer to
Page 230 of “STM32F3 and F4 Series Cortex M4 Core Programming Manual”.
-
The system timer is a peripheral in the CM3 core and is embedded in the NVIC. Because all CM3 chips have this timer, software migration between different CM3 devices is simplified.
-
The system timer is a 24-bit downward-decreasing counter. The time for each count of the counter is 1/SYSCLK. Generally, we set the system clock SYSCLK equal to 72M.
- The clock source of this timer can be an internal clock or an external clock. However, the specific source of STCLK is determined by the chip designer.
-
When the value of the reload value register decrements to 0, the system timer generates an interrupt, and the cycle continues.
- After SysTick is set to the initial value and enabled, the count value is decremented by 1 every system clock cycle. When counting to 0, the SysTick counter automatically reloads the initial value and continues counting. At the same time, the internal COUNT FLAG flag will be set to trigger an interrupt (if the interrupt is enabled).
-
As long as its enable bit in the SysTick control and status register is not cleared, it will never stop.
It is said in the M4 kernel programming manual: SysTick is a 24-bit system timer that will reload The value decreases to zero. The value is reloaded into the STK_LOAD register on the next clock edge and then decremented based on subsequent clocks.
Tick timer register
Part of the Systick content belongs to the NVIC control part. There are a total of 4 registers. The names and addresses are:
STK_CTRL 0xE000E010 -- Control register //It seems that this is the control register STK_LOAD 0xE000E014 -- Reload register STK_VAL 0xE000E018 -- Current value register STK_CALIB 0xE000E01C -- Calibration value register
STK_CTRL control register
There are 4 bits in the register that have meaning
- Bit 0: ENABLE, Systick enable bit (0: turn off the Systick function; 1: turn on the Systick function)
- Bit 1: TICKINT, Systick interrupt enable bit (0: turn off Systick interrupt; 1: turn on Systick interrupt)
- Bit 2: CLK SOURCE, Systick clock source selection (0: Use HCLK/8 as the Systick clock; 1: Use HCLK as the Systick clock)
- Bit 16: COUNT FLAG, Systick count comparison flag. When the count reaches 0, it is set to 1; when the timer starts to count again (CLK_LOAD rewrites the value), it is automatically cleared.
STK_LOAD reload register
Systick is a decrementing timer. When the timer decrements to 0, the value in the reload register will be reloaded and continues to decrement. The STK_LOAD reload register is a 24-bit register with a maximum count of 0xFFFFFF.
STK_VAL current value register
A 24-bit register that returns the current countdown value when read. Writing it clears it and also clears the COUNTFLAG flag in the SysTick control and status register.
STK_CALRB calibration value register
SysTick calibration value register
- Bit 31 NOREF: = 1 No external reference clock (STCLK not available), = 0 External reference clock available.
- Bit 30 SKEW: = 1 the calibration value is not accurate to 1ms, = 0 the calibration value is accurate to 1ms
- uncommonly used
Non-system initialization Systick timer
SysTick_Init
void SysTick_Init(u8 SYSCLK);
SysTick_Init(72);
//The clock of SYSTICK is fixed to 1/8 of the AHB clock //SYSCLK: system clock frequency void SysTick_Init(u8 SYSCLK) {<!-- --> SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); fac_us=SYSCLK/8; fac_ms=(u16)fac_us*1000; }
The system clock is 72/8M, and the counting time is 1/9000000 seconds. When converted into us, it is 1/9us. Then counting 72/8 times, that is, 9 times is 1us.
SysTick_CLKSourceConfig
Set the clock source of SysTick. The options are as follows:
#define SysTick_CLKSource_HCLK_Div8 ((uint32_t)0xFFFFFFFB) #define SysTick_CLKSource_HCLK ((uint32_t)0x00000004) #define IS_SYSTICK_CLK_SOURCE(SOURCE) (((SOURCE) == SysTick_CLKSource_HCLK) || \ ((SOURCE) == SysTick_CLKSource_HCLK_Div8))
Introduction to HCLK
delay_us register
void delay_us(u32 nus) {<!-- --> u32 temp; SysTick->LOAD = 9*nus; SysTick->VAL=0X00;//Clear the counter SysTick->CTRL=0X01;//Enable, reducing to zero means no action, using external clock source do {<!-- --> temp=SysTick->CTRL;//Read the current countdown value }while((temp & amp;0x01) & amp; & amp;(!(temp & amp;(1<<16))));//Waiting time to arrive //Enable and loop until the count reaches 0 SysTick->CTRL=0x00; //Close counter SysTick->VAL =0X00; //Clear the counter }
9*nus: Assume that the peripheral frequency is 9M, that is, divided by 8, then counting 9 times is 1us. The meaning of multiplying by 9 is the number of times corresponding to the parameter time, which is the reload value.
- Let’s take a look at the judgment conditions. The first bit is enable, and the 16th bit counts to 0.
Bit 16: COUNT FLAG, Systick count comparison flag. When the count reaches 0, it is set to 1; when the timer starts to count again (CLK_LOAD rewrites the value), it is automatically cleared.
Summarize the process
- First convert the number of us to be delayed into the number of SysTick clocks
- Write to LOAD register
- Clear the contents of the current register VAL
- Turn on the countdown function.
- When the countdown ends, nus is delayed.
- Finally close SysTick and clear the value of VAL
Notice:
- The value of nus cannot be too large. It must be ensured that nus<=(2^24)/fac_us, otherwise the delay time will be inaccurate.
- temp &0x01, this sentence is used to determine whether the systick timer is still on, which can prevent an infinite loop caused by unexpected shutdown of systick.
delay_us library function
//Delay nus //Note: The value of nus should not be greater than 798915us (the maximum value is 2^24/fac_us@fac_us=21) void delay_us(u32 nus) {<!-- --> u32 temp; SysTick->LOAD=nus*fac_us; //Time loading SysTick->VAL=0x00; //Clear the counter SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //Start the countdown do {<!-- --> temp=SysTick->CTRL; }while((temp & amp;0x01) & amp; & amp;!(temp & amp;(1<<16))); //Wait for time to arrive SysTick->CTRL & amp;=~SysTick_CTRL_ENABLE_Msk; //Close the counter SysTick->VAL =0X00; //Clear the counter }
delay_xms short time
//Delay nms //SysTick->LOAD is a 24-bit register, so the maximum delay is: //nms<=0xffffff*8*1000/SYSCLK //SYSCLK unit is Hz, nms unit is ms //Under 168M conditions, nms<=798ms void delay_xms(u16 nms) {<!-- --> u32 temp; SysTick->LOAD=(u32)nms*fac_ms; //Time loading (SysTick->LOAD is 24bit) SysTick->VAL =0x00; //Clear the counter SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //Start the countdown do {<!-- --> temp=SysTick->CTRL; }while((temp & amp;0x01) & amp; & amp;!(temp & amp;(1<<16))); //Wait for time to arrive SysTick->CTRL & amp;=~SysTick_CTRL_ENABLE_Msk; //Close the counter SysTick->VAL =0X00; //Clear the counter }
delay_ms long
//Delay nms //nms:0~65535 void delay_ms(u16 nms) {<!-- --> u8 repeat=nms/540; //540 is used here because some customers may use it for overclocking. //For example, when overclocked to 248M, the maximum delay_xms can only be about 541ms. u16 remain=nmsT0; while(repeat) {<!-- --> delay_xms(540); repeat--; } if(remain)delay_xms(remain); }
SysTick_Config
Set reload value. The internal part of this function is: SysTick->LOAD = 9*nus;
The parameter of SysTick_Config is a clock count, which means I want to interrupt after how many 1/fosc times.
static void BSP_CoreClockInit(void) {<!-- --> SysTick_Config(SystemCoreClock / 100); //10ms //SysTick_Config(720000); //10ms }
SystemCoreClock / 100 represents the number of clocks, that is, the value placed in the reload register. Each time a number is clocked, it takes 1/72000000s. Then the time to count SystemCoreClock / 100 (SystemCoreClock is 72M) is 10ms. By interrupting Set the flag bit in the systick to achieve the function of scheduled interrupt.
Function implementation
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) {<!-- --> if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */ SysTick->LOAD = ticks - 1; /* set reload register */ NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Systick Interrupt */ 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 */ }
In the interrupt priority setting of peripherals, the hardware numbers of peripherals are greater than or equal to zero, and the numbers of core peripherals are less than zero, which is equivalent to an IP.
- __NVIC_PRIO_BITS=4, because F4 uses four bits.
- Interrupt handling function IP:
typedef enum IRQn {<!-- --> /****** Cortex-M4 Processor Exceptions Numbers ************************************* ***************************/ NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */ MemoryManagement_IRQn = -12, /*!< 4 Cortex-M4 Memory Management Interrupt */ BusFault_IRQn = -11, /*!< 5 Cortex-M4 Bus Fault Interrupt */ UsageFault_IRQn = -10, /*!< 6 Cortex-M4 Usage Fault Interrupt */ SVCall_IRQn = -5, /*!< 11 Cortex-M4 SV Call Interrupt */ DebugMonitor_IRQn = -4, /*!< 12 Cortex-M4 Debug Monitor Interrupt */ PendSV_IRQn = -2, /*!< 14 Cortex-M4 Pend SV Interrupt */ SysTick_IRQn = -1, /*!< 15 Cortex-M4 System Tick Interrupt */ /****** STM32 specific Interrupt Numbers *************************************** *******************************/ WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */ PVD_IRQn = 1, /*!< PVD through EXTI Line detection Interrupt */ TAMP_STAMP_IRQn = 2, /*!< Tamper and TimeStamp interrupts through the EXTI line */ RTC_WKUP_IRQn = 3, /*!< RTC Wakeup interrupt through the EXTI line */ FLASH_IRQn = 4, /*!< FLASH global Interrupt */ RCC_IRQn = 5, /*!< RCC global Interrupt */ EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */ EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */ EXTI2_IRQn = 8, /*!< EXTI Line2 Interrupt */ EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */ EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */ DMA1_Stream0_IRQn = 11, /*!< DMA1 Stream 0 global Interrupt */ DMA1_Stream1_IRQn = 12, /*!< DMA1 Stream 1 global Interrupt */ DMA1_Stream2_IRQn = 13, /*!< DMA1 Stream 2 global Interrupt */ DMA1_Stream3_IRQn = 14, /*!< DMA1 Stream 3 global Interrupt */ DMA1_Stream4_IRQn = 15, /*!< DMA1 Stream 4 global Interrupt */ DMA1_Stream5_IRQn = 16, /*!< DMA1 Stream 5 global Interrupt */ DMA1_Stream6_IRQn = 17, /*!< DMA1 Stream 6 global Interrupt */ ADC_IRQn = 18, /*!< ADC1, ADC2 and ADC3 global Interrupts
Comparing the interrupt priorities of core peripherals and ordinary peripherals, although the two are not in the same register, when comparing, the priority register configuration of the core peripherals is also interpreted according to ordinary interpretation.
System RTOS delay
//Initialize delay function //When using the OS, this function will initialize the clock beat of the OS //SYSTICK's clock is fixed to 1/8 of the AHB clock //SYSCLK: system clock frequency void delay_init(u8 SYSCLK) {<!-- --> u32 reload; SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //168M, divided by 8 21M fac_us=SYSCLK/8; //Whether OS is used or not, fac_us needs to use 21M //168M is 168 times/us, for ticks it is 21 times/us, so timing 21 times is 1us, and the unit is fac_us reload=SYSCLK/8; //The number of counts per second, the unit is M reload*=1000000/delay_ostickspersec; //Set the overflow time according to delay_ostickspersec //reload is a 24-bit register, the maximum value is: 16777216, at 168M, it is about 0.7989s 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/delay_ostickspersec seconds SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //Enable SYSTICK }
What needs to be noted here is that the clock of SysTick is derived from HCLK divided by 8. Assuming that our external crystal oscillator is 8M,
Then multiply the frequency to 168M, then the clock of SysTick is 21Mhz, that is, every time the counter VAL of SysTick decreases by 1,
Represents that the time has passed 1/21us.
fac_us=SYSCLK/8; ; This sentence is to calculate how many SysTick clock cycles are needed to delay 1us at the SystemCoreClock clock frequency. For a 21M clock, 21 times is 1us, and 1 time is 1/21us. sysClk is 168. fac_us is 168/8 times.
Systick’s clock comes from the system clock divided by 8. Because of this, if the system clock is not a multiple of 8 (not divisible by 8), it will cause the delay function to be inaccurate. This is why we recommend choosing 8M for the external clock.