first commit

This commit is contained in:
Jérôme Delacotte
2025-03-06 11:15:32 +01:00
commit 7b30d6e298
5276 changed files with 2108927 additions and 0 deletions

View File

@@ -0,0 +1,447 @@
// vi:ts=4
// ---------------------------------------------------------------------------
// hd44780_NTCU165ECPB.h - hd44780_NTCU165ECPB i/o subclass for hd44780 library
// Copyright (c) 2016-2020 Bill Perry
//
// The API functionality provided by this library class is compatible
// with the API functionality of the Arduino LiquidCrystal library.
//
// ---------------------------------------------------------------------------
//
// This file is part of the hd44780 library
//
// hd44780_NTCU165ECPB is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation version 3 of the License.
//
// hd44780_NTCU165ECPB is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with hd44780_NTCU165ECPB. If not, see <http://www.gnu.org/licenses/>.
//
// ---------------------------------------------------------------------------
//
// It implements hd44780 library subclass i/o methods to control a
// Noritake CU165ECBP-T2J display.
// The Noritake CU165ECBP-T2J display is a 16x1 line VFD display.
// It is not a hd44780 display. So while this device is supported by hd44780,
// it will not be capable of supporting all the hd44780 capabilities.
// The subclass will do its best to emulatate hd44780 functions and map
// them to equivalent functionality when possible but certain capabilities
// will not be possible.
//
// Datasheet can be found here:
// http://www.blog.zapro.dk/wp-content/CU165.pdf
// Full datasheet/release notes:
// http://www.blog.zapro.dk/wp-content/CU165ECPB_T2J_specification.pdf
//
// The device uses SPI for communication.
// Pinout:
// 1 Vcc
// 2 GND
// 3 /CS (SS)
// 4 CLK (SCK)
// 5 DATA (MOSI)
//
// ---------------------------------------------------------------------------
// history
//
// 2017.12.23 bperrybap - added support LCD API 1.0 init()
// 2016.08.22 bperrybap - initial creation
//
// @author Bill Perry - bperrybap@opensource.billsworld.billandterrie.com
//
// ---------------------------------------------------------------------------
#ifndef hd44780_NTCU165ECPB_h
#define hd44780_NTCU165ECPB_h
class hd44780_NTCU165ECPB : public hd44780
{
public:
// ====================
// === constructors ===
// ====================
// no parameters: use h/w spi signals
// Note: This doesn't work for Leonardo since SS is not available and only drives an LED
hd44780_NTCU165ECPB() : hd44780(16,1), _cs(SS), _clk(SCK), _data(MOSI) { }
// supply alternate chip/slave select
// will use h/w spi with alternate chip select
hd44780_NTCU165ECPB(int cs) : hd44780(16,1), _cs(cs), _clk(SCK), _data(MOSI) { }
// supply pins for chip select, clock, and data
hd44780_NTCU165ECPB(int cs, int clock, int data) : hd44780(16,1), _cs(cs), _clk(clock), _data(data) { }
private:
// ====================
// === private data ===
// ====================
// Arduino Pin information
const uint8_t _cs; // arduino pint for slave select (chip select)
const uint8_t _clk; // arduino pin for clock
const uint8_t _data; // arduino pin for master out slave in (data)
// other internal variables
uint8_t _cgmode; // set when in cgramaddr mode
uint8_t _udf[5]; // udf buffer area
uint8_t _cgindx; // index into cgdata (will be 0 to 7)
uint8_t _cgchar; // custom character (0 to 7, this board goes to f)
// device commands
static const uint8_t CMD_SETDISPLAYLEN = 0x00; // lower 3 bits sets total digits/cols
// to display
// 0 is 9 and 7 means all 16 digits/cols
static const uint8_t CMD_SETBRIGHTNESS = 0x08; // lower 3 bits sets brigtness
// 0 is 1/16 and 7 is 14/16 max
static const uint8_t CMD_SETDIGSCAN160 = 0xF6; // set digit scan time to 160us
static const uint8_t CMD_SETDIGSCAN320 = 0xF7; // set digit scan time to 320us
static const uint8_t CMD_SETDIGPOINTER = 0xE0; // set column, lower 4 bits sets column
static const uint8_t CMD_NOAUTOINCREMENT = 0xF0; // no auto advance to next column
static const uint8_t CMD_AUTOINCREMENT = 0xF1; // auto advance to next column
static const uint8_t CMD_DISPLAYOFF = 0xF0; // all digits/dots off
static const uint8_t CMD_DISPLAYON = 0xF1; // normal display mode
static const uint8_t CMD_DISPLAYALLON = 0xF3; // all digits, all dots on
static const uint8_t CMD_STOREUDF = 0xFC; // begin user defined font (custom char)
// There are 16 custom chars, they are
// accessed/printed using 0x90-0x9F
// they are programmed using locations 0-F
// Each character glyph is 5 bytes.
// Each byte is vertical 7 pixels with the
// MSB at the top and the LSB dropped.
// The first byte is the left most column of
// the glyph.
// full command data is 7 bytes:
// 0xFC,<location (0-f)> 5 bytes of data
// start of custom user defined font (UDF) characters
// There are 16 UDF characters that start here
static const uint8_t UDF_BASE = 0x90;
// ==================================================
// === hd44780 i/o subclass virtual i/o functions ===
// ==================================================
//
// Note:
// It is not possible to read from the device.
// so ioread(), and & iostatus()
// will not be defined and will use the defaults in
// hd44780 which will return an apropriate error status
// ioinit() - Returns non zero if initialization failed.
int ioinit()
{
int status = 0;
// setup SPI signals
digitalWrite(_cs, HIGH);
pinMode(_cs, OUTPUT);
pinMode(_clk, OUTPUT);
digitalWrite(_clk, LOW);
pinMode(_data, OUTPUT);
// check to see if SPI has beginTransaction() and endTransaction()
// this was added in IDE 1.06 and so if using an IDE older than that,
// H/W spi will not be used
// This requires that <SPI.h> be included prior to this header
#if (defined(SPI_HAS_TRANSACTION) && !defined(ARDUINO_ARCH_ESP32)) || \
(defined(ARDUINO_ARCH_ESP32) && defined(_SPI_H_INCLUDED) && defined(SPI_HAS_TRANSACTION))
// check to see if h/w spi can be used
if((_data == MOSI) && (_clk == SCK))
SPI.begin();
#endif
// maybe look at cols to see how many should be turned on?
devicewrite(CMD_SETDISPLAYLEN|0x7); // show all 16 characters
devicewrite(CMD_SETDIGSCAN320); // set digit scan time to 320us
devicewrite(CMD_AUTOINCREMENT); // set auto advance to next column on writes
// for now turn on display and "backlight"
// clear and set to "home" address position
devicewrite(CMD_DISPLAYON);
devicewrite(CMD_SETBRIGHTNESS | 0x7); // max brightness
device_clear();
return ( status );
}
//
// iowrite() - send either a command or data byte to lcd
// returns zero on success, non zero on failure
//
// Things are a bit tricky here since this is not a hd44780 device.
// The code must look at the commands and emulate them or drop them
//
int iowrite(hd44780::iotype type, uint8_t value)
{
/*
* waitReady() is not called as this module does not need any execution time
* delays even when using a 4mHz h/w clock.
*/
/*
* 4 bit commands are part of low level hd44780 initalization.
* since this is not a hd44780 display, just throw them away
* and say they "worked"
*/
if(type == hd44780::HD44780_IOcmd4bit)
return(0);
if(type == hd44780::HD44780_IOcmd)
{
return(hd44780cmd(value));
}
if(_cgmode)
{
// in cgram mode so have to process custom character data.
// hd44780 font data is stored horizontally in 8 bytes
// with each byte being 1 row of dots
// with upper 3 bits of each byte ignored.
// first byte of the 8 bytes is upper row of dots.
// Noritake UDF format is vertical columns of 5 bytes with
// the LSB of each byte ignored as it only has 5x7 dots.
// the first byte is the right most column of 7 dots of the font.
//
// Because of this mismatch, the bits & bytes have to be flipped
// around and stored in the 5 UDF bytes until the full 8 hd44780 font
// bytes come in. Once all 8 hd44780 font bytes are in,
// the 5 byte UDF font definition can be pushed to the device.
for(int i = 0; i < 5; i++)
{
if( (value & (1<< i)))
{
_udf[4-i] |= (1 << (7- _cgindx));
}
else
{
_udf[4-i] &= ~(1 << (7-_cgindx));
}
}
_cgindx++;
if(_cgindx > 7) // is this the last of the 8 bytes?
{
// 0xFC,<location (0-f)> 5 bytes of data
devicewrite(CMD_STOREUDF);
devicewrite(_cgchar);
for(int i = 0; i < 5; i++)
{
devicewrite(_udf[i]);
}
// now send it again for the 8-f version
// to emulate the hd44780 custom chars
// that duplicate 0-7 at 8-f
devicewrite(CMD_STOREUDF);
devicewrite(_cgchar+8);
for(int i = 0; i < 5; i++)
{
devicewrite(_udf[i]);
}
// note, cgmode is still in effect.
// the UDF/font byte index is reset back to 0,
// and the cgchar location is bumped.
// this is to allow for the case when the code may
// be attempting to program more than a single character at once.
_cgindx = 0;
_cgchar++;
_cgchar &= 0xf;
}
return(0);
}
// upper 32 bytes are for commands so drop chars that are in the 0xE0 to 0xFF range
if(value >= 0xE0)
{
return(0);
}
// check for hd44780 custom font characters,
// The hd44780 character code must be mapped to the UDF characters
// which start at a different location.
if(value < 16)
{
value += UDF_BASE;
}
devicewrite(value);
return(0);
}
// iosetBacklight() - set backlight brightness
// Since this display does not use a backlight but can control pixel intensity
// use the backlight brightness to set the pixel intensity.
//
// Note:
// The dimmer value on the CU165 is 3 bit value
// other than the 000 value it looks like the value is mapped to a 4 bit
// value by adding a 0 msb.
// 000 is 1/16
// 001 is 2/16
// 010 is 4/16
// 011 is 6/16
// 100 is 8/16
// 101 is 10/16
// 110 is 12/16
// 111 is 14/16
//
// Becauswe of this, an API dimvalue of 0 does not turn off the display pixels
// so the code must check for that and explicitly turn off the display if the
// API dimvalue is zero.
int iosetBacklight(uint8_t dimvalue)
{
if(dimvalue)
{
// the dim value is 0-255 so devide by 32 to get a value 0-7
devicewrite(CMD_SETBRIGHTNESS | (dimvalue/32));
devicewrite(CMD_DISPLAYON);
}
else
{
devicewrite(CMD_DISPLAYOFF);
}
return(RV_ENOERR);
}
// ================================
// === internal class functions ===
// ================================
// devicwrite() - send a byte to the device
void devicewrite(uint8_t value)
{
// use h/w spi if we can
// note: checking for SPI support (SPI.h included) is messy since
// ESP32 core always defines SPI_HAS_TRANSACTION even when SPI.h is not included
#if (defined(SPI_HAS_TRANSACTION) && !defined(ARDUINO_ARCH_ESP32)) || \
(defined(ARDUINO_ARCH_ESP32) && defined(_SPI_H_INCLUDED) && defined(SPI_HAS_TRANSACTION))
if((_data == MOSI) && (_clk == SCK))
{
// NOTE: spec says 2Mhz is max, 4Mhz seems to work.
SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
digitalWrite(_cs,LOW); // select device
SPI.transfer(value);
delayMicroseconds(1); // must delay at least 130ns before de-selecting
digitalWrite(_cs,HIGH); // deselect device
SPI.endTransaction();
}
else
#endif
{
digitalWrite(_cs,LOW); // select device
myshiftOut(_data, _clk, MSBFIRST, value);
delayMicroseconds(1); // must delay at least 130ns before de-selecting
digitalWrite(_cs,HIGH); // deselect device
}
}
// can't use standard shiftOut() on esp32 because it is too fast for display
//
void myshiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val)
{
uint8_t i;
for (i = 0; i < 8; i++) {
if (bitOrder == LSBFIRST) {
digitalWrite(dataPin, val & 1);
val >>= 1;
} else {
digitalWrite(dataPin, (val & 128) != 0);
val <<= 1;
}
// insert delay on super fast processors to slow down clock
// and allow a bit of time for slew rate rise when using 3v processor with 5v logic
#if (F_CPU > 40000000)
delayMicroseconds(1); // min pulse width is 230ns
#endif
digitalWrite(clockPin, HIGH);
#if (F_CPU > 40000000) // insert delay on super fast processors to slow down clock
delayMicroseconds(1); // min pulse width is 230ns
#endif
digitalWrite(clockPin, LOW);
}
}
// hd44780cmd() - emulate hd44780 commands best we can
// for now, silently drop unsupported commands
int hd44780cmd(uint8_t value)
{
// detect the hd44780 command
if(value & HD44780_SETDDRAMADDR)
{
_cgmode = 0; // back to ddram mode
devicewrite(CMD_SETDIGPOINTER | (value & 0xf));
}
else if(value & HD44780_SETCGRAMADDR)
{
_cgmode = 1; // enter cgram mode
_cgindx = 0;
_cgchar = (value >> 3) & 0x7; // for now limmit to 8 custom like hd44780
}
else if(value & HD44780_FUNCTIONSET)
{
// not supported
}
else if(value & HD44780_CURDISPSHIFT)
{
// not supported
}
else if(value & HD44780_DISPLAYCONTROL)
{
if(value & HD44780_DISPLAYON)
devicewrite(CMD_DISPLAYON);
else
devicewrite(CMD_DISPLAYOFF);
}
else if(value & HD44780_ENTRYMODESET)
{
// not supported
}
else if(value & HD44780_RETURNHOME)
{
_cgmode = 0; // back to ddram mode
devicewrite(CMD_SETDIGPOINTER);
}
else if(value & HD44780_CLEARDISPLAY)
{
_cgmode = 0; // back to ddram mode
device_clear();
}
return(0);
}
void device_clear()
{
devicewrite(CMD_SETDIGPOINTER);
for(uint8_t col = 0; col < 16; col++)
{
devicewrite(' ');
}
devicewrite(CMD_SETDIGPOINTER);
}
}; // end of class definition
#endif