Fun with the TFT - FreeRTOS Debugging | Cypress Semiconductor
Fun with the TFT - FreeRTOS Debugging
If you have been following along with my TFT blogs you may have tried to use the debugger to figure out what was causing the crescent shapes bug. But, because I added FreeRTOS to the project, you’d have seen these warnings when starting the debugger.
Error: FreeRTOS: uxTopUsedPriority is not defined, consult the OpenOCD manual for a work-around
All this means is that the OCD connection software is looking for a symbol that is no longer part of the FreeRTOS code base. The actual debugging still works but you get no information about tasks, which is really handy when you have 6 tasks running the same C code.
There is a workaround to the problem that is easy to implement. You just define and use that variable. If you read my last blog you’ll know that I have something of an aversion to using global variables but this is a case where you simply have to. So I’ll suck it up and get on with it. Add this line at the top of the file, outside of any function.
int uxTopUsedPriority; // FreeRTOS/OCD debug workaround
Then, in main(), add a line that just sets it to the lowest priority.
uxTopUsedPriority = configMAX_PRIORITIES - 1; // FreeRTOS/OCD debug workaround
That’s all you need to do. It gets rid of the warning and turns on task-aware debugging. Cool, but what’s that? Well, start the debugger and put a breakpoint in your bounce() function, on the vTaskDelay() call is a good place. Then run the code until the breakpoint is hit. Look in the debugger view – you can see the 6 bounce tasks, plus a Timer Service and IDLE tasks.
Here are screenshots of the debugger view from before the OS starts (note the “No RTOS thread” message) and after hitting the breakpoint a couple of times. In the second picture you see all the threads and can work out where the code is when the task was stopped. In my picture b1 is suspended in the vTaskDelay() call and b2 has just hit the breakpoint.
Another cool thing to do with breakpoints is to make them task-specific. Go to the breakpoints view and locate the breakpoint in bounce(). Right-click to open the Breakpoint Properties window. Click on Filter and you’ll see a list of tasks with checkboxes. Unset all but one task and apply. Now run the code again and it will only break in the task you chose.
This can be really handy because you make the tools figure out whether you have stopped in the context you are actually interested in. But there is a price. It’s slow. This is because the breakpoint is still hit and the target register set and some memory has to be sent up to the debugger every time.
It’s what I call Heisenberg debugging. You can use the debugger to look at what’s happening, but the act of looking somewhat alters the behavior. When you are waiting for mission-critical events, like Bluetooth Low Energy connection events, this is a real problem. But when you are debugging a system with no such concerns, like our’s, it’s a useful tool. And fun too… put the breakpoint in your slowest-running task and watch the balls all crawl slowly along while your task is asleep.
Everyone who sees my screen when I am working on these blogs says I am re-creating “pong”. Well, that was not my plan… but why not? Maybe I should add a movable paddle and a score board!