2

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??

mehdi
  • 167
  • 11
  • Are you sure that the stack sizes are sufficent ? I afraid they're not when using (s)printf family functions. Also you have a look at the FreeRTOS API doc examples https://www.freertos.org/a00124.html and make use of xHigherPriorityTaskWoken flag in ISRs. Defining 'configASSERT' and enable stack offlow checking is a big help to catch a number of bugs like using the wrong interrupt prio etc. – HS2 Jul 04 '22 at 11:34
  • SemaphoreTake() should always be accompanied with a corresponding Give(). What is your printout? `buffer` seems to be a global variable. In a multithreading environment it should better a local variable. – user5329483 Jul 04 '22 at 20:06
  • @HS2 without giving semaphore from interrupt all tasks work with `sprintf` so block sizes are sufficient. I've tried the example you mentioned but there was no difference. There's a similar example in `semphr.h` file without the yield in the last line, but that function didn't change anything either. – mehdi Jul 05 '22 at 05:10
  • @user5329483 If you mean at the end of the normal task I should give the semaphore, I don't think it's required. And if I do that the task will loop in itself. with Buffer being global, and the `xSemaphoreGiveFromISR` line commented out, all tasks work fine and print the messages. It's seems the crash is caused by giving semaphore or task notification from callback function, but I can't figure it out. – mehdi Jul 05 '22 at 05:15
  • @mehdi Using the flag and yield will immediately schedule the task signaled if it’s the highest prio task ready to run (as documented). Otherwise the task gets scheduled after the next systick. This is a big difference. If the application seems to run properly without signaling the semaphore is not a guarantee that there is no data corruption. You should make use of the FreeRTOS debug features I mentioned. The code is correct and should work. Even though I’d omit the useless delay in the signaled task 02 or put it into an else branch. – HS2 Jul 05 '22 at 07:04
  • @HS2 Ok I'll try debugging the code. I defined another binary semaphore using freeRTOS api without HAL, and also used another mcu, but got the same result. Also [this](https://youtu.be/06TH2NgrKkA) didn't work for me. I feel that I'm missing a tiny detail here and it's driving me crazy. – mehdi Jul 05 '22 at 07:51
  • I overlooked that you're also using sprintf and printout in the ISR callback. Are you really sure that this works in an ISR ? Also note that the ISR stack is different to the task stacks. Did you try the code with debug printing commented ? However, I propose to add configASSERT and stack overflow checking 1st. – HS2 Jul 05 '22 at 16:17
  • @HS2 Yes I tried running without sprintf. According to 2 links in the question, and [faq](https://freertos.org/RTOS-Cortex-M3-M4.html) page, I'm pretty sure it has something to do with priority settings. – mehdi Jul 06 '22 at 03:18
  • 1. sprintf is not RTOS safe. 2. Do not use long I/O functions in ISRs. – 0___________ Jul 06 '22 at 09:24
  • @0___________ I removed the spritf. this is the isr callback function now: ``` if (htim->Instance == TIM1) { static BaseType_t xHigherPriorityTaskWoken; xHigherPriorityTaskWoken = pdFALSE; xSemaphoreGiveFromISR(binsemHandle, &xHigherPriorityTaskWoken); if (xHigherPriorityTaskWoken) { portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } } ``` – mehdi Jul 06 '22 at 09:32
  • printout in isr is bad as well – 0___________ Jul 06 '22 at 09:33
  • I would suggest if you just started with RTOS to blink the LEDs instead of printing text. – 0___________ Jul 06 '22 at 09:34
  • I did. As I said, Blinking and printing works without semaphore signaling in ISR. – mehdi Jul 06 '22 at 09:35

1 Answers1

0

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.

Anyway that was a stupid mistake, and I think cubemx creating freertos.c separate from main.c causes a little bit of confusion.

mehdi
  • 167
  • 11