From d5e0dd14fa70f9349c9c4d25ebee4df57f7aa0dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emil=20Gaj=C5=A1ak?= Date: Tue, 22 Feb 2022 17:00:56 +0100 Subject: [PATCH 1/2] Separated LEDMatrix to Matrix and MatrixOutput with IS31 implementation --- CMakeLists.txt | 43 +-- src/Devices/LEDmatrix/LEDmatrix.cpp | 5 - src/Devices/LEDmatrix/LEDmatrix.h | 79 ---- .../{LEDmatrix => Matrix}/Animation.cpp | 0 src/Devices/{LEDmatrix => Matrix}/Animation.h | 0 .../{LEDmatrix => Matrix}/Animation.impl | 0 src/Devices/{LEDmatrix => Matrix}/Font.hpp | 0 src/Devices/Matrix/IS31FL3731.cpp | 187 ++++++++++ src/Devices/Matrix/IS31FL3731.h | 38 ++ .../LEDmatrix.impl => Matrix/Matrix.cpp} | 345 +++++------------- src/Devices/Matrix/Matrix.h | 48 +++ src/Devices/Matrix/MatrixOutput.h | 25 ++ 12 files changed, 404 insertions(+), 366 deletions(-) delete mode 100644 src/Devices/LEDmatrix/LEDmatrix.cpp delete mode 100644 src/Devices/LEDmatrix/LEDmatrix.h rename src/Devices/{LEDmatrix => Matrix}/Animation.cpp (100%) rename src/Devices/{LEDmatrix => Matrix}/Animation.h (100%) rename src/Devices/{LEDmatrix => Matrix}/Animation.impl (100%) rename src/Devices/{LEDmatrix => Matrix}/Font.hpp (100%) create mode 100644 src/Devices/Matrix/IS31FL3731.cpp create mode 100644 src/Devices/Matrix/IS31FL3731.h rename src/Devices/{LEDmatrix/LEDmatrix.impl => Matrix/Matrix.cpp} (52%) create mode 100644 src/Devices/Matrix/Matrix.h create mode 100644 src/Devices/Matrix/MatrixOutput.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ea717b..cec40f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,19 +17,19 @@ if(WIN32 OR CYGWIN) endif() else() set(Arduino15 ~/.arduino15) - set(ArduinoLibs ~/Arduino/libraries) + set(ArduinoLibs /mnt/c/Users/emilg/Documents/Arduino/libraries) endif() # ESP32 -include_directories(${Arduino15}/packages/cm/hardware/esp32/1.1.1/cores/esp32) -include_directories(${Arduino15}/packages/cm/hardware/esp32/1.1.1/tools/sdk) -include_directories(${Arduino15}/packages/cm/hardware/esp32/1.1.1/tools/sdk/include) -include_directories(${Arduino15}/packages/cm/hardware/esp32/1.1.1/tools/sdk/include/esp32) -include_directories(${Arduino15}/packages/cm/hardware/esp32/1.1.1/tools/sdk/include/freertos) -include_directories(${Arduino15}/packages/cm/hardware/esp32/1.1.1/tools/sdk/include/spi_flash) -include_directories(${Arduino15}/packages/cm/hardware/esp32/1.1.1/tools/sdk/include/nvs_flash) -include_directories(${Arduino15}/packages/cm/hardware/esp32/1.1.1/tools/sdk/include/driver) -include_directories(${Arduino15}/packages/cm/hardware/esp32/1.1.1/tools/sdk/include/driver/driver) +include_directories(${Arduino15}/packages/cm/hardware/esp32/1.3.5/cores/esp32) +include_directories(${Arduino15}/packages/cm/hardware/esp32/1.3.5/tools/sdk) +include_directories(${Arduino15}/packages/cm/hardware/esp32/1.3.5/tools/sdk/include) +include_directories(${Arduino15}/packages/cm/hardware/esp32/1.3.5/tools/sdk/include/esp32) +include_directories(${Arduino15}/packages/cm/hardware/esp32/1.3.5/tools/sdk/include/freertos) +include_directories(${Arduino15}/packages/cm/hardware/esp32/1.3.5/tools/sdk/include/spi_flash) +include_directories(${Arduino15}/packages/cm/hardware/esp32/1.3.5/tools/sdk/include/nvs_flash) +include_directories(${Arduino15}/packages/cm/hardware/esp32/1.3.5/tools/sdk/include/driver) +include_directories(${Arduino15}/packages/cm/hardware/esp32/1.3.5/tools/sdk/include/driver/driver) # ESP8266 include_directories(${Arduino15}/packages/esp8266/hardware/esp8266/2.7.1/cores/esp8266) @@ -48,16 +48,16 @@ include_directories(${Arduino15}/packages/cm/hardware/esp8266/1.0.1/libraries/he include_directories(${Arduino15}/packages/cm/hardware/esp8266/1.0.1/libraries/ESP8266WiFi/src) # Package libs -include_directories(${Arduino15}/packages/cm/hardware/esp32/1.1.1/libraries/Wire/src) -include_directories(${Arduino15}/packages/cm/hardware/esp32/1.1.1/libraries/FS/src) -include_directories(${Arduino15}/packages/cm/hardware/esp32/1.1.1/libraries/SD/src) -include_directories(${Arduino15}/packages/cm/hardware/esp32/1.1.1/libraries/SPI/src) -include_directories(${Arduino15}/packages/cm/hardware/esp32/1.1.1/libraries/WiFi/src) -include_directories(${Arduino15}/packages/cm/hardware/esp32/1.1.1/libraries/SPIFFS/src) -include_directories(${Arduino15}/packages/cm/hardware/esp32/1.1.1/libraries/HTTPClient/src) -include_directories(${Arduino15}/packages/cm/hardware/esp32/1.1.1/libraries/TFT_eSPI) -include_directories(${Arduino15}/packages/cm/hardware/esp32/1.1.1/libraries/TFT_eSPI/Extensions) -include_directories(${Arduino15}/packages/cm/hardware/esp32/1.1.1/libraries/heatshrink) +include_directories(${Arduino15}/packages/cm/hardware/esp32/1.3.5/libraries/Wire/src) +include_directories(${Arduino15}/packages/cm/hardware/esp32/1.3.5/libraries/FS/src) +include_directories(${Arduino15}/packages/cm/hardware/esp32/1.3.5/libraries/SD/src) +include_directories(${Arduino15}/packages/cm/hardware/esp32/1.3.5/libraries/SPI/src) +include_directories(${Arduino15}/packages/cm/hardware/esp32/1.3.5/libraries/WiFi/src) +include_directories(${Arduino15}/packages/cm/hardware/esp32/1.3.5/libraries/SPIFFS/src) +include_directories(${Arduino15}/packages/cm/hardware/esp32/1.3.5/libraries/HTTPClient/src) +include_directories(${Arduino15}/packages/cm/hardware/esp32/1.3.5/libraries/TFT_eSPI) +include_directories(${Arduino15}/packages/cm/hardware/esp32/1.3.5/libraries/TFT_eSPI/Extensions) +include_directories(${Arduino15}/packages/cm/hardware/esp32/1.3.5/libraries/heatshrink) # External libs include_directories(${ArduinoLibs}/Keypad_I2Ca) @@ -65,6 +65,7 @@ include_directories(${ArduinoLibs}/Keypad/src) include_directories(${ArduinoLibs}/I2Cdev) include_directories(${ArduinoLibs}/MPU6050) include_directories(${ArduinoLibs}/SparkFun_ICM20948/src) +include_directories(${ArduinoLibs}/lvgl/src) AUX_SOURCE_DIRECTORY(src SOURCES) AUX_SOURCE_DIRECTORY(src/Audio SOURCES) @@ -73,7 +74,7 @@ AUX_SOURCE_DIRECTORY(src/Buffer SOURCES) AUX_SOURCE_DIRECTORY(src/Devices SOURCES) AUX_SOURCE_DIRECTORY(src/Devices/Motion SOURCES) AUX_SOURCE_DIRECTORY(src/Devices/SerialFlash SOURCES) -AUX_SOURCE_DIRECTORY(src/Devices/LEDmatrix SOURCES) +AUX_SOURCE_DIRECTORY(src/Devices/Matrix SOURCES) AUX_SOURCE_DIRECTORY(src/Display SOURCES) AUX_SOURCE_DIRECTORY(src/Elements SOURCES) AUX_SOURCE_DIRECTORY(src/FS SOURCES) diff --git a/src/Devices/LEDmatrix/LEDmatrix.cpp b/src/Devices/LEDmatrix/LEDmatrix.cpp deleted file mode 100644 index 49566d8..0000000 --- a/src/Devices/LEDmatrix/LEDmatrix.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "../../../Setup.hpp" - -#ifdef CIRCUITOS_LEDMATRIX -#include "LEDmatrix.impl" -#endif diff --git a/src/Devices/LEDmatrix/LEDmatrix.h b/src/Devices/LEDmatrix/LEDmatrix.h deleted file mode 100644 index 4b51895..0000000 --- a/src/Devices/LEDmatrix/LEDmatrix.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef SPENCER_LEDMATRIX_H -#define SPENCER_LEDMATRIX_H -/* -Modified version of Adafruits IS31FL3731 library (https://github.com/adafruit/Adafruit_IS31FL3731) - -This is a stripped-down version with no Adafruit-GFX library inheritance. -*/ - -#include -#include "Animation.h" -#include - -#define ISSI_ADDR_DEFAULT 0x74 - -#define ISSI_REG_CONFIG 0x00 -#define ISSI_REG_CONFIG_PICTUREMODE 0x00 -#define ISSI_REG_CONFIG_AUTOPLAYMODE 0x08 -#define ISSI_REG_CONFIG_AUDIOPLAYMODE 0x18 - -#define ISSI_CONF_PICTUREMODE 0x00 -#define ISSI_CONF_AUTOFRAMEMODE 0x04 -#define ISSI_CONF_AUDIOMODE 0x08 - -#define ISSI_REG_PICTUREFRAME 0x01 - -#define ISSI_REG_SHUTDOWN 0x0A -#define ISSI_REG_AUDIOSYNC 0x06 - -#define ISSI_COMMANDREGISTER 0xFD -#define ISSI_BANK_FUNCTIONREG 0x0B // helpfully called 'page nine' - -class LEDmatrixImpl : public LoopListener -{ -public: - LEDmatrixImpl(uint8_t width = 16, uint8_t height = 9); - bool begin(uint8_t sda = 22, uint8_t scl = 21, uint8_t addr = ISSI_ADDR_DEFAULT); - void drawPixel(int16_t x, int16_t y, uint16_t color); - void drawPixel(uint8_t i, uint8_t brightness); - void clear(void); - - void setLEDPWM(uint8_t lednum, uint8_t pwm, uint8_t bank = 0); - void audioSync(bool sync); - void setFrame(uint8_t b); - void displayFrame(uint8_t frame); - - void setRotation(uint8_t rotation); - uint8_t getRotation(); - void drawChar(int32_t x, int32_t y, unsigned char c, uint8_t brightness = 255, bool bigFont = 1); - void drawString(int32_t x, int32_t y, const char* c, uint8_t brightness = 255, bool bigFont = 1); - void drawString(int32_t x, int32_t y, String s, uint8_t brightness = 255, bool bigFont = 1); - void setBrightness(uint8_t _brightness); - uint8_t getBrightness(); - void push(); - void drawBitmap(int x, int y, uint width, uint height, uint8_t* data); - void drawBitmap(int x, int y, uint width, uint height, RGBpixel* data); - - void startAnimation(Animation* _animation, bool loop); - float getAnimationCompletionRate(); - void stopAnimation(); - void loop(uint _time) override; - -private: - void selectBank(uint8_t bank); - void writeRegister8(uint8_t bank, uint8_t reg, uint8_t data); - uint8_t readRegister8(uint8_t bank, uint8_t reg); - uint8_t _i2caddr, ///< The I2C address we expect to find the chip - _frame; ///< The frame (of 8) we are currently addressing - uint8_t width, height, brightness = 20, rotation = 2, prevBrightness = 0; - uint8_t *matrixBuffer = nullptr; - uint8_t *pastMatrixBuffer = nullptr; - - AnimationFrame* animationFrame = nullptr; - Animation* animation = nullptr; - bool animationLoop = 0; - uint currentFrameTime = 0; - uint animationStartMicros = 0; -}; - -#endif \ No newline at end of file diff --git a/src/Devices/LEDmatrix/Animation.cpp b/src/Devices/Matrix/Animation.cpp similarity index 100% rename from src/Devices/LEDmatrix/Animation.cpp rename to src/Devices/Matrix/Animation.cpp diff --git a/src/Devices/LEDmatrix/Animation.h b/src/Devices/Matrix/Animation.h similarity index 100% rename from src/Devices/LEDmatrix/Animation.h rename to src/Devices/Matrix/Animation.h diff --git a/src/Devices/LEDmatrix/Animation.impl b/src/Devices/Matrix/Animation.impl similarity index 100% rename from src/Devices/LEDmatrix/Animation.impl rename to src/Devices/Matrix/Animation.impl diff --git a/src/Devices/LEDmatrix/Font.hpp b/src/Devices/Matrix/Font.hpp similarity index 100% rename from src/Devices/LEDmatrix/Font.hpp rename to src/Devices/Matrix/Font.hpp diff --git a/src/Devices/Matrix/IS31FL3731.cpp b/src/Devices/Matrix/IS31FL3731.cpp new file mode 100644 index 0000000..781511f --- /dev/null +++ b/src/Devices/Matrix/IS31FL3731.cpp @@ -0,0 +1,187 @@ +#include "IS31FL3731.h" +#include + +#define ISSI_REG_CONFIG 0x00 +#define ISSI_REG_CONFIG_PICTUREMODE 0x00 +#define ISSI_REG_CONFIG_AUTOPLAYMODE 0x08 +#define ISSI_REG_CONFIG_AUDIOPLAYMODE 0x18 + +#define ISSI_CONF_PICTUREMODE 0x00 +#define ISSI_CONF_AUTOFRAMEMODE 0x04 +#define ISSI_CONF_AUDIOMODE 0x08 + +#define ISSI_REG_PICTUREFRAME 0x01 + +#define ISSI_REG_SHUTDOWN 0x0A +#define ISSI_REG_AUDIOSYNC 0x06 + +#define ISSI_COMMANDREGISTER 0xFD +#define ISSI_BANK_FUNCTIONREG 0x0B // helpfully called 'page nine' + + +IS31FL3731::IS31FL3731(uint width, uint height) : MatrixOutput(width, height){ + setI2C(); +} + +void IS31FL3731::init(){ + Wire.begin(sda, scl, _i2caddr); + Wire.setClock(400000); + + _frame = 0; + + // A basic scanner, see if it ACK's + Wire.beginTransmission(_i2caddr); + if(Wire.endTransmission() != 0){ + return; + } + + // shutdown + writeRegister8(ISSI_BANK_FUNCTIONREG, ISSI_REG_SHUTDOWN, 0x00); + + delay(10); + + // out of shutdown + writeRegister8(ISSI_BANK_FUNCTIONREG, ISSI_REG_SHUTDOWN, 0x01); + + // picture mode + writeRegister8(ISSI_BANK_FUNCTIONREG, ISSI_REG_CONFIG, + ISSI_REG_CONFIG_PICTUREMODE); + + displayFrame(_frame); + audioSync(false); + +} + +void IS31FL3731::push(void* data){ + auto matrixBuffer = (uint8_t*)data; + + selectBank(_frame); + for(uint8_t i = 0; i < 6; i++){ + Wire.beginTransmission(_i2caddr); + Wire.write((byte)0x24 + i * 24); + // write 24 bytes at once + for(uint8_t j = 0; j < 24; j++){ + Wire.write((uint8_t)(matrixBuffer[i * 24 + j] * brightness / 255)); + } + Wire.endTransmission(); + } + + for(uint8_t i = 0; i <= 0x11; i++){ + writeRegister8(_frame, i, 0xff); // each 8 LEDs on + } +} + +void IS31FL3731::setI2C(uint8_t sda, uint8_t scl, uint8_t addr){ + this->sda = sda; + this->scl = scl; + this->_i2caddr = addr; +} + + +/**************************************************************************/ +/*! + @brief Low level accesssor - sets a 8-bit PWM pixel value to a bank location + does not handle rotation, x/y or any rearrangements! + @param lednum The offset into the bank that corresponds to the LED + @param bank The bank/frame we will set the data in + @param pwm brightnes, from 0 (off) to 255 (max on) +*/ +/**************************************************************************/ +void IS31FL3731::setLEDPWM(uint8_t lednum, uint8_t pwm, uint8_t bank){ + if(lednum >= 144) + return; + writeRegister8(bank, 0x24 + lednum, (uint8_t)(pwm * brightness / 255)); +} + + +/**************************************************************************/ +/*! + @brief Switch to a given bank in the chip memory for future reads + @param bank The IS31 bank to switch to +*/ +/**************************************************************************/ +void IS31FL3731::selectBank(uint8_t bank){ + Wire.beginTransmission(_i2caddr); + Wire.write((byte)ISSI_COMMANDREGISTER); + Wire.write(bank); + Wire.endTransmission(); +} + +/**************************************************************************/ +/*! + @brief Enable the audio 'sync' for brightness pulsing (not really tested) + @param sync True to enable, False to disable +*/ +/**************************************************************************/ +void IS31FL3731::audioSync(bool sync){ + if(sync){ + writeRegister8(ISSI_BANK_FUNCTIONREG, ISSI_REG_AUDIOSYNC, 0x1); + }else{ + writeRegister8(ISSI_BANK_FUNCTIONREG, ISSI_REG_AUDIOSYNC, 0x0); + } +} + +/**************************************************************************/ +/*! + @brief Write one byte to a register located in a given bank + @param bank The IS31 bank to write the register location + @param reg the offset into the bank to write + @param data The byte value +*/ +/**************************************************************************/ +void IS31FL3731::writeRegister8(uint8_t bank, uint8_t reg, uint8_t data){ + selectBank(bank); + + Wire.beginTransmission(_i2caddr); + Wire.write((byte)reg); + Wire.write((byte)data); + Wire.endTransmission(); + // Serial.print("$"); Serial.print(reg, HEX); + // Serial.print(" = 0x"); Serial.println(data, HEX); +} + +/**************************************************************************/ +/*! + @brief Read one byte from a register located in a given bank + @param bank The IS31 bank to read the register location + @param reg the offset into the bank to read + @return 1 byte value +*/ +/**************************************************************************/ +uint8_t IS31FL3731::readRegister8(uint8_t bank, uint8_t reg){ + uint8_t x; + + selectBank(bank); + + Wire.beginTransmission(_i2caddr); + Wire.write((byte)reg); + Wire.endTransmission(); + + Wire.requestFrom(_i2caddr, (size_t)1); + x = Wire.read(); + + // Serial.print("$"); Serial.print(reg, HEX); + // Serial.print(": 0x"); Serial.println(x, HEX); + + return x; +} + +/**************************************************************************/ +/*! + @brief Set's this object's frame tracker (does not talk to the chip) + @param frame Ranges from 0 - 7 for the 8 frames +*/ +/**************************************************************************/ +void IS31FL3731::setFrame(uint8_t frame){ _frame = frame; } + +/**************************************************************************/ +/*! + @brief Have the chip set the display to the contents of a frame + @param frame Ranges from 0 - 7 for the 8 frames +*/ +/**************************************************************************/ +void IS31FL3731::displayFrame(uint8_t frame){ + if(frame > 7) + frame = 0; + writeRegister8(ISSI_BANK_FUNCTIONREG, ISSI_REG_PICTUREFRAME, frame); +} diff --git a/src/Devices/Matrix/IS31FL3731.h b/src/Devices/Matrix/IS31FL3731.h new file mode 100644 index 0000000..8eb05a3 --- /dev/null +++ b/src/Devices/Matrix/IS31FL3731.h @@ -0,0 +1,38 @@ +#ifndef CIRCUITOS_IS31FL3731_H +#define CIRCUITOS_IS31FL3731_H + +/* +Modified version of Adafruits IS31FL3731 library (https://github.com/adafruit/Adafruit_IS31FL3731) + +This is a stripped-down version with no Adafruit-GFX library inheritance. +*/ + +#include "MatrixOutput.h" + +#define ISSI_ADDR_DEFAULT 0x74 + +class IS31FL3731 : public MatrixOutput { +public: + IS31FL3731(uint width, uint height); + void init() override; + void push(void* data) override; + + void setI2C(uint8_t sda = 22, uint8_t scl = 21, uint8_t addr = ISSI_ADDR_DEFAULT); + +private: + uint8_t sda, scl, + _i2caddr, ///< The I2C address we expect to find the chip + _frame; ///< The frame (of 8) we are currently addressing + + void setLEDPWM(uint8_t lednum, uint8_t pwm, uint8_t bank = 0); + void audioSync(bool sync); + void setFrame(uint8_t b); + void displayFrame(uint8_t frame); + + void selectBank(uint8_t bank); + void writeRegister8(uint8_t bank, uint8_t reg, uint8_t data); + uint8_t readRegister8(uint8_t bank, uint8_t reg); +}; + + +#endif //CIRCUITOS_IS31FL3731_H diff --git a/src/Devices/LEDmatrix/LEDmatrix.impl b/src/Devices/Matrix/Matrix.cpp similarity index 52% rename from src/Devices/LEDmatrix/LEDmatrix.impl rename to src/Devices/Matrix/Matrix.cpp index 24c93b4..c6cd034 100644 --- a/src/Devices/LEDmatrix/LEDmatrix.impl +++ b/src/Devices/Matrix/Matrix.cpp @@ -1,12 +1,12 @@ -#include "LEDmatrix.h" -#include +#include "Matrix.h" #include "Font.hpp" + #ifndef _swap_int16_t #define _swap_int16_t(a, b) \ { \ - int16_t t = a; \ - a = b; \ - b = t; \ + int16_t t = a; \ + a = b; \ + b = t; \ } #endif @@ -18,84 +18,36 @@ */ /**************************************************************************/ -LEDmatrixImpl::LEDmatrixImpl(uint8_t _width, uint8_t _height) -{ +LEDmatrixImpl::LEDmatrixImpl(MatrixOutput &output, uint8_t _width, uint8_t _height) : output(output){ width = _width; height = _height; - matrixBuffer = (uint8_t*)calloc(width*height, sizeof(uint8_t)); - pastMatrixBuffer = (uint8_t*)calloc(width*height, sizeof(uint8_t)); + matrixBuffer = (uint8_t*)calloc(width * height, sizeof(uint8_t)); + pastMatrixBuffer = (uint8_t*)calloc(width * height, sizeof(uint8_t)); } /**************************************************************************/ /*! @brief Initialize hardware and clear display. - @param addr The I2C address we expect to find the chip at. - @returns True on success, false if chip isnt found. */ /**************************************************************************/ -bool LEDmatrixImpl::begin(uint8_t sda, uint8_t scl, uint8_t addr) { - Wire.begin(sda, scl, addr); - Wire.setClock(400000); - - _i2caddr = addr; - _frame = 0; - - // A basic scanner, see if it ACK's - Wire.beginTransmission(_i2caddr); - if (Wire.endTransmission() != 0) { - return false; - } - - // shutdown - writeRegister8(ISSI_BANK_FUNCTIONREG, ISSI_REG_SHUTDOWN, 0x00); - - delay(10); - - // out of shutdown - writeRegister8(ISSI_BANK_FUNCTIONREG, ISSI_REG_SHUTDOWN, 0x01); - - // picture mode - writeRegister8(ISSI_BANK_FUNCTIONREG, ISSI_REG_CONFIG, - ISSI_REG_CONFIG_PICTUREMODE); - - displayFrame(_frame); - - // all LEDs on & 0 PWM +void LEDmatrixImpl::begin(){ + output.init(); clear(); // set each led to 0 PWM push(); - for (uint8_t f = 0; f < 8; f++) { - for (uint8_t i = 0; i <= 0x11; i++) - writeRegister8(f, i, 0xff); // each 8 LEDs on - } - - audioSync(false); - clear(); - return true; } -/**************************************************************************/ -/*! - @brief Sets all LEDs on & 0 PWM for current frame. -*/ -/**************************************************************************/ -void LEDmatrixImpl::clear(void) { - memset(matrixBuffer, 0, width*height); +void LEDmatrixImpl::setOutput(MatrixOutput &output){ + LEDmatrixImpl::output = output; } /**************************************************************************/ /*! - @brief Low level accesssor - sets a 8-bit PWM pixel value to a bank location - does not handle rotation, x/y or any rearrangements! - @param lednum The offset into the bank that corresponds to the LED - @param bank The bank/frame we will set the data in - @param pwm brightnes, from 0 (off) to 255 (max on) + @brief Sets all LEDs on & 0 PWM for current frame. */ /**************************************************************************/ -void LEDmatrixImpl::setLEDPWM(uint8_t lednum, uint8_t pwm, uint8_t bank) { - if (lednum >= 144) - return; - writeRegister8(bank, 0x24 + lednum, (uint8_t)(pwm*brightness/255)); +void LEDmatrixImpl::clear(){ + memset(matrixBuffer, 0, width * height); } /**************************************************************************/ @@ -107,123 +59,27 @@ void LEDmatrixImpl::setLEDPWM(uint8_t lednum, uint8_t pwm, uint8_t bank) { @param color Despite being a 16-bit value, takes 0 (off) to 255 (max on) */ /**************************************************************************/ -void LEDmatrixImpl::drawPixel(int16_t x, int16_t y, uint16_t color) { - switch (getRotation()) { - case 1: - _swap_int16_t(x, y); - x = width - x - 1; - break; - case 2: - x = width - x - 1; - y = height - y - 1; - break; - case 3: - _swap_int16_t(x, y); - y = height - y - 1; - break; +void LEDmatrixImpl::drawPixel(int16_t x, int16_t y, uint16_t color){ + switch(getRotation()){ + case 1:_swap_int16_t(x, y); + x = width - x - 1; + break; + case 2: + x = width - x - 1; + y = height - y - 1; + break; + case 3:_swap_int16_t(x, y); + y = height - y - 1; + break; } - if ((x < 0) || (x >= 16)) + if((x < 0) || (x >= 16)) return; - if ((y < 0) || (y >= 9)) + if((y < 0) || (y >= 9)) return; - if (color > 255) + if(color > 255) color = 255; // PWM 8bit max matrixBuffer[x + y * 16] = color; - // setLEDPWM(x + y * 16, color, _frame); - return; -} - -/**************************************************************************/ -/*! - @brief Set's this object's frame tracker (does not talk to the chip) - @param frame Ranges from 0 - 7 for the 8 frames -*/ -/**************************************************************************/ -void LEDmatrixImpl::setFrame(uint8_t frame) { _frame = frame; } - -/**************************************************************************/ -/*! - @brief Have the chip set the display to the contents of a frame - @param frame Ranges from 0 - 7 for the 8 frames -*/ -/**************************************************************************/ -void LEDmatrixImpl::displayFrame(uint8_t frame) { - if (frame > 7) - frame = 0; - writeRegister8(ISSI_BANK_FUNCTIONREG, ISSI_REG_PICTUREFRAME, frame); -} - -/**************************************************************************/ -/*! - @brief Switch to a given bank in the chip memory for future reads - @param bank The IS31 bank to switch to -*/ -/**************************************************************************/ -void LEDmatrixImpl::selectBank(uint8_t bank) { - Wire.beginTransmission(_i2caddr); - Wire.write((byte)ISSI_COMMANDREGISTER); - Wire.write(bank); - Wire.endTransmission(); -} - -/**************************************************************************/ -/*! - @brief Enable the audio 'sync' for brightness pulsing (not really tested) - @param sync True to enable, False to disable -*/ -/**************************************************************************/ -void LEDmatrixImpl::audioSync(bool sync) { - if (sync) { - writeRegister8(ISSI_BANK_FUNCTIONREG, ISSI_REG_AUDIOSYNC, 0x1); - } else { - writeRegister8(ISSI_BANK_FUNCTIONREG, ISSI_REG_AUDIOSYNC, 0x0); - } -} - -/**************************************************************************/ -/*! - @brief Write one byte to a register located in a given bank - @param bank The IS31 bank to write the register location - @param reg the offset into the bank to write - @param data The byte value -*/ -/**************************************************************************/ -void LEDmatrixImpl::writeRegister8(uint8_t bank, uint8_t reg, uint8_t data) { - selectBank(bank); - - Wire.beginTransmission(_i2caddr); - Wire.write((byte)reg); - Wire.write((byte)data); - Wire.endTransmission(); - // Serial.print("$"); Serial.print(reg, HEX); - // Serial.print(" = 0x"); Serial.println(data, HEX); -} - -/**************************************************************************/ -/*! - @brief Read one byte from a register located in a given bank - @param bank The IS31 bank to read the register location - @param reg the offset into the bank to read - @return 1 byte value -*/ -/**************************************************************************/ -uint8_t LEDmatrixImpl::readRegister8(uint8_t bank, uint8_t reg) { - uint8_t x; - - selectBank(bank); - - Wire.beginTransmission(_i2caddr); - Wire.write((byte)reg); - Wire.endTransmission(); - - Wire.requestFrom(_i2caddr, (size_t)1); - x = Wire.read(); - - // Serial.print("$"); Serial.print(reg, HEX); - // Serial.print(": 0x"); Serial.println(x, HEX); - - return x; } /**************************************************************************/ @@ -236,19 +92,18 @@ uint8_t LEDmatrixImpl::readRegister8(uint8_t bank, uint8_t reg) { @param bigFont Flag to use bigger 5x7 or the smaller 3x5 font: true - big font, false - small font. */ /**************************************************************************/ -void LEDmatrixImpl::drawChar(int32_t x, int32_t y, unsigned char c, uint8_t _brightness, bool bigFont) -{ +void LEDmatrixImpl::drawChar(int32_t x, int32_t y, unsigned char c, uint8_t _brightness, bool bigFont){ if(bigFont){ uint8_t column[6]; uint8_t mask = 0x1; - for (int8_t i = 0; i < 5; i++) column[i] = pgm_read_byte(font + (c * 5) + i); + for(int8_t i = 0; i < 5; i++) column[i] = pgm_read_byte(font + (c * 5) + i); column[5] = 0; int8_t j, k; - for (j = 0; j < 8; j++) { - for (k = 0; k < 5; k++) { - if (column[k] & mask) { + for(j = 0; j < 8; j++){ + for(k = 0; k < 5; k++){ + if(column[k] & mask){ if((x + k) >= 0 && (y + j) >= 0 && (x + k) < width && (y + j) < height){ drawPixel(x + k, y + j, _brightness); } @@ -257,27 +112,27 @@ void LEDmatrixImpl::drawChar(int32_t x, int32_t y, unsigned char c, uint8_t _bri mask <<= 1; } }else{ - - if ((c >= TomThumb.first) && (c <= TomThumb.last)){ + + if((c >= TomThumb.first) && (c <= TomThumb.last)){ c -= TomThumb.first; - GFXglyph *glyph = &(TomThumb.glyph[c]); - uint8_t *bitmap = TomThumb.bitmap; + GFXglyph* glyph = &(TomThumb.glyph[c]); + uint8_t* bitmap = TomThumb.bitmap; uint16_t bo = pgm_read_word(&glyph->bitmapOffset); - uint8_t w = pgm_read_byte(&glyph->width), - h = pgm_read_byte(&glyph->height); - int8_t xo = pgm_read_byte(&glyph->xOffset), + uint8_t w = pgm_read_byte(&glyph->width), + h = pgm_read_byte(&glyph->height); + int8_t xo = pgm_read_byte(&glyph->xOffset), yo = pgm_read_byte(&glyph->yOffset); - uint8_t xx, yy, bits, bit=0; + uint8_t xx, yy, bits, bit = 0; - for(yy=0; yy= 0 && (y+yo+yy) >= 0 && (x+xo+xx) < width && (y+yo+yy) < height){ - drawPixel((x+xo+xx)%16, y+yo+yy, _brightness); + if(bits & 0x80){ + if((x + xo + xx) >= 0 && (y + yo + yy) >= 0 && (x + xo + xx) < width && (y + yo + yy) < height){ + drawPixel((x + xo + xx) % 16, y + yo + yy, _brightness); } } bits <<= 1; @@ -297,18 +152,15 @@ void LEDmatrixImpl::drawChar(int32_t x, int32_t y, unsigned char c, uint8_t _bri @param bigFont Flag to use bigger 5x7 or the smaller 3x5 font: true - big font, false - small font. */ /**************************************************************************/ -void LEDmatrixImpl::drawString(int32_t x, int32_t y, const char* c, uint8_t _brightness, bool bigFont) -{ +void LEDmatrixImpl::drawString(int32_t x, int32_t y, const char* c, uint8_t _brightness, bool bigFont){ size_t length = strlen(c); - for(size_t i = 0; i < length; i++) - { + for(size_t i = 0; i < length; i++){ drawChar(x, y, c[i], _brightness, bigFont); - x+= bigFont ? 6 : 4; + x += bigFont ? 6 : 4; } } -void LEDmatrixImpl::drawString(int32_t x, int32_t y, String s, uint8_t _brightness, bool bigFont) -{ +void LEDmatrixImpl::drawString(int32_t x, int32_t y, const String &s, uint8_t _brightness, bool bigFont){ drawString(x, y, s.c_str(), _brightness, bigFont); } @@ -318,9 +170,8 @@ void LEDmatrixImpl::drawString(int32_t x, int32_t y, String s, uint8_t _brightne @param _brightness Global brightness for the matrix. Ranges from 0 to 255. */ /**************************************************************************/ -void LEDmatrixImpl::setBrightness(uint8_t _brightness) -{ - brightness = _brightness; +void LEDmatrixImpl::setBrightness(uint8_t _brightness){ + output.setBrightness(_brightness); } /**************************************************************************/ @@ -329,9 +180,8 @@ void LEDmatrixImpl::setBrightness(uint8_t _brightness) @return Global brightness of the matrix. */ /**************************************************************************/ -uint8_t LEDmatrixImpl::getBrightness() -{ - return brightness; +uint8_t LEDmatrixImpl::getBrightness() const{ + return output.getBrightness(); } /**************************************************************************/ @@ -340,8 +190,7 @@ uint8_t LEDmatrixImpl::getBrightness() @param rot Desired rotation in clockwise direction (0-3). */ /**************************************************************************/ -void LEDmatrixImpl::setRotation(uint8_t rot) -{ +void LEDmatrixImpl::setRotation(uint8_t rot){ if(rot > 3) return; rotation = rot; } @@ -352,8 +201,7 @@ void LEDmatrixImpl::setRotation(uint8_t rot) @return Matrix rotation (0-3). */ /**************************************************************************/ -uint8_t LEDmatrixImpl::getRotation() -{ +uint8_t LEDmatrixImpl::getRotation() const{ return rotation; } @@ -362,22 +210,8 @@ uint8_t LEDmatrixImpl::getRotation() @brief Push the matrix buffer onto the matrix. */ /**************************************************************************/ -void LEDmatrixImpl::push() -{ - selectBank(_frame); - for (uint8_t i = 0; i < 6; i++) { - Wire.beginTransmission(_i2caddr); - Wire.write((byte)0x24 + i * 24); - // write 24 bytes at once - for (uint8_t j = 0; j < 24; j++) { - Wire.write((uint8_t)(matrixBuffer[i*24 + j]*brightness/255)); - } - Wire.endTransmission(); - } - - for (uint8_t i = 0; i <= 0x11; i++){ - writeRegister8(_frame, i, 0xff); // each 8 LEDs on - } +void LEDmatrixImpl::push(){ + output.push(matrixBuffer); } /**************************************************************************/ @@ -387,8 +221,7 @@ void LEDmatrixImpl::push() @param loop Sets animation loop. True - loop until stopAnimation() or another startAnimation(), False - no looping. */ /**************************************************************************/ -void LEDmatrixImpl::startAnimation(Animation* _animation, bool loop) -{ +void LEDmatrixImpl::startAnimation(Animation* _animation, bool loop){ stopAnimation(); animation = _animation; @@ -405,8 +238,7 @@ void LEDmatrixImpl::startAnimation(Animation* _animation, bool loop) @brief Stops running animation. */ /**************************************************************************/ -void LEDmatrixImpl::stopAnimation() -{ +void LEDmatrixImpl::stopAnimation(){ delete animation; animation = nullptr; animationFrame = nullptr; @@ -419,11 +251,10 @@ void LEDmatrixImpl::stopAnimation() @param _time Current millis() time, used for frame duration calculation. */ /**************************************************************************/ -void LEDmatrixImpl::loop(uint _time) -{ +void LEDmatrixImpl::loop(uint _time){ if(animationFrame != nullptr && animation != nullptr){ - currentFrameTime+=_time; - if(currentFrameTime >= animationFrame->duration*1000){ + currentFrameTime += _time; + if(currentFrameTime >= animationFrame->duration * 1000){ clear(); currentFrameTime = 0; animationFrame = animation->getNextFrame(); @@ -440,23 +271,22 @@ void LEDmatrixImpl::loop(uint _time) drawBitmap(0, 0, animation->getWidth(), animation->getHeight(), animationFrame->data); } } - bool noChange = 1; - if(prevBrightness == brightness) - { - for(uint8_t i = 0; i < width*height; i++){ + bool noChange = true; + if(prevBrightness == output.getBrightness()){ + for(uint8_t i = 0; i < width * height; i++){ if(matrixBuffer[i] != pastMatrixBuffer[i]){ - noChange = 0; + noChange = false; break; } } }else{ - noChange = 0; - prevBrightness = brightness; + noChange = false; + prevBrightness = output.getBrightness(); } if(!noChange){ push(); } - memcpy(pastMatrixBuffer, matrixBuffer, width*height); + memcpy(pastMatrixBuffer, matrixBuffer, width * height); } /**************************************************************************/ @@ -469,13 +299,10 @@ void LEDmatrixImpl::loop(uint _time) @param data Pointer to the bitmap. */ /**************************************************************************/ -void LEDmatrixImpl::drawBitmap(int x, int y, uint width, uint height, uint8_t* data) -{ - for(int i = 0; i < height; i++) - { - for(int j = 0; j < width; j++) - { - drawPixel(x + j, y + i, data[i*width + j]); +void LEDmatrixImpl::drawBitmap(int x, int y, uint width, uint height, uint8_t* data){ + for(int i = 0; i < height; i++){ + for(int j = 0; j < width; j++){ + drawPixel(x + j, y + i, data[i * width + j]); } } } @@ -490,13 +317,10 @@ void LEDmatrixImpl::drawBitmap(int x, int y, uint width, uint height, uint8_t* d @param data Pointer to the bitmap. */ /**************************************************************************/ -void LEDmatrixImpl::drawBitmap(int x, int y, uint width, uint height, RGBpixel* data) -{ - for(int i = 0; i < height; i++) - { - for(int j = 0; j < width; j++) - { - drawPixel(x + j, y + i, data[i*width + j].r); +void LEDmatrixImpl::drawBitmap(int x, int y, uint width, uint height, RGBpixel* data){ + for(int i = 0; i < height; i++){ + for(int j = 0; j < width; j++){ + drawPixel(x + j, y + i, data[i * width + j].r); } } } @@ -507,12 +331,11 @@ void LEDmatrixImpl::drawBitmap(int x, int y, uint width, uint height, RGBpixel* @return Completion rate (in percentage 0-100) for the current animation. If none are played, then defaults to zero. */ /**************************************************************************/ -float LEDmatrixImpl::getAnimationCompletionRate() -{ +float LEDmatrixImpl::getAnimationCompletionRate(){ if(animationFrame == nullptr || animation == nullptr) return 0.0; - return ((float)(micros() - animationStartMicros)) / ((float)(animation->getLoopDuration()*1000))*100; + return ((float)(micros() - animationStartMicros)) / ((float)(animation->getLoopDuration() * 1000)) * 100; } void LEDmatrixImpl::drawPixel(uint8_t i, uint8_t brightness){ matrixBuffer[i] = brightness; -} \ No newline at end of file +} diff --git a/src/Devices/Matrix/Matrix.h b/src/Devices/Matrix/Matrix.h new file mode 100644 index 0000000..30f7483 --- /dev/null +++ b/src/Devices/Matrix/Matrix.h @@ -0,0 +1,48 @@ +#ifndef SPENCER_LEDMATRIX_H +#define SPENCER_LEDMATRIX_H + +#include +#include "Animation.h" +#include +#include "MatrixOutput.h" + +class LEDmatrixImpl : public LoopListener { +public: + LEDmatrixImpl(MatrixOutput &output, uint8_t width = 16, uint8_t height = 9); + void setOutput(MatrixOutput &output); + void begin(); + void drawPixel(int16_t x, int16_t y, uint16_t color); + void drawPixel(uint8_t i, uint8_t brightness); + void clear(); + + void setRotation(uint8_t rotation); + uint8_t getRotation() const; + void drawChar(int32_t x, int32_t y, unsigned char c, uint8_t brightness = 255, bool bigFont = true); + void drawString(int32_t x, int32_t y, const char* c, uint8_t brightness = 255, bool bigFont = true); + void drawString(int32_t x, int32_t y, const String &s, uint8_t brightness = 255, bool bigFont = true); + void setBrightness(uint8_t _brightness); + uint8_t getBrightness() const; + void push(); + void drawBitmap(int x, int y, uint width, uint height, uint8_t* data); + void drawBitmap(int x, int y, uint width, uint height, RGBpixel* data); + + void startAnimation(Animation* _animation, bool loop); + float getAnimationCompletionRate(); + void stopAnimation(); + void loop(uint _time) override; + +private: + MatrixOutput &output; + + uint8_t width, height, rotation = 2, prevBrightness = 0; + uint8_t* matrixBuffer = nullptr; + uint8_t* pastMatrixBuffer = nullptr; + + AnimationFrame* animationFrame = nullptr; + Animation* animation = nullptr; + bool animationLoop = false; + uint currentFrameTime = 0; + uint animationStartMicros = 0; +}; + +#endif \ No newline at end of file diff --git a/src/Devices/Matrix/MatrixOutput.h b/src/Devices/Matrix/MatrixOutput.h new file mode 100644 index 0000000..cb84f81 --- /dev/null +++ b/src/Devices/Matrix/MatrixOutput.h @@ -0,0 +1,25 @@ +#ifndef CIRCUITOS_MATRIXOUTPUT_H +#define CIRCUITOS_MATRIXOUTPUT_H + +#include + +class MatrixOutput { +public: + MatrixOutput(uint width, uint height) : width(width), height(height){}; + virtual void init() = 0; + virtual void push(void* data) = 0; + + void setBrightness(uint8_t brightness){ + MatrixOutput::brightness = brightness; + } + uint8_t getBrightness() const{ + return brightness; + } + +protected: + uint width, height; + uint8_t brightness = 255; +}; + + +#endif //CIRCUITOS_MATRIXOUTPUT_H From de5ac3b7346405e9f41d1fe8c50e454bc8bbe0db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emil=20Gaj=C5=A1ak?= Date: Wed, 23 Feb 2022 15:17:26 +0100 Subject: [PATCH 2/2] Added ShiftMatrixOutput --- src/Devices/Matrix/ShiftMatrixOutput.cpp | 77 ++++++++++++++++++++++++ src/Devices/Matrix/ShiftMatrixOutput.h | 27 +++++++++ 2 files changed, 104 insertions(+) create mode 100644 src/Devices/Matrix/ShiftMatrixOutput.cpp create mode 100644 src/Devices/Matrix/ShiftMatrixOutput.h diff --git a/src/Devices/Matrix/ShiftMatrixOutput.cpp b/src/Devices/Matrix/ShiftMatrixOutput.cpp new file mode 100644 index 0000000..8942ce8 --- /dev/null +++ b/src/Devices/Matrix/ShiftMatrixOutput.cpp @@ -0,0 +1,77 @@ +#include "ShiftMatrixOutput.h" +#include + +#define PERIOD 1 +#define LH(pin) do { digitalWrite((pin), LOW); delayMicroseconds(PERIOD); digitalWrite((pin), HIGH); delayMicroseconds(PERIOD); } while(0) +#define HL(pin) do { digitalWrite((pin), HIGH); delayMicroseconds(PERIOD); digitalWrite((pin), LOW); delayMicroseconds(PERIOD); } while(0) + +ShiftMatrixOutput* ShiftMatrixOutput::instance = nullptr; + +ShiftMatrixOutput::ShiftMatrixOutput(uint width, uint height) : MatrixOutput(width, height){ + instance = this; + + numShifts = ceil((float)(width * height) / 8.0f); //uses serialized 8bit shift regs + matrixBuffer = (uint8_t*)malloc(width*height); + + timer = timerBegin(0, 80, true); + timerAttachInterrupt(timer, timerInterrupt, true); // P3= edge triggered +} + +void ShiftMatrixOutput::init(){ + pinMode(dataPin, OUTPUT); + pinMode(clockPin, OUTPUT); + pinMode(loadPin, OUTPUT); + + timerAlarmWrite(timer, pushInterval*1000, true); //50ms refresh interval + timerAlarmEnable(timer); + timerStart(timer); +} + +void ShiftMatrixOutput::push(void* data){ + mutex.lock(); + memcpy(matrixBuffer, data, width*height); + mutex.unlock(); +} + +void ShiftMatrixOutput::setPins(uint8_t dataPin, uint8_t clockPin, uint8_t loadPin){ + this->dataPin = dataPin; + this->clockPin = clockPin; + this->loadPin = loadPin; +} + +void IRAM_ATTR ShiftMatrixOutput::timerInterrupt(){ + instance->pushToShift(); +} + +void ShiftMatrixOutput::pushToShift(){ + mutex.lock(); + //iterate by rows + for(int i = 0; i < height; ++i){ + digitalWrite(clockPin, LOW); + LH(loadPin); + + for(int j = 0; j < numShifts * 8; j++){ + if(i*width + j >= width*height){ + digitalWrite(dataPin, LOW); + continue; + } + + //column pins + if(j >= height){ + //push data for current row to column pins + digitalWrite(dataPin, matrixBuffer[i*width + j]); + }else{ //row pins + + //turn on ith row, turn others off + if(j == i){ + digitalWrite(dataPin, HIGH); + }else{ + digitalWrite(dataPin, LOW); + } + } + HL(clockPin); + } + delay(1); + } + mutex.unlock(); +} diff --git a/src/Devices/Matrix/ShiftMatrixOutput.h b/src/Devices/Matrix/ShiftMatrixOutput.h new file mode 100644 index 0000000..2a17a3b --- /dev/null +++ b/src/Devices/Matrix/ShiftMatrixOutput.h @@ -0,0 +1,27 @@ +#ifndef CIRCUITOS_SHIFTMATRIXOUTPUT_H +#define CIRCUITOS_SHIFTMATRIXOUTPUT_H + +#include "MatrixOutput.h" +#include "../../Sync/Mutex.h" + +class ShiftMatrixOutput : public MatrixOutput { +public: + ShiftMatrixOutput(uint width, uint height); + void init() override; + void push(void* data) override; + + void setPins(uint8_t dataPin, uint8_t clockPin, uint8_t loadPin); +private: + uint8_t dataPin = 0, clockPin = 0, loadPin = 0, numShifts = 0; + uint8_t* matrixBuffer; + Mutex mutex; + + void pushToShift(); + static ShiftMatrixOutput* instance; + hw_timer_t* timer = nullptr; + static void timerInterrupt(); + uint32_t pushInterval = 50; //ms +}; + + +#endif //CIRCUITOS_SHIFTMATRIXOUTPUT_H