From d08f14be3bac73d9c491a8c5a5196cf2f907d6bf Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Mon, 15 Nov 2021 12:50:02 +0000 Subject: [PATCH 01/14] Rename user module mySetup.cpp to myHal.cpp, and function mySetup() to halSetup() within it. --- .gitignore | 1 + IODevice.cpp | 18 +++++++++++------- ...up.cpp_example.txt => myHal.cpp_example.txt | 8 ++++---- 3 files changed, 16 insertions(+), 11 deletions(-) rename mySetup.cpp_example.txt => myHal.cpp_example.txt (97%) diff --git a/.gitignore b/.gitignore index b0b8666..61eedc4 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ config.h .vscode/extensions.json mySetup.h mySetup.cpp +myHal.cpp myAutomation.h myFilter.cpp myAutomation.h diff --git a/IODevice.cpp b/IODevice.cpp index c7ab7c0..63a6d8b 100644 --- a/IODevice.cpp +++ b/IODevice.cpp @@ -28,8 +28,9 @@ #define USE_FAST_IO #endif -// Link to mySetup function. If not defined, the function reference will be NULL. -extern __attribute__((weak)) void mySetup(); +// Link to halSetup function. If not defined, the function reference will be NULL. +extern __attribute__((weak)) void halSetup(); +extern __attribute__((weak)) void mySetup(); // Deprecated function name, output warning if it's declared //================================================================================================================== // Static methods @@ -61,12 +62,15 @@ void IODevice::begin() { } _initPhase = false; - // Call user's mySetup() function (if defined in the build in mySetup.cpp). + // Check for presence of deprecated mySetup() function, and output warning. + if (mySetup) + DIAG(F("WARNING: mySetup() function should be renamed to halSetup()")); + + // Call user's halSetup() function (if defined in the build in myHal.cpp). // The contents will depend on the user's system hardware configuration. - // The mySetup.cpp file is a standard C++ module so has access to all of the DCC++EX APIs. - if (mySetup) { - mySetup(); - } + // The myHal.cpp file is a standard C++ module so has access to all of the DCC++EX APIs. + if (halSetup) + halSetup(); } // Overarching static loop() method for the IODevice subsystem. Works through the diff --git a/mySetup.cpp_example.txt b/myHal.cpp_example.txt similarity index 97% rename from mySetup.cpp_example.txt rename to myHal.cpp_example.txt index e93ac53..6ea5c00 100644 --- a/mySetup.cpp_example.txt +++ b/myHal.cpp_example.txt @@ -1,10 +1,10 @@ -// Sample mySetup.cpp file. +// Sample myHal.cpp file. // -// To use this file, copy it to mySetup.cpp and uncomment the directives and/or +// To use this file, copy it to myHal.cpp and uncomment the directives and/or // edit them to satisfy your requirements. // Note that if the file has a .cpp extension it WILL be compiled into the build -// and the mySetup() function WILL be invoked. +// and the halSetup() function WILL be invoked. // // To prevent this, temporarily rename it to mySetup.txt or similar. // @@ -128,7 +128,7 @@ // referenced by commands in mySetup.h. //======================================================================= -void mySetup() { +void halSetup() { // Alternative way of creating a module driver, which has to be within the mySetup() function // The other devices can also be created in this way. The parameter lists for the From c90ea0c6dfc0696fdf4f7fa6aaf3844a32afd432 Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Mon, 15 Nov 2021 13:25:11 +0000 Subject: [PATCH 02/14] Improve validation of parameters to non-HAL digital calls. When testing CS in minimal HAL mode but with mySetup.h and myAutomation.h files present, I experienced freezing of the arduino because the standard pinMode, digitalWrite etc don't validate the pin number passed to them. So I've added checks on the pin number to the configure, write and read functions in the minimal HAL. --- IODevice.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/IODevice.cpp b/IODevice.cpp index 63a6d8b..b61ecf8 100644 --- a/IODevice.cpp +++ b/IODevice.cpp @@ -305,18 +305,16 @@ bool IODevice::owns(VPIN id) { // Minimal implementations of public HAL interface, to support Arduino pin I/O and nothing more. void IODevice::begin() { DIAG(F("NO HAL CONFIGURED!")); } -bool IODevice::configure(VPIN pin, ConfigTypeEnum, int, int p[]) { +bool IODevice::configure(VPIN pin, ConfigTypeEnum configType, int nParams, int p[]) { + if (configType!=CONFIGURE_INPUT || nParams!=1 || pin >= NUM_DIGITAL_PINS) return false; #ifdef DIAG_IO DIAG(F("Arduino _configurePullup Pin:%d Val:%d"), pin, p[0]); #endif - if (p[0]) { - pinMode(pin, INPUT_PULLUP); - } else { - pinMode(pin, INPUT); - } + pinMode(pin, p[0] ? INPUT_PULLUP : INPUT); return true; } void IODevice::write(VPIN vpin, int value) { + if (vpin >= NUM_DIGITAL_PINS) return; digitalWrite(vpin, value); pinMode(vpin, OUTPUT); } @@ -324,6 +322,7 @@ void IODevice::writeAnalogue(VPIN, int, uint8_t, uint16_t) {} bool IODevice::isBusy(VPIN) { return false; } bool IODevice::hasCallback(VPIN) { return false; } int IODevice::read(VPIN vpin) { + if (vpin >= NUM_DIGITAL_PINS) return 0; return !digitalRead(vpin); // Return inverted state (5v=0, 0v=1) } int IODevice::readAnalogue(VPIN vpin) { From 6c98f9015119bc54a5f72a5081ffe5f0f478f233 Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Mon, 15 Nov 2021 14:30:27 +0000 Subject: [PATCH 03/14] Reduce I2C interrupt time Reduce the time spent with interrupts disabled in I2CManager response code by enabling interrupts after the state machine has finished. Also, some comment changes. --- I2CManager.h | 7 ++++++- I2CManager_NonBlocking.h | 12 +++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/I2CManager.h b/I2CManager.h index 25ab004..1163261 100644 --- a/I2CManager.h +++ b/I2CManager.h @@ -107,11 +107,16 @@ * the loop() function is called, and may be adequate under some circumstances. * The advantage of NOT using interrupts is that the impact of I2C upon the DCC waveform (when accurate timing mode isn't in use) * becomes almost zero. - * This mechanism is under evaluation and should not be relied upon as yet. * */ +// Uncomment following line to enable Wire library instead of native I2C drivers //#define I2C_USE_WIRE + +// Uncomment following line to disable the use of interrupts by the native I2C drivers. +//#define I2C_NO_INTERRUPTS + +// Default to use interrupts within the native I2C drivers. #ifndef I2C_NO_INTERRUPTS #define I2C_USE_INTERRUPTS #endif diff --git a/I2CManager_NonBlocking.h b/I2CManager_NonBlocking.h index 3bdfc38..112e51e 100644 --- a/I2CManager_NonBlocking.h +++ b/I2CManager_NonBlocking.h @@ -129,6 +129,10 @@ uint8_t I2CManagerClass::read(uint8_t i2cAddress, uint8_t *readBuffer, uint8_t r /*************************************************************************** * checkForTimeout() function, called from isBusy() and wait() to cancel * requests that are taking too long to complete. + * This function doesn't fully work as intended so is not currently called. + * Instead we check for an I2C hang-up and report an error from + * I2CRB::wait(), but we aren't able to recover from the hang-up. Such faults + * may be caused by an I2C wire short for example. ***************************************************************************/ void I2CManagerClass::checkForTimeout() { unsigned long currentMicros = micros(); @@ -163,7 +167,10 @@ void I2CManagerClass::loop() { #if !defined(I2C_USE_INTERRUPTS) handleInterrupt(); #endif - checkForTimeout(); + // Timeout is now reported in I2CRB::wait(), not here. + // I've left the code, commented out, as a reminder to look at this again + // in the future. + //checkForTimeout(); } /*************************************************************************** @@ -175,6 +182,9 @@ void I2CManagerClass::handleInterrupt() { // Update hardware state machine I2C_handleInterrupt(); + // Enable interrupts to minimise effect on other interrupt code + interrupts(); + // Check if current request has completed. If there's a current request // and state isn't active then state contains the completion status of the request. if (state != I2C_STATE_ACTIVE && currentRequest != NULL) { From 82f121c8efa945a7155fd4c466e72979d1e41977 Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Mon, 15 Nov 2021 14:45:03 +0000 Subject: [PATCH 04/14] Some comment changes --- myHal.cpp_example.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/myHal.cpp_example.txt b/myHal.cpp_example.txt index 6ea5c00..832dad6 100644 --- a/myHal.cpp_example.txt +++ b/myHal.cpp_example.txt @@ -6,7 +6,7 @@ // Note that if the file has a .cpp extension it WILL be compiled into the build // and the halSetup() function WILL be invoked. // -// To prevent this, temporarily rename it to mySetup.txt or similar. +// To prevent this, temporarily rename it to myHal.txt or similar. // #include "IODevice.h" @@ -20,7 +20,7 @@ // Examples of statically defined HAL directives (alternative to the create() call). -// These have to be outside of the mySetup() function. +// These have to be outside of the halSetup() function. //======================================================================= // The following directive defines a PCA9685 PWM Servo driver module. @@ -123,14 +123,14 @@ //======================================================================= -// The function mySetup() is invoked from CS if it exists within the build. -// It is called just before mysetup.h is executed, so things set up within here can be +// The function halSetup() is invoked from CS if it exists within the build. +// It is called before mySetup.h is executed, so things set up within here can be // referenced by commands in mySetup.h. //======================================================================= void halSetup() { - // Alternative way of creating a module driver, which has to be within the mySetup() function + // Alternative way of creating a module driver, which has to be within the halSetup() function // The other devices can also be created in this way. The parameter lists for the // create() function are identical to the parameter lists for the declarations. From 620dcbf925ce06a4e7b3a7f25739e6a701ef0e18 Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Mon, 15 Nov 2021 14:58:12 +0000 Subject: [PATCH 05/14] Update myHal.cpp_example.txt Update examples --- myHal.cpp_example.txt | 227 ++++++++++++++++++++---------------------- 1 file changed, 108 insertions(+), 119 deletions(-) diff --git a/myHal.cpp_example.txt b/myHal.cpp_example.txt index 832dad6..13a6b4b 100644 --- a/myHal.cpp_example.txt +++ b/myHal.cpp_example.txt @@ -1,142 +1,131 @@ // Sample myHal.cpp file. // // To use this file, copy it to myHal.cpp and uncomment the directives and/or -// edit them to satisfy your requirements. +// edit them to satisfy your requirements. If you only want to use up to +// two MCP23017 GPIO Expander modules and/or up to two PCA9685 Servo modules, +// then you don't need this file as DCC++EX configures these for free! // Note that if the file has a .cpp extension it WILL be compiled into the build // and the halSetup() function WILL be invoked. // -// To prevent this, temporarily rename it to myHal.txt or similar. +// To prevent this, temporarily rename the file to myHal.txt or similar. // +// Include devices you need. #include "IODevice.h" -#include "IO_HCSR04.h" -#include "IO_VL53L0X.h" +#include "IO_HCSR04.h" // Ultrasonic range sensor +#include "IO_VL53L0X.h" // Laser time-of-flight sensor +#include "IO_DFPlayer.h" // MP3 sound player -// The #if directive prevent compile errors for Uno and Nano by excluding the -// HAL directives from the build. -#if !defined(IO_NO_HAL) - - -// Examples of statically defined HAL directives (alternative to the create() call). -// These have to be outside of the halSetup() function. - -//======================================================================= -// The following directive defines a PCA9685 PWM Servo driver module. -//======================================================================= -// The parameters are: -// First Vpin=100 -// Number of VPINs=16 (numbered 100-115) -// I2C address of module=0x40 - -//PCA9685 pwmModule1(100, 16, 0x40); - - -//======================================================================= -// The following directive defines an MCP23017 16-port I2C GPIO Extender module. -//======================================================================= -// The parameters are: -// First Vpin=196 -// Number of VPINs=16 (numbered 196-211) -// I2C address of module=0x22 - -//MCP23017 gpioModule2(196, 16, 0x22); - - -// Alternative form, which allows the INT pin of the module to request a scan -// by pulling Arduino pin 40 to ground. Means that the I2C isn't being polled -// all the time, only when a change takes place. Multiple modules' INT pins -// may be connected to the same Arduino pin. - -//MCP23017 gpioModule2(196, 16, 0x22, 40); - - -//======================================================================= -// The following directive defines an MCP23008 8-port I2C GPIO Extender module. -//======================================================================= -// The parameters are: -// First Vpin=300 -// Number of VPINs=8 (numbered 300-307) -// I2C address of module=0x22 - -//MCP23008 gpioModule3(300, 8, 0x22); - - -//======================================================================= -// The following directive defines a PCF8574 8-port I2C GPIO Extender module. -//======================================================================= -// The parameters are: -// First Vpin=200 -// Number of VPINs=8 (numbered 200-207) -// I2C address of module=0x23 - -//PCF8574 gpioModule4(200, 8, 0x23); - - -// Alternative form using INT pin (see above) - -//PCF8574 gpioModule4(200, 8, 0x23, 40); - - -//======================================================================= -// The following directive defines an HCSR04 ultrasonic ranging module. -//======================================================================= -// The parameters are: -// Vpin=2000 (only one VPIN per directive) -// Number of VPINs=1 -// Arduino pin connected to TRIG=30 -// Arduino pin connected to ECHO=31 -// Minimum trigger range=20cm (VPIN goes to 1 when <20cm) -// Maximum trigger range=25cm (VPIN goes to 0 when >25cm) -// Note: Multiple devices can be configured by using a different ECHO pin -// for each one. The TRIG pin can be shared between multiple devices. -// Be aware that the 'ping' of one device may be received by another -// device and position them accordingly! - -//HCSR04 sonarModule1(2000, 30, 31, 20, 25); -//HCSR04 sonarModule2(2001, 30, 32, 20, 25); - - -//======================================================================= -// The following directive defines a single VL53L0X Time-of-Flight range sensor. -//======================================================================= -// The parameters are: -// VPIN=5000 -// Number of VPINs=1 -// I2C address=0x29 (default for this chip) -// Minimum trigger range=200mm (VPIN goes to 1 when <20cm) -// Maximum trigger range=250mm (VPIN goes to 0 when >25cm) - -//VL53L0X tofModule1(5000, 1, 0x29, 200, 250); - -// For multiple VL53L0X modules, add another parameter which is a VPIN connected to the -// module's XSHUT pin. This allows the modules to be configured, at start, -// with distinct I2C addresses. In this case, the address 0x29 is only used during -// initialisation to configure each device in turn with the desired unique I2C address. -// The examples below have the modules' XSHUT pins connected to the first two pins of -// the first MCP23017 module (164 and 165), but Arduino pins may be used instead. -// The first module here is given I2C address 0x30 and the second is 0x31. - -//VL53L0X tofModule1(5000, 1, 0x30, 200, 250, 164); -//VL53L0X tofModule2(5001, 1, 0x31, 200, 250, 165); - - -//======================================================================= +//========================================================================== // The function halSetup() is invoked from CS if it exists within the build. -// It is called before mySetup.h is executed, so things set up within here can be -// referenced by commands in mySetup.h. -//======================================================================= +// The setup calls are included between the open and close braces "{ ... }". +// Comments (lines preceded by "//") are optional. +//========================================================================== void halSetup() { - // Alternative way of creating a module driver, which has to be within the halSetup() function - // The other devices can also be created in this way. The parameter lists for the - // create() function are identical to the parameter lists for the declarations. + //======================================================================= + // The following directive defines a PCA9685 PWM Servo driver module. + //======================================================================= + // The parameters are: + // First Vpin=100 + // Number of VPINs=16 (numbered 100-115) + // I2C address of module=0x40 + + //PCA9685::create(100, 16, 0x40); + + + //======================================================================= + // The following directive defines an MCP23017 16-port I2C GPIO Extender module. + //======================================================================= + // The parameters are: + // First Vpin=196 + // Number of VPINs=16 (numbered 196-211) + // I2C address of module=0x22 //MCP23017::create(196, 16, 0x22); + // Alternative form, which allows the INT pin of the module to request a scan + // by pulling Arduino pin 40 to ground. Means that the I2C isn't being polled + // all the time, only when a change takes place. Multiple modules' INT pins + // may be connected to the same Arduino pin. + + //MCP23017::create(196, 16, 0x22, 40); + + + //======================================================================= + // The following directive defines an MCP23008 8-port I2C GPIO Extender module. + //======================================================================= + // The parameters are: + // First Vpin=300 + // Number of VPINs=8 (numbered 300-307) + // I2C address of module=0x22 + + //MCP23008::create(300, 8, 0x22); + + + //======================================================================= + // The following directive defines a PCF8574 8-port I2C GPIO Extender module. + //======================================================================= + // The parameters are: + // First Vpin=200 + // Number of VPINs=8 (numbered 200-207) + // I2C address of module=0x23 + + //PCF8574::create(200, 8, 0x23); + + + // Alternative form using INT pin (see above) + + //PCF8574::create(200, 8, 0x23, 40); + + + //======================================================================= + // The following directive defines an HCSR04 ultrasonic ranging module. + //======================================================================= + // The parameters are: + // Vpin=2000 (only one VPIN per directive) + // Number of VPINs=1 + // Arduino pin connected to TRIG=30 + // Arduino pin connected to ECHO=31 + // Minimum trigger range=20cm (VPIN goes to 1 when <20cm) + // Maximum trigger range=25cm (VPIN goes to 0 when >25cm) + // Note: Multiple devices can be configured by using a different ECHO pin + // for each one. The TRIG pin can be shared between multiple devices. + // Be aware that the 'ping' of one device may be received by another + // device and position them accordingly! + + //HCSR04::create(2000, 30, 31, 20, 25); + //HCSR04::create(2001, 30, 32, 20, 25); + + + //======================================================================= + // The following directive defines a single VL53L0X Time-of-Flight range sensor. + //======================================================================= + // The parameters are: + // VPIN=5000 + // Number of VPINs=1 + // I2C address=0x29 (default for this chip) + // Minimum trigger range=200mm (VPIN goes to 1 when <20cm) + // Maximum trigger range=250mm (VPIN goes to 0 when >25cm) + + //VL53L0X::create(5000, 1, 0x29, 200, 250); + + // For multiple VL53L0X modules, add another parameter which is a VPIN connected to the + // module's XSHUT pin. This allows the modules to be configured, at start, + // with distinct I2C addresses. In this case, the address 0x29 is only used during + // initialisation to configure each device in turn with the desired unique I2C address. + // The examples below have the modules' XSHUT pins connected to the first two pins of + // the first MCP23017 module (164 and 165), but Arduino pins may be used instead. + // The first module here is given I2C address 0x30 and the second is 0x31. + + //VL53L0X::create(5000, 1, 0x30, 200, 250, 164); + //VL53L0X::create(5001, 1, 0x31, 200, 250, 165); + + //======================================================================= // Play mp3 files from a Micro-SD card, using a DFPlayer MP3 Module. //======================================================================= From 197228c3b0992b69dcb4c42a523a5a45abfd93a3 Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Mon, 15 Nov 2021 16:13:54 +0000 Subject: [PATCH 06/14] Update version to 3.2.0 rc4 --- version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.h b/version.h index ca3fc4e..bba59fb 100644 --- a/version.h +++ b/version.h @@ -3,7 +3,7 @@ #include "StringFormatter.h" -#define VERSION "3.2.0 rc3" +#define VERSION "3.2.0 rc4" // 3.2.0 Major functional and non-functional changes. // New HAL added for I/O (digital and analogue inputs and outputs, servos etc). // Support for MCP23008, MCP23017 and PCF9584 I2C GPIO Extender modules. From d7fd9e1538bd2eec5906f0ac4ace6da731323bdb Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Mon, 15 Nov 2021 16:16:55 +0000 Subject: [PATCH 07/14] Committing a SHA --- GITHUB_SHA.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index 674c2ef..a00a8be 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "ee5db61" +#define GITHUB_SHA "197228c" From 53113e981d317924be42348feb6f32e5abe63e9d Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Sun, 21 Nov 2021 17:56:06 +0000 Subject: [PATCH 08/14] Update IO_PCF8574.h Correct handling of input in immediate mode, --- IO_PCF8574.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IO_PCF8574.h b/IO_PCF8574.h index dea5e2c..58c4654 100644 --- a/IO_PCF8574.h +++ b/IO_PCF8574.h @@ -75,7 +75,7 @@ private: if (immediate) { uint8_t buffer[1]; I2CManager.read(_I2CAddress, buffer, 1); - _portInputState = ((uint16_t)buffer) & 0xff; + _portInputState = buffer[0]; } else { requestBlock.wait(); // Wait for preceding operation to complete // Issue new request to read GPIO register @@ -86,7 +86,7 @@ private: // This function is invoked when an I/O operation on the requestBlock completes. void _processCompletion(uint8_t status) override { if (status == I2C_STATUS_OK) - _portInputState = ((uint16_t)inputBuffer[0]) & 0xff; + _portInputState = inputBuffer[0]; else _portInputState = 0xff; } From 106fb612dc3bc5fd3f3b99fa21e6f3d48e70575d Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Sun, 21 Nov 2021 17:56:29 +0000 Subject: [PATCH 09/14] Committing a SHA --- GITHUB_SHA.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index a00a8be..62137e9 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "197228c" +#define GITHUB_SHA "53113e9" From 88fa5ad37cb03b9b691399294b427325b9ede38c Mon Sep 17 00:00:00 2001 From: Asbelos Date: Wed, 24 Nov 2021 12:02:16 +0000 Subject: [PATCH 10/14] VPIN in RMFT2::doSignal --- RMFT2.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/RMFT2.cpp b/RMFT2.cpp index 5a91541..c2a99d3 100644 --- a/RMFT2.cpp +++ b/RMFT2.cpp @@ -720,10 +720,10 @@ void RMFT2::kill(const FSH * reason, int operand) { byte opcode=GET_OPCODE; if (opcode==OPCODE_ENDEXRAIL) return; if (opcode!=OPCODE_SIGNAL) continue; - byte redpin=GET_OPERAND(0); + VPIN redpin=GET_OPERAND(0); if (redpin!=id)continue; - byte amberpin=GET_OPERAND(1); - byte greenpin=GET_OPERAND(2); + VPIN amberpin=GET_OPERAND(1); + VPIN greenpin=GET_OPERAND(2); // If amberpin is zero, synthesise amber from red+green IODevice::write(redpin,red || (amber && (amberpin==0))); if (amberpin) IODevice::write(amberpin,amber); From 2be3e276f9e6d1c00d7493f9538dcb5b7621c9a9 Mon Sep 17 00:00:00 2001 From: Asbelos Date: Wed, 24 Nov 2021 12:02:40 +0000 Subject: [PATCH 11/14] Committing a SHA --- GITHUB_SHA.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index 62137e9..e18387b 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "53113e9" +#define GITHUB_SHA "88fa5ad" From 97f34506217605e41b01f14b3a8c8c8bfd5efa7b Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Wed, 24 Nov 2021 12:53:03 +0000 Subject: [PATCH 12/14] Simplify OLED driver initialisation. Simplify the initialisation in the SSD1306Ascii driver, by removing some of the complex structures that were inherited from the library on which it is based. This should also allow it to compile on the ESP32 platform. --- SSD1306Ascii.cpp | 170 ++++++++++++++++++++--------------------------- SSD1306Ascii.h | 25 +------ 2 files changed, 72 insertions(+), 123 deletions(-) diff --git a/SSD1306Ascii.cpp b/SSD1306Ascii.cpp index 17fd5a2..2fc23c2 100644 --- a/SSD1306Ascii.cpp +++ b/SSD1306Ascii.cpp @@ -89,28 +89,93 @@ const uint8_t FLASH SSD1306AsciiWire::blankPixels[30] = {0x40, // First byte specifies data mode 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + +//============================================================================== +// this section is based on https://github.com/adafruit/Adafruit_SSD1306 + +/** Initialization commands for a 128x32 or 128x64 SSD1306 oled display. */ +const uint8_t FLASH SSD1306AsciiWire::Adafruit128xXXinit[] = { + // Init sequence for Adafruit 128x32/64 OLED module + 0x00, // Set to command mode + SSD1306_DISPLAYOFF, + SSD1306_SETDISPLAYCLOCKDIV, 0x80, // the suggested ratio 0x80 + SSD1306_SETMULTIPLEX, 0x3F, // ratio 64 (initially) + SSD1306_SETDISPLAYOFFSET, 0x0, // no offset + SSD1306_SETSTARTLINE | 0x0, // line #0 + SSD1306_CHARGEPUMP, 0x14, // internal vcc + SSD1306_MEMORYMODE, 0x02, // page mode + SSD1306_SEGREMAP | 0x1, // column 127 mapped to SEG0 + SSD1306_COMSCANDEC, // column scan direction reversed + SSD1306_SETCOMPINS, 0X12, // set COM pins + SSD1306_SETCONTRAST, 0x7F, // contrast level 127 + SSD1306_SETPRECHARGE, 0xF1, // pre-charge period (1, 15) + SSD1306_SETVCOMDETECT, 0x40, // vcomh regulator level + SSD1306_DISPLAYALLON_RESUME, + SSD1306_NORMALDISPLAY, + SSD1306_DISPLAYON +}; + +//------------------------------------------------------------------------------ +// This section is based on https://github.com/stanleyhuangyc/MultiLCD + +/** Initialization commands for a 128x64 SH1106 oled display. */ +const uint8_t FLASH SSD1306AsciiWire::SH1106_132x64init[] = { + 0x00, // Set to command mode + SSD1306_DISPLAYOFF, + SSD1306_SETDISPLAYCLOCKDIV, 0X80, // set osc division + SSD1306_SETMULTIPLEX, 0x3F, // ratio 64 + SSD1306_SETDISPLAYOFFSET, 0X00, // set display offset + SSD1306_SETSTARTPAGE | 0X0, // set page address + SSD1306_SETSTARTLINE | 0x0, // set start line + SH1106_SET_PUMP_MODE, SH1106_PUMP_ON, // set charge pump enable + SSD1306_SEGREMAP | 0X1, // set segment remap + SSD1306_COMSCANDEC, // Com scan direction + SSD1306_SETCOMPINS, 0X12, // set COM pins + SSD1306_SETCONTRAST, 0x80, // 128 + SSD1306_SETPRECHARGE, 0X1F, // set pre-charge period + SSD1306_SETVCOMDETECT, 0x40, // set vcomh + SH1106_SET_PUMP_VOLTAGE | 0X2, // 8.0 volts + SSD1306_NORMALDISPLAY, // normal / reverse + SSD1306_DISPLAYON +}; + //============================================================================== // SSD1306AsciiWire Method Definitions //------------------------------------------------------------------------------ // Constructor SSD1306AsciiWire::SSD1306AsciiWire(int width, int height) { + m_displayWidth = width; + m_displayHeight = height; // Set size in characters in base class lcdRows = height / 8; lcdCols = width / 6; + m_col = 0; + m_row = 0; + m_colOffset = 0; I2CManager.begin(); I2CManager.setClock(400000L); // Set max supported I2C speed for (byte address = 0x3c; address <= 0x3d; address++) { if (I2CManager.exists(address)) { + m_i2cAddr = address; + if (m_displayWidth==132 && m_displayHeight==64) { + // SH1106 display. This uses 128x64 centered within a 132x64 OLED. + m_colOffset = 2; + I2CManager.write_P(address, SH1106_132x64init, sizeof(SH1106_132x64init)); + } else if (m_displayWidth==128 && (m_displayHeight==64 || m_displayHeight==32)) { + // SSD1306 128x64 or 128x32 + I2CManager.write_P(address, Adafruit128xXXinit, sizeof(Adafruit128xXXinit)); + if (m_displayHeight == 32) + I2CManager.write(address, 5, 0, // Set command mode + SSD1306_SETMULTIPLEX, 0x1F, // ratio 32 + SSD1306_SETCOMPINS, 0x02); // sequential COM pins, disable remap + } else { + DIAG(F("OLED configuration option not recognised")); + return; + } // Device found DIAG(F("%dx%d OLED display configured on I2C:x%x"), width, height, address); - if (width == 132) - begin(&SH1106_132x64, address); - else if (height == 32) - begin(&Adafruit128x32, address); - else - begin(&Adafruit128x64, address); // Set singleton address lcdDisplay = this; clear(); @@ -132,23 +197,6 @@ void SSD1306AsciiWire::clearNative() { } } -// Initialise device -void SSD1306AsciiWire::begin(const DevType* dev, uint8_t i2cAddr) { - m_i2cAddr = i2cAddr; - m_col = 0; - m_row = 0; - const uint8_t* table = (const uint8_t*)GETFLASHW(&dev->initcmds); - uint8_t size = GETFLASH(&dev->initSize); - m_displayWidth = GETFLASH(&dev->lcdWidth); - m_displayHeight = GETFLASH(&dev->lcdHeight); - m_colOffset = GETFLASH(&dev->colOffset); - I2CManager.write_P(m_i2cAddr, table, size); - if (m_displayHeight == 32) - I2CManager.write(m_i2cAddr, 5, 0, // Set command mode - SSD1306_SETMULTIPLEX, 0x1F, // ratio 32 - SSD1306_SETCOMPINS, 0x02); // sequential COM pins, disable remap -} - //------------------------------------------------------------------------------ // Set cursor position (by text line) @@ -209,82 +257,6 @@ size_t SSD1306AsciiWire::writeNative(uint8_t ch) { return 1; } -//============================================================================== -// this section is based on https://github.com/adafruit/Adafruit_SSD1306 - -/** Initialization commands for a 128x32 or 128x64 SSD1306 oled display. */ -const uint8_t FLASH SSD1306AsciiWire::Adafruit128xXXinit[] = { - // Init sequence for Adafruit 128x32/64 OLED module - 0x00, // Set to command mode - SSD1306_DISPLAYOFF, - SSD1306_SETDISPLAYCLOCKDIV, 0x80, // the suggested ratio 0x80 - SSD1306_SETMULTIPLEX, 0x3F, // ratio 64 (initially) - SSD1306_SETDISPLAYOFFSET, 0x0, // no offset - SSD1306_SETSTARTLINE | 0x0, // line #0 - SSD1306_CHARGEPUMP, 0x14, // internal vcc - SSD1306_MEMORYMODE, 0x02, // page mode - SSD1306_SEGREMAP | 0x1, // column 127 mapped to SEG0 - SSD1306_COMSCANDEC, // column scan direction reversed - SSD1306_SETCOMPINS, 0X12, // set COM pins - SSD1306_SETCONTRAST, 0x7F, // contrast level 127 - SSD1306_SETPRECHARGE, 0xF1, // pre-charge period (1, 15) - SSD1306_SETVCOMDETECT, 0x40, // vcomh regulator level - SSD1306_DISPLAYALLON_RESUME, - SSD1306_NORMALDISPLAY, - SSD1306_DISPLAYON -}; - -/** Initialize a 128x32 SSD1306 oled display. */ -const DevType FLASH SSD1306AsciiWire::Adafruit128x32 = { - Adafruit128xXXinit, - sizeof(Adafruit128xXXinit), - 128, - 32, - 0 -}; - -/** Initialize a 128x64 oled display. */ -const DevType FLASH SSD1306AsciiWire::Adafruit128x64 = { - Adafruit128xXXinit, - sizeof(Adafruit128xXXinit), - 128, - 64, - 0 -}; -//------------------------------------------------------------------------------ -// This section is based on https://github.com/stanleyhuangyc/MultiLCD - -/** Initialization commands for a 128x64 SH1106 oled display. */ -const uint8_t FLASH SSD1306AsciiWire::SH1106_132x64init[] = { - 0x00, // Set to command mode - SSD1306_DISPLAYOFF, - SSD1306_SETDISPLAYCLOCKDIV, 0X80, // set osc division - SSD1306_SETMULTIPLEX, 0x3F, // ratio 64 - SSD1306_SETDISPLAYOFFSET, 0X00, // set display offset - SSD1306_SETSTARTPAGE | 0X0, // set page address - SSD1306_SETSTARTLINE | 0x0, // set start line - SH1106_SET_PUMP_MODE, SH1106_PUMP_ON, // set charge pump enable - SSD1306_SEGREMAP | 0X1, // set segment remap - SSD1306_COMSCANDEC, // Com scan direction - SSD1306_SETCOMPINS, 0X12, // set COM pins - SSD1306_SETCONTRAST, 0x80, // 128 - SSD1306_SETPRECHARGE, 0X1F, // set pre-charge period - SSD1306_SETVCOMDETECT, 0x40, // set vcomh - SH1106_SET_PUMP_VOLTAGE | 0X2, // 8.0 volts - SSD1306_NORMALDISPLAY, // normal / reverse - SSD1306_DISPLAYON -}; - -/** Initialize a 132x64 oled SH1106 display. */ -const DevType FLASH SSD1306AsciiWire::SH1106_132x64 = { - SH1106_132x64init, - sizeof(SH1106_132x64init), - 128, - 64, - 2 // SH1106 is a 132x64 controller but most OLEDs are only attached - // to columns 2-129. -}; - //------------------------------------------------------------------------------ diff --git a/SSD1306Ascii.h b/SSD1306Ascii.h index 90a7e7e..312a62f 100644 --- a/SSD1306Ascii.h +++ b/SSD1306Ascii.h @@ -32,21 +32,6 @@ //#define NOLOWERCASE //------------------------------------------------------------------------------ -// Device initialization structure. - -struct DevType { - /* Pointer to initialization command bytes. */ - const uint8_t* initcmds; - /* Number of initialization bytes */ - const uint8_t initSize; - /* Width of the display in pixels */ - const uint8_t lcdWidth; - /** Height of the display in pixels. */ - const uint8_t lcdHeight; - /* Column offset RAM to display. Used to pick start column of SH1106. */ - const uint8_t colOffset; -}; - // Constructor class SSD1306AsciiWire : public LCDDisplay { public: @@ -55,25 +40,17 @@ class SSD1306AsciiWire : public LCDDisplay { SSD1306AsciiWire(int width, int height); // Initialize the display controller. - void begin(const DevType* dev, uint8_t i2cAddr); + void begin(uint8_t i2cAddr); // Clear the display and set the cursor to (0, 0). void clearNative() override; // Set cursor to start of specified text line void setRowNative(byte line) override; - - // Initialize the display controller. - void init(const DevType* dev); // Write one character to OLED size_t writeNative(uint8_t c) override; - // Display characteristics / initialisation - static const DevType FLASH Adafruit128x32; - static const DevType FLASH Adafruit128x64; - static const DevType FLASH SH1106_132x64; - bool isBusy() override { return requestBlock.isBusy(); } private: From 746350b8463efad6edfd4bed11f8b4ba1b824fde Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Wed, 24 Nov 2021 12:54:02 +0000 Subject: [PATCH 13/14] Update version to 3.2.0 rc5 --- version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.h b/version.h index bba59fb..3089db9 100644 --- a/version.h +++ b/version.h @@ -3,7 +3,7 @@ #include "StringFormatter.h" -#define VERSION "3.2.0 rc4" +#define VERSION "3.2.0 rc5" // 3.2.0 Major functional and non-functional changes. // New HAL added for I/O (digital and analogue inputs and outputs, servos etc). // Support for MCP23008, MCP23017 and PCF9584 I2C GPIO Extender modules. From f05b3d1730d5ec30fa4f282bfebf015abcede9ad Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Wed, 24 Nov 2021 13:02:35 +0000 Subject: [PATCH 14/14] Committing a SHA --- GITHUB_SHA.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index e18387b..7cf2ed1 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "88fa5ad" +#define GITHUB_SHA "a2f8a8e"