I’m using FreeRTOS on ZedBoard (Zynq 7020) as development platform, and Xilinx Vitis 2023.2 SDK. I have FreeRTOS up and running, tick timer working, multitasking working, lwip (TCP, UDP) working. But if a task calls vTaskDelay(), that task never wakes up. I trace this behavior to whether lwip_init() is called or not. If lwip_init() is not called, vTaskDelay() works fine. From my searches, there seemed to be a problem with GIC (interrupt controller) re-initialize, and connect ISRs after vTaskStartScheduler(). I would think that lwip_init() connects ethernet ISR at some point. Has anyone managed to have FreeRTOS+lwip working with functional vTaskDelay()?
I think Xilinx provide projects that use both FreeRTOS and lwIP at the same time. The pre-Vitus tools have a wizard that creates projects that allow you to use either a bare metal or FreeRTOS BSP at the time of project creation, and allows you to add in lwIP. Does Vitus have a similar workflow?
I agree the interrupt controller initialisation sequence is most likely the cause. I presume the tick count is no longer incrementing when a task fails to return from vTaskDelay(), and the same issue will be present for any other delay, such as blocking to wait on a queue with a timeout.
Yes, Vitis 2023.2 still has such example projects even though the workflow is now different. I did use the FreeRTOS+lwIP example project in Vitis 2023.2 to get going.
The strangest thing is that i have other tasks and they are still functional after the LED task calls vTaskDelay() and never wakes up, thus the LED stops blinking. The other tasks being the network task itself and my application task pending on a socket. I can still ping the board and the UDP application task can still receive/send UDP messages to/from a Windows host perfectly. Perhaps the network task is interrupt driven and the kernel does not depend on tick count to wake the socket pending task. If indeed something had happened to the tick count, task context switching would no longer function. I’ll monitor the tick ISR to see if it still triggers. And I will put in another task reading from a queue with timeout to see if it still works after the LED task calls vTaskDelay().
If none of those other tasks are waiting on timed events, Richard’s explanations still apply.
To help others who may find this thread, i post my solution here. This problem is not new, and there had been other suggestions going back several years that one can find with web search. My post is specific to the Vitis 2023.2 install as that’s what i’m working with. I have no idea what had come before.
vTaskStartScheduler() installs the tick timer interrupt handler. It winds its way through the call stack and eventually calls xscugic.c, XScuGic_CfgInitialize() with its own XScuGic instance.
lwip_init() has nothing to do with ethernet interrupts which is handled by xemac_add(). xemac_add() winds its way through the call stack and eventually calls XScuGic_CfgInitialize() with its own XScuGic instance.
XScuGic_CfgInitialize() has buitin guard to prevent doing inititialization more than once with the same XScuGic instance. But since it is called with two separate XScuGic instances it does initialization twice. The second time clobbers the first time thus wiping the tick timer handler.
To minimize side effects, I add but a few changes to XScuGic_CfgInitialize(). Here are my changes:
- Add a guard to prevent certain actions from being done more than once.
- Put the guard around the for loop.
- Put the guard around the call to XScuGic_Stop().
s32 XScuGic_CfgInitialize(XScuGic *InstancePtr,
XScuGic_Config *ConfigPtr,
u32 EffectiveAddr)
{
…
static int32_t XScuGic_CfgInitialize_Done = 0;
…
if (InstancePtr->IsReady != XIL_COMPONENT_IS_READY) {
…
if (!XScuGic_CfgInitialize_Done) {
for (Int_Id = 0U; Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS;
Int_Id++) {
…
}
}
…
if (!XScuGic_CfgInitialize_Done) {
XScuGic_Stop(InstancePtr);
}
…
InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
XScuGic_CfgInitialize_Done = 1;
}
return XST_SUCCESS;
}
After these code changes, my test shows that ethernet is functional, and task(s) that call vTaskDelay() wake up as expected.
Thank you for sharing your solution!