Adafruit-RGB_matrix_Panel(32*16)
Diff: RGBmatrixPanel.cpp
- Revision:
- 3:aa3762e0dfee
- Parent:
- 2:6136465ffd3a
- Child:
- 4:0ff6053c4bb2
diff -r 6136465ffd3a -r aa3762e0dfee RGBmatrixPanel.cpp --- a/RGBmatrixPanel.cpp Sat May 24 11:43:34 2014 +0000 +++ b/RGBmatrixPanel.cpp Sat May 24 17:33:23 2014 +0000 @@ -1,4 +1,5 @@ #define DEBUG +#undef DEBUG #include "RGBmatrixPanel.h" #include "gamma.h" @@ -19,7 +20,7 @@ { nRows = rows; // Number of multiplexed rows; actual height is 2X this // Allocate and initialize matrix buffer: - int buffsize = 32 * nRows * 3, // x3 = 3 bytes holds 4 planes "packed" + int buffsize = 32*nRows*3, // 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); @@ -33,29 +34,27 @@ } // Constructor for 16x32 panel: -RGBmatrixPanel::RGBmatrixPanel(PinName a, PinName b, PinName c, PinName sclk, PinName latch, PinName oe, bool dbuf) +RGBmatrixPanel::RGBmatrixPanel(PinName r1,PinName r2,PinName g1,PinName g2,PinName b1,PinName b2,PinName a,PinName b, PinName c, PinName sclk, PinName latch, PinName oe, bool dbuf) :Adafruit_GFX(32, 16), _sclk(sclk), _latch(latch), _oe(oe), - _a(a), - _b(b), - _c(c), - _d(NC) + _d(NC), + _dataBus(r1,g1,b1,r2,g2,b2), + _rowBus(c,b,a) { init(8, dbuf); } // Constructor for 32x32 panel: -RGBmatrixPanel::RGBmatrixPanel(PinName a, PinName b, PinName c, PinName d, PinName sclk, PinName latch, PinName oe, bool dbuf) +RGBmatrixPanel::RGBmatrixPanel(PinName r1,PinName r2,PinName g1,PinName g2,PinName b1,PinName b2,PinName a,PinName b,PinName c,PinName d,PinName sclk,PinName latch,PinName oe,bool dbuf) :Adafruit_GFX(32, 32), _sclk(sclk), _latch(latch), _oe(oe), - _a(a), - _b(b), - _c(c), - _d(d)// Init 32x32-specific elements: + _d(d),// Init 32x32-specific elements: + _dataBus(r1,g1,b1,r2,g2,b2), + _rowBus(c,b,a) { init(16,dbuf); } @@ -74,14 +73,15 @@ DATAPORT = 0; */ - // Set up Timer1 for interrupt: + // Set up Timer for interrupt: + _refresh.attach(activePanel,(&RGBmatrixPanel::updateDisplay),0.001); //updateDisplay() called every 1ms /* - TCCR1A = _BV(WGM11); // Mode 14 (fast PWM), OC1A off - TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // Mode 14, no prescale - ICR1 = 100; - TIMSK1 |= _BV(TOIE1); // Enable Timer1 interrupt - sei(); // Enable global interrupts - */ + TCCR1A = _BV(WGM11); // Mode 14 (fast PWM), OC1A off + TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // Mode 14, no prescale + ICR1 = 100; + TIMSK1 |= _BV(TOIE1); // Enable Timer1 interrupt + sei(); // Enable global interrupts + */ } // Original RGBmatrixPanel library used 3/3/3 color. Later version used @@ -242,7 +242,7 @@ // Data is stored in the high 6 bits so it can be quickly // copied to the DATAPORT register w/6 output lines. for(; bit < limit; bit <<= 1) { - ptr[0] &= ~(_BV(2)|_BV(3)|_BV(4)); // Mask(0b0001110) out R,G,B in one op + ptr[0] &= ~(_BV(2)|_BV(3)|_BV(4)); // Mask(0b00011100) out R,G,B in one op if(r & bit) *ptr |= _BV(2); // Plane N R: bit 2 if(g & bit) *ptr |= _BV(3); // Plane N G: bit 3 if(b & bit) *ptr |= _BV(4); // Plane N B: bit 4 @@ -293,14 +293,18 @@ // draw over every pixel. (No effect if double-buffering is not enabled.) void RGBmatrixPanel::swapBuffers(bool copy) { - log_debug("call swapBuffers %s",copy?"TRUE":"FALSE"); + log_debug("call swapBuffers %s","\r\n"); if(matrixbuff[0] != matrixbuff[1]) { // To avoid 'tearing' display, actual swap takes place in the interrupt // handler, at the end of a complete screen refresh cycle. swapflag = true; // Set flag here, then... while(swapflag == true) wait_ms(1); // wait for interrupt to clear it - if(copy == true) + if(copy == true) { + log_debug("\tmemcpy %s","\r\n"); memcpy(matrixbuff[backindex], matrixbuff[1-backindex], 32 * nRows * 3); + } else { + log_debug("\tnot memcpy %s","\r\n"); + } } } @@ -312,19 +316,19 @@ void RGBmatrixPanel::dumpMatrix(void) { log_debug("call dumpMatrix%s","\r\n"); - int i, buffsize=32*nRows*3; - for(i=0; i<buffsize; i++) { - if(i%(32*nRows)==0) { + int buffsize=32*nRows*3; + for(int item=0; item<buffsize; item++) { + if(item%(32*nRows)==0) { + for(int i=0; i<32*5; i++) { + log_debug("-%c",'\0'); + } log_debug("-%s","\r\n"); } - log_debug("0x%c",'\0'); - log_debug("%02X",matrixbuff[backindex][i]); - if(i < (buffsize - 1)) { - if((i & 7) == 7) log_debug(",\r\n"); - else log_debug(","); - } + log_debug("0x%02X",matrixbuff[backindex][item]); + if((item%32)==31) log_debug(",\r\n"); + else log_debug(","); } - log_debug("\n};%s","\r\n"); + log_debug("%s","\r\n"); } // -------------------- Interrupt handler stuff -------------------- @@ -382,41 +386,25 @@ void RGBmatrixPanel::updateDisplay(void) { - /* - uint8_t i, tick, tock, *ptr; - uint16_t t, duration; - - *oeport |= oepin; // Disable LED output during row/plane switchover - *latport |= latpin; // Latch data loaded during *prior* interrupt - - // Calculate time to next interrupt BEFORE incrementing plane #. - // This is because duration is the display time for the data loaded - // on the PRIOR interrupt. CALLOVERHEAD is subtracted from the - // result because that time is implicit between the timer overflow - // (interrupt triggered) and the initial LEDs-off line at the start - // of this method. - t = (nRows > 8) ? LOOPTIME : (LOOPTIME * 2); - duration = ((t + CALLOVERHEAD * 2) << plane) - CALLOVERHEAD; - - // Borrowing a technique here from Ray's Logic: - // www.rayslogic.com/propeller/Programming/AdafruitRGB/AdafruitRGB.htm - // This code cycles through all four planes for each scanline before - // advancing to the next line. While it might seem beneficial to - // advance lines every time and interleave the planes to reduce - // vertical scanning artifacts, in practice with this panel it causes - // a green 'ghosting' effect on black pixels, a much worse artifact. - - if(++plane >= nPlanes) { // Advance plane counter. Maxed out? + //log_debug("call updateDisplay\t(plane,row)=(%d,%d)\r\n",plane,row); + _oe=1; + _latch=1; + if(++plane >= nPlanes) { // Advance plane counter. Maxed out? plane = 0; // Yes, reset to plane 0, and if(++row >= nRows) { // advance row counter. Maxed out? - row = 0; // Yes, reset row counter, then... - if(swapflag == true) { // Swap front/back buffers if requested + row= 0; // Yes, reset row counter, then... + if(swapflag == true) { // Swap front/back buffers if requested backindex = 1 - backindex; + log_debug("\t\treset swapflag%s","\r\n"); swapflag = false; } + log_debug("\tReset into front buffer[%d]%s",backindex,"\r\n"); buffptr = matrixbuff[1-backindex]; // Reset into front buffer } } else if(plane == 1) { + log_debug("\r\n\tset row@(%d,%d)\r\n",plane,row); + + /* // Plane 0 was loaded on prior interrupt invocation and is about to // latch now, so update the row address lines before we do that: if(row & 0x1) *addraport |= addrapin; @@ -429,58 +417,40 @@ if(row & 0x8) *addrdport |= addrdpin; else *addrdport &= ~addrdpin; } + */ } - + _rowBus=row; + _oe=0; + _latch=0; // buffptr, being 'volatile' type, doesn't take well to optimization. // A local register copy can speed some things up: - ptr = (uint8_t *)buffptr; - - ICR1 = duration; // Set interval for next interrupt - TCNT1 = 0; // Restart interrupt timer - *oeport &= ~oepin; // Re-enable output - *latport &= ~latpin; // Latch down - - // Record current state of SCLKPORT register, as well as a second - // copy with the clock bit set. This makes the innnermost data- - // pushing loops faster, as they can just set the PORT state and - // not have to load/modify/store bits every single time. It's a - // somewhat rude trick that ONLY works because the interrupt - // handler is set ISR_BLOCK, halting any other interrupts that - // might otherwise also be twiddling the port at the same time - // (else this would clobber them). - tock = SCLKPORT; - tick = tock | sclkpin; - - if(plane > 0) { // 188 ticks from TCNT1=0 (above) to end of function - - // Planes 1-3 copy bytes directly from RAM to PORT without unpacking. - // The least 2 bits (used for plane 0 data) are presumed masked out - // by the port direction bits. + uint8_t *ptr = (uint8_t *)buffptr; + /* + ICR1 = duration; // Set interval for next interrupt + TCNT1 = 0; // Restart interrupt timer + *oeport &= ~oepin; // Re-enable output + *latport &= ~latpin; // Latch down - // 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 - #define pew asm volatile( \ - "ld __tmp_reg__, %a[ptr]+" "\n\t" \ - "out %[data] , __tmp_reg__" "\n\t" \ - "out %[clk] , %[tick]" "\n\t" \ - "out %[clk] , %[tock]" "\n" \ - :: [ptr] "e" (ptr), \ - [data] "I" (_SFR_IO_ADDR(DATAPORT)), \ - [clk] "I" (_SFR_IO_ADDR(SCLKPORT)), \ - [tick] "r" (tick), \ - [tock] "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 - + // Record current state of SCLKPORT register, as well as a second + // copy with the clock bit set. This makes the innnermost data- + // pushing loops faster, as they can just set the PORT state and + // not have to load/modify/store bits every single time. It's a + // somewhat rude trick that ONLY works because the interrupt + // handler is set ISR_BLOCK, halting any other interrupts that + // might otherwise also be twiddling the port at the same time + // (else this would clobber them). + tock = SCLKPORT; + tick = tock | sclkpin; + */ + if(plane > 0) { // 188 ticks from TCNT1=0 (above) to end of function + for(int i=0; i<32; i++) { + _dataBus=(ptr[i] << 6) | ((ptr[i+32] << 4)&0x30) | ((ptr[i+64] << 2)&0x0C)>>2; + _sclk=1; + _sclk=0; + } buffptr += 32; - - } else { // 920 ticks from TCNT1=0 (above) to end of function - + } else { + // 920 ticks from TCNT1=0 (above) to end of function // Planes 1-3 (handled above) formatted their data "in place," // their layout matching that out the output PORT register (where // 6 bits correspond to output data lines), maximizing throughput @@ -490,14 +460,12 @@ // 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++) { - DATAPORT = - ( ptr[i] << 6) | - ((ptr[i+32] << 4) & 0x30) | - ((ptr[i+64] << 2) & 0x0C); - SCLKPORT = tick; // Clock lo - SCLKPORT = tock; // Clock hi + for(int i=0; i<32; i++) { + _dataBus=(ptr[i] << 6) | ((ptr[i+32] << 4)&0x30) | ((ptr[i+64] << 2)&0x0C)>>2; + _sclk=1; + _sclk=0; + log_debug("\t\t %02x@(%d,%d)",_dataBus.read(),plane,row); } + //buffptr += 32; } - */ }