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/).
## [0.2.1] - 2024-01-08
- add ESP8266 performance figures.
- update readme.md
- clean up examples
## [0.2.0] - 2024-01-02
- Fix #6, clean up code
- 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);
_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
// 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;
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;
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++ )
{

View File

@ -2,13 +2,14 @@
//
// FILE: I2C_LCD.h
// AUTHOR: Rob.Tillaart
// VERSION: 0.2.0
// VERSION: 0.2.1
// DATE: 2023-12-16
// PURPOSE: Arduino library for 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 "Wire.h"
@ -105,9 +106,9 @@ private:
uint8_t _dataPin[4] = { 16, 32, 64, 128 }; // == pin 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 _backLightPol = 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**.
#### 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 |
|:-----------:|:-------:|:-------:|:-------:|:-------:|:-------:|
| 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 |
Measurement is the time in microseconds to write 8 characters.
Use the sketch I2C_LCD_performance.ino to make measurements.
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.
However the 0.1.1 is more robust as far as tested.
| I2C clock | 0.1.0 | 0.1.1 | 0.1.4 | 0.2.0 | 0.2.1 | notes |
|:-----------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|
| 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 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.
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.
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.
@ -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)
| I2C clock | 0.2.0 | notes |
|:-----------:|:-------:|:-------:|
| 100000 | 4352 |
| 200000 | 2480 |
| 300000 | 1824 |
| 400000 | 1544 |
| 500000 | 1352 |
| 600000 | 1216 |
| 700000 | 1128 |
| 800000 | 1072 |
On average ~1.7% slower, as that code is pretty optimized too.
| I2C clock | 0.2.0 | 0.2.1 | notes |
|:-----------:|:-------:|:-------:|:-------:|
| 100000 | 4352 | 4352 |
| 200000 | 2480 | 2480 |
| 300000 | 1824 | 1824 |
| 400000 | 1544 | 1544 |
| 500000 | 1352 | 1360 |
| 600000 | 1216 | 1224 |
| 700000 | 1128 | 1124 |
| 800000 | 1072 | 1072 |
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.
This is often a trade between code size, memory used and speed.
@ -306,11 +330,6 @@ Not reset-able.
#### Must
- 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
@ -323,10 +342,12 @@ Not reset-able.
- function to define the tab-stops, instead of hard coded ones.
- make a separate include file for charmaps by name.
- I2C_LCD_spectrum.h ?
- investigate reading busy flag over I2C.
- derived class for I2C_LCD4567 (optimized pins)
#### 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.
- implement unit tests (possible?)
- add timestamp last print

View File

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

View File

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

View File

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

View File

@ -4,11 +4,9 @@
// URL: https://github.com/RobTillaart/I2C_LCD
#include "Arduino.h"
#include "Wire.h"
#include "I2C_LCD.h"
// test 20x4 + 16x2
#define BACKLIGHT_PIN 3
#define En_pin 2
@ -23,6 +21,24 @@
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()
{
Serial.begin(115200);
@ -41,7 +57,6 @@ void setup()
lcd.display();
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 --

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,9 +8,6 @@
// (mine got corrupted)
#include "Arduino.h"
#include "Wire.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
#include "Arduino.h"
#include "Wire.h"
#include "I2C_LCD.h"
#include "I2C_LCD_special_chars.h"
I2C_LCD lcd(39);

View File

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

View File

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

View File

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

View File

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

View File

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