-
Notifications
You must be signed in to change notification settings - Fork 872
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixes for several lcd_1602_i2c.c issues #597
Comments
Apologies if this is a stupid question, but the datasheet that you're quoting is for a parallel-controlled LCD (e.g. https://uk.rs-online.com/web/p/lcd-monochrome-displays/2109029 ) but I believe the |
@lurch Not a dumb question at all, happy to clarify. Quick background and terminology: All of the various "LCDxxxx" modules (xxxx = 1602 or 2004) that I've come But the underlying timing requirements of the base LCD board are unaffected So the effect of the relatively slow I2C bridge is simply to reduce the rate The problems with the original example code are related to the following (a) Minimum assertion time for the "E" ('enable') line. (b) Minimum required delays between the issuance of the first three For the three LCD base vendors for which I have datasheets (Shenzen Eone The two interrelated problems with the example code vis a vis the above (1) The initialization delay requirements (b) are not explicitly enforced (2) The assertion time for the E line is being artificially extended The explanation as to why the example code actually works at all, despite And the explanation as to the curious "things don't work" comment -- which So the example code is, effectively, "working by accident". A secondary effect of (2) is that the artificially long E delay slows all The fixes for the above fortuitously-working situation are straightforward: So there you go. Hope the above long-winded yappage answers your questions. If you're still skeptical or curious, I'd suggest making up an original/fixed One additional note that may have been confusing: In my original post,
rather than the cited WaveShare datasheet. So if you were headscratching |
Thanks for the superbly detailed explanation! ❤️ Would you like to submit a PR with your suggested changes against the |
I'm not a party to this but am compelled to say this is by far the best level of detail and overall explanation I've seen outside a work setting. Pro stuff, A+. |
Decline, sorry. |
Re the following comment in
lcd_toggle_enable()
accompanying the valueof 600 us for
DELAY_US
:Various datasheets I've come across for these 16x2 (and 20x4) modules from
3-4 different manufacturers show the Enable minimum active pulse dwell
(e.g. t_w,min, on p. 14 of [1]) as 250 ns or less. So that 600 us value is
excessive by more than three orders of magnitude.
The reason that the example code needs that huge value in order to "work"
properly is because the required delays (e.g. per [1], p. 17) between the
first three initialization commands are missing from
lcd_init().
But thetime expended in
lcd_toggle_enable()
, due that artificially huge 600 usDELAY_US
is fortuitously compensating (partially) for the missingdelays in
lcd_init()
(sincelcd_init()
invokeslcd_toggle_enable()
via
lcd_send_byte()
on every write operation.)Behavior observed with the present code, due to the above issues:
Unreliable initialization: Malformed screen characters occasionally
appear immediately after init. (Observed on approximately 5 % of
inits of most 16x2 units that I have, depending on LCD vendor, and
considerably more often (perhaps 10% - 20%) on the 20x4 modules,
which have near-identical interface specs).
Write times much slower than the LCD module is capable of.
Write times scale poorly with I2C clock rate. (For example,
increasing the I2C clock by a factor of 10 leads to only about
20% reduction in write times; see examples below.)
To address these issues: If you insert explicit delays between the first
two writes in lcd_init() in order to satisfy the requirements in [1], e.g.
then you can reduce DELAY_US down to 1 us, or even eliminate it entirely,
since the I2C comm delays alone will easily meet the 250 ns t_w,min
requirement. The 5 ms example value above is even conservative; per [1],
only 4.1 ms is required between the first two init commands and 100 us
between the second and third.
These two mods eliminate the initialization reliability issue entirely,
and provide significantly improved per-character write times as well.
More importantly, the write times scale approximately in proportion to
I2C clock rate, as one would expect. (The original code scales poorly
with I2C clock rate because the huge 600 us delay in
lcd_toggle_enable()
is incurred on every I2C write, i.e. a massive overhead on every write
operation.)
Timing examples, on Pico RP2040:
Original vs. fixed: I2C clock 100 kHz:
Original vs. fixed: I2C clock 1 MHz:
REFERENCES
[1] Typical spec sheet for one particular manufacturer (WaveShare)
of these ubiquitius 16x2 LCD modules:
Datasheets for similar modules from other vendors give generally
similar figures for t_w,min and for the requred delays between
the initialization commands. So this WaveShare example datasheet
is not an outlier.
The text was updated successfully, but these errors were encountered: