The SysTick system tick timer is not unique to STM32. It is part of the Cortex core. CM3 has a special exception type for it and it has a place in the interrupt vector table (exception number 15). In this way, it can be easily ported to chips with CM3 cores from different manufacturers. Especially for software with real-time operating systems, it is generally used as the time base of the entire system, so it is very important for the operating system.
However, there is very little introduction to it in the STM32 development manual, almost to the extent of being glossed over. For a detailed introduction to SysTick, please refer to Chapter 8 on page 133 and Chapter 13 on page 179 of the "Cortex-M3 Authoritative Guide".
When I first came into contact with SysTick, because it belongs to the kernel interrupt priority, I always had a question: is it higher or lower than all maskable interrupt priorities, or are they in the same setting position?
At first, I thought that the kernel interrupt priority was higher than all maskable interrupt priorities. After carefully reading the information and doing experiments, I found that this was not the case.
SysTick has four registers in total:
1. This register is represented by the SysTick->CTRL variable in the system code; 2. This register is represented by the SysTick->LOAD variable in the system code; 3. This register is represented by the SysTick->VAL variable in the system code; 4. This register is represented by the SysTick->CALIB variable in the system code. It has not been used and is not often used, so it will not be introduced for the time being. The offsets of these registers are shown in the figure below:
The definition of the above register structure in \CMSIS\CM3\CoreSupport core_cm3.h is as follows:
/
**@addtogroup CMSIS_CM3_SysTick CMSIS CM3 SysTick
memory mapped structure for SysTick
@{
*/
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;
SysTick is a 24-bit timer, which means it can count up to 224 clock pulses at a time. This pulse count value is saved in the SysTick->VAL current count value register. It can only count down. Each time a clock pulse is received, the value of SysTick->VAL is reduced by 1 until it reaches 0. Then the hardware automatically reloads the value in the reload register SysTick->LOAD to SysTick->VAL and recounts. When the SysTick->VAL value counts to 0, an exception is triggered and the void SysTick_Handler(void) function is called. The timer interrupt event can be processed in this interrupt service function, which is generally a count-down operation for the set value. As long as the 0th enable bit in the SysTick control and status register SysTick->CTRL is not cleared, it will never stop.
It is a system exception, a kernel-level interrupt, and the priority can be set. The specific settings are also in core_cm3.h code as follows:
/**
* @brief Initialize and start the SysTick counter and its interrupt.
*
* @param ticks number of ticks between two interrupts
* @return 1 = failed, 0 = successful
*
* Initialise the system tick timer and its interrupt and start the
* system tick timer / counter in free running mode to generate
* periodical interrupts.
*/
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);
SysTick->VAL = 0;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk;
return (0); /* Function successful */
}
In this code, the priority is set by the NVIC_SetPriority() function. This function can set both kernel interrupt priority and external interrupt priority, which is quite powerful, but requires manual calculation of preemption and slave priorities, which is not very convenient. When jumping into this function, we can calculate that Systick has the lowest default priority (the effect is equivalent to SCB->SHP[11] = 0xF0. If you calculate, SHP[11] corresponds to the Systick priority setting). For maskable interrupts, the priority is generally set by the NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct) function. For specific applications, please refer to the sample code below.
After introducing the theory, I found that I still didn't understand the initial doubt! Now let's implement it to reveal the truth.
First set an event interrupt and set the priority higher.
void Exti_Config(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line1;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Event;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
Note: In my experiment, the interrupt grouping was initially initialized as follows:
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Set as the second group.
Trigger an external interrupt event in the system tick interrupt and light up LED1:
void SysTick_Handler(void)
{
EXTI_GenerateSWInterrupt(EXTI_SWIER_SWIER1);
LED_1 = ON;
Delay();
}
Light up LED0 in the external interrupt processing function as follows:
void EXTI1_IRQHandler(void)
{
if (EXTI_GetITStatus(EXTI_Line1) != RESET)
{
EXTI_ClearITPendingBit(EXTI_Line1);
LED_0 = ON;
Delay();
}
}
When the external interrupt priority is higher, it can preempt the Systick interrupt and execute first. The experimental result of the above code is that LED0 lights up first, and then returns to LED1 to light up.
But when the external interrupt is set to the same priority as systick, the systick priority will be relatively high. For example, change the above priority to:
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
Then LED1 will light up first, and EXTI1_IRQHandler will execute only after the SysTick_Handle function is executed.
From the above experiments, it can be concluded that when the priorities are the same, kernel-level interrupts take precedence over external maskable interrupts. However, when the priority of an external maskable interrupt is set higher than that of a kernel-level interrupt, it can preempt the kernel interrupt.
In addition, I personally think that if you want to achieve accurate systick delay, it is best to set the systick priority higher, such as NVIC_SetPriority (SysTick_IRQn, 0);
That is, by setting SCB->SHP[11] = 0x00; the priority of systick can be higher than any external interrupt. At this time, the delay will be less affected by other interrupts and will be more accurate.
Previous article:Summary of systick usage errors
Next article:Detailed explanation of Systick delay function
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Wi-Fi 8 specification is on the way: 2.4/5/6GHz triple-band operation
- Wi-Fi 8 specification is on the way: 2.4/5/6GHz triple-band operation
- Vietnam's chip packaging and testing business is growing, and supply-side fragmentation is splitting the market
- Vietnam's chip packaging and testing business is growing, and supply-side fragmentation is splitting the market
- Three steps to govern hybrid multicloud environments
- Three steps to govern hybrid multicloud environments
- Microchip Accelerates Real-Time Edge AI Deployment with NVIDIA Holoscan Platform
- Microchip Accelerates Real-Time Edge AI Deployment with NVIDIA Holoscan Platform
- Melexis launches ultra-low power automotive contactless micro-power switch chip
- Melexis launches ultra-low power automotive contactless micro-power switch chip
- How to measure BLE power consumption
- TI Embedded Live Month - Registration starts now to support efficient, intelligent and low-power system design~
- Four input modes of MCU
- How to replace TMS320C6416TGLZ7 chip
- I would like to ask how to connect the ground on the PCB board of the monitoring equipment and the board ground?
- Overvoltage, overcurrent and overtemperature detection circuit
- Recruitment: Assistant Optical Engineer, Assistant Electronic Engineer, Assistant CAE Engineer, Assistant Structural Engineer
- Multi-core DSP products in the SoC era
- Detailed explanation of Altera series FPGA chip IP core
- SinlinxA33 Modify the configuration file to change the output serial port