STM32H7 M7 with LL HAL freeRTOS not running

I’ve set up a project with LL library using TIM7 as the clock source for FreeRTOS, where FreeRTOS is configured outside CubeMX. Running on STM32H743ZI2 Nucleo board

Everything works independently, but not with vTaskStartScheduler(). Without vTaskStartScheduler, the timer, UART, ticks, everything works correctly. It is a simple blink program, but I am not able to decipher if it is a problem with interrupt priority for TIMER7 (which needs to be high since it is the clock source of FreeRTOS) or stack issue or something else entirely. Completely set up by m,e but just stuck very close to working condition. Please help.

main.c


int main(void)
{
  MPU_Config();

  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_UART4_Init();
  MX_TIM7_Init();

  BSP_LED_Init(LED_GREEN);
  BSP_LED_Init(LED_YELLOW);
  BSP_LED_Init(LED_RED);

  char stringForError[] = "Error for freeRTOS 0";
  char stringForSucceess0[] = "Success for freeRTOS 0";
  LL_TIM_EnableCounter(TIM7);         // Start counting
  
  write_data_to_uart((uint8_t *)&stringForSucceess0, sizeof(stringForSucceess0));
  
  TaskHandle_t xTaskHandle1;
  TaskHandle_t xTaskHandle2;
  TaskStatus_t xTaskDetails;
  eTaskState xTaskState;


  BaseType_t ret = xTaskCreate(blinkLeds,  "Blink_Multiple_LED", 128 * 2, NULL, configMAX_PRIORITIES - 2, &xTaskHandle1);
  if(ret != pdPASS){
    write_data_to_uart((uint8_t *)&stringForError, sizeof(stringForError));
    write_data_to_uart((uint8_t *)&ret, sizeof(ret));
    LL_GPIO_TogglePin(GPIOE, LL_GPIO_PIN_1);
  }
  
  ret = xTaskCreate(blinkLED,   "Blink_1_LED"       , 128 * 2, NULL, configMAX_PRIORITIES - 2, &xTaskHandle2);
  
  if(ret != pdPASS){
    write_data_to_uart((uint8_t *)&stringForError, sizeof(stringForError));
    write_data_to_uart((uint8_t *)&ret, sizeof(ret));
    LL_GPIO_TogglePin(GPIOB, LL_GPIO_PIN_14);
  }

  char stringForSucceess[] = "Success for freeRTOS 1";
  write_data_to_uart((uint8_t *)&stringForSucceess, sizeof(stringForSucceess));
  markTaskScheduleRunning();
  vTaskStartScheduler();

  while (1)
  {
  }
}


static void MX_TIM7_Init(void)
{

  LL_TIM_InitTypeDef TIM_InitStruct = {0};

  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM7);


  NVIC_SetPriority(TIM7_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 1, 0));
  NVIC_EnableIRQ(TIM7_IRQn);



  LL_TIM_EnableIT_UPDATE(TIM7);


  TIM_InitStruct.Prescaler = 63;
  TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
  TIM_InitStruct.Autoreload = 999;
  LL_TIM_Init(TIM7, &TIM_InitStruct);
  LL_TIM_EnableARRPreload(TIM7);
  LL_TIM_SetTriggerOutput(TIM7, LL_TIM_TRGO_UPDATE);
  LL_TIM_DisableMasterSlaveMode(TIM7);

}



static void blinkLeds(void *argument){
    write_data_to_uart((uint8_t*)(&stringForMessage1), sizeof(stringForMessage1));

    LL_GPIO_TogglePin(GPIOB, LL_GPIO_PIN_14| LL_GPIO_PIN_0);
    vTaskDelay(pdMS_TO_TICKS(500));
}

static void blinkLED(void *argument){
    write_data_to_uart((uint8_t*)(&stringForMessage2), sizeof(stringForMessage2));

    LL_GPIO_TogglePin(GPIOE, LL_GPIO_PIN_1);
    vTaskDelay(pdMS_TO_TICKS(1000));
}

void vApplicationIdleHook(void)
{
   char stringForIdle[] = "Idle task is running";
    write_data_to_uart((uint8_t*)(&stringForIdle), sizeof(stringForIdle));
    vTaskDelay(pdMS_TO_TICKS(1000));
}

FreeRTOSConfig.h

 #ifndef FREERTOS_CONFIG_H
 #define FREERTOS_CONFIG_H
 extern uint32_t SystemCoreClock;

 /******************************************************************************/
 /* Hardware description related definitions. **********************************/
 /******************************************************************************/
 
#define configCPU_CLOCK_HZ                         ( SystemCoreClock )

 /******************************************************************************/
 /* Scheduling behaviour related definitions. **********************************/
 /******************************************************************************/
 
 #define configTICK_RATE_HZ                         ( ( unsigned long ) 1000 )
 #define configUSE_SYS_TICK                         0   // Ensure SysTick is enabled for FreeRTOS
 #define configUSE_PREEMPTION                       1
 #define configUSE_TIME_SLICING                     1
 #define configUSE_PORT_OPTIMISED_TASK_SELECTION    1
 #define configUSE_TICKLESS_IDLE                    1
 #define configMAX_PRIORITIES                       5U
 #define configMINIMAL_STACK_SIZE                   128U
 #define configMAX_TASK_NAME_LEN                    8U
 #define configTICK_TYPE_WIDTH_IN_BITS              TICK_TYPE_WIDTH_32_BITS
 #define configIDLE_SHOULD_YIELD                    1
 #define configTASK_NOTIFICATION_ARRAY_ENTRIES      1U
 #define configQUEUE_REGISTRY_SIZE                  0U
 #define configENABLE_BACKWARD_COMPATIBILITY        1
 #define configNUM_THREAD_LOCAL_STORAGE_POINTERS    0
 #define configSTACK_DEPTH_TYPE                     size_t
 #define configMESSAGE_BUFFER_LENGTH_TYPE           size_t
 #define configUSE_NEWLIB_REENTRANT                 0
 
 /******************************************************************************/
 /* Software timer related definitions. ****************************************/
 /******************************************************************************/
 
 #define configUSE_TIMERS                1
 #define configTIMER_TASK_PRIORITY       ( configMAX_PRIORITIES - 1U )
 #define configTIMER_TASK_STACK_DEPTH    configMINIMAL_STACK_SIZE
 #define configTIMER_QUEUE_LENGTH        10U
 
 /******************************************************************************/
 /* Memory allocation related definitions. *************************************/
 /******************************************************************************/
 
 #define configSUPPORT_STATIC_ALLOCATION              1
 #define configSUPPORT_DYNAMIC_ALLOCATION             1
 #define configTOTAL_HEAP_SIZE                        (16 * 1024U)
 #define configAPPLICATION_ALLOCATED_HEAP             0
 #define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP    0
 #define configUSE_MINI_LIST_ITEM                     0
 
 /******************************************************************************/
 /* Interrupt nesting behaviour configuration. *********************************/
 /******************************************************************************/
 /*
 #define configKERNEL_INTERRUPT_PRIORITY          0U
 #define configMAX_SYSCALL_INTERRUPT_PRIORITY     0U
 #define configMAX_API_CALL_INTERRUPT_PRIORITY    0U
*/
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
#define __NVIC_PRIO_BITS                            4U
#define configMAX_SYSCALL_INTERRUPT_PRIORITY (5 << (8 - __NVIC_PRIO_BITS))  // = 80
 /******************************************************************************/
 /* Hook and callback function related definitions. ****************************/
 /******************************************************************************/
 
 #define configUSE_IDLE_HOOK                   1
 #define configUSE_TICK_HOOK                   0
 #define configUSE_MALLOC_FAILED_HOOK          1
 #define configUSE_DAEMON_TASK_STARTUP_HOOK    0
 #define configCHECK_FOR_STACK_OVERFLOW        2
 
 /******************************************************************************/
 /* Run time and task stats gathering related definitions. *********************/
 /******************************************************************************/
 
 #define configGENERATE_RUN_TIME_STATS           0
 #define configUSE_TRACE_FACILITY                1
 #define configUSE_STATS_FORMATTING_FUNCTIONS    0
 #define configKERNEL_PROVIDED_STATIC_MEMORY     1
 
 /******************************************************************************/
 /* Definitions that include or exclude functionality. *************************/
 /******************************************************************************/
 
 #define configUSE_TASK_NOTIFICATIONS           1
 #define configUSE_MUTEXES                      1
 #define configUSE_RECURSIVE_MUTEXES            1
 #define configUSE_COUNTING_SEMAPHORES          1
 #define configUSE_QUEUE_SETS                   1
 #define configUSE_APPLICATION_TASK_TAG         1
 #define configOVERRIDE_DEFAULT_TICK_CONFIGURATION 1
 #define INCLUDE_vTaskPrioritySet               1
 #define INCLUDE_uxTaskPriorityGet              1
 #define INCLUDE_vTaskDelete                    1
 #define INCLUDE_vTaskSuspend                   1
 #define INCLUDE_xResumeFromISR                 1
 #define INCLUDE_vTaskDelayUntil                1
 #define INCLUDE_vTaskDelay                     1
 #define INCLUDE_xTaskGetSchedulerState         1
 #define INCLUDE_xTaskGetCurrentTaskHandle      1
 #define INCLUDE_uxTaskGetStackHighWaterMark    1
 #define INCLUDE_xTaskGetIdleTaskHandle         1
 #define INCLUDE_eTaskGetState                  1
 #define INCLUDE_xEventGroupSetBitFromISR       1
 #define INCLUDE_xTimerPendFunctionCall         1
 #define INCLUDE_xTaskAbortDelay                1
 #define INCLUDE_xTaskGetHandle                 1
 #define INCLUDE_xTaskResumeFromISR             1
 
 
#define vPortSVCHandler                         vPortSVCHandler
#define xPortPendSVHandler                      xPortPendSVHandler
#define xPortSysTickHandler                     xPortSysTickHandler

 #endif /* FREERTOS_CONFIG_H */
 

stm32h7xx_it.c:


static uint32_t counter = 0;
static char data[] = "1 second done!!!\r";
static char stringForSysTick[] = "SysTick is running\r";
static bool isTaskScheduleRunning = false;
void xPortSysTickHandler(void); 
void markTaskScheduleRunning(void);
void TIM7_IRQHandler(void)
{
 if (LL_TIM_IsActiveFlag_UPDATE(TIM7)) {
    if(isTaskScheduleRunning){
      xPortSysTickHandler();
    }

    counter++;
    if (counter == 1000) {
        counter = 0;
        write_data_to_uart((uint8_t *)&data, sizeof(data));     
        if(isTaskScheduleRunning){
          write_data_to_uart((uint8_t *)&stringForSysTick, sizeof(stringForSysTick));
        }
    }

  }

void markTaskScheduleRunning(void){
  char stringForTaskSchedule[] = "Task schedule is running\r";
  write_data_to_uart((uint8_t *)&stringForTaskSchedule, sizeof(stringForTaskSchedule));
    isTaskScheduleRunning = true;
}  LL_TIM_ClearFlag_UPDATE(TIM7);
}

SysTick is a hardware timer inside the CM4/7, and by default FreeRTOS uses it to generate the OS tick, a software event. It appears you want to use TIM7 instead of SysTick to generate the OS tick. Do you have a specific purpose or requirement for using TIM7 instead of SysTick? If not, just let FreeRTOS use SysTick.

If you do need TIM7, then you must override a couple of functions in the portable layer. And for now, you should turn off tickless idle until you get things up and running.

Note, the FreeRTOS tick is supposed to have a very LOW priority (high number).

Would you break the code in debugger and see what it is doing?

I did and there is no message in the debugger. I am very new to FreeRTOS. Any suggestions what I should be looking for?

I did try to check vTaskGetInfo and got the tasks as “running” when the vTaskStartScheduler was even commented out. Could point to the problem but I am unable to figure out what or where to look for with FreeRTOS

It is 0, the highest priority possible, with that being said, I am not sure if it works correctly as I start the “ticks” for FreeRTOS immediately before starting schedule but because of the CPU clock freq and IRQ priority I suspect some ticks already get excuted before vTaskStartScheduler takes effect. Any suggestion on how I can fix it?

I do want to use TIM7 rather than SysTick as this is first step towards a complex project I am planning to build where this will be a key requirement. My purpose is not to use TIM7, but it is NOT TO USE SYSTICK.

What functions you need to override? Can you please let me know and I’ll reconfirm I am doing what is needed

You should check the callstack.

Why don’t you configure a project using CubeMX and get it working? This why you’ll have something to compare against.

Implement vPortSetupTimerInterrupt and move your TIM7 initialization code to this function.

That is NOT a correct priority for ANY ISR that interfaces with FreeRTOS, especially the Tick interrupt.

You probably want to read up on more of the documentation for using FreeRTOS on Cortex M processors.

To add to @richard-damon’s answer, you want configMAX_SYSCALL_INTERRUPT_PRIORITY to be at the lowest priority possible for your application, meaning you want it at the priority level of interrupts you want to be able to call FreeRTOS’s FromISR functions in. This config is set in your project’s FreeRTOSConfig.h. FreeRTOS critical sections (taskENTER_CRITICAL) mask all interrupts below this chosen priority level - this is to allow you to call FromISR functions within interrupts at or below this level. The tick interrupt must be disabled when in a critical section as it modifies FreeRTOS-Kernel globals. So effectively by choosing the highest priority for the tick interrupt, you are forcing configMAX_SYSCALL_INTERRUPT_PRIORITY to also be the highest priority, meaning critical sections of the FreeRTOS-Kernel will completely block all of your system’s interrupts. This is bad for a number of reasons - mainly that critical interrupts are also masked when in a FreeRTOS critical section - for example, the UART interrupts :). I imagine your system problems stem from not setting configMAX_SYSCALL_INTERRUPT_PRIORITY to 0 (again this is a bad idea, but worth trying to see if it will work after you update the timer interrupt setup code per @aggarg), meaning the tick interrupt is not disabled when in a critical section, causing corruption of the kernel. So to summarize, choose the lowest interrupt priority possible for your application that you will need to make fromISR function calls in, set configMAX_SYSCALL_INTERRUPT_PRIORITY to that value, setup the timer interrupt so it is lower than the chosen priority.