0.2.1 I2C_LCD

This commit is contained in:
Rob Tillaart 2024-01-10 21:21:56 +01:00
parent 5a91c75655
commit a519265ba3
21 changed files with 156 additions and 110 deletions

View File

@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/). and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.2.1] - 2024-01-08
- add ESP8266 performance figures.
- update readme.md
- clean up examples
## [0.2.0] - 2024-01-02 ## [0.2.0] - 2024-01-02
- Fix #6, clean up code - Fix #6, clean up code
- rewrote the bitsInOrder optimization - rewrote the bitsInOrder optimization

View File

@ -67,10 +67,10 @@ void I2C_LCD::config (uint8_t address, uint8_t enable, uint8_t readWrite, uint8_
_backLightPin = ( 1 << backLight); _backLightPin = ( 1 << backLight);
_backLightPol = polarity; _backLightPol = polarity;
_pinsInOrder = ((data4 == 4) && (data5 == 5) && (data6 == 6) && (data7 == 7)); _pin4567 = ((data4 == 4) && (data5 == 5) && (data6 == 6) && (data7 == 7));
// if pins are 0,1,2,3 they are also in order // if pins are 0,1,2,3 they are also in order
// but the shift/mask in send() should be different // but the shift/mask in send() should be different
// needs investigation if this optimization is worth it. // 4,5,6,7 is most used afaik.
} }
@ -408,12 +408,12 @@ void I2C_LCD::send(uint8_t value, bool dataFlag)
if (_backLight) MSN |= _backLightPin; if (_backLight) MSN |= _backLightPin;
uint8_t LSN = MSN; uint8_t LSN = MSN;
if (_pinsInOrder) // 4,5,6,7 only == most used. if (_pin4567) // 4,5,6,7 only == most used.
{ {
MSN |= value & 0xF0; MSN |= value & 0xF0;
LSN |= value << 4; LSN |= value << 4;
} }
else // ~ 1.7% slower UNO. else // ~ 1.7% slower UNO. (adds 4 us / char)
{ {
for ( uint8_t i = 0; i < 4; i++ ) for ( uint8_t i = 0; i < 4; i++ )
{ {

View File

@ -2,13 +2,14 @@
// //
// FILE: I2C_LCD.h // FILE: I2C_LCD.h
// AUTHOR: Rob.Tillaart // AUTHOR: Rob.Tillaart
// VERSION: 0.2.0 // VERSION: 0.2.1
// DATE: 2023-12-16 // DATE: 2023-12-16
// PURPOSE: Arduino library for I2C_LCD // PURPOSE: Arduino library for I2C_LCD
// URL: https://github.com/RobTillaart/I2C_LCD // URL: https://github.com/RobTillaart/I2C_LCD
#define I2C_LCD_LIB_VERSION (F("0.2.0")) #define I2C_LCD_LIB_VERSION (F("0.2.1"))
#include "Arduino.h" #include "Arduino.h"
#include "Wire.h" #include "Wire.h"
@ -105,9 +106,9 @@ private:
uint8_t _dataPin[4] = { 16, 32, 64, 128 }; // == pin 4, 5, 6, 7 uint8_t _dataPin[4] = { 16, 32, 64, 128 }; // == pin 4, 5, 6, 7
// minor optimization only for pins = 4,5,6,7 // minor optimization only for pins = 4,5,6,7
bool _pinsInOrder = true; bool _pin4567 = true;
uint8_t _backLightPin = 8; uint8_t _backLightPin = 8;
uint8_t _backLightPol = 1; uint8_t _backLightPol = 1;
uint8_t _backLight = 1; uint8_t _backLight = 1;

View File

@ -75,25 +75,49 @@ it is far easier to get the nibble (half bytes) to send.
First performance tests are good. See example **I2C_LCD_performance.ino**. First performance tests are good. See example **I2C_LCD_performance.ino**.
#### dataPins in ascending order
The performance measurement is done on an UNO, data pins are in ascending order. #### dataPins in ascending order UNO
| I2C clock | 0.1.0 | 0.1.1 | 0.1.4 | 0.2.0 | notes | Measurement is the time in microseconds to write 8 characters.
|:-----------:|:-------:|:-------:|:-------:|:-------:|:-------:| Use the sketch I2C_LCD_performance.ino to make measurements.
| 100000 | 4316 | 4640 | 4312 | 4316 |
| 200000 | 2440 | 2760 | 2456 | 2448 |
| 300000 | 1780 | 2108 | 1792 | 1792 |
| 400000 | 1496 | 1820 | 1512 | 1508 | (1)
| 500000 | 1308 | 1632 | 1324 | 1332 |
| 600000 | 1176 | 1500 | 1188 | 1188 |
| 700000 | 1076 | 1400 | 1084 | 1084 |
| 800000 | 1024 | 1348 | 1040 | 1044 |
Note 1: 0.1.0 problems with spectrum examples - too much data too fast killed my display. Measurements done with **UNO** (5V, 16 MHz), data pins are in ascending order.
Timing in the 0.1.1 version is roughly 400 us slower than 0.1.0 for 8 characters. | I2C clock | 0.1.0 | 0.1.1 | 0.1.4 | 0.2.0 | 0.2.1 | notes |
However the 0.1.1 is more robust as far as tested. |:-----------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|
| 100000 | 4316 | 4640 | 4312 | 4316 | 4316 |
| 200000 | 2440 | 2760 | 2456 | 2448 | 2448 |
| 300000 | 1780 | 2108 | 1792 | 1792 | 1792 |
| 400000 | 1496 | 1820 | 1512 | 1508 | 1508 | (1)
| 500000 | 1308 | 1632 | 1324 | 1332 | 1332 |
| 600000 | 1176 | 1500 | 1188 | 1188 | 1188 |
| 700000 | 1076 | 1400 | 1084 | 1084 | 1084 |
| 800000 | 1024 | 1348 | 1040 | 1044 | 1044 |
_Note 1: 0.1.0 had problems with spectrum examples - too much data too fast, corrupted my display.
Timing in the 0.1.1 version is roughly 400 us slower than 0.1.0 for 8 characters. However the 0.1.1 is more robust as far as tested.
Advice is to use version 0.2.0 or higher._
Measurements with **ESP8266** (3V3, single core 80 MHz), data pins are in ascending order.
| I2C clock | 0.2.0 | notes |
|:-----------:|:-------:|:-------:|
| 100000 | 5355 |
| 200000 | 2637 |
| 300000 | 1730 |
| 400000 | 1294 |
| 500000 | 1025 |
| 600000 | 823 |
| 700000 | 688 | clear() blocked
| 800000 | 570 |
Given the above measurements, the I2C speed should be 400 KHz or max 600 KHz.
Of course also depending on wire length etc.
#### Tuning
In the file **I2C_LCD.cpp** there is this line you can tune the hard delay In the file **I2C_LCD.cpp** there is this line you can tune the hard delay
in microseconds after every character. in microseconds after every character.
@ -105,10 +129,11 @@ const uint8_t I2C_LCD_CHAR_DELAY = 20;
``` ```
The datasheet states one need the 37 us so 40 us is a very safe value. The datasheet states one need the 37 us so 40 us is a very safe value.
However the I2C at 400K takes at least 40 us to send an address and the first 4 bits. However the I2C at 400 KHz takes at least 40 us to send an address and
the first 4 bits.
So 20 us is a safe value, and 10 us or even 0 us should work well. So 20 us is a safe value, and 10 us or even 0 us should work well.
The math above does not include other overhead like preparing the bits etc. The math above does not include other overhead like preparing the bits etc.
At 100K the I2C for 2 bytes takes 160 us, so it can safely set to 0. At 100 KHz the I2C for 2 bytes takes 160 us, so it can safely set to 0.
Setting the delay to zero (0.1.4), gives roughly the 0.1.0 timing again. Setting the delay to zero (0.1.4), gives roughly the 0.1.0 timing again.
@ -117,19 +142,18 @@ Setting the delay to zero (0.1.4), gives roughly the 0.1.0 timing again.
The performance measurement is done on an UNO. (order is simulated) The performance measurement is done on an UNO. (order is simulated)
| I2C clock | 0.2.0 | notes | | I2C clock | 0.2.0 | 0.2.1 | notes |
|:-----------:|:-------:|:-------:| |:-----------:|:-------:|:-------:|:-------:|
| 100000 | 4352 | | 100000 | 4352 | 4352 |
| 200000 | 2480 | | 200000 | 2480 | 2480 |
| 300000 | 1824 | | 300000 | 1824 | 1824 |
| 400000 | 1544 | | 400000 | 1544 | 1544 |
| 500000 | 1352 | | 500000 | 1352 | 1360 |
| 600000 | 1216 | | 600000 | 1216 | 1224 |
| 700000 | 1128 | | 700000 | 1128 | 1124 |
| 800000 | 1072 | | 800000 | 1072 | 1072 |
On average ~1.7% slower, as that code is pretty optimized too.
Per character 4 micros slower, on average +1.7%, than when data pins are {4,5,6,7}, as the alternative code is optimized too.
Note: Performance is also a matter of developing an optimal algorithm. Note: Performance is also a matter of developing an optimal algorithm.
This is often a trade between code size, memory used and speed. This is often a trade between code size, memory used and speed.
@ -306,11 +330,6 @@ Not reset-able.
#### Must #### Must
- update documentation - update documentation
- analyse the bitsInOrder optimization in more depth
- is the ~1.7% speed gain worth 24 bytes.
- at 100 KHz => 544 -> 539 = 5 us / character
- code would be simpler / smaller.
- current implementation only works for 4,5,6,7
#### Should #### Should
@ -323,10 +342,12 @@ Not reset-able.
- function to define the tab-stops, instead of hard coded ones. - function to define the tab-stops, instead of hard coded ones.
- make a separate include file for charmaps by name. - make a separate include file for charmaps by name.
- I2C_LCD_spectrum.h ? - I2C_LCD_spectrum.h ?
- investigate reading busy flag over I2C. - derived class for I2C_LCD4567 (optimized pins)
#### Wont (for now). #### Wont (for now).
- investigate reading busy flag over I2C.
- not successful so far.
- **size_t write(array, length)** is not implemented as there was no gain. - **size_t write(array, length)** is not implemented as there was no gain.
- implement unit tests (possible?) - implement unit tests (possible?)
- add timestamp last print - add timestamp last print

View File

@ -4,11 +4,9 @@
// URL: https://github.com/RobTillaart/I2C_LCD // URL: https://github.com/RobTillaart/I2C_LCD
#include "Arduino.h"
#include "Wire.h"
#include "I2C_LCD.h" #include "I2C_LCD.h"
// test 20x4 + 16x2 // test 20x4 + 16x2
#define BACKLIGHT_PIN 3 #define BACKLIGHT_PIN 3
#define En_pin 2 #define En_pin 2

View File

@ -7,11 +7,9 @@
// ESP32, RP2040, teensy // ESP32, RP2040, teensy
#include "Arduino.h"
#include "Wire.h"
#include "I2C_LCD.h" #include "I2C_LCD.h"
// test 20x4 + 16x2 // test 20x4 + 16x2
#define BACKLIGHT_PIN 3 #define BACKLIGHT_PIN 3
#define En_pin 2 #define En_pin 2

View File

@ -4,11 +4,9 @@
// URL: https://github.com/RobTillaart/I2C_LCD // URL: https://github.com/RobTillaart/I2C_LCD
#include "Arduino.h"
#include "Wire.h"
#include "I2C_LCD.h" #include "I2C_LCD.h"
// test 20x4 + 16x2 // test 20x4 + 16x2
#define BACKLIGHT_PIN 3 #define BACKLIGHT_PIN 3
#define En_pin 2 #define En_pin 2

View File

@ -4,11 +4,9 @@
// URL: https://github.com/RobTillaart/I2C_LCD // URL: https://github.com/RobTillaart/I2C_LCD
#include "Arduino.h"
#include "Wire.h"
#include "I2C_LCD.h" #include "I2C_LCD.h"
// test 20x4 + 16x2 // test 20x4 + 16x2
#define BACKLIGHT_PIN 3 #define BACKLIGHT_PIN 3
#define En_pin 2 #define En_pin 2
@ -23,6 +21,24 @@
I2C_LCD lcd(39); I2C_LCD lcd(39);
void printTime()
{
uint32_t now = millis() / 1000;
uint16_t hours = now / 3600;
now -= hours * 3600;
uint16_t minutes = now / 60;
uint16_t seconds = now - minutes * 60;
if (hours < 10) lcd.print(0);
lcd.print(hours);
lcd.print(":");
if (minutes < 10) lcd.print(0);
lcd.print(minutes);
lcd.print(":");
if (seconds < 10) lcd.print(0);
lcd.print(seconds);
}
void setup() void setup()
{ {
Serial.begin(115200); Serial.begin(115200);
@ -41,7 +57,6 @@ void setup()
lcd.display(); lcd.display();
lcd.clear(); lcd.clear();
} }
@ -53,23 +68,4 @@ void loop()
} }
void printTime()
{
uint32_t now = millis() / 1000;
uint16_t hours = now / 3600;
now -= hours * 3600;
uint16_t minutes = now / 60;
uint16_t seconds = now - minutes * 60;
if (hours < 10) lcd.print(0);
lcd.print(hours);
lcd.print(":");
if (minutes < 10) lcd.print(0);
lcd.print(minutes);
lcd.print(":");
if (seconds < 10) lcd.print(0);
lcd.print(seconds);
}
// -- END OF FILE -- // -- END OF FILE --

View File

@ -4,9 +4,6 @@
// URL: https://github.com/RobTillaart/I2C_LCD // URL: https://github.com/RobTillaart/I2C_LCD
#include "Arduino.h"
#include "Wire.h"
#include "I2C_LCD.h" #include "I2C_LCD.h"

View File

@ -4,11 +4,9 @@
// URL: https://github.com/RobTillaart/I2C_LCD // URL: https://github.com/RobTillaart/I2C_LCD
#include "Arduino.h"
#include "Wire.h"
#include "I2C_LCD.h" #include "I2C_LCD.h"
// test 20x4 + 16x2 // test 20x4 + 16x2
#define BACKLIGHT_PIN 3 #define BACKLIGHT_PIN 3
#define En_pin 2 #define En_pin 2

View File

@ -4,9 +4,6 @@
// URL: https://github.com/RobTillaart/I2C_LCD // URL: https://github.com/RobTillaart/I2C_LCD
#include "Arduino.h"
#include "Wire.h"
#include "I2C_LCD.h" #include "I2C_LCD.h"

View File

@ -4,9 +4,6 @@
// URL: https://github.com/RobTillaart/I2C_LCD // URL: https://github.com/RobTillaart/I2C_LCD
#include "Arduino.h"
#include "Wire.h"
#include "I2C_LCD.h" #include "I2C_LCD.h"

View File

@ -4,10 +4,9 @@
// URL: https://github.com/RobTillaart/I2C_LCD // URL: https://github.com/RobTillaart/I2C_LCD
#include "Arduino.h"
#include "Wire.h"
#include "I2C_LCD.h" #include "I2C_LCD.h"
I2C_LCD lcd(39); I2C_LCD lcd(39);

View File

@ -8,9 +8,6 @@
// (mine got corrupted) // (mine got corrupted)
#include "Arduino.h"
#include "Wire.h"
#include "I2C_LCD.h" #include "I2C_LCD.h"

View File

@ -0,0 +1,54 @@
IDE: 1.8.19
Board: UNO
I2C_LCD\examples\I2C_LCD_performance\I2C_LCD_performance.ino
I2C_LCD_LIB_VERSION: 0.2.1
Note: This is with pins not in order. adds 4 us/char extra.
performance
speed: 100000
print time (us): 4352
clear time (us): 2544
performance
speed: 200000
print time (us): 2480
clear time (us): 2316
performance
speed: 300000
print time (us): 1824
clear time (us): 2236
performance
speed: 400000
print time (us): 1544
clear time (us): 2196
performance
speed: 500000
print time (us): 1360
clear time (us): 2172
performance
speed: 600000
print time (us): 1224
clear time (us): 2156
performance
speed: 700000
print time (us): 1124
clear time (us): 2148
performance
speed: 800000
print time (us): 1072
clear time (us): 2136

View File

@ -4,12 +4,10 @@
// URL: https://github.com/RobTillaart/I2C_LCD // URL: https://github.com/RobTillaart/I2C_LCD
#include "Arduino.h"
#include "Wire.h"
#include "I2C_LCD.h" #include "I2C_LCD.h"
#include "I2C_LCD_special_chars.h" #include "I2C_LCD_special_chars.h"
I2C_LCD lcd(39); I2C_LCD lcd(39);

View File

@ -4,11 +4,9 @@
// URL: https://github.com/RobTillaart/I2C_LCD // URL: https://github.com/RobTillaart/I2C_LCD
#include "Arduino.h"
#include "Wire.h"
#include "I2C_LCD.h" #include "I2C_LCD.h"
// test 20x4 + 16x2 // test 20x4 + 16x2
#define BACKLIGHT_PIN 3 #define BACKLIGHT_PIN 3
#define En_pin 2 #define En_pin 2

View File

@ -4,11 +4,9 @@
// URL: https://github.com/RobTillaart/I2C_LCD // URL: https://github.com/RobTillaart/I2C_LCD
#include "Arduino.h"
#include "Wire.h"
#include "I2C_LCD.h" #include "I2C_LCD.h"
// test 20x4 + 16x2 // test 20x4 + 16x2
#define BACKLIGHT_PIN 3 #define BACKLIGHT_PIN 3
#define En_pin 2 #define En_pin 2

View File

@ -6,11 +6,9 @@
// TODO: add your favo weather prediction code // TODO: add your favo weather prediction code
#include "Arduino.h"
#include "Wire.h"
#include "I2C_LCD.h" #include "I2C_LCD.h"
// test 20x4 + 16x2 // test 20x4 + 16x2
#define BACKLIGHT_PIN 3 #define BACKLIGHT_PIN 3
#define En_pin 2 #define En_pin 2
@ -82,9 +80,6 @@ void setup()
lcd.print(windDirection[random(8)]); lcd.print(windDirection[random(8)]);
lcd.print(" "); lcd.print(" ");
} }
// optional wind-direction
} }

View File

@ -15,7 +15,7 @@
"type": "git", "type": "git",
"url": "https://github.com/RobTillaart/I2C_LCD.git" "url": "https://github.com/RobTillaart/I2C_LCD.git"
}, },
"version": "0.2.0", "version": "0.2.1",
"license": "MIT", "license": "MIT",
"frameworks": "*", "frameworks": "*",
"platforms": "*", "platforms": "*",

View File

@ -1,5 +1,5 @@
name=I2C_LCD name=I2C_LCD
version=0.2.0 version=0.2.1
author=Rob Tillaart <rob.tillaart@gmail.com> author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com> maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for I2C_LCD. sentence=Arduino library for I2C_LCD.