FreeRTOS alongside code with bursts of heavy interrupt usage

Hey there!

I’m writing an application using freeRTOS and have a bit of an issue.
It’s using an STM32F4 and freertos is included from cube mx

I’ve imported a 44780 LCD driver which uses its “own” hardware timer to very quickly repeatedly drive the communication function that handles all the communication with the 4x20 character LCD module.

What seems to happen is my user interface task runs, which results in a screen redraw, and that screen redraw process takes about 50ms all up (out of a 300ms period… note that this period is meant to be 250ms but the screen control code blocks this process too)

while that redraw happens, nothing else can basically run… and I’m not sure that pulling down that raw interrupt priority or trying to replace it with something driven from freeRTOS would be a great idea…

NOW that’s not the end of the world… none of the code is time critical to 50ms… in fact I’m expecting my “critical tasks” that take 100us or so to run, to run at a 100ms period and the display to run about 250ms period… And the base system tick fro freertos is 1ms -

But it’d be nice to be able to have all my tasks next start time NOT be blown out by 50ms every time they are running or scheduled to restart when the screen redraws… even if the 50ms blocks them occasionally, there’s still heaps of dead time in the application, and so if there was a way to schedule tasks to a regular period rather than asking them to halt for a set period of time at the end of the task (I use osDelay() as that’s what the examples I have use…)

I guess I’d like to know what other people have done when using an LCD module with freeRTOS… I imagine it’s a pretty common thing.

OK… well I discovered vTaskDelayUntil() and implemented that for my tasks…
Unfortunately tasks are still being delayed every time the LCD is updated… so I guess this means it’s not just the tasks being locked out, but the actual RTOS ticks!

Would love some pointers here from people who have dealt with similar, as I’ve not had this with freertos before. Till now, my RTOS tick was never blocked out like this by anything else as all the intensive IO stuff I’ve handled under freeRTOS on STM32 were assisted by DMA, and really only needed attention via interrupts occasionally. or could even just be left till they were looked at by tasks.

I guess I need to either

  1. make sure the freertos system tick interrupt is higher than the timer based interrupt for writing the LCD and see if it damages the LCD writing
  2. live with it…
  3. get rid of the timer based interrupt for triggering the LCD state machine code, and speed up the freeRTOS ticks to some crazy rate, and try to get a highest priority task to drive the LCD state machine code…

My guess is that what is happening is that the LCD driver is spending all the CPU in the ISR. It could be that this is part of the Cubes problem of poorly written ISRs (I have have seen some drivers that block for time periods in the ISR, which does basically stop the rest of the system).

Another possibility is that the ISR action just takes all the processing power.

I would look closely at the display specs and the driver and see if it can be modified to be more friendly to the rest of the system, perhaps even using a non-interrupt based driver, as the data transfer to the display probably doesn’t need to have a real tight deadline.

1 Like

Concurring with Richard D - I have seen some of those drivers poll inside the driver’s interrupt code, making the ISRs execute for a very long time. It might be that you need to re-implement the interrupt such that it defers the processing to a low priority task using a non interrupt driver driver, or alternatively, re-implement the driver to make it event driven (for example, if it is a serial bus such as SPI, generate a new interrupt at the end of each transaction rather than sitting in the interrupt waiting for the current transaction to complete). You need to make sure updating the display is not too slow though - as the human eye doesn’t find that appealing.

First thing is to determine if my suspicion of what is causing the behaviour you describe is correct though - step through the ISR code in the debugger to see what it is doing.

1 Like

thanks Richard and Richard!

this 44780 library written for stm32 is just something I found online and got up and running with minimal work (so free, but now it looks like I got what I paid for) I was hoping to keep using it, because I kind of like the whole construction is uses with a message queue that you write to from the application, and and executive that runs it - I thought that would make it pretty robust… but read on…

I spent some more time looking into it… played about with reducing the interrupt priority from the timer but that’s not helping either… seems like the culprit is a delay_us() blocking function it uses… which in turn uses direct control of the Data Watchpoint and Trace (DWT) unit from the cortex m core… to create either one or two 50us blocks every time it toggles the enable pin… (which it does every time it sets or reads 4 bits on the bus, which it does multiple times for each bus operation…) I’m guessing that doing this in a function called by an interrupt that is running relatively fast is what’s blocking my freeRTOS ticks, because I haven’t seen any explicit disabling of ISRs.

Starting to feel pretty confident that the way forward is to kill the timer based interrupt (or wind it way back) and confirm that opens up enough time for my 1ms rtos ticks to happen, and what the LCD looks like when it’s having commands sent a bit slower.

I also probed the ISR function and confirmed that interrupt fires every 200us.

I also noticed the executive function (the one launched by the interrupt handler from a timer) is recursive. it calls itself repeatedly to traverse the entire message queue it finds when called… so it plays silly buggers with the stack, and blocks for an unknown multiple of 100us (often 250+ multiples) each time it runs… Aaaargh! Looks like this library is needing a bit of a rewrite whether I like it or not.

Dealing with the LCD message queue one message (or just a few) at a time (rather than running through the complete queue) plus firing the interrupt every 2ms rather than every 200us should give freeRTOS room to breathe, I hope.

OK… problem mitigated by severely reducing the blocking time.

I had a look at the chipset datasheet and there’s really no reason that the enable strobe needs to be 50us… I changed it to 5us, and everything blasts through 10x faster… the commands are being cleared out super fast, under 200us, and so the freeRTOS tick isn’t being choked out anymore.

still need to fix the recursion… :frowning:

I’m guessing whoever developed this library had an eval board and a breadboard and long breadboard patch leads, and all the stray capacitance that these things come with.

Thanks for your help, Richards.

Another thing to do to make the driver more RTOS friendly would be a small modification to the ISR to have it defer the actual operation to a task that the ISR defers to. The ISR then is very short, being basically just the activation of this driver task, and then you stop blocking the system.

1 Like