Task get stuck in vTaskDelay and triggers WWDG_IRQHandler () [STM32_f4]

Here is an excerpt of the code I am running:

// Task 1000ms
TaskHandle_t xTaskHandle_1000ms;
const char NAME_1000MS[] = "Task_1000ms";
const size_t STACK_SIZE_1000MS = 256;
const uint8_t PRIORITY_1000MS = 2;
const struct TaskParams TASK_PARAMS_1000MS = {.PERIOD = 1000};

// Task 200ms
TaskHandle_t xTaskHandle_200ms;
const char NAME_200MS[] = "Task_200ms";
const size_t STACK_SIZE_200MS = 256;
const uint8_t PRIORITY_200MS = 2;
const struct TaskParams TASK_PARAMS_200MS = {.PERIOD = 200};

void application_setup() {
  xTaskCreate(task_1000ms, NAME_1000MS, STACK_SIZE_1000MS,
              (void *)&TASK_PARAMS_1000MS, PRIORITY_1000MS,

  xTaskCreate(task_200ms, NAME_200MS, STACK_SIZE_200MS,
              (void *)&TASK_PARAMS_200MS, PRIORITY_200MS, *&xTaskHandle_200ms);


static void task_1000ms(void *pVParameters) // This is a task.
  const struct TaskParams *params = (struct TaskParams *)pVParameters;

  while (1) {
    // Run activities

Once the program enters vTaskDelay, as commented above, it never comes out.

Here is where it gets stuck:

WWDG_IRQHandler () at startup_stm32f446xx.s:114
114       b  Infinite_Loop

The task_200ms does not do anything. Even if I completely remove it, I get the same issue.
What should I check? Is there anything special in FreeRTOSConfig.h that I should enable/disable?

wwdg looks like the windowed watchdog which appears to be enabled. If so you need to disarm it frequently. Do not enable it until you have working code to disarm it timely.

The WWDG seems disabled:

Screenshot 2024-01-31 at 21.40.30

Some more info: in startup_stm32f446xx.s, line 114 I have that b Infinite_Loop line that you see in the following excerpt:

    .section  .text.Default_Handler,"ax",%progbits
  b  Infinite_Loop
  .size  Default_Handler, .-Default_Handler

And here is the interrupt table setup:

so are you sure that you enter vTaskDelay(), or is it possible that your code faults in debug_main or on the way out? What do the two functions do? If you replace them with a simple increment of a global variable, do you still see the faults?

Thanks for the suggestion.
I replaced the task with the following:

uint32_t global_var1 = 0;
static void task_1000ms(void *pVParameters) 
  const struct TaskParams *params = (struct TaskParams *)pVParameters;
  while (1) {
    vTaskDelay(pdMS_TO_TICKS(params->PERIOD)); // one tick delay (15ms)
    ; // break point here never reached. 

but the problem is still there. :frowning: I may think that the problem may rely on some generated file from CubeMX but I am not sure.
Let me know if you need more info!

Did you enable stack checking and configASSERT ? Is any task running ?
Can you put breakpoints to the task functions to see if they are invoked or not and maybe step thru the code ?
The WWDG handler symbol might be unrelated and misleading.

Yes! I have done that already. I stepped into both blink_main() and debug_main() and everything looks correct there.
I put a breakpoint just before and after vTaskDelay()

In debug_main() I have the following code:

#define NOOP ({ ; })
void debug_main() {

  TaskStatus_t xTaskDetails_1000ms;

  /* Check the handle is not NULL. */

  /* Use the handle to obtain further information about the task. */
  vTaskGetInfo(xTaskHandle_1000ms, &xTaskDetails_1000ms, pdTRUE, eInvalid);

  volatile UBaseType_t number = xTaskDetails_1000ms.xTaskNumber;
  volatile eTaskState state = xTaskDetails_1000ms.eCurrentState;
  volatile configSTACK_DEPTH_TYPE watermark =
  volatile UBaseType_t priority = xTaskDetails_1000ms.uxCurrentPriority;

  NOOP; // breakpoint here!

I placed a breakpoint before and after calling vTaskDelay. Until before the call all ok, but once entered vTaskDelay things get stuck. I try to step into vTaskDelay now…

EDIT: done. I put a breakpoint on the vTaskDelay call and I stepped into the function. After a number of steps inside vTaskDelay I went back to the main while(1) loop and I could have seen global_var1 increasing its value at each iteration. Hence, it went through. I manually stepped for 3 iterations. Then, I hit Continue button in the debugger and… everything hung again. I hit Ctrl+C and, again, I was again in the following

WWDG_IRQHandler () at startup_stm32f446xx.s:114
114       b  Infinite_Loop

so it may be the wwdg after all. Have you checked the related sfrs to see if some code enables it after all?

No, I should dig into the manual for getting at this low level and now it is quite late and I need to sleep :smiley:

I will study how to check it tomorrow (it would be the first time I do something at so low level) but if you have any other ideas on what could possible be/what to try without going so deep, I am all ear.

Goodnight in the meantime and thanks for the support! :slight_smile:

Good morning! :smiley:

I finally made a test, I write next the procedure I followed to be sure that I didn’t do things wrong.

I checked on the stm32 f4 datasheet and the WWDG address range is 0x4000 2C00 - 0x4000 2FFF and then the Control register (WWDG_CR) Address offset: 0x00 Reset value: 0x0000 007F and I want to see the status of Bit7 WDGA:Activationbit.

Once my system got stuck, I run print (*((volatile uint32_t *)0x40002C00) >> 7) & 0x01 from gdb obtaining 0, thus suggesting that the WWDG is not enabled.

Make sense?

I keep on going with my investigation and I made the following test.
I made a new CubeMX project and I edited the Makefile to pick the CubeMX FreeRTOS files rather than the files from the latest FreeRTOS release.
That is I replaced the following lines:

freertos/croutine.c \
freertos/event_groups.c \
freertos/list.c \
freertos/queue.c \
freertos/stream_buffer.c \
freertos/tasks.c \
freertos/timers.c \
freertos/portable/MemMang/heap_4.c \

with the following lines (Middlewares … are the files from CubeMX):

Middlewares/Third_Party/FreeRTOS/Source/croutine.c \
Middlewares/Third_Party/FreeRTOS/Source/event_groups.c \
Middlewares/Third_Party/FreeRTOS/Source/list.c \
Middlewares/Third_Party/FreeRTOS/Source/queue.c \
Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c \
Middlewares/Third_Party/FreeRTOS/Source/tasks.c \
Middlewares/Third_Party/FreeRTOS/Source/timers.c \
Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c \
Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c \

and the following lines:

-Ifreertos/include \

with the following lines:

-IMiddlewares/Third_Party/FreeRTOS/Source/include \
-IMiddlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 \
-IMiddlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F \

and nothing more. The FreeRTOSConfig.h file is the same. The memory scheme used is heap_4.c for both.

By using the “Middlewares” FreeRTOS version, then things work well.

What I noticed is that in the source there is Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c \ which actually makes all the difference. If I include this file in the build when using the “vanilla” freertos (i.e. the freertos set of files/included etc, rather than the Middlewares set). Then, everything works. Inspection of such a file shows a number of FreeRTOS settings that go beyond my scope of knowledge and that make everything to work.

If anyone wants to take a look at that file and explain what is going on, it would be appreciated.

My conclusion is that it is perhaps safer (or at least less troublesome) to use the FreeRTOS version shipped with STM32CubeMX, even if it may be an older version.
I also noticed that when FreeRTOS is selected from CubeMx, then some settings are automatically fixed (for example some interrupt priorities are automatically set to a value greater than 0, etc.).

Is your complete project available somewhere? If not, can you share your FreeRTOSConfig.h?


Everything is in stm32_platform folder. The FreeRTOSConfig.h is under Core/Inc.
There are both the version of FreeRTOS: the one from CubeMX in Middelwares, the latest freertos is in freertos folder.

Add the following line here:

#define xPortSysTickHandler SysTick_Handler 
1 Like

Ok, I understand what is that but it was not easy to find out!

However, now it works.
I had a vApplicationGetIdleTaskMemory() error, that I fixed by setting #define configSUPPORT_STATIC_ALLOCATION 0 in FreeRTOSConfig.

Glad that it works.

If you want to use static allocation, you can also set configKERNEL_PROVIDED_STATIC_MEMORY to 1 to use kernel provided default implementations of these callbacks.

1 Like