首先,看m0内核的编程手册,可以看到systick控制和状态寄存器说明如下:
bit1是sistick异常请求使能位;
然后再在自己的工程中全局搜索SysTick_CTRL_TICKINT_Msk这个变量,可以搜到它的定义就是systick CTRL的bit1位:
另外,可以看到在core_cm0.h中有这样的一个函数:(这是systick的配置函数,可以看到里面有对systick控制状态寄存器CTRL的设置,即使能systick异常中断)
这里就是开启systick中断的地方,这个SysTick_Config函数被HAL_SYSTICK_Config--》HAL_InitTick--》HAL_Init调用,所以通过cubemx生成的工程在main()的最开始就是HAL_Init函数,也就是已进入main,systick中断就被打开了。
另外,在stm32f0xx_hal.c中还有一个开启systick中断的弱定义函数(这个函数没有被调用),如果调用这个函数也会使能systick中断:
上面是关于在keil下裸机工程的systick中断开启;
下面看一下基于rtt的keil工程的systick中断实在哪里开启的,如果你是用cubemx自动生成的基于rtt的工程,那么就会有一个boards.c文件,在里面有个rt_hw_board_init()函数,进入函数里有个语句 _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND); 仔细看一下这个函数定义(下面代码部分),里面有对systick控制状态寄存器的设置_SYSTICK_CTRL = 0x07; 这就是将控制状态寄存器的bit0-2设为1,再看上面的systick寄存器的说明,就知道这句就是开启systick中断的;
所以如果你的工程是用cubemx生成的基于rtt的keil工程,你如果把下面函数的这一句_SYSTICK_CTRL = 0x07; 和上面SysTick_Config函数中的 SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk;
这句注释掉,再次在线调试,就会发现systick进不了中断了。
// Holds the system core clock, which is the system clock
// frequency supplied to the SysTick timer and the processor
// core clock.
extern uint32_t SystemCoreClock;
static uint32_t _SysTick_Config(rt_uint32_t ticks)
{
if ((ticks - 1) > 0xFFFFFF)
{
return 1;
}
_SYSTICK_LOAD = ticks - 1;
_SYSTICK_PRI = 0xFF;
_SYSTICK_VAL = 0;
_SYSTICK_CTRL = 0x07; //这里开启了systick中断
return 0;
}
【另一个问题记录】
这里再说明一个问题,就是如果工程是基于rtt的keil中断,比如再硬件外设初始化的时候,有可能会出现卡死在hal库的while循环里面出不来,那是以为内hal库的HAL_GetTick这个函数获取的全局变量uwTickPrio值一直是0,因为基于rtt的工程的systick_handler函数处理的rtt的rt_tick++,而没有对HAL库的tick变量uwTickPrio进行++;
解决方法有两个:
一,让HAL_GetTick()获取有效的tick值,可以重写HAL_GetTick函数来解决这个问题:
uint32_t HAL_GetTick(void){
return rt_tick_get();
}
也可以直接在rt_tick_increase()函数中对uwTickPrio进行++,个人建议最好不要改rtt的内核代码;
二,改变HAL库的tick时基,可以换成定时器1,2,3等等其中的任何一个。配置如下:
这样HAL库的时基和rtthread的时基就不是同一个时基了,这样配置的好处时,不用自己动手改代码,cubemx会自动生成HAL库的tick++功能函数,如下面代码,生成在mian.c中。坏处是,这样功能会增加一些,因为多开了一个硬件定时器。
/**
* @brief Period elapsed callback in non blocking mode
* @note This function is called when TIM1 interrupt took place, inside
* HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
* a global variable "uwTick" used as application time base.
* @param htim : TIM handle
* @retval None
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* USER CODE BEGIN Callback 0 */
/* USER CODE END Callback 0 */
if (htim->Instance == TIM1) {
HAL_IncTick();
}
/* USER CODE BEGIN Callback 1 */
/* USER CODE END Callback 1 */
}
生成的代码中也有对HAL时基的配置函数(在stm32f0xx_hal_timebase_tim.c中):
/**
* @brief This function configures the TIM1 as a time base source.
* The time source is configured to have 1ms time base with a dedicated
* Tick interrupt priority.
* @note This function is called automatically at the beginning of program after
* reset by HAL_Init() or at any time when clock is configured, by HAL_RCC_ClockConfig().
* @param TickPriority: Tick interrupt priority.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
RCC_ClkInitTypeDef clkconfig;
uint32_t uwTimclock = 0;
uint32_t uwPrescalerValue = 0;
uint32_t pFLatency;
/*Configure the TIM1 IRQ priority */
HAL_NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn, TickPriority ,0);
/* Enable the TIM1 global Interrupt */
HAL_NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);
/* Enable TIM1 clock */
__HAL_RCC_TIM1_CLK_ENABLE();
/* Get clock configuration */
HAL_RCC_GetClockConfig(&clkconfig, &pFLatency);
/* Compute TIM1 clock */
uwTimclock = HAL_RCC_GetPCLK1Freq();//获取PCLK1时钟频率
/* Compute the prescaler value to have TIM1 counter clock equal to 1MHz */
uwPrescalerValue = (uint32_t) ((uwTimclock / 1000000) - 1);
/* Initialize TIM1 */
htim1.Instance = TIM1;
/* Initialize TIMx peripheral as follow:
+ Period = [(TIM1CLK/1000) - 1]. to have a (1/1000) s time base.
+ Prescaler = (uwTimclock/1000000 - 1) to have a 1MHz counter clock.
+ ClockDivision = 0
+ Counter direction = Up
*/
htim1.Init.Period = (1000000 / 1000) - 1;
htim1.Init.Prescaler = uwPrescalerValue;
htim1.Init.ClockDivision = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
if(HAL_TIM_Base_Init(&htim1) == HAL_OK)
{
/* Start the TIM time Base generation in interrupt mode */
return HAL_TIM_Base_Start_IT(&htim1);
}
/* Return function status */
return HAL_ERROR;
}
以上就是对HAL库外设初始化失败进入死循环的解决方法。