0.1.1 MATRIX7219

This commit is contained in:
Rob Tillaart 2023-07-30 14:34:46 +02:00
parent 46e0c8395c
commit b98eacaaa9
14 changed files with 458 additions and 76 deletions

View File

@ -6,10 +6,19 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.1.1] - 2023-07-29
- update AVR performance (from FastShiftOut)
- add **writeZero()** (generic improvement)
- test performance ESP32
- add clock example
- add 8 queens example
- update readme.md
- update keywords.txt
## [0.1.0] - 2023-07-28
- initial version
## [0.0.1] - eons ago
- first tests

View File

@ -1,7 +1,7 @@
//
// FILE: MATRIX7219.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// VERSION: 0.1.1
// DATE: 2023-07-28
// PURPOSE: Arduino Library for 8x8 LED MATRIX MAX7219
// URL: https://github.com/RobTillaart/MATRIX7219
@ -30,6 +30,16 @@ MATRIX7219::MATRIX7219(uint8_t dataPin, uint8_t selectPin, uint8_t clockPin, uin
digitalWrite(_dataPin, HIGH);
digitalWrite(_selectPin,HIGH);
digitalWrite(_clockPin, HIGH);
#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR)
uint8_t _port = digitalPinToPort(_dataPin);
_dataOutRegister = portOutputRegister(_port);
_dataOutBit = digitalPinToBitMask(_dataPin);
_port = digitalPinToPort(_clockPin);
_clockRegister = portOutputRegister(_port);
_clockBit = digitalPinToBitMask(_clockPin);
#endif
}
@ -52,7 +62,7 @@ void MATRIX7219::begin()
{
digitalWrite(_selectPin, LOW);
_write(MATRIX7219_DECODE_MODE);
_write(0x00); // No decode for digits 70
_writeZero(); // No decode for digits 70
digitalWrite(_selectPin, HIGH);
}
for (int m = 0; m < _matrices; m++)
@ -66,7 +76,7 @@ void MATRIX7219::begin()
{
digitalWrite(_selectPin, LOW);
_write(MATRIX7219_DISPLAY_TEST);
_write(0x00); // normal mode
_writeZero(); // normal mode
digitalWrite(_selectPin, HIGH);
}
}
@ -92,7 +102,7 @@ void MATRIX7219::displayOff()
for (int m = 0; m < _matrices; m++)
{
_write(MATRIX7219_SHUT_DOWN);
_write(0x00);
_writeZero();
}
digitalWrite(_selectPin, HIGH);
}
@ -117,7 +127,7 @@ void MATRIX7219::displayTest(bool on)
{
_write(MATRIX7219_DISPLAY_TEST);
if (on) _write(0x01);
else _write(0x00);
else _writeZero();
}
digitalWrite(_selectPin, HIGH);
}
@ -131,7 +141,7 @@ void MATRIX7219::clear()
for (int m = 0; m < _matrices; m++)
{
_write(row);
_write(0);
_writeZero();
}
digitalWrite(_selectPin, HIGH);
}
@ -143,8 +153,8 @@ void MATRIX7219::setRow(uint8_t row, uint8_t value, uint8_t matrix)
digitalWrite(_selectPin, LOW);
for (int m = _matrices; m > matrix; m--)
{
_write(0);
_write(0);
_writeZero();
_writeZero();
}
if (_swap) row = 9 - row;
@ -153,10 +163,10 @@ void MATRIX7219::setRow(uint8_t row, uint8_t value, uint8_t matrix)
if (_reverse) value = _reverse8(value);
_write(value);
for (int m = matrix-1; m > 0; m--)
for (int m = matrix - 1; m > 0; m--)
{
_write(0);
_write(0);
_writeZero();
_writeZero();
}
digitalWrite(_selectPin, HIGH);
}
@ -208,24 +218,71 @@ bool MATRIX7219::getSwap()
//
void MATRIX7219::_write(uint8_t b)
{
#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR)
uint8_t cbmask1 = _clockBit;
uint8_t cbmask2 = ~_clockBit;
uint8_t outmask1 = _dataOutBit;
uint8_t outmask2 = ~_dataOutBit;
for (uint8_t mask = 0x80; mask > 0; mask >>= 1)
{
digitalWrite(_clockPin, LOW);
digitalWrite(_dataPin, (b & mask) > 0);
digitalWrite(_clockPin, HIGH);
uint8_t oldSREG = SREG;
noInterrupts();
if ((b & mask) == 0) *_dataOutRegister &= outmask2;
else *_dataOutRegister |= outmask1;
*_clockRegister |= cbmask1;
*_clockRegister &= cbmask2;
SREG = oldSREG;
}
#else
uint8_t clk = _clockPin;
uint8_t dat = _dataPin;
for (uint8_t mask = 0x80; mask > 0; mask >>= 1)
{
digitalWrite(clk, LOW);
digitalWrite(dat, (b & mask) > 0);
digitalWrite(clk, HIGH);
}
#endif
}
// optimization not for release 0.1.0
// optimization
void MATRIX7219::_writeZero()
{
#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR)
uint8_t cbmask1 = _clockBit;
uint8_t cbmask2 = ~_clockBit;
// uint8_t outmask1 = _dataOutBit;
uint8_t outmask2 = ~_dataOutBit;
*_dataOutRegister &= outmask2;
for (uint8_t mask = 0x80; mask > 0; mask >>= 1)
{
uint8_t oldSREG = SREG;
noInterrupts();
*_clockRegister |= cbmask1;
*_clockRegister &= cbmask2;
SREG = oldSREG;
}
#else
uint8_t clk = _clockPin;
digitalWrite(_dataPin, LOW);
for (uint8_t mask = 0x80; mask > 0; mask >>= 1)
{
digitalWrite(_clockPin, LOW);
digitalWrite(_clockPin, HIGH);
digitalWrite(clk, LOW);
digitalWrite(clk, HIGH);
}
#endif
}

View File

@ -2,7 +2,7 @@
//
// FILE: MATRIX7219.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// VERSION: 0.1.1
// DATE: 2023-07-28
// PURPOSE: Arduino Library for 8x8 LED MATRIX MAX7219
// URL: https://github.com/RobTillaart/MATRIX7219
@ -11,7 +11,7 @@
#include "Arduino.h"
#define MATRIX7219_LIB_VERSION (F("0.1.0"))
#define MATRIX7219_LIB_VERSION (F("0.1.1"))
class MATRIX7219
@ -22,14 +22,13 @@ public:
uint8_t getMatrixCount();
void begin();
// bright = 0..15
void setBrightness(uint8_t bright = 2);
void displayOff();
void displayOn();
void displayTest(bool on = false);
void clear();
void clear();
// row = 1..8
// value = 0..255
void setRow(uint8_t row, uint8_t value, uint8_t matrix);
@ -47,6 +46,17 @@ private:
void _writeZero(); // optimized writing of all 0
uint8_t _reverse8(uint8_t in);
#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR)
volatile uint8_t *_dataOutRegister;
uint8_t _dataOutBit;
volatile uint8_t *_clockRegister;
uint8_t _clockBit;
#endif
uint8_t _dataPin;
uint8_t _selectPin;
uint8_t _clockPin;

View File

@ -79,16 +79,48 @@ For adapting the layout if needed.
## Performance
Preliminary tests - MATRIX7219_performance.ino
#### 0.1.0 UNO
| version | function | time (us) | notes |
|:---------:|:-------------:|:-----------:|:--------|
| 0.1.0 | begin | 796 |
| 0.1.0 | clear | 1572 |
| 0.1.0 | count | 4 |
| 0.1.0 | setRow(255) | 204 | setReverse has minimal influence
| 0.1.0 | setRow(0) | 200 |
| 0.1.0 | setBrightness | 208 |
MATRIX7219_performance.ino with UNO 16 MHz
| board | function | time (us) | notes |
|:-------:|:-------------:|:-----------:|:--------|
| UNO | begin | 796 |
| UNO | clear | 1572 |
| UNO | count | 4 |
| UNO | setRow(255) | 204 | setReverse has minimal influence
| UNO | setRow(0) | 200 |
| UNO | setBrightness | 208 |
#### 0.1.1 UNO
Optimized registers for UNO (for AVR from FastShiftOut).
2.5 to 4.2 times faster. (price: a few bytes storage).
| board | function | time (us) | notes |
|:-------:|:-------------:|:-----------:|:--------|
| UNO | begin | 196 | 2.5x
| UNO | clear | 368 | 4.2x
| UNO | count | 4 | idem
| UNO | setRow(255) | 56 | 3.5x
| UNO | setRow(0) | 56 | 3.5x
| UNO | setBrightness | 56 | 3.5x
#### 0.1.1 ESP32
First test ESP32
| board | function | time (us) | notes |
|:-------:|:-------------:|:-----------:|:--------|
| ESP32 | begin | 37 |
| ESP32 | clear | 47 |
| ESP32 | count | 2 |
| ESP32 | setRow(255) | 12 |
| ESP32 | setRow(0) | 8 |
| ESP32 | setBrightness | 8 |
## Future
@ -96,31 +128,26 @@ Preliminary tests - MATRIX7219_performance.ino
#### Must
- improve documentation
- Buffering version => 8 bytes per Matrix.
- Single matrix version (faster)
-
#### Should
- test other platforms
- performance testing
- increase.
- add unit tests
- create a derived class for a single 8x8 matrix.
- if performance gain is enough?
- create a derived class with a buffer
- create a derived class with a buffer => 8 bytes per Matrix.
- goal is to have **setPixel(x,y)** and **clearPixel(x,y)**
- reverse from CRC for real reverse
- design first (performance)
#### Could
- examples
- 8x8 as debugger (dump variables)
- clock ? binary - other?
- add unit tests
- need simulator / mock-up
- defaults for invert, reverse, swap? (false).
#### Wont (unless requested)
- create a derived class for a single 8x8 matrix.
- if performance gain is enough?
- store last set brightness.
- **uint8_t getBrightness()**
#### Wont
- not needed yet

View File

@ -0,0 +1,86 @@
//
// FILE: MATRIX7219_clock.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo of MATRIX7219 8x8 LED MATRIX MAX7219
// URL: https://github.com/RobTillaart/MATRIX7219
#include "MATRIX7219.h"
//uint8_t dataPin = 2;
//uint8_t selectPin = 3;
//uint8_t clockPin = 4;
//uint8_t count = 1;
// ESP32
uint8_t dataPin = 21;
uint8_t selectPin = 22;
uint8_t clockPin = 23;
uint8_t count = 1;
MATRIX7219 mx(dataPin, selectPin, clockPin, count);
uint8_t hr = 9;
uint8_t mi = 58;
uint8_t sc = 00;
uint32_t lastTime = 0;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("MATRIX7219_LIB_VERSION: ");
Serial.println(MATRIX7219_LIB_VERSION);
Serial.println();
mx.begin();
mx.clear();
mx.setBrightness(3);
mx.setSwap(true);
}
void loop()
{
// "simple" binary clock
if (millis() - lastTime >= 1000)
{
lastTime = millis();
sc++;
if (sc == 60)
{
sc = 0;
mi++;
}
if (mi == 60)
{
mi = 0;
hr++;
}
if (hr == 24)
{
hr = 0;
}
mx.setRow(1, hr / 10, 1);
mx.setRow(2, hr % 10, 1);
mx.setRow(4, mi / 10, 1);
mx.setRow(5, mi % 10, 1);
mx.setRow(7, sc / 10, 1);
mx.setRow(8, sc % 10, 1);
Serial.print(hr / 10);
Serial.print(hr % 10);
Serial.print(":");
Serial.print(mi / 10);
Serial.print(mi % 10);
Serial.print(":");
Serial.print(sc / 10);
Serial.print(sc % 10);
Serial.println();
}
}
// -- END OF FILE --

View File

@ -34,7 +34,6 @@ void setup()
mx.displayTest(true);
delay(1000);
mx.displayTest(false);
}
@ -58,3 +57,4 @@ void loop()
// -- END OF FILE --

View File

@ -7,9 +7,15 @@
#include "MATRIX7219.h"
uint8_t dataPin = 2;
uint8_t selectPin = 3;
uint8_t clockPin = 4;
//uint8_t dataPin = 2;
//uint8_t selectPin = 3;
//uint8_t clockPin = 4;
//uint8_t count = 1;
// ESP32
uint8_t dataPin = 21;
uint8_t selectPin = 22;
uint8_t clockPin = 23;
uint8_t count = 1;
MATRIX7219 mx(dataPin, selectPin, clockPin, count);
@ -24,21 +30,21 @@ void setup()
Serial.print("MATRIX7219_LIB_VERSION: ");
Serial.println(MATRIX7219_LIB_VERSION);
Serial.println();
delay(100);
delay(1000);
start = micros();
mx.begin();
stop = micros();
Serial.print("BEGIN:\t");
Serial.println(stop - start);
delay(100);
delay(1000);
start = micros();
mx.clear();
stop = micros();
Serial.print("CLEAR:\t");
Serial.println(stop - start);
delay(100);
delay(1000);
start = micros();
uint8_t n = mx.getMatrixCount();
@ -47,28 +53,28 @@ void setup()
Serial.print(stop - start);
Serial.print("\t");
Serial.println(n);
delay(100);
delay(1000);
start = micros();
mx.setRow(1, 255, 1);
stop = micros();
Serial.print(" 255:\t");
Serial.println(stop - start);
delay(100);
delay(1000);
start = micros();
mx.setRow(1, 0, 1);
stop = micros();
Serial.print(" 000:\t");
Serial.println(stop - start);
delay(100);
delay(1000);
start = micros();
mx.setBrightness(3);
stop = micros();
Serial.print("BRIGHT:\t");
Serial.println(stop - start);
delay(100);
delay(1000);
}

View File

@ -0,0 +1,30 @@
IDE: 1.8.19
Board: UNO (16 MHz)
MATRIX7219_performance.ino
MATRIX7219_LIB_VERSION: 0.1.1
BEGIN: 196
CLEAR: 368
COUNT: 4 1
255: 56
000: 56
BRIGHT: 56
-------------------------------------
IDE: 1.8.19
Board: ESP32 (240 MHz)
MATRIX7219_LIB_VERSION: 0.1.1
BEGIN: 37
CLEAR: 47
COUNT: 2 1
255: 12
000: 8
BRIGHT: 8

View File

@ -0,0 +1,138 @@
//
// FILE: MATRIX7219_queens.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo of MATRIX7219 8x8 LED MATRIX MAX7219
// URL: https://github.com/RobTillaart/MATRIX7219
//
// this demo visualizes the eight queens problem
//
#include "MATRIX7219.h"
// UNO
//uint8_t dataPin = 2;
//uint8_t selectPin = 3;
//uint8_t clockPin = 4;
//uint8_t count = 1;
// ESP32
uint8_t dataPin = 21;
uint8_t selectPin = 22;
uint8_t clockPin = 23;
uint8_t count = 1;
MATRIX7219 mx(dataPin, selectPin, clockPin, count);
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("MATRIX7219_LIB_VERSION: ");
Serial.println(MATRIX7219_LIB_VERSION);
Serial.println();
mx.begin();
mx.clear();
mx.setBrightness(3);
mx.setReverse(true);
brute_force_queens();
}
void loop()
{
}
// 8 queens brute force algorithm based upon
// https://stackoverflow.com/questions/64235088/8-queens-brute-force-problem-is-not-printing-out-the-results-c
bool ok(uint8_t board[])
{
// for all queens
for (uint8_t i = 0; i < 8; i++)
{
// check the queens "below"
for (uint8_t j = i + 1; j < 8; j++)
{
// checks same row, up diagonal, down diagonal for other queens
if (board[i] == board[j] || (j - i) == abs(board[j] - board[i]))
{
return false;
}
}
}
return true;
}
void printBoard(uint8_t board[], int count)
{
Serial.print(millis());
Serial.print("\tSolution: ");
Serial.print(count);
Serial.print("\t: ");
for (uint8_t i = 0; i < 8; i++)
{
Serial.print(board[i]);
Serial.print(' ');
}
Serial.println();
for (int n = 1; n < 9; n++)
{
mx.setRow(n, 1 << board[n - 1], 1);
}
}
int brute_force_queens()
{
uint8_t board[8];
int count = 0;
for (uint8_t i0 = 0; i0 < 8; i0 ++)
{
board[0] = i0;
for (uint8_t i1 = 0; i1 < 8; i1 ++)
{
board[1] = i1;
for (uint8_t i2 = 0; i2 < 8; i2 ++)
{
board[2] = i2;
for (uint8_t i3 = 0; i3 < 8; i3 ++)
{
board[3] = i3;
for (uint8_t i4 = 0; i4 < 8; i4 ++)
{
board[4] = i4;
for (uint8_t i5 = 0; i5 < 8; i5 ++)
{
board[5] = i5;
for (uint8_t i6 = 0; i6 < 8; i6 ++)
{
board[6] = i6;
for (uint8_t i7 = 0; i7 < 8; i7 ++)
{
board[7] = i7;
if (ok(board))
{
printBoard(board, ++count);
}
}
}
}
}
}
}
}
}
return count;
}
// -- END OF FILE --

View File

@ -5,21 +5,22 @@ MATRIX7219 KEYWORD1
# Methods and Functions (KEYWORD2)
begin KEYWORD2
getMatrixCount KEYWORD2
setBrightness KEYWORD2
displayOff KEYWORD2
displayOn KEYWORD2
displayTest KEYWORD2
clear KEYWORD2
setPixel KEYWORD2
clearPixel KEYWORD2
setRow KEYWORD2
setInvert KEYWORD2
getInvert KEYWORD2
setReverse KEYWORD2
getReverse KEYWORD2
setSwap KEYWORD2
getSwap KEYWORD2

View File

@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/MATRIX7219.git"
},
"version": "0.1.0",
"version": "0.1.1",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*",

View File

@ -1,5 +1,5 @@
name=MATRIX7219
version=0.1.0
version=0.1.1
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino Library for 8x8 LED MATRIX MAX7219.

View File

@ -46,6 +46,24 @@ unittest(test_constructor)
}
unittest(test_layout)
{
MATRIX7219 mx(3, 4, 5, 1);
assertFalse(mx.getInvert());
assertFalse(mx.getReverse());
assertFalse(mx.getSwap());
mx.setInvert(true);
mx.setReverse(true);
mx.setSwap(true);
assertTrue(mx.getInvert());
assertTrue(mx.getReverse());
assertTrue(mx.getSwap());
}
unittest_main()