STM32 FreeRTOS 从 ISR 中提供二进制信号量不起作用

问题描述 投票:0回答:2

我使用stm32cubemx为stm32f103生成了一个RTOS-cmsis_v1项目,并定义了四个任务,如下所示:

  osThreadDef(defaultTask, StartDefaultTask, osPriorityLow, 0, 128);
  defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);

  /* definition and creation of normal */
  osThreadDef(normal, StartTask02, osPriorityNormal, 0, 128);
  normalHandle = osThreadCreate(osThread(normal), NULL);

  /* definition and creation of high */
  osThreadDef(high, StartTask03, osPriorityAboveNormal, 0, 128);
  highHandle = osThreadCreate(osThread(high), NULL);

  /* definition and creation of low */
  osThreadDef(low, StartTask04, osPriorityBelowNormal, 0, 128);
  lowHandle = osThreadCreate(osThread(low), NULL);

二进制信号量:

  osSemaphoreDef(binsem);
  binsemHandle = osSemaphoreCreate(osSemaphore(binsem), 1);

以及一个每 1 秒生成一次中断的计时器。 任务函数和中断服务程序:

void StartTask02(void const * argument)
{
  for (;;) {
    sprintf(buffer, "normal waiting for semaphore\r\n");
    printout();
    if (xSemaphoreTake(binsemHandle, portMAX_DELAY)) {
      sprintf(buffer, "normal begin\r\n");
      printout();

      sprintf(buffer, "normal end\r\n");
      printout();
    }

    osDelay(1000);
  }
}

void StartTask03(void const * argument)
{
  for (;;) {
    sprintf(buffer, "high begin\r\n");
    printout();

    sprintf(buffer, "high end\r\n");
    printout();
    osDelay(1000);
  }
}

void StartTask04(void const * argument)
{
  for (;;) {
    sprintf(buffer, "low begin\r\n");
    printout();

    sprintf(buffer, "low end\r\n\r\n");
    printout();

    osDelay(1000);
  }
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {

    if (htim->Instance == TIM1) {
    static BaseType_t xHigherPriorityTaskWoken;
    xHigherPriorityTaskWoken = pdFALSE;
    xSemaphoreGiveFromISR(binsemHandle, &xHigherPriorityTaskWoken);
    if (xHigherPriorityTaskWoken) {
      portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
  }

  
  if (htim->Instance == TIM4) {
    HAL_IncTick();
  }
}

问题是当我运行代码时,中断仅执行一次,并且没有任何任务正在运行。如果我注释掉

xSemaphoreGiveFromISR(binsemHandle, NULL);
所有任务(除了正常任务,因为信号量检查)都会运行,并且每秒都会激活中断。
TIM4
用作时基,
TIM1
中断的默认优先级为
14
。 基于 this 解决方案,我检查了
configKERNEL_INTERRUPT_PRIORITY
的值,并将其定义为
15 << 4
。 并且同样基于this解决方案,将
configMAX_SYSCALL_INTERRUPT_PRIORITY
的值设置为
5 << 4
。但是将
TIM1
中断的优先级更改为 15、240、255 等也没有帮助。

在任务之间传递和获取信号量没有问题。

我还测试了在

xSemaphoreGiveFromISR
函数中使用
TIM1_IRQ_Handler()
而不是回调,但没有运气。使用
xTaskNotifyGive
代替信号量也不起作用。

编辑

所以我将定时器中断优先级设置为 7 并使用

configASSERT()
检查它,没有错误。打印寄存器的值也会得到值 112,即
7<<4

  /* Initialize interrupts */
  //MX_NVIC_Init();
  /* USER CODE BEGIN 2 */
  NVIC_SetPriority(TIM1_IRQn, 7);
  NVIC_EnableIRQ(TIM1_IRQn);
  sprintf(buffer, "%u\r\n", NVIC->IP[TIM1_IRQn]);
  printout();
  configASSERT(NVIC->IP[TIM1_IRQn] == 112);

这里是

FreeRTOSconfig.h
内核和最大优先级值的文件定义:

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY   15
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5

并根据this页面,以及下图

计时器应该能够从 ISR 调用 freertos API 函数。

当注释掉ISR回调函数中的

xSemaphoreGiveFromISR()
时,所有任务和中断都起作用。但取消注释会导致崩溃,这意味着计时器中断不允许从 ISR 调用 freertos API 函数。

我在这里错过了什么??

stm32 microcontroller freertos cmsis
2个回答
0
投票

这也是让任务通知发挥作用的方法。 在 osKernelStart() 之后调用 HAL_TIM_Base_Start_IT()。


0
投票

好的!所以问题是我在 main.c 文件中启动调度程序之前

启用了计时器中断:

HAL_TIM_Base_Start_IT(&htim1); /* Call init function for freertos objects (in freertos.c) */ MX_FREERTOS_Init(); /* Start scheduler */ osKernelStart();
因此,将 

HAL_TIM_Base_Start_IT(&htim1);

 函数移至 
freertos.c
 并将其放在 
AFTER 信号量定义之后,一切正常(甚至从 ISR 打印)。

osSemaphoreDef(binsem); binsemHandle = osSemaphoreCreate(osSemaphore(binsem), 1); HAL_TIM_Base_Start_IT(&htim1);
我在 freeRTOS 文档中发现了一些文档提到了这一点,但我没有注意它,现在我找不到它在哪里。如果我找到该文档,我会在此处添加链接。

© www.soinside.com 2019 - 2024. All rights reserved.