Non-blocking print to LCD

Hi, I am running a project on a MEGA2560 and using a 20x4 LCD display driven via I2C.

I need to periodically (say 1 per second) output a short status message on the LCD (say 15 chars) over the I2C bus.

I understand the “Serial.print” output is non-blocking (as long as you dont flood the buffer) but is the same true for the I2C bus ??

In the case of “Serial” I guess that the buffering is handled at the device driver level and so may not be part of the “print” class ??

I need the status message not to cause hesitation in the normal code flow – is there a way to achieve this ??

Best regards,
Dave

The regular Wire.h is blocking.

A backpack requires several I2C bytes per character written on the LCD.

In practice a human will not notice the execution time.
Try it for yourself.

You would not use blocking I2C in a Guided Missile.

David.

This is a frustration with many libraries and comes from the desire to create an interface that completes a task in a single function call, automatically making it blocking. If you need it to be non blocking you will have to write your own non blocking driver. Write the data to a buffer then have code that puts the data a byte at a time into the I2C buffer. You will have to learn how to control the I2C hardware, which means carefully studying the datasheet for the controller.

Wire.h handles everything with interrupts.

beginTransmission(), write(), ... simply sets up data in a buffer.
endTransmission() starts the I2C sequence and waits for completion.

i.e. it is blocking for your foreground logic.

If you split the endTransmission() function into two:
startI2Csequence()
isI2CsequenceBusy()

you can get on with the rest of your life while the I2C is running.

Note that you will have to check isI2CsequenceBusy() before you use a new beginTransmission() "set up"

Similarly with requestFrom()

Most Arduino sketches will want endTransmission() or requestFrom() to complete. So I can understand the reasoning.

The OP is concerned that the I2C backpack behaviour might be noticeable. This is unlikely.

However some LiquidCrystal_I2C libraries are spectacularly crap.
I advise you to use "hd44780" library.

David.

The short answer to your question is no, there is now way to provide non blocking i/o to a character LCD using existing libraries.
To write your own code to do that is massive undertaking, and even then I'm not sure you would end up much better off than some of the already available alternatives.

While I know it is very common practice these days, not just in Arduino code, but all over the place to write code that essentially does some sort of polling so it very much depends on a particular speed of some sort of looping code, IMO, it is very bad practice and it concerns me greatly.
i.e. if "bad" things can happen, or there is a poor user experience if there are intermittent delays or the "loop" has variable timing, then, IMO, the overall s/w design for the project is wrong.

My question in this case i how much time is too long when updating the display?
is 25ms too long to print your 15 character message to the LCD?

There are several ways to reduce that. Like:

  • updating the display less often (doesn't reduce the actual update time, but reduces the frequency of delays)
  • only printing what has changed,
  • changing to a better/faster library
  • running the i2c bus faster.

The hd44780 library is much faster than other LCD libraries.

If you don't have any 100khz slaves on bus, you could also run the i2c bus a 400Khz as most PCF8574 chips will operate at 400 kHz.

When using hd44780 library hd44780_I2Cexp i/o class and running 400Khz, you will get LCD update times that are actually faster (and hence lower delays) than using the LiquidCrystal library which uses Arduino pins to directly control the LCD.

For Example here are the transfer times needed to send a single character to the LCD:

1487 us  LiquidCrystal_I2C
 555 us  hd44780 hd44780_I2Cexp i/o class
 284 us  LiqudCrystal
 205 us  hd44780 hd44780_I2Cexp i/o class @ 400 khz

Using that, you can calculate the timing delay overhead to send 15 characters based on the h/w and library used.
With the LiqudCrystal_I2C library you would be blocked for 22.3ms whereas when using the hd44780 library at 400kHz it would reduce to around 3ms

So you can see, without changing anything, the blocking time for LCD updates can be reduced by a factor of 3 by just changing to the hd44780 library and by a factor 7 by changing to the hd44780 library and running the i2c bus a 400khz.

Other things like updating less often and only printing what has changed are also very effective at reducing overheads.

--- bill

Firstly, let me appologise for not replying earlier to these excelent responses … although I set “notify me of replies” I received none and it wasnt in my junk/spam folder either!! :frowning:

I have to use I2C because of lack of pins for use on the LCD.
I am using a joystick to control a stepper motor and outputting a 15 char message to the LCD once a second causes a noticable “jerk” in the steppers movement.

The libraries I am currently using are <Wire.h> and <LiquidCrystal_PCF8574.h>

I note with great interest Bill’s comparason of the other libraries and I will certainly have a good look at them :slight_smile:

Beast regards,
Dave

Here is the byte timing with the numbers for the LiquidCrystal_PCF8574 library.

1487 us  LiquidCrystal_I2C
1018 us  LiquidCrystal_PCF8574
 555 us  hd44780 hd44780_I2Cexp i/o class
 423 us  LiquidCrystal_PCF8574 @ 400kHz
 284 us  LiqudCrystal (using 4 bit direct pin control)
 205 us  hd44780 hd44780_I2Cexp i/o class @ 400 kHz

The hd44780_I2Cexp i/o class is quite a bit faster than the LiquidCrystal_PCF8574 library updating the display on the same hardware.
About 1.8x the speed at the default 100 kHz block and about 2x the speed at 400 kHz

This is running on the exact same Uno board and LCD display and i2c backpack.

All that said. This is new information:

I am using a joystick to control a stepper motor and outputting a 15 char message to the LCD once a second causes a noticable "jerk" in the steppers movement.

This may not be solvable.
The Wire library uses interrupts and it is possible that that Wire code can cause some jitter to the servo timing which also uses interrupts.
This normally isn't so much of a "jerk" but rather some twitching.

The "jerk" you refer to could be due to the foreground code (your sketch) as depending on how you wrote your code to do position changes the sketch code could be getting delayed in its ability update positions on consistent time boundaries.
These delays could cause inconstant movements or movements that are not as smooth when changing positions from input like a joystick.

--- bill

OK I changed over to the "hd44780 hd44780_I2Cexp" libraries at 400 and it made a significant difference, there is still a minor "twich" once a second when the steppers are moving, but it is almost unnoticeable.

So, I declare that as solved :wink:

Thanks for all the help guys,
Dave

Not sure what you are printing on the LCD, but if some of it is static (not changing) you could get some further improvements, by not reprinting the static information.

i.e. just position to the location that has changed and update that portion of the display.

And you should really avoid using clear() or home() as those are very slow.
hd44780 at least will not wait for their completion like other libraries.
But you will take a delay hit if you subsequently send another instruction to the LCD less than 2ms after clear() or home()

--- bill