关于cortex m0内核systick中断的开启

首先,看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库外设初始化失败进入死循环的解决方法。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值