0.1.0 I2C_LCD

This commit is contained in:
Rob Tillaart 2023-12-17 13:01:57 +01:00
parent 380fb0b5c6
commit eb376d242e
17 changed files with 917 additions and 0 deletions

View File

@ -0,0 +1,28 @@
platforms:
rpipico:
board: rp2040:rp2040:rpipico
package: rp2040:rp2040
gcc:
features:
defines:
- ARDUINO_ARCH_RP2040
warnings:
flags:
packages:
rp2040:rp2040:
url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
- uno
# - due
# - zero
# - leonardo
- m4
- esp32
- esp8266
# - mega2560
- rpipico

4
libraries/I2C_LCD/.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,4 @@
# These are supported funding model platforms
github: RobTillaart

View File

@ -0,0 +1,13 @@
name: Arduino-lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: arduino/arduino-lint-action@v1
with:
library-manager: update
compliance: strict

View File

@ -0,0 +1,17 @@
---
name: Arduino CI
on: [push, pull_request]
jobs:
runTest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6
- run: |
gem install arduino_ci
arduino_ci.rb

View File

@ -0,0 +1,18 @@
name: JSON check
on:
push:
paths:
- '**.json'
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: json-syntax-check
uses: limitusus/json-syntax-check@v1
with:
pattern: "\\.json$"

View File

@ -0,0 +1,12 @@
# Change Log I2C_LCD
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.1.0] - 2023-12-16
- initial version
- goal is to optimize footprint & performance

View File

@ -0,0 +1,251 @@
//
// FILE: I2C_LCD.cpp
// AUTHOR: Rob.Tillaart@gmail.com
// VERSION: 0.1.0
// DATE: 2023-12-16
// PUPROSE: Arduino library for I2C_LCD
// URL: https://github.com/RobTillaart/I2C_LCD
#include "I2C_LCD.h"
// TODO redo simplify names shorter
// or keep them compatible?
#define I2C_LCD_CLEARDISPLAY 0x01
#define I2C_LCD_RETURNHOME 0x02
#define I2C_LCD_ENTRYMODESET 0x04
#define I2C_LCD_DISPLAYCONTROL 0x08
#define I2C_LCD_CURSORSHIFT 0x10
#define I2C_LCD_FUNCTIONSET 0x20
#define I2C_LCD_SETCGRAMADDR 0x40
#define I2C_LCD_SETDDRAMADDR 0x80
#define I2C_LCD_ENTRYRIGHT 0x00
#define I2C_LCD_ENTRYLEFT 0x02
#define I2C_LCD_ENTRYSHIFTINCREMENT 0x01
#define I2C_LCD_ENTRYSHIFTDECREMENT 0x00
#define I2C_LCD_DISPLAYON 0x04
#define I2C_LCD_DISPLAYOFF 0x00
#define I2C_LCD_CURSORON 0x02
#define I2C_LCD_CURSOROFF 0x00
#define I2C_LCD_BLINKON 0x01
#define I2C_LCD_BLINKOFF 0x00
#define I2C_LCD_DISPLAYMOVE 0x08
#define I2C_LCD_CURSORMOVE 0x00
#define I2C_LCD_MOVERIGHT 0x04
#define I2C_LCD_MOVELEFT 0x00
#define I2C_LCD_8BITMODE 0x10
#define I2C_LCD_4BITMODE 0x00
#define I2C_LCD_2LINE 0x08
#define I2C_LCD_1LINE 0x00
#define I2C_LCD_5x10DOTS 0x04
#define I2C_LCD_5x8DOTS 0x00
I2C_LCD::I2C_LCD(uint8_t address, TwoWire * wire)
{
_address = address;
_wire = wire;
}
void I2C_LCD::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)
{
if (_address != address) return; // compatible
_enable = ( 1 << enable);
_readWrite = ( 1 << readwrite);
_registerSelect = ( 1 << registerselect);
_dataPin[0] = ( 1 << data4);
_dataPin[1] = ( 1 << data5);
_dataPin[2] = ( 1 << data6);
_dataPin[3] = ( 1 << data7);
_backLight = ( 1 << backlight);
_pinsInOrder = ((data4 < data5) && (data5 < data6) && (data6 < data7));
}
void I2C_LCD::begin(uint8_t cols, uint8_t rows)
{
_cols = cols;
_rows = rows;
// ALL LOW.
_wire->beginTransmission(_address);
_wire->write(0x00);
_wire->endTransmission();
// wait for 50 ms
delay(50);
// Force 4 bit mode // todo timing...
write4bits(0x03);
delay(5);
write4bits(0x03);
delay(1);
write4bits(0x03);
delay(1);
write4bits(0x02);
delay(1);
// set "two" lines LCD - always a 20 x 4 for now.
sendCommand(I2C_LCD_FUNCTIONSET | I2C_LCD_2LINE);
}
void I2C_LCD::setBacklight(bool on)
{
if (on) display(); // todo fix for real.
else noDisplay();
}
void I2C_LCD::display()
{
sendCommand(I2C_LCD_DISPLAYCONTROL | I2C_LCD_DISPLAYON );
}
void I2C_LCD::noDisplay()
{
sendCommand(I2C_LCD_DISPLAYCONTROL | I2C_LCD_DISPLAYOFF);
}
void I2C_LCD::clear()
{
sendCommand(I2C_LCD_CLEARDISPLAY);
delay(2);
}
void I2C_LCD::home()
{
sendCommand(I2C_LCD_RETURNHOME);
delay(2);
}
void I2C_LCD::setCursor(uint8_t col, uint8_t row)
{
uint8_t startpos[4] = { 0x00, 0x40, 0x14, 0x54 };
sendCommand(I2C_LCD_SETDDRAMADDR | (startpos[row] + col) );
}
size_t I2C_LCD::write(uint8_t c)
{
sendData(c); // add timestamp..
return 1;
};
//////////////////////////////////////////////////////////
//
// PRIVATE
//
// TODO merge these two
// optimize 95% identical.
void I2C_LCD::sendCommand(uint8_t value)
{
uint8_t MSN = _backLight;
uint8_t LSN = MSN;
// pins are in the right order.
// TODO determine a flag and
if (_pinsInOrder)
{
MSN |= value & 0xF0;
LSN |= value << 4;
}
else
{
uint8_t tmp = value >> 4;
for ( uint8_t i = 0; i < 4; i++ )
{
if ( tmp & 0x01 ) MSN |= _dataPin[i];
tmp >>= 1;
}
tmp = value & 0x0F;
for ( uint8_t i = 0; i < 4; i++ )
{
if ( tmp & 0x01 ) LSN |= _dataPin[i];
tmp >>= 1;
}
}
_wire->beginTransmission(_address);
_wire->write(MSN | _enable);
_wire->write(MSN);
_wire->write(LSN | _enable);
_wire->write(LSN);
_wire->endTransmission();
}
void I2C_LCD::sendData(uint8_t value)
{
uint8_t MSN = _registerSelect | _backLight;
uint8_t LSN = MSN;
// if pins are in the right order speed up.
// todo determine a flag in config.
if (_pinsInOrder)
{
MSN |= value & 0xF0;
LSN |= value << 4;
}
else
{
uint8_t tmp = value >> 4;
for ( uint8_t i = 0; i < 4; i++ )
{
if ( tmp & 0x01 ) MSN |= _dataPin[i];
tmp >>= 1;
}
tmp = value & 0x0F;
for ( uint8_t i = 0; i < 4; i++ )
{
if ( tmp & 0x01 ) LSN |= _dataPin[i];
tmp >>= 1;
}
}
_wire->beginTransmission(_address);
_wire->write(MSN | _enable);
_wire->write(MSN);
_wire->write(LSN | _enable);
_wire->write(LSN);
_wire->endTransmission();
}
// really needed for setup
void I2C_LCD::write4bits(uint8_t value)
{
uint8_t cmd = _backLight;
for ( uint8_t i = 0; i < 4; i++ )
{
if ( value & 0x01 ) cmd |= _dataPin[i];
value >>= 1;
}
_wire->beginTransmission(_address);
_wire->write(cmd | _enable);
// _wire->endTransmission();
// _wire->beginTransmission(_address);
_wire->write(cmd);
_wire->endTransmission();
}
// -- END OF FILE --

View File

@ -0,0 +1,69 @@
#pragma once
//
// FILE: I2C_LCD.h
// AUTHOR: Rob.Tillaart@gmail.com
// VERSION: 0.1.0
// DATE: 2023-12-16
// PUPROSE: Arduino library for I2C_LCD
// URL: https://github.com/RobTillaart/I2C_LCD
#define I2C_LCD_LIB_VERSION (F("0.1.0"))
#include "Arduino.h"
#include "Wire.h"
class I2C_LCD : public Print
{
public:
explicit I2C_LCD(uint8_t address, TwoWire * wire = &Wire);
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);
void begin(uint8_t cols = 20, uint8_t rows = 4);
void setBacklight(bool on); // backlight() / noBacklight()
void display();
void noDisplay();
void clear();
void home();
void setCursor(uint8_t col, uint8_t row);
// TODO private..
// PRINT INTERFACE
size_t write(uint8_t c);
void sendData(uint8_t value);
void sendCommand(uint8_t value);
void write4bits(uint8_t value);
private:
uint8_t _address = 0;
TwoWire * _wire = NULL;
// defaults
uint8_t _enable;
uint8_t _readWrite;
uint8_t _registerSelect;
uint8_t _backLight;
uint8_t _dataPin[4];
// TODO backlight status
uint8_t _cols = 20;
uint8_t _rows = 4;
bool _pinsInOrder;
};
// -- END OF FILE --

21
libraries/I2C_LCD/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023-2023 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
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

155
libraries/I2C_LCD/README.md Normal file
View File

@ -0,0 +1,155 @@
[![Arduino CI](https://github.com/RobTillaart/I2C_LCD/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
[![Arduino-lint](https://github.com/RobTillaart/I2C_LCD/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/I2C_LCD/actions/workflows/arduino-lint.yml)
[![JSON check](https://github.com/RobTillaart/I2C_LCD/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/I2C_LCD/actions/workflows/jsoncheck.yml)
[![GitHub issues](https://img.shields.io/github/issues/RobTillaart/I2C_LCD.svg)](https://github.com/RobTillaart/I2C_LCD/issues)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/I2C_LCD/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/RobTillaart/I2C_LCD.svg?maxAge=3600)](https://github.com/RobTillaart/I2C_LCD/releases)
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/robtillaart/library/I2C_LCD.svg)](https://registry.platformio.org/libraries/robtillaart/I2C_LCD)
# I2C_LCD
Arduino library for I2C_LCD LCD displays.
## Description
Experimental library for the I2C LCD display, typical 20 x 4 characters.
The goal of the library is to minimize footprint and improve performance.
This is partly done by dedicate the library to I2C only.
The library is inspired by the excellent LiquidCrystel_I2C library of F. Malpartida.
- https://github.com/fmalpartida/New-LiquidCrystal
The library implements the print interface, so all data types are printable.
#### Compatibility
Not 100% compatible with F. Malpartida's I2C library, however the differences are
not that large.
Furthermore the 0.1.0 version does not support all functionality so there is still
a lot to implement.
So if you need such functionality, you still should use the **New-liquidCrystal** library.
#### Tests
Only tested on an UNO and a 20 x 4 character LCD.
## Performance
The most important optimization is to send a byte in a single I2C transaction.
This takes 5 bytes to transport, which is 3 less than the reference.
Furthermore there is an optimization if the pins are in order, as then
it is far easier to get the nibble (half bytes).
First performance tests are good. See example **I2C_LCD_performance.ino**.
The performance measurement is done on an UNO, pins are in order.
| I2C clock | time (us) | notes |
|:-----------:|:-----------:|:-------:|
| 100000 | 4316 |
| 200000 | 2440 |
| 300000 | 1780 |
| 400000 | 1496 | recommended
| 500000 | 1308 |
| 600000 | 1176 |
| 700000 | 1076 |
| 800000 | 1024 |
#### Related
- https://github.com/fmalpartida/New-LiquidCrystal
## Interface
```cpp
#include "I2C_LCD.h"
```
#### Constructor
- **I2C_LCD(uint8_t address, TwoWire \* wire = &Wire)** Constructor,
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)** pin configuration.
Will change in the future.
- **void begin(uint8_t cols = 20, uint8_t rows = 4)** initializes library size.
#### Other
- **void setBacklight(bool on)** not implemented yet
- **void display()** set display on
- **void noDisplay()** set display off
- **void clear()** clear the screen and set cursor to 0, 0.
- **void home()** set cursor to 0, 0.
- **void setCursor(uint8_t col, uint8_t row)** set cursor to given position.
There is no check yet if this is out of range.
#### Print interface
- **size_t write(uint8_t c)**
Array writing not supported.
#### Low level API
In the first version these are public, however they probably should be private.
- **void sendData(uint8_t value)**
- **void sendCommand(uint8_t value)**
- **void write4bits(uint8_t value)**
## Future
#### Must
- update documentation
#### Should
- fix TODO's in code
- implement functional range
- test with other platforms
- test with other display sizes
- test more
- make a PR for New-LiquidCrystal library to implement there too.
#### Could
- implement unit tests (possible?)
- add examples
- Wire1, Wire2 etc
- solve MAGIC numbers (defaults)
- add timestamp last print
- position control in write().
#### Wont
## Support
If you appreciate my libraries, you can support the development and maintenance.
Improve the quality of the libraries by providing issues and Pull Requests, or
donate through PayPal or GitHub sponsors.
Thank you,

View File

@ -0,0 +1,69 @@
// FILE: I2C_LCD_demo.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo I2C_LCD library
// URL: todo
#include "Arduino.h"
#include "Wire.h"
#include "I2C_LCD.h"
#define BACKLIGHT_PIN 3
#define En_pin 2
#define Rw_pin 1
#define Rs_pin 0
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7
I2C_LCD lcd(39);
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println(__FILE__);
Serial.print("I2C_LCD_LIB_VERSION: ");
Serial.println(I2C_LCD_LIB_VERSION);
Serial.println();
lcd.config(39, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin, BACKLIGHT_PIN);
Wire.begin();
Wire.setClock(400000);
lcd.begin(20, 4);
lcd.display();
delay(1000);
lcd.noDisplay();
delay(1000);
lcd.display();
lcd.clear();
lcd.home();
lcd.setCursor(3, 3);
uint32_t start = micros();
lcd.print(__TIME__);
uint32_t stop = micros();
lcd.setCursor(10, 0);
lcd.print(stop - start);
}
void loop()
{
lcd.home();
lcd.print(millis());
delay(1000);
}
// -- END OF FILE --

View File

@ -0,0 +1,85 @@
// FILE: I2C_LCD_performance.ino
// AUTHOR: Rob Tillaart
// PURPOSE: per I2C_LCD library
// URL: https://github.com/RobTillaart/I2C_LCD
#include "Arduino.h"
#include "Wire.h"
#include "I2C_LCD.h"
#define BACKLIGHT_PIN 3
#define En_pin 2
#define Rw_pin 1
#define Rs_pin 0
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7
I2C_LCD lcd(39);
void performance(uint32_t speed)
{
Serial.println(__FUNCTION__);
Serial.print("speed:\t");
Serial.println(speed);
delay(100);
Wire.setClock(speed);
lcd.setCursor(3, 3);
uint32_t start = micros();
lcd.print(__TIME__);
uint32_t stop = micros();
Serial.print("time (us): ");
Serial.println(stop - start);
Serial.println();
delay(100);
}
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println(__FILE__);
Serial.print("I2C_LCD_LIB_VERSION: ");
Serial.println(I2C_LCD_LIB_VERSION);
Serial.println();
lcd.config(39, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin, BACKLIGHT_PIN);
Wire.begin();
Wire.setClock(400000);
lcd.begin(20, 4);
lcd.display();
delay(1000);
lcd.noDisplay();
delay(1000);
lcd.display();
lcd.clear();
for (uint32_t speed = 100000; speed <= 800000; speed += 100000)
{
performance(speed);
}
Wire.setClock(100000);
}
void loop()
{
lcd.home();
lcd.print(millis());
delay(1000);
}
// -- END OF FILE --

View File

@ -0,0 +1,42 @@
IDE: 1.8.19
Board: UNO
I2C_LCD\examples\I2C_LCD_performance\I2C_LCD_performance.ino
I2C_LCD_LIB_VERSION: 0.1.0
performance
speed: 100000
time (us): 4316
performance
speed: 200000
time (us): 2440
performance
speed: 300000
time (us): 1780
performance
speed: 400000
time (us): 1496
performance
speed: 500000
time (us): 1308
performance
speed: 600000
time (us): 1176
performance
speed: 700000
time (us): 1076
performance
speed: 800000
time (us): 1024

View File

@ -0,0 +1,40 @@
# Syntax Colouring Map For I2C_LCD
# Data types (KEYWORD1)
I2C_LCD KEYWORD1
# Methods and Functions (KEYWORD2)
begin KEYWORD2
config KEYWORD2
setBacklight KEYWORD2
display KEYWORD2
noDisplay KEYWORD2
clear KEYWORD2
home KEYWORD2
setCursor KEYWORD2
# LOW LEVEL API
write KEYWORD2
sendData KEYWORD2
sendCommand KEYWORD2
write4bits KEYWORD2
# Constants (LITERAL1)
I2C_LCD_LIB_VERSION LITERAL1
AD9833_MAX_FREQ LITERAL1
AD9833_MAX_PHASE LITERAL1
AD9833_OFF LITERAL1
AD9833_SINE LITERAL1
AD9833_SQUARE1 LITERAL1
AD9833_SQUARE2 LITERAL1
AD9833_TRIANGLE LITERAL1

View File

@ -0,0 +1,23 @@
{
"name": "I2C_LCD",
"keywords": "HD44780, 20x4",
"description": "Arduino library for I2C_LCD.",
"authors":
[
{
"name": "Rob Tillaart",
"email": "Rob.Tillaart@gmail.com",
"maintainer": true
}
],
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/I2C_LCD.git"
},
"version": "0.1.0",
"license": "MIT",
"frameworks": "*",
"platforms": "*",
"headers": "I2C_LCD.h"
}

View File

@ -0,0 +1,11 @@
name=I2C_LCD
version=0.1.0
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for I2C_LCD.
paragraph=HD44780, 20x4
category=Display
url=https://github.com/RobTillaart/I2C_LCD
architectures=*
includes=I2C_LCD.h
depends=

View File

@ -0,0 +1,59 @@
//
// FILE: unit_test_001.cpp
// AUTHOR: Rob Tillaart
// DATE: 2023-12-17
// PURPOSE: unit tests for the I2C_LCD
// https://github.com/RobTillaart/I2C_LCD
// https://github.com/Arduino-CI/arduino_ci/blob/master/REFERENCE.md
//
// supported assertions
// ----------------------------
// assertEqual(expected, actual)
// assertNotEqual(expected, actual)
// assertLess(expected, actual)
// assertMore(expected, actual)
// assertLessOrEqual(expected, actual)
// assertMoreOrEqual(expected, actual)
// assertTrue(actual)
// assertFalse(actual)
// assertNull(actual)
#include <ArduinoUnitTests.h>
#include "Arduino.h"
#include "I2C_LCD.h"
unittest_setup()
{
fprintf(stderr, "I2C_LCD_LIB_VERSION: %s\n", (char *) I2C_LCD_LIB_VERSION);
}
unittest_teardown()
{
}
unittest(test_constants)
{
assertEqual(1, 1);
}
unittest(test_constructor)
{
I2C_LCD lcd(0x39);
assertEqual(1, 1);
}
unittest_main()
// -- END OF FILE --