índice
2. Precauções para configuração de systick
1. Introdução
O processamento do núcleo CM4 é igual ao do CM3. Inclui um temporizador SysTick interno . O SysTick é um temporizador de contagem regressiva de 24 bits. Quando a contagem chega a 0, ele recarrega automaticamente o valor inicial de temporização do registrador RELOAD. Enquanto não limpar o bit de habilitação no controle SysTick e registro de status, ele nunca irá parar. Desta forma, a systick pode ser usada para realizar a função de temporização de atraso, sem ocupar o temporizador do sistema. Systick também é usado como a batida do relógio do sistema, como freeRTOS e outros SO. Quando o agendador é iniciado, o systick é configurado como o relógio do sistema para fornecer ao sistema uma batida do coração. Existem 4 registros CTRL, LOAD, VAL, CALIB no systick
2. Precauções para configuração de systick
No código gerado usando a configuração CubeMX, uma função SystemClock_Config () será gerada automaticamente para configurar o relógio do microcomputador de chip único, e o systick será configurado
void SystemClock_Config()
{
...........
LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK);
LL_SetSystemCoreClock(32000000);
#ifndef SYSTICK_IRQ
LL_Init1msTick(32000000); //使能systick但是不开启systick中断
#else
SysTick_Config(SystemCoreClock / 1000);//使能systick同时开启systick中断
#endif
}
Mas o que precisa de atenção aqui é se é necessário habilitar a interrupção do systick! ! ! !
1. Se você deseja usar a systick apenas como um atraso e o programa não deseja ser interrompido por interrupções, você só precisa habilitar a systick em vez de habilitar as interrupções da systick e chamar LL_Init1msTick.
void LL_Init1msTick(uint32_t HCLKFrequency)
---> LL_InitTick(HCLKFrequency, 1000U);
---> __STATIC_INLINE void LL_InitTick(uint32_t HCLKFrequency, uint32_t Ticks)
{
/* Configure the SysTick to have interrupt in 1ms time base */
SysTick->LOAD = (uint32_t)((HCLKFrequency / Ticks) - 1UL); /* set reload register */
SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable the Systick Timer */
}
Mas você mesmo precisa escrever a função de atraso e não pode usar o HAL_Delay () fornecido pela biblioteca HAL. O motivo é o seguinte: A implementação de HAL_Delay depende de uma variável uwTickFreq, uwTickFreq é acumulada em HAL_IncTick e precisa ser chamada periodicamente na função de interrupção SysTick_Handler, de modo que HAL_Delay tenha um benchmark
__weak void HAL_IncTick(void)
{
uwTick += uwTickFreq;
}
__weak uint32_t HAL_GetTick(void)
{
return uwTick;
}
__weak void HAL_Delay(uint32_t Delay)
{
uint32_t tickstart = HAL_GetTick();
uint32_t wait = Delay;
/* Add a period to guaranty minimum wait */
if (wait < HAL_MAX_DELAY)
{
wait += (uint32_t)(uwTickFreq);
}
while((HAL_GetTick() - tickstart) < wait)
{
}
}
Custom us delay
void my_delay_us(uint32_t nus)
{
uint32_t temp;
uint32_t fac_us = SystemCoreClock/1000000; //为系统时钟的1/1000000
SysTick->LOAD = nus*fac_us; //时间加载
SysTick->VAL = 0x00; //清空计数器
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk ; //开始倒数
do
{
temp = SysTick->CTRL;
}
while((temp & 0x01) &&! (temp&(1 << 16))); //等待时间到达
SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick->VAL = 0X00; //清空计数器
}
2. Se você quiser usar a batida do relógio do sistema de assento da systick, você precisa ligar a interrupção da systick, você pode chamar diretamente SysTick_Config para configurar, ou você pode usar HAL_Init para configurar, a configuração HAL_Init irá eventualmente chamar a função SysTick_Config
HAL_Init(void)
---> HAL_InitTick(uint32_t TickPriority)
---> 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 */
}
Depois que essa configuração for concluída, osSystickHandler e HAL_IncTick precisam ser chamados na interrupção do systick
void SysTick_Handler(void)
{
osSystickHandler();//为OS提供系统时钟节拍
HAL_IncTick();//为HAL库提供时钟基准
}