STM32FreeRTOS Task Notification Question

Post here first, or if you can't find a relevant section!
Post Reply
JimEli
Posts: 20
Joined: Sat Apr 17, 2021 11:33 pm

STM32FreeRTOS Task Notification Question

Post by JimEli »

I can't seem to get a task notification to work from an ISR. I'm using the official STM core with an STM32F446RE Nucleo board. Here is a very simple proof of concept (which doesn't blink). Am I using the notification API wrong?

Code: Select all

#include <STM32FreeRTOS.h>

TIM_HandleTypeDef timerInstance;
static TaskHandle_t ht = NULL;

void task(void* p) {
  while (1)   {
    ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
    HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
  }
}

void initTimer()  {
  // TIM2 Update Event (Hz)  @ 1 Hz
  __TIM2_CLK_ENABLE();
  timerInstance.Instance = TIM2 ;
  timerInstance.Init.Period = 83999;
  timerInstance.Init.Prescaler = 999;
  timerInstance.Init.CounterMode = TIM_COUNTERMODE_UP;
  timerInstance.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  timerInstance.Init.RepetitionCounter = 0;
  HAL_TIM_Base_Init(&timerInstance);
  HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(TIM2_IRQn);
  HAL_TIM_Base_Start_IT(&timerInstance);
}

extern "C" void TIM2_IRQHandler() { HAL_TIM_IRQHandler(&timerInstance); }
extern "C" void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { vTaskNotifyGiveFromISR(ht, NULL); }

void setup()  {
  pinMode(LED_BUILTIN, OUTPUT);
  initTimer();
  xTaskCreate(task, "task", 2048, NULL, 1, &ht);
  vTaskStartScheduler();
}

void loop() { }
I'm using a sketch level "build_opt.h" file with "-DHAL_TIM_MODULE_ONLY".

The really odd thing is, if I use my home-grown semaphore in place of the notification, it blinks properly:

Code: Select all

#include <STM32FreeRTOS.h>
#include <atomic>

class Mutex {
  volatile std::atomic_flag mutex = ATOMIC_FLAG_INIT;
public:
  void acquire() { while (mutex.test_and_set()); }
  void release() { mutex.clear(); }
};

class Semaphore {
  volatile std::atomic<size_t> value;
  Mutex mutex;
public:
  explicit Semaphore(size_t n = 0) {
    if (n > 0)
      value = n;
    else
      value = 0;
  }

  void take() {
    mutex.acquire();
    while (std::atomic_load(&value) <= 0);
    atomic_fetch_sub(&value, 1);
    mutex.release();
  }

  size_t give() { return std::atomic_fetch_add(&value, 1); }
};

TIM_HandleTypeDef timerInstance;
Semaphore s;

void task(void* p) {
  while (1)   {
    s.take();
    HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
  }
}

void initTimer()  {
  // TIM2 Update Event (Hz)  @ 1 Hz
  __TIM2_CLK_ENABLE();
  timerInstance.Instance = TIM2 ;
  timerInstance.Init.Period = 83999;
  timerInstance.Init.Prescaler = 999;
  timerInstance.Init.CounterMode = TIM_COUNTERMODE_UP;
  timerInstance.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  timerInstance.Init.RepetitionCounter = 0;
  HAL_TIM_Base_Init(&timerInstance);
  HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(TIM2_IRQn);
  HAL_TIM_Base_Start_IT(&timerInstance);
}

extern "C" void TIM2_IRQHandler() { HAL_TIM_IRQHandler(&timerInstance); }
extern "C" void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { s.give(); }

void setup()  {
  pinMode(LED_BUILTIN, OUTPUT);
  initTimer();
  xTaskCreate(task, "task", 2048, NULL, 1, NULL);
  vTaskStartScheduler();
}

void loop() { }
JimEli
Posts: 20
Joined: Sat Apr 17, 2021 11:33 pm

Re: STM32FreeRTOS Task Notification Question

Post by JimEli »

After running inside the SW4STM32 and debugging extensively, I determined the issues:
1. The ISR priority needed to be increased.
2. The task handle needed to be initialized prior to establishing the ISR.

These are the 2 tweaks to the program to make it run:

Code: Select all

  HAL_NVIC_SetPriority(TIM2_IRQn, 5, 0);
  …
  xTaskCreate(task, NULL, 2048, NULL, 1, &ht);
  InitializeTimer();
  vTaskStartScheduler();
FreeRTOS is loaded with "gotchas."
Post Reply

Return to “General discussion”