diff --git a/lib/lib_display/LedControl/src/LedControl.cpp b/lib/lib_display/LedControl/src/LedControl.cpp index baaa3802c..5807aa6af 100644 --- a/lib/lib_display/LedControl/src/LedControl.cpp +++ b/lib/lib_display/LedControl/src/LedControl.cpp @@ -47,28 +47,26 @@ LedControl::LedControl(int dataPin, int clkPin, int csPin, int numDevices) { SPI_MOSI=dataPin; SPI_CLK=clkPin; SPI_CS=csPin; - if (numDevices <= 0 || numDevices > MAX72XX_MAX_DEVICES) - numDevices = MAX72XX_MAX_DEVICES; + if(numDevices<=0 || numDevices>8 ) + numDevices=8; maxDevices = numDevices; pinMode(SPI_MOSI,OUTPUT); pinMode(SPI_CLK,OUTPUT); pinMode(SPI_CS,OUTPUT); digitalWrite(SPI_CS,HIGH); SPI_MOSI=dataPin; - - memset(status, (byte)0, 8 * MAX72XX_MAX_DEVICES); - memset(deviceDataBuff, (byte)0, MAX72XX_MAX_DEVICES); - - // display test - spiTransfer_allDevices(OP_DISPLAYTEST, deviceDataBuff); + for(int i=0;i<64;i++) + status[i]=0x00; + for(int i=0;i=maxDevices) return; @@ -96,13 +89,6 @@ void LedControl::setScanLimit(int addr, int limit) { spiTransfer(addr, OP_SCANLIMIT,limit); } -void LedControl::setScanLimit_allDevices(int limit) { - if(limit <0 || limit>8) return; - - memset(deviceDataBuff, (byte)limit, maxDevices); - spiTransfer_allDevices(OP_SCANLIMIT,deviceDataBuff); -} - void LedControl::setIntensity(int addr, int intensity) { if(addr<0 || addr>=maxDevices) return; @@ -110,15 +96,6 @@ void LedControl::setIntensity(int addr, int intensity) { spiTransfer(addr, OP_INTENSITY,intensity); } -void LedControl::setIntensity_allDevices(int intensity) -{ - if (intensity < 0 | intensity > 15) - return; - - memset(deviceDataBuff, (byte)intensity, maxDevices); - spiTransfer_allDevices(OP_INTENSITY, deviceDataBuff); -} - void LedControl::clearDisplay(int addr) { int offset; @@ -131,16 +108,6 @@ void LedControl::clearDisplay(int addr) { } } -void LedControl::clearDisplay_allDevices() -{ - memset(status, (byte)0, 8 * maxDevices); - memset(deviceDataBuff, (byte)0, maxDevices); - for (int row = 0; row < 8; row++) - { - spiTransfer_allDevices(row + 1, deviceDataBuff); - } -} - void LedControl::setLed(int addr, int row, int column, boolean state) { int offset; byte val=0x00; @@ -171,15 +138,6 @@ void LedControl::setRow(int addr, int row, byte value) { spiTransfer(addr, row+1,status[offset+row]); } -void LedControl::setRow_allDevices(int row, byte *value) -{ - if (row < 0 || row > 7) - return; - for (int addr = 0; addr < maxDevices; addr++) - status[addr * 8 + row] = value[addr]; - spiTransfer_allDevices(row + 1, value); -} - void LedControl::setColumn(int addr, int col, byte value) { byte val; @@ -237,7 +195,7 @@ void LedControl::spiTransfer(int addr, volatile byte opcode, volatile byte data) int maxbytes=maxDevices*2; for(int i=0;i= 0; i--) - shiftOut(SPI_MOSI, SPI_CLK, MSBFIRST, spidata[i]); - //latch the data onto the display - digitalWrite(SPI_CS, HIGH); -} + diff --git a/lib/lib_display/LedControl/src/LedControl.h b/lib/lib_display/LedControl/src/LedControl.h index 4fc7523df..f8180d07d 100644 --- a/lib/lib_display/LedControl/src/LedControl.h +++ b/lib/lib_display/LedControl/src/LedControl.h @@ -35,10 +35,6 @@ #include #endif -#ifndef MAX72XX_MAX_DEVICES -#define MAX72XX_MAX_DEVICES 32 // maximum number of devices based on MXA7219/MAX7221 -#endif - /* * Segments to be switched on for characters and digits on * 7-Segment Displays @@ -65,15 +61,12 @@ const static byte charTable [] PROGMEM = { class LedControl { private : /* The array for shifting the data to the devices */ - byte spidata[2 * MAX72XX_MAX_DEVICES]; - /* Send out a single command to one device */ + byte spidata[16]; + /* Send out a single command to the device */ void spiTransfer(int addr, byte opcode, byte data); - /* Send out a command with the same opcode to all devices */ - void spiTransfer_allDevices(byte opcode, const byte* data); /* We keep track of the led-status for all 8 devices in this array */ - byte status[8 * MAX72XX_MAX_DEVICES]; - byte deviceDataBuff[MAX72XX_MAX_DEVICES]; + byte status[64]; /* Data is shifted out of this pin*/ int SPI_MOSI; /* The clock is signaled on this pin */ @@ -109,7 +102,6 @@ class LedControl { * for normal operation. */ void shutdown(int addr, bool status); - void shutdown_allDevices( bool status); /* * Set the number of digits (or rows) to be displayed. @@ -120,7 +112,6 @@ class LedControl { * limit number of digits to be displayed (1..8) */ void setScanLimit(int addr, int limit); - void setScanLimit_allDevices(int limit); /* * Set the brightness of the display. @@ -129,7 +120,6 @@ class LedControl { * intensity the brightness of the display. (0..15) */ void setIntensity(int addr, int intensity); - void setIntensity_allDevices(int intensity); /* * Switch all Leds on the display off. @@ -137,7 +127,6 @@ class LedControl { * addr address of the display to control */ void clearDisplay(int addr); - void clearDisplay_allDevices(); /* * Set the status of a single Led. @@ -160,14 +149,6 @@ class LedControl { */ void setRow(int addr, int row, byte value); - /** - * @brief Set data for the same row of all devices - * - * @param row [0..8] - * @param value array of bytes, one for each device - */ - void setRow_allDevices(int row, byte* value); - /* * Set all 8 Led's in a column to a new state * Params: diff --git a/lib/lib_display/LedControl/src/LedMatrix.cpp b/lib/lib_display/LedControl/src/LedMatrix.cpp index 59882cd15..929a09418 100644 --- a/lib/lib_display/LedControl/src/LedMatrix.cpp +++ b/lib/lib_display/LedControl/src/LedMatrix.cpp @@ -1,5 +1,5 @@ /* - * LedMatrix.h - Extends the Library LedControl for multiple 8x8 LED dot matrix modules, based on MAX7219/MAX7221 + * LedMatrix.h - Extends the Library LedControl for multiple 8x8 LED dot matrix maxDevices, based on MAX7219/MAX7221 * Copyright (c) 2021 Michael Beuss * * Permission is hereby granted, free of charge, to any person @@ -29,7 +29,26 @@ #include "font_6x8_horizontal_MSB.h" //#include "font_8x8_horizontal_latin_MSB.h" -// public +//the opcodes for the MAX7221 and MAX7219 +#define OP_NOOP 0 +#define OP_DIGIT0 1 +#define OP_DIGIT1 2 +#define OP_DIGIT2 3 +#define OP_DIGIT3 4 +#define OP_DIGIT4 5 +#define OP_DIGIT5 6 +#define OP_DIGIT6 7 +#define OP_DIGIT7 8 +#define OP_DECODEMODE 9 +#define OP_INTENSITY 10 +#define OP_SCANLIMIT 11 +#define OP_SHUTDOWN 12 +#define OP_DISPLAYTEST 15 + +// test +#include "LedControl.h" +LedControl* ledControl = nullptr; +// end text LedMatrix::LedMatrix(int dataPin, int clkPin, int csPin, unsigned int colums, unsigned int rows) { if (colums * rows > MAX72XX_MAX_DEVICES) @@ -52,22 +71,36 @@ LedMatrix::LedMatrix(int dataPin, int clkPin, int csPin, unsigned int colums, un modulesPerCol = rows; displayWidth = colums * 8; displayHeight = rows * 8; - modules = colums * rows; + maxDevices = colums * rows; moduleOrientation = ORIENTATION_UPSIDE_DOWN; // use setOrientation() to turn it - ledControl = new LedControl(dataPin, clkPin, csPin, modules); // initializes all connected LED matrix modules textBuf[0] = 0; textWidth = 0; textPosX = 0; textPosY = 0; appendTextBuf[0] = 0; setScrollAppendText(" "); - shutdown(false); // false: on, true: off - clear(); - setIntensity(7); + + // initialize all connected MAX7219/MAX7221 devices + SPI_MOSI = dataPin; + SPI_CLK = clkPin; + SPI_CS = csPin; + pinMode(SPI_MOSI, OUTPUT); + pinMode(SPI_CLK, OUTPUT); + pinMode(SPI_CS, OUTPUT); + SPI_MOSI = dataPin; + + //spiTransfer_value(OP_DISPLAYTEST, 0); // display test + spiTransfer_value(OP_SCANLIMIT, 7); // scanlimit is set to max on startup + spiTransfer_value(OP_DECODEMODE, 0); // decode is done in source + clearDisplay(); + //spiTransfer_value(OP_SHUTDOWN, 0); //we go into shutdown-mode (LEDs off) on startup + setIntensity(7); // initialize with the half of the maximum intensity [0..15] + power(true); // power on; } bool LedMatrix::drawText( const char *str, bool clearBefore) { + if(clearBefore) clearDisplay(); strncpy(textBuf, str, TEXT_BUFFER_SIZE -1); textPosX = 0; textPosY = 0; @@ -75,7 +108,6 @@ bool LedMatrix::drawText( const char *str, bool clearBefore) if(textWidth < displayWidth) { // text fits into the display, place it into the center - if(clearBefore) clear(); textPosX = (displayWidth - textWidth) / 2; // center } else @@ -125,21 +157,29 @@ bool LedMatrix::scrollText() void LedMatrix::power(bool on) { - shutdown(!on); // power(false) shuts down the display with shutdown(true) + byte value = 0; // 0: shutdown + if(on) value = 1; // 1: power on + spiTransfer_value(OP_SHUTDOWN, value); // power(false) shuts down the display } bool LedMatrix::clearDisplay(void) { - textBuf[0] = 0; memset(textBuf, 0, TEXT_BUFFER_SIZE); textWidth = 0; - clear(); + memset(buffer, 0, MATRIX_BUFFER_SIZE); + for (int row = 0; row < 8; row++) + { + spiTransfer_value(row + 1, 0); + } return true; } -bool LedMatrix::setIntensity(byte dim) +bool LedMatrix::setIntensity(byte intensity) { - ledControl->setIntensity_allDevices(dim); // 1..15 + if (intensity < 0 || intensity > 15) + return false; + + spiTransfer_value(OP_INTENSITY, intensity); return true; } @@ -186,25 +226,8 @@ void LedMatrix::refresh() int deviceRow = 0; for(int ledRow = 7; ledRow >= 0; ledRow--) // refresh from buttom to top { - for( int addr = 0; addr < modules; addr++) + for( int addr = 0; addr < maxDevices; addr++) { - switch(moduleOrientation) - { - case ORIENTATION_NORMAL: - col = addr % modulesPerRow; - pixelRow = (addr / modulesPerRow) * 8 + ledRow; - bufPos = pixelRow * modulesPerRow + col; - deviceDataBuff[addr] = buffer[bufPos]; - deviceRow = ledRow; - break; - case ORIENTATION_UPSIDE_DOWN: - col = addr % modulesPerRow; - pixelRow = (addr / modulesPerRow) * 8 + deviceRow; - bufPos = pixelRow * modulesPerRow + col; - deviceDataBuff[addr] = revereBitorder(buffer[bufPos]); // mirror - deviceRow = 7 - ledRow; // upside down - break; - } if(moduleOrientation == ORIENTATION_NORMAL || moduleOrientation == ORIENTATION_UPSIDE_DOWN) { col = addr % modulesPerRow; @@ -224,7 +247,7 @@ void LedMatrix::refresh() } } } - ledControl->setRow_allDevices(deviceRow, deviceDataBuff); // upside down + setRow_allDevices(deviceRow, deviceDataBuff); } } @@ -254,58 +277,6 @@ bool LedMatrix::drawCharAt( char c, const int x, const int y) return true; } -bool LedMatrix::shutdown(bool b) -{ - for (int addr = 0; addr < modules; addr++) - { - ledControl->shutdown(addr, b); // b: false: on, true: off - } - return true; -} - -bool LedMatrix::clear(void) -{ - memset(buffer, 0, MATRIX_BUFFER_SIZE); - ledControl->clearDisplay_allDevices(); - return true; -} - -void LedMatrix::refreshByteOfBuffer(int i) -{ - int line = i / modulesPerRow; - int addr = (line / 8) * modulesPerRow + i % modulesPerRow; - byte b = buffer[i]; - if (moduleOrientation == ORIENTATION_NORMAL || moduleOrientation == ORIENTATION_UPSIDE_DOWN) - { - int rowOfAddr = 0; - if (moduleOrientation == ORIENTATION_NORMAL) - { - rowOfAddr = line % 8; // ORIENTATION_NORMAL - } - else - { - rowOfAddr = 7 - line % 8; // ORIENTATION_UPSIDE_DOWN - b = revereBitorder(b); - } - ledControl->setRow(addr, rowOfAddr, b); - } - else - { - // ORIENTATION_TURN_RIGHT or ORIENTATION_TURN_LEFT - int colOfAddr = 0; - if (moduleOrientation == ORIENTATION_TURN_LEFT) - { - colOfAddr = line % 8; // ORIENTATION_TURN_LEFT - } - else - { - colOfAddr = 7 - line % 8; // ORIENTATION_TURN_RIGHT - b = revereBitorder(b); - } - ledControl->setColumn(addr, colOfAddr, b); - } -} - byte LedMatrix::revereBitorder (byte b) { static const byte lookup[16] = { @@ -320,3 +291,37 @@ void LedMatrix::appendSpace() strncat(textBuf, appendTextBuf, TEXT_BUFFER_SIZE -1); textWidth = strlen(textBuf) * charWidth; } + +void LedMatrix::setRow_allDevices(int row, byte *data) +{ + if (row < 0 || row > 7) + return; + spiTransfer_array(row + 1, data); +} + +void LedMatrix::spiTransfer_array(byte opcode, const byte* data) { + // create an array with the data to shift out + for (int addr = 0; addr < maxDevices; addr++) + { + spidata[addr * 2 + 1] = opcode; + spidata[addr * 2] = data[addr]; + } + // enable the line + digitalWrite(SPI_CS, LOW); + // shift out the data + for (int i = maxDevices * 2 -1; i >= 0; i--) + { + shiftOut(SPI_MOSI, SPI_CLK, MSBFIRST, spidata[i]); + } + // latch the data onto the display + digitalWrite(SPI_CS, HIGH); +} + +void LedMatrix::spiTransfer_value(byte opcode, byte value) +{ + memset(deviceDataBuff, (byte)value, maxDevices); + spiTransfer_array(opcode, deviceDataBuff); +} + + + diff --git a/lib/lib_display/LedControl/src/LedMatrix.h b/lib/lib_display/LedControl/src/LedMatrix.h index 9fee69a5f..aec15d052 100644 --- a/lib/lib_display/LedControl/src/LedMatrix.h +++ b/lib/lib_display/LedControl/src/LedMatrix.h @@ -1,5 +1,5 @@ /* - * LedMatrix.h - Extends the Library LedControl for multiple 8x8 LED dot matrix modules, based on MAX7219/MAX7221 + * LedMatrix.h - Extends the Library LedControl for multiple 8x8 LED dot matrix devices, based on MAX7219/MAX7221 * Copyright (c) 2021 Michael Beuss * * Permission is hereby granted, free of charge, to any person @@ -27,16 +27,27 @@ #ifndef LedMatrix_h #define LedMatrix_h -#include +#include + +#if (ARDUINO >= 100) +#include +#else +#include +#endif + +#ifndef MAX72XX_MAX_DEVICES +#define MAX72XX_MAX_DEVICES 32 // maximum number of devices based on MXA7219/MAX7221 +#endif #define MATRIX_BUFFER_SIZE MAX72XX_MAX_DEVICES * 8 // 8 bytes per modul. One byte represents 8 LEDs. #define TEXT_BUFFER_SIZE 256 // maximum text length that can be scrolled #define TEXT_APPEND_BUFFER_SIZE 16 // used for characters that are appended to the scroll text, before it repeats +#define SPI_BUFFER_SIZE MAX72XX_MAX_DEVICES * 2 // buffer size fort shifting commands to all devices (2 bytes each) /** - * @brief LedMatric controls multiple 8x8 LED dot matrx modules. - * All modules in rows and clolums together build a common display pixel matrix. + * @brief LedMatrix controls multiple 8x8 LED dot matrx devices. + * All devices in rows and clolums together build a common display pixel matrix. * */ class LedMatrix @@ -54,8 +65,8 @@ class LedMatrix /** * @brief Construct a new LED Matrix object * - * @param colums of 8x8 LED dot matrix modules - * @param rows of 8x8 LED dot matrix modules + * @param colums of 8x8 LED dot matrix devices + * @param rows of 8x8 LED dot matrix devices */ LedMatrix(int dataPin, int clkPin, int csPin, unsigned int colums, unsigned int rows); @@ -139,23 +150,48 @@ class LedMatrix void refresh(); private: + bool drawCharAt( char c, int x, int y ); // Draws a character to a defined position - bool shutdown(bool b); // shutdown(true) switches the display off. Text and pixels can be set while it is off. shutdown(false) switches the display on. - bool clear(void); // clears the display content - void refreshByteOfBuffer( int i); // sends one byte of the buffer to the display. This updates an 8 pixel row of one matrix module. byte revereBitorder(byte b); // returnes the byte in the reverse bit order. void appendSpace(); // appends characters to the end of the text to get a distance to the repeating scroll text + // device contrl MAX7219/MAX7221 + /** + * @brief Set data for the same row of all devices + * + * @param row [0..8] + * @param value array of bytes, one for each device + */ + void setRow_allDevices(int row, byte* value); + + /* Send out a command with the same opcode to all devices */ + /** + * @brief sends opcode with specific data values to each device + * + * @param opcode + * @param data array of byte values (data[0] is the value for the first device) + */ + void spiTransfer_array(byte opcode, const byte* data); + + /** + * @brief sends opcode with same value to all devices + */ + void spiTransfer_value(byte opcode, byte value); + + private: + int SPI_MOSI; // Data is shifted out of this pin + int SPI_CLK; // The clock is signaled on this pin + int SPI_CS; // This one is driven LOW for chip selectzion + unsigned int modulesPerRow; unsigned int modulesPerCol; unsigned int displayWidth; // matrix width [pixel] unsigned int displayHeight; // matrix height [pixel] - unsigned int modules; // number of 8x8 mudules + int maxDevices; // number of used 8x8 devices uint8_t moduleOrientation; byte buffer[MATRIX_BUFFER_SIZE]; byte deviceDataBuff[MAX72XX_MAX_DEVICES]; - LedControl* ledControl; int charWidth; int charHeight; char textBuf[TEXT_BUFFER_SIZE]; @@ -163,6 +199,7 @@ class LedMatrix int textWidth; // width of text [pixel] int textPosX; // horizontal pixel position of scrolling text int textPosY; // vertical pixelposition of scrolling text; + byte spidata[SPI_BUFFER_SIZE]; // The array for shifting the data to the devices }; diff --git a/tasmota/xdsp_19_max7219_matrix.ino b/tasmota/xdsp_19_max7219_matrix.ino index 82a4a24bb..ecf500670 100644 --- a/tasmota/xdsp_19_max7219_matrix.ino +++ b/tasmota/xdsp_19_max7219_matrix.ino @@ -128,13 +128,6 @@ bool MAX7291Matrix_initDriver(void) Settings->display_rows = LedMatrix_settings.modulesPerCol; Settings->display_cols[1] = LedMatrix_settings.modulesPerCol; max7219_Matrix = new LedMatrix(Pin(GPIO_MAX7219DIN), Pin(GPIO_MAX7219CLK), Pin(GPIO_MAX7219CS), LedMatrix_settings.modulesPerRow, LedMatrix_settings.modulesPerCol); - if( LedMatrix_settings.show_clock == 0) - { - Settings->display_mode = 0; // text mode - } - else{ - Settings->display_mode = 1; // clock mode - } max2791Matrix_initDriver_done = true; AddLog(LOG_LEVEL_INFO, PSTR("MTX: MAX7291Matrix_initDriver DIN:%d CLK:%d CS:%d size(%dx%d)"), Pin(GPIO_MAX7219DIN), Pin(GPIO_MAX7219CLK), Pin(GPIO_MAX7219CS), LedMatrix_settings.modulesPerRow, LedMatrix_settings.modulesPerCol); @@ -144,8 +137,13 @@ bool MAX7291Matrix_initDriver(void) // FUNC_DISPLAY_INIT bool MAX7291Matrix_init(void) { + Settings->display_mode = 0; // text mode + LedMatrix_settings.show_clock = 0; // no clock + int intensity = GetDisplayDimmer16(); // 0..15 max7219_Matrix->setIntensity(intensity); + + max7219_Matrix->power(true); // power on if(Settings->display_rotate <= 3) { max7219_Matrix->setOrientation((LedMatrix::ModuleOrientation)Settings->display_rotate ); @@ -223,6 +221,8 @@ bool MAX7291Matrix_clock(void) Settings->display_mode = 1; break; default: + //LedMatrix_settings.timeFormat = XdrvMailbox.payload; + //Settings->display_mode = 1; return false; } @@ -280,13 +280,11 @@ bool Xdsp19(uint8_t function) case FUNC_DISPLAY_DRAW_STRING: case FUNC_DISPLAY_SCROLLTEXT: case FUNC_DISPLAY_SEVENSEG_TEXT: - Settings->display_mode = 0; // text mode - LedMatrix_settings.show_clock = 0; // disable clock mode + if(Settings->display_mode != 0) MAX7291Matrix_init(); result = max7219_Matrix->drawText(XdrvMailbox.data, true); // true: clears display before drawing text break; case FUNC_DISPLAY_SEVENSEG_TEXTNC: - Settings->display_mode = 0; // text mode - LedMatrix_settings.show_clock = 0; // disable clock mode + if(Settings->display_mode != 0) MAX7291Matrix_init(); result = max7219_Matrix->drawText(XdrvMailbox.data, false); // false: does not clear display before drawing text break; case FUNC_DISPLAY_SCROLLDELAY: