Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 60 additions & 29 deletions RGBmatrixPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ performance and/or lower CPU utilization:
#define DATAPORT PORTA
#define DATADIR DDRA
#define SCLKPORT PORTB

#elif defined(__SAM3X8E__)
// Arduino Due uses the SAM3X8E.
#define DATAPORT PORTC
#define DATADIR tobedefined
#define SCLKPORT tobedefined

#elif defined(__AVR_ATmega32U4__)
// Arduino Leonardo is still a work in progress -- DO NOT USE!!!
// Unlike the Uno, digital pins 2-7 do NOT map to a contiguous port
Expand Down Expand Up @@ -79,12 +86,13 @@ static RGBmatrixPanel *activePanel = NULL;

// Code common to both the 16x32 and 32x32 constructors:
void RGBmatrixPanel::init(uint8_t rows, uint8_t a, uint8_t b, uint8_t c,
uint8_t sclk, uint8_t latch, uint8_t oe, boolean dbuf) {
uint8_t sclk, uint8_t latch, uint8_t oe, boolean dbuf, uint8_t pwidth) {

nRows = rows; // Number of multiplexed rows; actual height is 2X this
nPanels = pwidth;

// Allocate and initialize matrix buffer:
int buffsize = 32 * nRows * 3, // x3 = 3 bytes holds 4 planes "packed"
int buffsize = 32 * nRows * 3 * nPanels, // x3 = 3 bytes holds 4 planes "packed"
allocsize = (dbuf == true) ? (buffsize * 2) : buffsize;
if(NULL == (matrixbuff[0] = (uint8_t *)malloc(allocsize))) return;
memset(matrixbuff[0], 0, allocsize);
Expand Down Expand Up @@ -122,19 +130,19 @@ void RGBmatrixPanel::init(uint8_t rows, uint8_t a, uint8_t b, uint8_t c,
// Constructor for 16x32 panel:
RGBmatrixPanel::RGBmatrixPanel(
uint8_t a, uint8_t b, uint8_t c,
uint8_t sclk, uint8_t latch, uint8_t oe, boolean dbuf) :
Adafruit_GFX(32, 16) {
uint8_t sclk, uint8_t latch, uint8_t oe, boolean dbuf, uint8_t pwidth) :
Adafruit_GFX(32*pwidth, 16) {

init(8, a, b, c, sclk, latch, oe, dbuf);
init(8, a, b, c, sclk, latch, oe, dbuf, pwidth);
}

// Constructor for 32x32 panel:
RGBmatrixPanel::RGBmatrixPanel(
uint8_t a, uint8_t b, uint8_t c, uint8_t d,
uint8_t sclk, uint8_t latch, uint8_t oe, boolean dbuf) :
Adafruit_GFX(32, 32) {
uint8_t sclk, uint8_t latch, uint8_t oe, boolean dbuf, uint8_t pwidth) :
Adafruit_GFX(32*pwidth, 32) {

init(16, a, b, c, sclk, latch, oe, dbuf);
init(16, a, b, c, sclk, latch, oe, dbuf, pwidth);

// Init a few extra 32x32-specific elements:
_d = d;
Expand Down Expand Up @@ -296,14 +304,17 @@ void RGBmatrixPanel::drawPixel(int16_t x, int16_t y, uint16_t c) {
ptr = &matrixbuff[backindex][y * WIDTH * (nPlanes - 1) + x]; // Base addr
// Plane 0 is a tricky case -- its data is spread about,
// stored in least two bits not used by the other planes.
ptr[64] &= ~B00000011; // Plane 0 R,G mask out in one op
if(r & 1) ptr[64] |= B00000001; // Plane 0 R: 64 bytes ahead, bit 0
if(g & 1) ptr[64] |= B00000010; // Plane 0 G: 64 bytes ahead, bit 1
if(b & 1) ptr[32] |= B00000001; // Plane 0 B: 32 bytes ahead, bit 0
else ptr[32] &= ~B00000001; // Plane 0 B unset; mask out
ptr=ptr+64*nPanels;
*ptr &= ~B00000011; // Plane 0 R,G mask out in one op
if(r & 1) *ptr |= B00000001; // Plane 0 R: 64 bytes ahead, bit 0
if(g & 1) *ptr |= B00000010; // Plane 0 G: 64 bytes ahead, bit 1
ptr=ptr-32*nPanels;
if(b & 1) *ptr |= B00000001; // Plane 0 B: 32 bytes ahead, bit 0
else *ptr &= ~B00000001; // Plane 0 B unset; mask out
// The remaining three image planes are more normal-ish.
// Data is stored in the high 6 bits so it can be quickly
// copied to the DATAPORT register w/6 output lines.
ptr=ptr-32*nPanels;
for(; bit < limit; bit <<= 1) {
*ptr &= ~B00011100; // Mask out R,G,B in one op
if(r & bit) *ptr |= B00000100; // Plane N R: bit 2
Expand All @@ -316,8 +327,8 @@ void RGBmatrixPanel::drawPixel(int16_t x, int16_t y, uint16_t c) {
// bits, except for the plane 0 stuff, using 2 least bits.
ptr = &matrixbuff[backindex][(y - nRows) * WIDTH * (nPlanes - 1) + x];
*ptr &= ~B00000011; // Plane 0 G,B mask out in one op
if(r & 1) ptr[32] |= B00000010; // Plane 0 R: 32 bytes ahead, bit 1
else ptr[32] &= ~B00000010; // Plane 0 R unset; mask out
if(r & 1) ptr[32*nPanels] |= B00000010; // Plane 0 R: 32 bytes ahead, bit 1
else ptr[32*nPanels] &= ~B00000010; // Plane 0 R unset; mask out
if(g & 1) *ptr |= B00000001; // Plane 0 G: bit 0
if(b & 1) *ptr |= B00000010; // Plane 0 B: bit 0
for(; bit < limit; bit <<= 1) {
Expand All @@ -335,7 +346,7 @@ void RGBmatrixPanel::fillScreen(uint16_t c) {
// For black or white, all bits in frame buffer will be identically
// set or unset (regardless of weird bit packing), so it's OK to just
// quickly memset the whole thing:
memset(matrixbuff[backindex], c, 32 * nRows * 3);
memset(matrixbuff[backindex], c, 32 * nRows * 3 * nPanels);
} else {
// Otherwise, need to handle it the long way:
Adafruit_GFX::fillScreen(c);
Expand All @@ -360,7 +371,7 @@ void RGBmatrixPanel::swapBuffers(boolean copy) {
swapflag = true; // Set flag here, then...
while(swapflag == true) delay(1); // wait for interrupt to clear it
if(copy == true)
memcpy(matrixbuff[backindex], matrixbuff[1-backindex], 32 * nRows * 3);
memcpy(matrixbuff[backindex], matrixbuff[1-backindex], 32 * nRows * 3 * nPanels);
}
}

Expand All @@ -371,7 +382,7 @@ void RGBmatrixPanel::swapBuffers(boolean copy) {
// back into the display using a pgm_read_byte() loop.
void RGBmatrixPanel::dumpMatrix(void) {

int i, buffsize = 32 * nRows * 3;
int i, buffsize = 32 * nRows * 3 * nPanels;

Serial.print("\n\n"
"#include <avr/pgmspace.h>\n\n"
Expand Down Expand Up @@ -409,7 +420,7 @@ ISR(TIMER1_OVF_vect, ISR_BLOCK) { // ISR_BLOCK important -- see notes later
// Both numbers are rounded up slightly to allow a little wiggle room
// should different compilers produce slightly different results.
#define CALLOVERHEAD 60 // Actual value measured = 56
#define LOOPTIME 200 // Actual value measured = 188
#define LOOPTIME 350 // Actual value measured = 188
// The "on" time for bitplane 0 (with the shortest BCM interval) can
// then be estimated as LOOPTIME + CALLOVERHEAD * 2. Each successive
// bitplane then doubles the prior amount of time. We can then
Expand Down Expand Up @@ -444,6 +455,7 @@ ISR(TIMER1_OVF_vect, ISR_BLOCK) { // ISR_BLOCK important -- see notes later
void RGBmatrixPanel::updateDisplay(void) {
uint8_t i, tick, tock, *ptr;
uint16_t t, duration;
uint8_t panelcount;

*oeport |= oepin; // Disable LED output during row/plane switchover
*latport |= latpin; // Latch data loaded during *prior* interrupt
Expand Down Expand Up @@ -516,6 +528,7 @@ void RGBmatrixPanel::updateDisplay(void) {
// The least 2 bits (used for plane 0 data) are presumed masked out
// by the port direction bits.

#if defined(__AVR__)
// A tiny bit of inline assembly is used; compiler doesn't pick
// up on opportunity for post-increment addressing mode.
// 5 instruction ticks per 'pew' = 160 ticks total
Expand All @@ -525,16 +538,33 @@ void RGBmatrixPanel::updateDisplay(void) {
asm volatile("out %0,%1" :: "I"(_SFR_IO_ADDR(SCLKPORT)),"r"(tick)); \
asm volatile("out %0,%1" :: "I"(_SFR_IO_ADDR(SCLKPORT)),"r"(tock));

// Loop is unrolled for speed:
pew pew pew pew pew pew pew pew
pew pew pew pew pew pew pew pew
pew pew pew pew pew pew pew pew
pew pew pew pew pew pew pew pew


for (panelcount = 0; panelcount < nPanels; panelcount++)
{
// Loop is unrolled for speed:
pew pew pew pew pew pew pew pew
pew pew pew pew pew pew pew pew
pew pew pew pew pew pew pew pew
pew pew pew pew pew pew pew pew
}

// From the "Unsolved Mysteries" department: "buffptr += 32" doesn't
// work here, scrambles the display. "buffptr = ptr" does, even though
// both should produce the same results. Couldn't tell you why.
buffptr = ptr;
#else // Code for none AVR (i.e. Duo and ARM based systems)
for(i=0; i<(32*nPanels); i++)
{
DATAPORT = ptr[i];
SCLKPORT = tick; // Clock lo
SCLKPORT = tock; // Clock hi
}
buffptr += (32*nPanels);
#endif





} else { // 920 ticks from TCNT1=0 (above) to end of function

Expand All @@ -547,13 +577,14 @@ void RGBmatrixPanel::updateDisplay(void) {
// output for plane 0 is handled while plane 3 is being displayed...
// because binary coded modulation is used (not PWM), that plane
// has the longest display interval, so the extra work fits.
for(i=0; i<32; i++) {
for(i=0; i<(32*nPanels); i++) {
DATAPORT =
( ptr[i] << 6) |
((ptr[i+32] << 4) & 0x30) |
((ptr[i+64] << 2) & 0x0C);
( ptr[i] << 6) |
((ptr[i+(32*nPanels)] << 4) & 0x30) |
((ptr[i+(64*nPanels)] << 2) & 0x0C);
SCLKPORT = tick; // Clock lo
SCLKPORT = tock; // Clock hi

}
}
}
Expand Down
16 changes: 11 additions & 5 deletions RGBmatrixPanel.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@ class RGBmatrixPanel : public Adafruit_GFX {

// Constructor for 16x32 panel:
RGBmatrixPanel(uint8_t a, uint8_t b, uint8_t c,
uint8_t sclk, uint8_t latch, uint8_t oe, boolean dbuf);
uint8_t sclk, uint8_t latch, uint8_t oe, boolean dbuf, uint8_t pwidth);
/* Parameters
a, b, c are the pins used for addressing the rows
cclk, latch and oe are the pins used for Serial Clock, Latach and Output Enable
dbuf enables double buffering. This will use 2x RAM for frame buffer, but will give nice smooth animation
pwidth is the number of Panels used together in a multi panel configuration
*/

// Constructor for 32x32 panel (adds 'd' pin):
// Constructor for 32x32 panel (adds 'd' pin): (THIS HAS NOT BEEN TESTED WITH MULTIPLE PANELS)
RGBmatrixPanel(uint8_t a, uint8_t b, uint8_t c, uint8_t d,
uint8_t sclk, uint8_t latch, uint8_t oe, boolean dbuf);
uint8_t sclk, uint8_t latch, uint8_t oe, boolean dbuf,uint8_t pwidth);

void
begin(void),
Expand All @@ -38,12 +44,12 @@ class RGBmatrixPanel : public Adafruit_GFX {
private:

uint8_t *matrixbuff[2];
uint8_t nRows, nPlanes, backindex;
uint8_t nRows, nPlanes, backindex, nPanels;
boolean swapflag;

// Init/alloc code common to both constructors:
void init(uint8_t rows, uint8_t a, uint8_t b, uint8_t c,
uint8_t sclk, uint8_t latch, uint8_t oe, boolean dbuf);
uint8_t sclk, uint8_t latch, uint8_t oe, boolean dbuf, uint8_t pwidth);

// PORT register pointers, pin bitmasks, pin numbers:
volatile uint8_t
Expand Down