0.2.0 I2C_LCD

This commit is contained in:
Rob Tillaart 2024-01-03 11:05:18 +01:00
parent 92fe94f226
commit 9e09cca8ef
21 changed files with 171 additions and 99 deletions

View File

@ -6,6 +6,16 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.2.0] - 2024-01-02
- Fix #6, clean up code
- rewrote the bitsInOrder optimization
- optimized send() a bit.
- add clear() measurement to performance sketch.
- update readme.md
- minor edits
----
## [0.1.4] - 2023-12-28
- changed return type of **begin()**. Returns false if LCD not found on I2C bus.
- made initialization delay(100) in **begin()** a bit smarter.
@ -14,7 +24,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- add **I2C_LCD_custom_chars.h** with examples.
- add examples
## [0.1.3] - 2023-12-22
- add support for **16x4** and **10x4** display.
- minimized footprint **setCursor()**

View File

@ -1,9 +1,9 @@
//
// FILE: I2C_LCD.cpp
// AUTHOR: Rob.Tillaart@gmail.com
// VERSION: 0.1.4
// AUTHOR: Rob.Tillaart
// VERSION: 0.2.0
// DATE: 2023-12-16
// PUPROSE: Arduino library for I2C_LCD
// PURPOSE: Arduino library for I2C_LCD
// URL: https://github.com/RobTillaart/I2C_LCD
@ -67,12 +67,16 @@ void I2C_LCD::config (uint8_t address, uint8_t enable, uint8_t readWrite, uint8_
_backLightPin = ( 1 << backLight);
_backLightPol = polarity;
_pinsInOrder = ((data4 < data5) && (data5 < data6) && (data6 < data7));
_pinsInOrder = ((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.
}
bool I2C_LCD::begin(uint8_t cols, uint8_t rows)
{
// no check for range, user responsibility, defaults are 20x4
_cols = cols;
_rows = rows;
@ -86,15 +90,18 @@ bool I2C_LCD::begin(uint8_t cols, uint8_t rows)
// Figure 24 for procedure on 4-bit initialization
// wait for more than 15 ms
// if other objects initialize earlier there will be less blocking time.
// => assumes display is started at same time as MCU
while (millis() < 100) delay(1);
// Force 4 bit mode
// Force 4 bit mode, see datasheet.
// times are taken longer for robustness.
// note this is typically only called once.
write4bits(0x03);
delayMicroseconds(5000); // > 4.1 millis
delayMicroseconds(5000); // datasheet > 4.1 millis
write4bits(0x03);
delayMicroseconds(200); // > 100 usec
delayMicroseconds(200); // datasheet > 100 usec
write4bits(0x03);
delayMicroseconds(200); // > 100 usec
delayMicroseconds(200); // datasheet > 100 usec
// command to set 4 bit interface
write4bits(0x02);
@ -178,7 +185,7 @@ void I2C_LCD::home()
{
sendCommand(I2C_LCD_RETURNHOME);
_pos = 0;
delay(2);
delayMicroseconds(1600); // datasheet states 1520.
}
@ -186,6 +193,7 @@ bool I2C_LCD::setCursor(uint8_t col, uint8_t row)
{
if ((col >= _cols) || (row >= _rows)) return false;
// more efficient address / offset calculation (no lookup so far).
uint8_t offset = 0x00;
if (row & 0x01) offset += 0x40;
if (row & 0x02) offset += _cols;
@ -327,7 +335,7 @@ void I2C_LCD::createChar(uint8_t index, uint8_t * charmap)
size_t I2C_LCD::write(uint8_t c)
{
size_t n = 0;
if (c == (uint8_t)'\t') // TAB char
if (c == (uint8_t)'\t') // handle TAB char
{
while (((_pos % 4) != 0) && (_pos < _cols))
{
@ -336,13 +344,13 @@ size_t I2C_LCD::write(uint8_t c)
}
return n;
}
if (_pos < _cols) // overflow protect
if (_pos < _cols) // overflow protect.
{
sendData(c);
_pos++;
return 1;
}
// not allowed to print.
// not allowed to print beyond display, so return 0.
return 0;
};
@ -392,27 +400,25 @@ void I2C_LCD::sendData(uint8_t value)
void I2C_LCD::send(uint8_t value, bool dataFlag)
{
// calculate both most and least significant nibble
// calculate both
// MSN == most significant nibble and
// LSN == least significant nibble
uint8_t MSN = 0;
if (dataFlag) MSN = _registerSelect;
if (_backLight) MSN |= _backLightPin;
uint8_t LSN = MSN;
if (_pinsInOrder)
if (_pinsInOrder) // 4,5,6,7 only == most used.
{
MSN |= value & 0xF0;
LSN |= value << 4;
}
else
else // ~ 1.7% slower UNO.
{
for ( uint8_t i = 0; i < 4; i++ )
{
if ( value & 0x01 ) LSN |= _dataPin[i];
value >>= 1;
}
for ( uint8_t i = 0; i < 4; i++ )
{
if ( value & 0x01 ) MSN |= _dataPin[i];
if ( value & 0x10 ) MSN |= _dataPin[i];
value >>= 1;
}
}

View File

@ -1,14 +1,14 @@
#pragma once
//
// FILE: I2C_LCD.h
// AUTHOR: Rob.Tillaart@gmail.com
// VERSION: 0.1.4
// AUTHOR: Rob.Tillaart
// VERSION: 0.2.0
// DATE: 2023-12-16
// PUPROSE: Arduino library for I2C_LCD
// PURPOSE: Arduino library for I2C_LCD
// URL: https://github.com/RobTillaart/I2C_LCD
#define I2C_LCD_LIB_VERSION (F("0.1.4"))
#define I2C_LCD_LIB_VERSION (F("0.2.0"))
#include "Arduino.h"
#include "Wire.h"
@ -102,8 +102,12 @@ private:
uint8_t _enable = 4;
uint8_t _readWrite = 2;
uint8_t _registerSelect = 1;
uint8_t _dataPin[4] = { 16, 32, 64, 128 };
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;
uint8_t _backLightPin = 8;
uint8_t _backLightPol = 1;
uint8_t _backLight = 1;
@ -113,8 +117,6 @@ private:
// DISPLAYCONTROL bit always on, set in constructor.
uint8_t _displayControl = 0;
// optimization
bool _pinsInOrder = true;
// overflow protection
uint8_t _pos = 0;

View File

@ -1,9 +1,9 @@
#pragma once
//
// FILE: I2C_LCD_custom_chars.h
// AUTHOR: Rob.Tillaart@gmail.com
// AUTHOR: Rob.Tillaart
// VERSION: see library.properties
// PUPROSE: Arduino library for I2C_LCD
// PURPOSE: Arduino library for I2C_LCD
// URL: https://github.com/RobTillaart/I2C_LCD
// https://maxpromer.github.io/LCD-Character-Creator/
//

View File

@ -1,16 +1,15 @@
#pragma once
//
// FILE: I2C_LCD_special_chars.h
// AUTHOR: Rob.Tillaart@gmail.com
// AUTHOR: Rob.Tillaart
// VERSION: see library.properties
// DATE: 2023-12-16
// PUPROSE: Arduino library for I2C_LCD
// PURPOSE: Arduino library for I2C_LCD
// URL: https://github.com/RobTillaart/I2C_LCD
// SPECIAL CHARS,
// will only work on displays with ROM CODE A00
//
const char LCD_ALPHA = 0xE0;
const char LCD_BETA = 0xE2;

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2023-2023 Rob Tillaart
Copyright (c) 2023-2024 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -75,18 +75,20 @@ 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.
| I2C clock | 0.1.0 | 0.1.1 | 0.1.4 | notes |
|:-----------:|:-----------:|:-----------:|:-----------:|:-------:|
| 100000 | 4316 | 4640 | 4312 |
| 200000 | 2440 | 2760 | 2456 |
| 300000 | 1780 | 2108 | 1792 |
| 400000 | 1496 | 1820 | 1512 | (1)
| 500000 | 1308 | 1632 | 1324 |
| 600000 | 1176 | 1500 | 1188 |
| 700000 | 1076 | 1400 | 1084 |
| 800000 | 1024 | 1348 | 1040 |
| 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 |
Note 1: 0.1.0 problems with spectrum examples - too much data too fast killed my display.
@ -110,6 +112,25 @@ At 100K 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.
#### DataPins not in ascending order
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.
Note: Performance is also a matter of developing an optimal algorithm.
This is often a trade between code size, memory used and speed.
See **I2C_LCD_demo_spectrum_row.ino** for an example.
@ -139,7 +160,7 @@ mandatory address and optional alternative I2C bus.
- **void config(uint8_t address, uint8_t enable, uint8_t readWrite, uint8_t registerSelect,
uint8_t data4, uint8_t data5, uint8_t data6, uint8_t data7,
uint8_t backlight, uint8_t polarity)** pin configuration.
Will change in the future.
Will probably change in the future, less compatible.
- **bool begin(uint8_t cols = 20, uint8_t rows = 4)** initializes library size.
User must call the appropriate **Wire.begin()** before calling **lcd.begin(()**
It is advised to initialize the LCD as last device as it blocks until 100 milliseconds
@ -149,7 +170,8 @@ since startup have passed to give the LCD time to boot.
#### Backlight
- **void setBacklightPin(uint8_t pin, uint8_t polarity)** idem.
- **void setBacklightPin(uint8_t pin, uint8_t polarity)** pin should be 0..7, polarity 0..1.
There are no checks, user is responsible.
- **void setBacklight(bool on)** if backlight is off, the display is also set off.
- **void backlight()** wrapper for setBacklight(true).
- **void noBacklight()** wrapper for setBacklight(false).
@ -203,12 +225,12 @@ There are 8 slots to place a special character, index 0..7.
The custom characters can be printed with **special(index)** which is
a wrapper around **write((uint8_t)index)**
- **void createChar(uint8_t index, uint8_t \* charmap)**
- **void createChar(uint8_t index, uint8_t \* charmap)** index = 0..7.
- **size_t special(uint8_t index)** to print the special char.
See examples e.g. spectrum, for how to use custom characters.
See also I2C_LCD_custom_chars.h
See also **I2C_LCD_custom_chars.h**
Finally, there is a very handy online tool to create characters.
- https://maxpromer.github.io/LCD-Character-Creator/
@ -284,6 +306,11 @@ 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
@ -295,10 +322,10 @@ 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.
#### Wont for now.
#### Wont (for now).
- **size_t write(array, length)** is not implemented as there was no gain.
- implement unit tests (possible?)

View File

@ -3,9 +3,6 @@
// PURPOSE: demo I2C_LCD library
// URL: https://github.com/RobTillaart/I2C_LCD
// WARNING: do not overfeed your display with too much data
// too fast as it may not be able to handle
// (mine got corrupted)
#include "Arduino.h"
#include "Wire.h"

View File

@ -6,11 +6,6 @@
// this example only works on boards that support Wire1
// ESP32, RP2040, teensy
// WARNING: do not overfeed your display with too much data
// too fast as it may not be able to handle
// (mine got corrupted)
#include "Arduino.h"
#include "Wire.h"

View File

@ -3,9 +3,6 @@
// PURPOSE: demo I2C_LCD library
// URL: https://github.com/RobTillaart/I2C_LCD
// WARNING: do not overfeed your display with too much data
// too fast as it may not be able to handle
// (mine got corrupted)
#include "Arduino.h"
#include "Wire.h"
@ -41,7 +38,7 @@ void setup()
Wire.setClock(100000);
lcd.begin(20, 4);
// show centering
// show centring
lcd.clear();
lcd.center(0, "1234567890");
lcd.center(1, "123456789");

View File

@ -3,10 +3,6 @@
// PURPOSE: demo I2C_LCD library
// URL: https://github.com/RobTillaart/I2C_LCD
// WARNING: do not overfeed your display with too much data
// too fast as it may not be able to handle
// (mine got corrupted)
#include "Arduino.h"
#include "Wire.h"

View File

@ -3,16 +3,12 @@
// PURPOSE: demo I2C_LCD library
// URL: https://github.com/RobTillaart/I2C_LCD
// WARNING: do not overfeed your display with too much data
// too fast as it may not be able to handle
// (mine got corrupted)
#include "Arduino.h"
#include "Wire.h"
#include "I2C_LCD.h"
// #include "I2C_LCD_spectrum.h"
// test 20x4 + 16x2
#define BACKLIGHT_PIN 3

View File

@ -3,10 +3,6 @@
// PURPOSE: demo I2C_LCD library
// URL: https://github.com/RobTillaart/I2C_LCD
// WARNING: do not overfeed your display with too much data
// too fast as it may not be able to handle
// (mine got corrupted)
#include "Arduino.h"
#include "Wire.h"

View File

@ -3,10 +3,6 @@
// PURPOSE: demo I2C_LCD library a.k.a skyline demo
// URL: https://github.com/RobTillaart/I2C_LCD
// WARNING: do not overfeed your display with too much data
// too fast as it may not be able to handle
// (mine got corrupted)
#include "Arduino.h"
#include "Wire.h"
@ -102,7 +98,7 @@ void setup()
for (int i = 0; i < 80; i += 1)
{
spectrumRow(1, 80 - i);
// delay(100);
// delay(100);
}
uint32_t stop = millis();
Serial.println(stop - start);
@ -114,12 +110,12 @@ void setup()
for (int i = 0; i < 80; i += 1)
{
spectrumRow2(2, i);
// delay(100);
// delay(100);
}
for (int i = 0; i < 80; i += 1)
{
spectrumRow2(2, 80 - i);
// delay(100);
// delay(100);
}
stop = millis();
Serial.println(stop - start);
@ -145,7 +141,7 @@ void spectrumRow(uint8_t row, int value)
lcd.setCursor(4, row);
for (uint8_t col = 4; col < 20; col++)
{
if (value <= 0) lcd.print(' '); // replace with _
if (value <= 0) lcd.print(' '); // replace with _
else if (value >= 5) lcd.special(255);
else lcd.special(value - 1);
value -= 5;
@ -184,7 +180,7 @@ void spectrumRow2(uint8_t row, int value)
for (uint8_t col = start + 4; col < end + 4; col++)
{
if (value <= 0) lcd.print(' '); // replace with _
if (value <= 0) lcd.print(' '); // replace with _
else if (value >= 5) lcd.special(255);
else lcd.special(value - 1);
value -= 5;

View File

@ -20,8 +20,8 @@ uint8_t media_player[8][8] =
{ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B }, // pause
{ 0x10, 0x18, 0x1C, 0x1F, 0x1F, 0x1C, 0x18, 0x10 }, // start
{ 0x11, 0x19, 0x1D, 0x1F, 0x1F, 0x1D, 0x19, 0x11 }, // skip forward
{ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, // todo
{ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 } // todo
{ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, // free
{ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 } // free
};

View File

@ -3,9 +3,6 @@
// PURPOSE: demo I2C_LCD library
// URL: https://github.com/RobTillaart/I2C_LCD
// WARNING: do not overfeed your display with too much data
// too fast as it may not be able to handle
// (mine got corrupted)
#include "Arduino.h"
#include "Wire.h"

View File

@ -40,11 +40,21 @@ void performance(uint32_t speed)
uint32_t start = micros();
lcd.print(__TIME__);
uint32_t stop = micros();
lcd.setCursor(0, 3);
Serial.print("time (us): ");
lcd.setCursor(0, 1);
Serial.print("print time (us): ");
Serial.println(stop - start);
delay(1000);
// clear
start = micros();
lcd.clear();
stop = micros();
lcd.setCursor(0, 2);
Serial.print("clear time (us): ");
Serial.println(stop - start);
Serial.println();
delay(100);
delay(1000);
}

View File

@ -0,0 +1,53 @@
IDE: 1.8.19
Board: UNO
I2C_LCD\examples\I2C_LCD_performance\I2C_LCD_performance.ino
I2C_LCD_LIB_VERSION: 0.2.0
performance
speed: 100000
print time (us): 4316
clear time (us): 2544
performance
speed: 200000
print time (us): 2448
clear time (us): 2312
performance
speed: 300000
print time (us): 1792
clear time (us): 2232
performance
speed: 400000
print time (us): 1508
clear time (us): 2192
performance
speed: 500000
print time (us): 1332
clear time (us): 2172
performance
speed: 600000
print time (us): 1188
clear time (us): 2152
performance
speed: 700000
print time (us): 1084
clear time (us): 2140
performance
speed: 800000
print time (us): 1044
clear time (us): 2140

View File

@ -3,10 +3,6 @@
// PURPOSE: demo I2C_LCD library
// URL: https://github.com/RobTillaart/I2C_LCD
// WARNING: do not overfeed your display with too much data
// too fast as it may not be able to handle
// (mine got corrupted)
#include "Arduino.h"
#include "Wire.h"

View File

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

View File

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