I want to use a library for an LCD for STM32: LiquidCrystal, and possibly some other libraries.

I noticed this library is full of HAL_Delay calls, not only during initialisation but also during processing functions.

My application needs to read MIDI data and process them, preferably within 10 ms, so a HAL_Delay of 1, 2, 5 and 50 ms as are part of e.g. that LiquidCrystal library is messing up the MIDI data.

What should I do (in general or specific) to use libraries using HAL_Delay calls inside a time critical application? Things I can come up with:

  • Rewrite the library using interrupts? (seems like a lot of work)
  • Use another MCU (STM32) to handle that (more hardware/soldering work)
  • A better solution?
  • 2
    \$\begingroup\$ Can you process the MIDI data in an interrupt handler? \$\endgroup\$ – Steve G May 24 at 9:37
  • \$\begingroup\$ @SteveG I can process the incoming/outgoing data, but not the processing itself (I need to do quite some lookup/calculations on it before sending). \$\endgroup\$ – Michel Keijzers May 24 at 9:40

If your cycle time allows for it (read: is fast enough) another approach is to split the library so that the function is returning at each delay.

The function will be called at each cycle and it then can decide if the necessary time has passed since the last action and do the next steps to the next delay.

Though you might want to use this approach only if the library is quite relaxed to the maximum time needed and your system has a well defined cycle time.

  • \$\begingroup\$ Yes, I think that's a good option, especially in that library it doesn't matter to wait longer than needed, I just have to make some kind of mechanism to buffer things possibly. \$\endgroup\$ – Michel Keijzers May 24 at 10:09

You can implement an RTOS and replace the HAL_Delay for the equivalent Thread_Sleep function available.

But the library doesn't look very complicated, you can probably pick any of the options and do it in equal time.

A secondary MCU is almost never the right answer.

  • \$\begingroup\$ Thanks, not sure if I want to add another concept (RTOS) though. But good to know that is also an alternative.Maybe at a (much) later stage I want to use a separate MCU for the screen but that's because I might have multiple MCUs connecting to that single GUI device. \$\endgroup\$ – Michel Keijzers May 24 at 10:08

Rather do the MIDI processing in interrupts.

I assume you are receiving MIDI data through a UART, and there is a receive interrupt that stores incoming data in a buffer.

The problem is that you'd lose data if it can't be processed in less than 320 µs (the time to receive one byte) in the receive interrupt handler. If the processing would take more time, you'll need a second interrupt handler.

Use the PENDSV interrupt for the processing. Give it a lower priority than the receive interrupt, so that it can continue receiving data. It should also have lower priority than the SysTick interrupt, otherwise it would block the delays based on that.

This way, the processing can run on lower priority than the hardware interrupts, but it will still preempt the application libraries.

  • \$\begingroup\$ Thanks for this interesting idea, I have to check if I can use it, I might get MIDI data from 3 different sources eventually, so that 320 us might be tricky to reach, also depending on the calculations/processing I need to do (I need to work that out better). \$\endgroup\$ – Michel Keijzers May 24 at 10:43
  • 1
    \$\begingroup\$ Then you'd have 3 receive interrupts, each could set a flag and trigger PENDSV when its buffer needs processing. \$\endgroup\$ – berendi May 24 at 10:56
  • \$\begingroup\$ True, thanks, guess the amount does not matter, just the processing time ... I cannot answer that now, but I will take your idea into account for this project (and otherwise) for other projects. \$\endgroup\$ – Michel Keijzers May 24 at 11:01

The library is clearly not optimal for your usage, it does show that it is a port of Arduino library to STM32 HAL. While it is very general and configurable how the LCD is connected to GPIO pins, there are some downsides like the delay system.

First of all, the LCD could be connected to a CPU with 1 MHz (1 microsecond) bus cycles. Most commands take up to 50 microsecods to finish execution, so it could execute at least 20000 commands per second. The slowest command takes 2 milliseconds. So the bus cycle delays in the code are roughly 2000 times longer than necessary, just because the minimum delay it uses is 1 ms.

The delays are really an issue. In fact, as you can call HAL_delay at any given moment in time, the next systick will happen anywhere between 0 and 1 milliseconds, so these delays can be even too short as the systick might happen after 1 microsecond. Replace with tuned busy loop to get down to microsecond delays accurately.

  • Don't use another CPU for this. Better spent energy would be to rewrite suitable LCD driver from scratch.
  • Using interrupts might be a solution, depending on what you mean by that. For instance, writing one character per systick interrupt might work. But only after the delays are fixed to have 1 microsecond bus cycles.
  • Yes, many solutions. For example, use another LCD driver that suits your usage better. Use the BUSY flag from LCD, to know when it is ready, instead of always waiting long enough time. Also the suggestions in other answers are good.

Also, when choosing which libraries to use, always consider the licence of libraries what they allow you to do and what they prevent you from doing.

  • \$\begingroup\$ Thanks for all this useful information. Maybe (since I never did it before) this quite easy library code is fairly easy to rewrite anyway. Btw, the project is just for my own use. \$\endgroup\$ – Michel Keijzers May 24 at 19:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.