STM32 Freertos提供ISR的二进制信号

发布于 2025-02-12 16:09:24 字数 3923 浏览 0 评论 0原文

我已经使用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 解决方案我检查了config> configKernel_inter_inter_interrupt_priority,并且已定义为15&lt&lt&lt&lt&lt&lt ;< 4。 并且也基于 this 解决方案,code> configmax_syscall_inter_interrupt_priority设置为5&lt&lt ;< 4。但是,将tim1中断为15、240、255等的优先级也无济于事。

在任务之间给出和占用信号是没有问题的。

另外,我使用xsemaphoregivefromisrtim1_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

并且根据此页面和下图

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

在ISR回调函数中,评论XsemaphoregiveFromisr()时,所有任务和中断工作。但是不进行评估会导致崩溃,这意味着不允许通过ISR调用Freertos API函数的计时器中断。

我在这里想念什么?

I've generated a RTOS-cmsis_v1 project for stm32f103 using stm32cubemx and defined four tasks as below:

  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);

a binary semaphore:

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

and a timer which generates an interrupt every 1 second.
Task functions and interrupt service routine:

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();
  }
}

The problem is when I run the code, the interrupt executes only once and none of the task are running. If I comment out the xSemaphoreGiveFromISR(binsemHandle, NULL); all tasks (except normal, because of the semaphore check) run and also interrupt gets activated every second.
TIM4 is used as time base and the default priority of TIM1 interrupt was 14.
Based on this solution I checked the value of configKERNEL_INTERRUPT_PRIORITY and it's defined as 15 << 4.
And also based on this solution, the value of configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5 << 4. But changing the priority level of TIM1 interrupt to 15, 240, 255, and etc didn't help either.

Giving and taking semaphores between tasks has no problem.

Also I tested using xSemaphoreGiveFromISR in TIM1_IRQ_Handler() function instead of the callback, but no luck. Using xTaskNotifyGive instead of semaphore didn't work either.

Edit

So I set my timer interrupt priority to 7 and checked it using configASSERT() and no errors. Printing the value of the register also gives the value 112 which is 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);

and here are FreeRTOSconfig.h file definitions for kernel and max priority values:

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY   15
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5

and according to this page, and the diagram below Example interrupt priority configuration

the timer should be able to call freertos API functions from ISR.

When commenting out the xSemaphoreGiveFromISR() in the ISR callback function, all tasks and the interrupt work. But un-commenting it results in a crash, which means the timer interrupt is not allowed to call freertos API functions fro ISR.

WHAT AM I MISSING HERE??

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

猫腻 2025-02-19 16:09:24

好的!因此,问题在于,在启动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(&amp; amp; htim1)之后;函数freertos.c并将其放置在信号量定义之后,一切正常(甚至从ISR)。

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

  HAL_TIM_Base_Start_IT(&htim1);

我遇到了一些文档,在弗雷托斯文档中提到了这一点,但我没有对此表示关注,现在找不到它在哪里。如果找到文档,我将在此处添加一个链接。

OK! So the problem was that I was enabling the timer interrupt BEFORE starting the scheduler in the main.c file:

  HAL_TIM_Base_Start_IT(&htim1);

  /* Call init function for freertos objects (in freertos.c) */
  MX_FREERTOS_Init();

  /* Start scheduler */
  osKernelStart();

So after moving the HAL_TIM_Base_Start_IT(&htim1); function to freertos.c and putting it AFTER the semaphore definition, everything works fine (even printing from ISR).

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

  HAL_TIM_Base_Start_IT(&htim1);

I came across some document mentioning this in freeRTOS documentation but I didn't pay attentions to it and now I can't find where it was. I'll add a link to it here if I found the document.

喜爱纠缠 2025-02-19 16:09:24

这也是获取任务通知工作的方法。
调用hal_tim_base_start_it() OSKERNELSTART()之后。

This is also the way to get task notifications to work.
Call HAL_TIM_Base_Start_IT() AFTER osKernelStart().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文