max7219 dot matrix ready for pull request

This commit is contained in:
Michael 2021-12-03 16:50:55 +01:00
parent 09974f8873
commit 306ed0d2dd
5 changed files with 162 additions and 197 deletions

View File

@ -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;i++) {
spiTransfer(i,OP_DISPLAYTEST,0);
//scanlimit is set to max on startup
setScanLimit_allDevices(7);
setScanLimit(i,7);
//decode is done in source
memset(deviceDataBuff, (byte)0, MAX72XX_MAX_DEVICES);
spiTransfer_allDevices(OP_DECODEMODE, deviceDataBuff);
clearDisplay_allDevices();
spiTransfer(i,OP_DECODEMODE,0);
clearDisplay(i);
//we go into shutdown-mode on startup
shutdown_allDevices(true);
shutdown(i,true);
}
}
int LedControl::getDeviceCount() {
@ -84,11 +82,6 @@ void LedControl::shutdown(int addr, bool b) {
spiTransfer(addr, OP_SHUTDOWN,1);
}
void LedControl::shutdown_allDevices(bool b) {
memset(deviceDataBuff, (byte)b, maxDevices);
spiTransfer_allDevices(OP_SHUTDOWN, deviceDataBuff);
}
void LedControl::setScanLimit(int addr, int limit) {
if(addr<0 || addr>=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<maxbytes;i++)
spidata[i]=(byte)OP_NOOP;
spidata[i]=(byte)0;
//put our device data into the array
spidata[offset+1]=opcode;
spidata[offset]=data;
@ -250,18 +208,4 @@ void LedControl::spiTransfer(int addr, volatile byte opcode, volatile byte data)
digitalWrite(SPI_CS,HIGH);
}
void LedControl::spiTransfer_allDevices(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);
//Now 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);
}

View File

@ -35,10 +35,6 @@
#include <WProgram.h>
#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:

View File

@ -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);
}

View File

@ -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 <LedControl.h>
#include <pgmspace.h>
#if (ARDUINO >= 100)
#include <Arduino.h>
#else
#include <WProgram.h>
#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
};

View File

@ -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: