STM32H7 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. I’m doing this because I need highly accurate timing with FreeRTOS.

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), a stack issue, or something else entirely. With priority of 0 for Timer7IRQ, I get a tick hook message, otherwise with priority of 5 or numerical higher number till 15, there is no breakpoint hit in the TIM7_IRQHandler.
It was completely set up by me, but it is stuck very close to working condition. Please help.

main.c

int main(void)
{

  /* USER CODE BEGIN 1 */
//   TaskHandle_t xHandleLED1,

  /* USER CODE END 1 */

  /* MPU Configuration--------------------------------------------------------*/
  MPU_Config();

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */
    SCB_EnableICache();
    SCB_EnableDCache();

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_UART4_Init();
  MX_TIM7_Init();
  /* USER CODE BEGIN 2 */
  LL_TIM_EnableCounter(TIM7);         // Start counting
  /* USER CODE END 2 */

  /* Initialize leds */
  BSP_LED_Init(LED_GREEN);
  BSP_LED_Init(LED_YELLOW);
  BSP_LED_Init(LED_RED);

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  TaskHandle_t xTaskHandle1;
  TaskHandle_t xTaskHandle2;
  xTaskCreate(blinkLeds,"2LED", 256, NULL, 1, &xTaskHandle1);
  xTaskCreate(blinkLED,"led_1", 256, NULL, 1, &xTaskHandle2);
  markTaskScheduleRunning();
  vTaskStartScheduler();


  while (1)
  {
    /* USER CODE END WHILE */


    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}


static void MX_TIM7_Init(void)
{

  /* USER CODE BEGIN TIM7_Init 0 */

  /* USER CODE END TIM7_Init 0 */

  LL_TIM_InitTypeDef TIM_InitStruct = {0};

  /* Peripheral clock enable */
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM7);

  /* TIM7 interrupt Init */
  NVIC_SetPriority(TIM7_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
  // NVIC_SetPriority(TIM7_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0));
  NVIC_EnableIRQ(TIM7_IRQn);

  /* USER CODE BEGIN TIM7_Init 1 */

  // NVIC_DisableIRQ(TIM7_IRQn);
  LL_TIM_EnableIT_UPDATE(TIM7);

  /* USER CODE END TIM7_Init 1 */
  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);
  /* USER CODE BEGIN TIM7_Init 2 */
  // LL_TIM_DisableCounter(TIM7);
  LL_TIM_EnableIT_UPDATE(TIM7);
  /* USER CODE END TIM7_Init 2 */

}

  /* USER CODE BEGIN MX_GPIO_Init_2 */

  /* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */

void write_data_to_uart(uint8_t* data, uint8_t length){
    if(data == NULL)    return;
    while(length > 0){
        while(!LL_USART_IsActiveFlag_TC(UART4));
        LL_USART_TransmitData8(UART4, (uint8_t)(*data));
        length--;
        data++;
    }
}

static void blinkLeds(void *argument){
    // write_data_to_uart((uint8_t*)(&stringForMessage1), sizeof(stringForMessage1));
  char stringfortask1[] = "task 1 running correctly";
	while(1){
      write_data_to_uart((uint8_t*)(&stringfortask1), sizeof(stringfortask1));
    LL_GPIO_TogglePin(GPIOB, LL_GPIO_PIN_14| LL_GPIO_PIN_0);
        vTaskDelay(pdMS_TO_TICKS(800));
	}
}

static void blinkLED(void *argument){
  char stringfortask1[] = "running correctly the second task";
	while(1){
      write_data_to_uart((uint8_t*)(&stringfortask1), sizeof(stringfortask1));
    LL_GPIO_TogglePin(GPIOE, LL_GPIO_PIN_1);
        vTaskDelay(pdMS_TO_TICKS(500));
	}
}

void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
{
  char stringForMallocError[] = "Error for Stack overflow ";
  while (1){
      write_data_to_uart((uint8_t*)(&stringForMallocError), sizeof(stringForMallocError));
      vTaskDelay(pdMS_TO_TICKS(1000));
  }
}

void vApplicationMallocFailedHook(void)
{
    char stringForMallocError[] = "Error for malloc";
    while (1){
        write_data_to_uart((uint8_t*)(&stringForMallocError), sizeof(stringForMallocError));
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

void vApplicationIdleHook(void)
{
   char stringForIdle[] = "Idle task is running";
   if(counter %1000 == 0){
    counter++;
    write_data_to_uart((uint8_t*)(&stringForIdle), sizeof(stringForIdle));
   }
}

void vApplicationTickHook(void)
{
    char stringForIdle[] = "Tick hook task is running";
    write_data_to_uart((uint8_t*)(&stringForIdle), sizeof(stringForIdle));
    vTaskDelay(pdMS_TO_TICKS(3000));
}

void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )
{
    static StaticTask_t xIdleTaskTCBBuffer;
    static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];

    // Pass the buffers to FreeRTOS
    *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer;
    *ppxIdleTaskStackBuffer = uxIdleTaskStack;
    *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}

void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize )
{
    // The buffer that will hold the task's TCB (Task Control Block)
    static StaticTask_t xTimerTaskTCBBuffer;

    // The buffer that will hold the task's stack
    static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ];

    // Pass the buffers to FreeRTOS
    *ppxTimerTaskTCBBuffer = &xTimerTaskTCBBuffer;
    *ppxTimerTaskStackBuffer = uxTimerTaskStack;
    *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}

FreeRTOSConfig.h


 /* Ensure stdint is only used by the compiler, and not the assembler. */
 #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
     #include <stdint.h>
     extern uint32_t SystemCoreClock;
 #endif
 
 // CRITICAL FIXES:
 #define configUSE_PREEMPTION                    1
 #define configUSE_IDLE_HOOK                     1  // CHANGED: Enable for debugging
 #define configUSE_TICK_HOOK                     1  // CHANGED: Enable for debugging
 #define configCPU_CLOCK_HZ                      ( SystemCoreClock )
 #define configTICK_RATE_HZ                      ( ( TickType_t ) 1000 )
 #define configMAX_PRIORITIES                    ( 7 )
 #define configMINIMAL_STACK_SIZE                ( ( uint16_t ) 256 )  // CHANGED: Reduced from 512
 #define configTOTAL_HEAP_SIZE                   ( ( size_t ) ( 64 * 1024 ) )
 #define configMAX_TASK_NAME_LEN                 ( 16 )
 #define configUSE_TRACE_FACILITY                1
 #define configUSE_16_BIT_TICKS                  0
 #define configIDLE_SHOULD_YIELD                 1
 #define configUSE_MUTEXES                       1
 #define configQUEUE_REGISTRY_SIZE               8
 #define configCHECK_FOR_STACK_OVERFLOW          2  // CHANGED: Enable stack overflow detection
 #define configUSE_RECURSIVE_MUTEXES             1
 #define configUSE_MALLOC_FAILED_HOOK            1  // CHANGED: Enable for debugging
 #define configUSE_APPLICATION_TASK_TAG          0
 #define configUSE_COUNTING_SEMAPHORES           1
 #define configGENERATE_RUN_TIME_STATS           0
 
 // CRITICAL FIX: Enable dynamic allocation
 #define configSUPPORT_STATIC_ALLOCATION         0  // CHANGED: Disable static
 #define configSUPPORT_DYNAMIC_ALLOCATION        1  // ADDED: Enable dynamic allocation
 
 /* Co-routine definitions. */
 #define configUSE_CO_ROUTINES                   0
 #define configMAX_CO_ROUTINE_PRIORITIES         ( 2 )
 
 /* Software timer definitions. */
 #define configUSE_TIMERS                        0
 #define configTIMER_TASK_PRIORITY               ( 2 )
 #define configTIMER_QUEUE_LENGTH                10
 #define configTIMER_TASK_STACK_DEPTH            ( configMINIMAL_STACK_SIZE * 2 )
 
 /* Set the following definitions to 1 to include the API function, or zero
 to exclude the API function. */
 #define INCLUDE_vTaskPrioritySet                1
 #define INCLUDE_uxTaskPriorityGet               1
 #define INCLUDE_vTaskDelete                     1
 #define INCLUDE_vTaskCleanUpResources           1
 #define INCLUDE_vTaskSuspend                    1
 #define INCLUDE_vTaskDelayUntil                 1
 #define INCLUDE_vTaskDelay                      1
 #define INCLUDE_xQueueGetMutexHolder            1
 #define INCLUDE_xTaskGetSchedulerState          1
 #define INCLUDE_eTaskGetState                   1
 #define INCLUDE_uxTaskGetStackHighWaterMark     1  // ADDED: For stack debugging
 
 /* Cortex-M specific definitions. */
 #ifdef __NVIC_PRIO_BITS
  /* __NVIC_PRIO_BITS will be specified when CMSIS is being used. */
  #define configPRIO_BITS                        __NVIC_PRIO_BITS
 #else
  #define configPRIO_BITS                        4        /* 15 priority levels */
 #endif
 
 /* The lowest interrupt priority that can be used in a call to a "set priority"
 function. */
 #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY     0xf
 
 /* The highest interrupt priority that can be used by any interrupt service
 routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
 INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
 PRIORITY THAN THIS! (higher priorities are lower numeric values. */
 #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY  5
 
 /* Interrupt priorities used by the kernel port layer itself.  These are generic
 to all Cortex-M ports, and do not rely on any particular library functions. */
 #define configKERNEL_INTERRUPT_PRIORITY     ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
 /* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
 See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
 #define configMAX_SYSCALL_INTERRUPT_PRIORITY  ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
 
 /* Normal assert() semantics without relying on the provision of an assert.h
 header file. */
 #define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }
 
 /* CRITICAL FIX: These MUST be commented out when using custom tick source (TIM7)
    Uncomment ONLY if using SysTick for FreeRTOS tick */
 // #define vPortSVCHandler    SVC_Handler
 // #define xPortPendSVHandler PendSV_Handler
 // #define xPortSysTickHandler SysTick_Handler
 
 /* ADDED: Memory management scheme - use heap_4.c */
 #define configUSE_NEWLIB_REENTRANT              0
 
 #endif /* FREERTOS_CONFIG_H */

stm32h7xx_it.c:


void TIM7_IRQHandler(void)
{
 if (LL_TIM_IsActiveFlag_UPDATE(TIM7)) {

xPortSysTickHandler();
  }
  LL_TIM_ClearFlag_UPDATE(TIM7);
}

In fact the FreeRTOS related interrupts have intentionally the lowest prio.

I’m not sure but I think you should comment only xPortSysTickHandlerbecause of using TIM7 but not all other FreeRTOS handlers.

As @hs2 already pointed out, you likely need SVC and PendSV handler. Please uncomment these lines and see if it works.

I did try what you suggested but that isn’t it. I think that for priority lower than the highest, the freeRTOS doesn’t simple run,

Why I think so? Because of this:

The freeRTOS is enabeled but there are no ticks which is why there is no operation. I am having a hard time solving this exact issue. @aggarg any idea?

Can you step through the xPortStartScheduler and see if you are able to jump to the first task? Does the interrupt work if you do not use FreeRTOS?

Can you share the complete project?

I try but the PC doesn’t enter the first task.

I can sure. It is on GitHub here

I see that you are using Keil MDK and I am trying to see if I can get a license. Meanwhile, if you can create a STM32CubeIDE project, I can give it a try sooner.