Adafruit-RGB_matrix_Panel(32*16)
Dependencies: Adafruit-GFX
RGBmatrixPanel.cpp@8:6d98c8cd8045, 2014-05-25 (annotated)
- Committer:
- lelect
- Date:
- Sun May 25 12:02:10 2014 +0000
- Revision:
- 8:6d98c8cd8045
- Parent:
- 6:b594794a132e
DigitalOut* array test
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
lelect | 2:6136465ffd3a | 1 | #define DEBUG |
lelect | 5:1f8409ee8850 | 2 | #undef DEBUG |
lelect | 0:06d9443a018f | 3 | #include "RGBmatrixPanel.h" |
lelect | 0:06d9443a018f | 4 | #include "gamma.h" |
lelect | 0:06d9443a018f | 5 | |
lelect | 0:06d9443a018f | 6 | #define nPlanes 4 |
lelect | 0:06d9443a018f | 7 | |
lelect | 0:06d9443a018f | 8 | // The fact that the display driver interrupt stuff is tied to the |
lelect | 0:06d9443a018f | 9 | // singular Timer1 doesn't really take well to object orientation with |
lelect | 0:06d9443a018f | 10 | // multiple RGBmatrixPanel instances. The solution at present is to |
lelect | 0:06d9443a018f | 11 | // allow instances, but only one is active at any given time, via its |
lelect | 0:06d9443a018f | 12 | // begin() method. The implementation is still incomplete in parts; |
lelect | 0:06d9443a018f | 13 | // the prior active panel really should be gracefully disabled, and a |
lelect | 0:06d9443a018f | 14 | // stop() method should perhaps be added...assuming multiple instances |
lelect | 0:06d9443a018f | 15 | // are even an actual need. |
lelect | 4:0ff6053c4bb2 | 16 | //static RGBmatrixPanel *activePanel = NULL; |
lelect | 0:06d9443a018f | 17 | |
lelect | 0:06d9443a018f | 18 | // Code common to both the 16x32 and 32x32 constructors: |
lelect | 2:6136465ffd3a | 19 | void RGBmatrixPanel::init(uint8_t rows, bool dbuf) |
lelect | 0:06d9443a018f | 20 | { |
lelect | 0:06d9443a018f | 21 | nRows = rows; // Number of multiplexed rows; actual height is 2X this |
lelect | 0:06d9443a018f | 22 | // Allocate and initialize matrix buffer: |
lelect | 3:aa3762e0dfee | 23 | int buffsize = 32*nRows*3, // x3 = 3 bytes holds 4 planes "packed" |
lelect | 0:06d9443a018f | 24 | allocsize = (dbuf == true) ? (buffsize * 2) : buffsize; |
lelect | 0:06d9443a018f | 25 | if(NULL == (matrixbuff[0] = (uint8_t *)malloc(allocsize))) return; |
lelect | 0:06d9443a018f | 26 | memset(matrixbuff[0], 0, allocsize); |
lelect | 0:06d9443a018f | 27 | // If not double-buffered, both buffers then point to the same address: |
lelect | 0:06d9443a018f | 28 | matrixbuff[1] = (dbuf == true) ? &matrixbuff[0][buffsize] : matrixbuff[0]; |
lelect | 0:06d9443a018f | 29 | |
lelect | 0:06d9443a018f | 30 | plane = nPlanes - 1; |
lelect | 0:06d9443a018f | 31 | row = nRows - 1; |
lelect | 0:06d9443a018f | 32 | swapflag = false; |
lelect | 0:06d9443a018f | 33 | backindex = 0; // Array index of back buffer |
lelect | 0:06d9443a018f | 34 | } |
lelect | 0:06d9443a018f | 35 | |
lelect | 0:06d9443a018f | 36 | // Constructor for 16x32 panel: |
lelect | 3:aa3762e0dfee | 37 | 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) |
lelect | 2:6136465ffd3a | 38 | :Adafruit_GFX(32, 16), |
lelect | 5:1f8409ee8850 | 39 | _rowBus(a,b,c), |
lelect | 5:1f8409ee8850 | 40 | _d(NC), |
lelect | 2:6136465ffd3a | 41 | _sclk(sclk), |
lelect | 2:6136465ffd3a | 42 | _latch(latch), |
lelect | 5:1f8409ee8850 | 43 | _oe(oe) |
lelect | 0:06d9443a018f | 44 | { |
lelect | 8:6d98c8cd8045 | 45 | PinName pins[6] = {r1,g1,b1,r2,g2,b2}; |
lelect | 8:6d98c8cd8045 | 46 | for(int i=0; i<6; i++) { |
lelect | 8:6d98c8cd8045 | 47 | _pin[i] = (pins[i] != NC) ? new DigitalOut(pins[i]) : 0; |
lelect | 8:6d98c8cd8045 | 48 | } |
lelect | 2:6136465ffd3a | 49 | init(8, dbuf); |
lelect | 0:06d9443a018f | 50 | } |
lelect | 0:06d9443a018f | 51 | |
lelect | 0:06d9443a018f | 52 | // Constructor for 32x32 panel: |
lelect | 3:aa3762e0dfee | 53 | 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) |
lelect | 2:6136465ffd3a | 54 | :Adafruit_GFX(32, 32), |
lelect | 5:1f8409ee8850 | 55 | _rowBus(a,b,c), |
lelect | 5:1f8409ee8850 | 56 | _d(d),// Init 32x32-specific elements: |
lelect | 2:6136465ffd3a | 57 | _sclk(sclk), |
lelect | 2:6136465ffd3a | 58 | _latch(latch), |
lelect | 5:1f8409ee8850 | 59 | _oe(oe) |
lelect | 0:06d9443a018f | 60 | { |
lelect | 8:6d98c8cd8045 | 61 | PinName pins[6] = {r1,g1,b1,r2,g2,b2}; |
lelect | 8:6d98c8cd8045 | 62 | for(int i=0; i<6; i++) { |
lelect | 8:6d98c8cd8045 | 63 | _pin[i] = (pins[i] != NC) ? new DigitalOut(pins[i]) : 0; |
lelect | 8:6d98c8cd8045 | 64 | } |
lelect | 2:6136465ffd3a | 65 | init(16,dbuf); |
lelect | 0:06d9443a018f | 66 | } |
lelect | 0:06d9443a018f | 67 | |
lelect | 0:06d9443a018f | 68 | void RGBmatrixPanel::begin(void) |
lelect | 0:06d9443a018f | 69 | { |
lelect | 0:06d9443a018f | 70 | |
lelect | 0:06d9443a018f | 71 | backindex = 0; // Back buffer |
lelect | 0:06d9443a018f | 72 | buffptr = matrixbuff[1 - backindex]; // -> front buffer |
lelect | 4:0ff6053c4bb2 | 73 | // activePanel = this; // For interrupt hander |
lelect | 0:06d9443a018f | 74 | |
lelect | 3:aa3762e0dfee | 75 | // Set up Timer for interrupt: |
lelect | 4:0ff6053c4bb2 | 76 | #ifndef DEBUG |
lelect | 6:b594794a132e | 77 | _refresh.attach_us(this,(&RGBmatrixPanel::updateDisplay),200); //updateDisplay() called every 1ms |
lelect | 4:0ff6053c4bb2 | 78 | #else |
lelect | 5:1f8409ee8850 | 79 | _refresh.attach(this,(&RGBmatrixPanel::updateDisplay),0.5); //updateDisplay() called every 2s |
lelect | 4:0ff6053c4bb2 | 80 | #endif |
lelect | 0:06d9443a018f | 81 | } |
lelect | 0:06d9443a018f | 82 | |
lelect | 0:06d9443a018f | 83 | // Original RGBmatrixPanel library used 3/3/3 color. Later version used |
lelect | 0:06d9443a018f | 84 | // 4/4/4. Then Adafruit_GFX (core library used across all Adafruit |
lelect | 0:06d9443a018f | 85 | // display devices now) standardized on 5/6/5. The matrix still operates |
lelect | 0:06d9443a018f | 86 | // internally on 4/4/4 color, but all the graphics functions are written |
lelect | 0:06d9443a018f | 87 | // to expect 5/6/5...the matrix lib will truncate the color components as |
lelect | 0:06d9443a018f | 88 | // needed when drawing. These next functions are mostly here for the |
lelect | 0:06d9443a018f | 89 | // benefit of older code using one of the original color formats. |
lelect | 0:06d9443a018f | 90 | |
lelect | 0:06d9443a018f | 91 | // Promote 3/3/3 RGB to Adafruit_GFX 5/6/5 |
lelect | 0:06d9443a018f | 92 | uint16_t RGBmatrixPanel::Color333(uint8_t r, uint8_t g, uint8_t b) |
lelect | 0:06d9443a018f | 93 | { |
lelect | 0:06d9443a018f | 94 | // RRRrrGGGgggBBBbb |
lelect | 0:06d9443a018f | 95 | return ((r & 0x7) << 13) | ((r & 0x6) << 10) | |
lelect | 0:06d9443a018f | 96 | ((g & 0x7) << 8) | ((g & 0x7) << 5) | |
lelect | 0:06d9443a018f | 97 | ((b & 0x7) << 2) | ((b & 0x6) >> 1); |
lelect | 0:06d9443a018f | 98 | } |
lelect | 0:06d9443a018f | 99 | |
lelect | 0:06d9443a018f | 100 | // Promote 4/4/4 RGB to Adafruit_GFX 5/6/5 |
lelect | 0:06d9443a018f | 101 | uint16_t RGBmatrixPanel::Color444(uint8_t r, uint8_t g, uint8_t b) |
lelect | 0:06d9443a018f | 102 | { |
lelect | 0:06d9443a018f | 103 | // RRRRrGGGGggBBBBb |
lelect | 0:06d9443a018f | 104 | return ((r & 0xF) << 12) | ((r & 0x8) << 8) | |
lelect | 0:06d9443a018f | 105 | ((g & 0xF) << 7) | ((g & 0xC) << 3) | |
lelect | 0:06d9443a018f | 106 | ((b & 0xF) << 1) | ((b & 0x8) >> 3); |
lelect | 0:06d9443a018f | 107 | } |
lelect | 0:06d9443a018f | 108 | |
lelect | 0:06d9443a018f | 109 | // Demote 8/8/8 to Adafruit_GFX 5/6/5 |
lelect | 0:06d9443a018f | 110 | // If no gamma flag passed, assume linear color |
lelect | 0:06d9443a018f | 111 | uint16_t RGBmatrixPanel::Color888(uint8_t r, uint8_t g, uint8_t b) |
lelect | 0:06d9443a018f | 112 | { |
lelect | 0:06d9443a018f | 113 | return ((r & 0xF8) << 11) | ((g & 0xFC) << 5) | (b >> 3); |
lelect | 0:06d9443a018f | 114 | } |
lelect | 0:06d9443a018f | 115 | |
lelect | 0:06d9443a018f | 116 | // 8/8/8 -> gamma -> 5/6/5 |
lelect | 1:0078213d3fa4 | 117 | uint16_t RGBmatrixPanel::Color888(uint8_t r, uint8_t g, uint8_t b, bool gflag) |
lelect | 0:06d9443a018f | 118 | { |
lelect | 0:06d9443a018f | 119 | if(gflag) { // Gamma-corrected color? |
lelect | 1:0078213d3fa4 | 120 | r = gamma[r]; // Gamma correction table maps |
lelect | 1:0078213d3fa4 | 121 | g = gamma[g]; // 8-bit input to 4-bit output |
lelect | 1:0078213d3fa4 | 122 | b = gamma[b]; |
lelect | 0:06d9443a018f | 123 | return (r << 12) | ((r & 0x8) << 8) | // 4/4/4 -> 5/6/5 |
lelect | 0:06d9443a018f | 124 | (g << 7) | ((g & 0xC) << 3) | |
lelect | 0:06d9443a018f | 125 | (b << 1) | ( b >> 3); |
lelect | 0:06d9443a018f | 126 | } // else linear (uncorrected) color |
lelect | 0:06d9443a018f | 127 | return ((r & 0xF8) << 11) | ((g & 0xFC) << 5) | (b >> 3); |
lelect | 0:06d9443a018f | 128 | } |
lelect | 0:06d9443a018f | 129 | |
lelect | 1:0078213d3fa4 | 130 | uint16_t RGBmatrixPanel::ColorHSV(long hue, uint8_t sat, uint8_t val, bool gflag) |
lelect | 0:06d9443a018f | 131 | { |
lelect | 0:06d9443a018f | 132 | |
lelect | 0:06d9443a018f | 133 | uint8_t r, g, b, lo; |
lelect | 0:06d9443a018f | 134 | uint16_t s1, v1; |
lelect | 0:06d9443a018f | 135 | |
lelect | 0:06d9443a018f | 136 | // Hue |
lelect | 0:06d9443a018f | 137 | hue %= 1536; // -1535 to +1535 |
lelect | 0:06d9443a018f | 138 | if(hue < 0) hue += 1536; // 0 to +1535 |
lelect | 0:06d9443a018f | 139 | lo = hue & 255; // Low byte = primary/secondary color mix |
lelect | 0:06d9443a018f | 140 | switch(hue >> 8) { // High byte = sextant of colorwheel |
lelect | 0:06d9443a018f | 141 | case 0 : |
lelect | 0:06d9443a018f | 142 | r = 255 ; |
lelect | 0:06d9443a018f | 143 | g = lo ; |
lelect | 0:06d9443a018f | 144 | b = 0 ; |
lelect | 0:06d9443a018f | 145 | break; // R to Y |
lelect | 0:06d9443a018f | 146 | case 1 : |
lelect | 0:06d9443a018f | 147 | r = 255 - lo; |
lelect | 0:06d9443a018f | 148 | g = 255 ; |
lelect | 0:06d9443a018f | 149 | b = 0 ; |
lelect | 0:06d9443a018f | 150 | break; // Y to G |
lelect | 0:06d9443a018f | 151 | case 2 : |
lelect | 0:06d9443a018f | 152 | r = 0 ; |
lelect | 0:06d9443a018f | 153 | g = 255 ; |
lelect | 0:06d9443a018f | 154 | b = lo ; |
lelect | 0:06d9443a018f | 155 | break; // G to C |
lelect | 0:06d9443a018f | 156 | case 3 : |
lelect | 0:06d9443a018f | 157 | r = 0 ; |
lelect | 0:06d9443a018f | 158 | g = 255 - lo; |
lelect | 0:06d9443a018f | 159 | b = 255 ; |
lelect | 0:06d9443a018f | 160 | break; // C to B |
lelect | 0:06d9443a018f | 161 | case 4 : |
lelect | 0:06d9443a018f | 162 | r = lo ; |
lelect | 0:06d9443a018f | 163 | g = 0 ; |
lelect | 0:06d9443a018f | 164 | b = 255 ; |
lelect | 0:06d9443a018f | 165 | break; // B to M |
lelect | 0:06d9443a018f | 166 | default: |
lelect | 0:06d9443a018f | 167 | r = 255 ; |
lelect | 0:06d9443a018f | 168 | g = 0 ; |
lelect | 0:06d9443a018f | 169 | b = 255 - lo; |
lelect | 0:06d9443a018f | 170 | break; // M to R |
lelect | 0:06d9443a018f | 171 | } |
lelect | 0:06d9443a018f | 172 | |
lelect | 0:06d9443a018f | 173 | // Saturation: add 1 so range is 1 to 256, allowig a quick shift operation |
lelect | 0:06d9443a018f | 174 | // on the result rather than a costly divide, while the type upgrade to int |
lelect | 0:06d9443a018f | 175 | // avoids repeated type conversions in both directions. |
lelect | 0:06d9443a018f | 176 | s1 = sat + 1; |
lelect | 0:06d9443a018f | 177 | r = 255 - (((255 - r) * s1) >> 8); |
lelect | 0:06d9443a018f | 178 | g = 255 - (((255 - g) * s1) >> 8); |
lelect | 0:06d9443a018f | 179 | b = 255 - (((255 - b) * s1) >> 8); |
lelect | 0:06d9443a018f | 180 | |
lelect | 0:06d9443a018f | 181 | // Value (brightness) & 16-bit color reduction: similar to above, add 1 |
lelect | 0:06d9443a018f | 182 | // to allow shifts, and upgrade to int makes other conversions implicit. |
lelect | 0:06d9443a018f | 183 | v1 = val + 1; |
lelect | 0:06d9443a018f | 184 | if(gflag) { // Gamma-corrected color? |
lelect | 2:6136465ffd3a | 185 | r = gamma[(r * v1) >> 8]; // Gamma correction table maps |
lelect | 2:6136465ffd3a | 186 | g = gamma[(g * v1) >> 8]; // 8-bit input to 4-bit output |
lelect | 2:6136465ffd3a | 187 | b = gamma[(b * v1) >> 8]; |
lelect | 2:6136465ffd3a | 188 | //before pgm_read_byte(&gamma[(b * v1) >> 8]) |
lelect | 0:06d9443a018f | 189 | } else { // linear (uncorrected) color |
lelect | 0:06d9443a018f | 190 | r = (r * v1) >> 12; // 4-bit results |
lelect | 0:06d9443a018f | 191 | g = (g * v1) >> 12; |
lelect | 0:06d9443a018f | 192 | b = (b * v1) >> 12; |
lelect | 0:06d9443a018f | 193 | } |
lelect | 0:06d9443a018f | 194 | return (r << 12) | ((r & 0x8) << 8) | // 4/4/4 -> 5/6/5 |
lelect | 0:06d9443a018f | 195 | (g << 7) | ((g & 0xC) << 3) | |
lelect | 0:06d9443a018f | 196 | (b << 1) | ( b >> 3); |
lelect | 0:06d9443a018f | 197 | } |
lelect | 0:06d9443a018f | 198 | |
lelect | 0:06d9443a018f | 199 | void RGBmatrixPanel::drawPixel(int16_t x, int16_t y, uint16_t c) |
lelect | 0:06d9443a018f | 200 | { |
lelect | 0:06d9443a018f | 201 | uint8_t r, g, b, bit, limit, *ptr; |
lelect | 0:06d9443a018f | 202 | if((x < 0) || (x >= _width) || (y < 0) || (y >= _height)) return; |
lelect | 0:06d9443a018f | 203 | switch(rotation) { |
lelect | 0:06d9443a018f | 204 | case 1: |
lelect | 0:06d9443a018f | 205 | swap(x, y); |
lelect | 0:06d9443a018f | 206 | x = _rawWidth - 1 - x; |
lelect | 0:06d9443a018f | 207 | break; |
lelect | 0:06d9443a018f | 208 | case 2: |
lelect | 0:06d9443a018f | 209 | x = _rawWidth - 1 - x; |
lelect | 0:06d9443a018f | 210 | y = _rawHeight - 1 - y; |
lelect | 0:06d9443a018f | 211 | break; |
lelect | 0:06d9443a018f | 212 | case 3: |
lelect | 0:06d9443a018f | 213 | swap(x, y); |
lelect | 0:06d9443a018f | 214 | y = _rawHeight - 1 - y; |
lelect | 0:06d9443a018f | 215 | break; |
lelect | 0:06d9443a018f | 216 | } |
lelect | 0:06d9443a018f | 217 | |
lelect | 0:06d9443a018f | 218 | // Adafruit_GFX uses 16-bit color in 5/6/5 format, while matrix needs |
lelect | 0:06d9443a018f | 219 | // 4/4/4. Pluck out relevant bits while separating into R,G,B: |
lelect | 0:06d9443a018f | 220 | r = c >> 12; // RRRRrggggggbbbbb |
lelect | 0:06d9443a018f | 221 | g = (c >> 7) & 0xF; // rrrrrGGGGggbbbbb |
lelect | 0:06d9443a018f | 222 | b = (c >> 1) & 0xF; // rrrrrggggggBBBBb |
lelect | 0:06d9443a018f | 223 | // Loop counter stuff |
lelect | 4:0ff6053c4bb2 | 224 | //log_debug("(%X, %X, %X)@(%d,%d)%s",r,g,b,x,y,"\t"); |
lelect | 0:06d9443a018f | 225 | bit = 2; |
lelect | 0:06d9443a018f | 226 | limit = 1 << nPlanes; |
lelect | 0:06d9443a018f | 227 | |
lelect | 0:06d9443a018f | 228 | if(y < nRows) { |
lelect | 2:6136465ffd3a | 229 | // Data for the upper half of the display is stored in the lower bits of each byte. |
lelect | 2:6136465ffd3a | 230 | ptr = &matrixbuff[backindex][y*_rawWidth*(nPlanes-1) + x]; // Base addr |
lelect | 4:0ff6053c4bb2 | 231 | // Plane 0 is a tricky case -- its data is spread about, stored in least two bits not used by the other planes. |
lelect | 4:0ff6053c4bb2 | 232 | ptr[64] &= ~(_BV(1)|_BV(0)); // Plane 0 R,G mask(0b11111100) out in one op |
lelect | 2:6136465ffd3a | 233 | if(r & 1) ptr[64] |= _BV(0); // Plane 0 R: 64 bytes ahead, bit 0 |
lelect | 2:6136465ffd3a | 234 | if(g & 1) ptr[64] |= _BV(1); // Plane 0 G: 64 bytes ahead, bit 1 |
lelect | 2:6136465ffd3a | 235 | if(b & 1) ptr[32] |= _BV(0); // Plane 0 B: 32 bytes ahead, bit 0 |
lelect | 2:6136465ffd3a | 236 | else ptr[32] &= ~_BV(0); // Plane 0 B unset; mask out |
lelect | 0:06d9443a018f | 237 | // The remaining three image planes are more normal-ish. |
lelect | 0:06d9443a018f | 238 | // Data is stored in the high 6 bits so it can be quickly |
lelect | 0:06d9443a018f | 239 | // copied to the DATAPORT register w/6 output lines. |
lelect | 0:06d9443a018f | 240 | for(; bit < limit; bit <<= 1) { |
lelect | 5:1f8409ee8850 | 241 | *ptr &= ~(_BV(4)|_BV(3)|_BV(2)) ; // Mask(0b11100011) out R,G,B in one op |
lelect | 4:0ff6053c4bb2 | 242 | if(r & bit) *ptr |= _BV(2); // Plane N R: bit 2 |
lelect | 4:0ff6053c4bb2 | 243 | if(g & bit) *ptr |= _BV(3); // Plane N G: bit 3 |
lelect | 4:0ff6053c4bb2 | 244 | if(b & bit) *ptr |= _BV(4); // Plane N B: bit 4 |
lelect | 4:0ff6053c4bb2 | 245 | ptr += _rawWidth; // Advance to next bit plane |
lelect | 0:06d9443a018f | 246 | } |
lelect | 0:06d9443a018f | 247 | } else { |
lelect | 2:6136465ffd3a | 248 | // Data for the lower half of the display is stored in the upper bits, except for the plane 0 stuff, using 2 least bits. |
lelect | 2:6136465ffd3a | 249 | ptr = &matrixbuff[backindex][(y-nRows)*_rawWidth*(nPlanes-1) + x]; |
lelect | 4:0ff6053c4bb2 | 250 | *ptr &= ~(_BV(1)|_BV(0)); // Plane 0 G,B mask out in one op |
lelect | 2:6136465ffd3a | 251 | if(r & 1) ptr[32] |= _BV(1); // Plane 0 R: 32 bytes ahead, bit 1 |
lelect | 4:0ff6053c4bb2 | 252 | else ptr[32] &= ~_BV(1); // Plane 0 R unset; mask out |
lelect | 2:6136465ffd3a | 253 | if(g & 1) *ptr |= _BV(0); // Plane 0 G: bit 0 |
lelect | 2:6136465ffd3a | 254 | if(b & 1) *ptr |= _BV(1); // Plane 0 B: bit 0 |
lelect | 0:06d9443a018f | 255 | for(; bit < limit; bit <<= 1) { |
lelect | 4:0ff6053c4bb2 | 256 | *ptr &= ~(_BV(7)|_BV(6)|_BV(5)); // Mask out R,G,B in one op |
lelect | 2:6136465ffd3a | 257 | if(r & bit) *ptr |= _BV(5); // Plane N R: bit 5 |
lelect | 2:6136465ffd3a | 258 | if(g & bit) *ptr |= _BV(6); // Plane N G: bit 6 |
lelect | 2:6136465ffd3a | 259 | if(b & bit) *ptr |= _BV(7); // Plane N B: bit 7 |
lelect | 2:6136465ffd3a | 260 | ptr += _rawWidth; // Advance to next bit plane |
lelect | 0:06d9443a018f | 261 | } |
lelect | 0:06d9443a018f | 262 | } |
lelect | 0:06d9443a018f | 263 | } |
lelect | 0:06d9443a018f | 264 | |
lelect | 0:06d9443a018f | 265 | void RGBmatrixPanel::fillScreen(uint16_t c) |
lelect | 0:06d9443a018f | 266 | { |
lelect | 0:06d9443a018f | 267 | if((c == 0x0000) || (c == 0xffff)) { |
lelect | 0:06d9443a018f | 268 | // For black or white, all bits in frame buffer will be identically |
lelect | 0:06d9443a018f | 269 | // set or unset (regardless of weird bit packing), so it's OK to just |
lelect | 0:06d9443a018f | 270 | // quickly memset the whole thing: |
lelect | 0:06d9443a018f | 271 | memset(matrixbuff[backindex], c, 32 * nRows * 3); |
lelect | 0:06d9443a018f | 272 | } else { |
lelect | 0:06d9443a018f | 273 | // Otherwise, need to handle it the long way: |
lelect | 0:06d9443a018f | 274 | Adafruit_GFX::fillScreen(c); |
lelect | 0:06d9443a018f | 275 | } |
lelect | 0:06d9443a018f | 276 | } |
lelect | 0:06d9443a018f | 277 | |
lelect | 0:06d9443a018f | 278 | // Return address of back buffer -- can then load/store data directly |
lelect | 0:06d9443a018f | 279 | uint8_t *RGBmatrixPanel::backBuffer() |
lelect | 0:06d9443a018f | 280 | { |
lelect | 0:06d9443a018f | 281 | return matrixbuff[backindex]; |
lelect | 0:06d9443a018f | 282 | } |
lelect | 0:06d9443a018f | 283 | |
lelect | 0:06d9443a018f | 284 | // For smooth animation -- drawing always takes place in the "back" buffer; |
lelect | 0:06d9443a018f | 285 | // this method pushes it to the "front" for display. Passing "true", the |
lelect | 0:06d9443a018f | 286 | // updated display contents are then copied to the new back buffer and can |
lelect | 0:06d9443a018f | 287 | // be incrementally modified. If "false", the back buffer then contains |
lelect | 0:06d9443a018f | 288 | // the old front buffer contents -- your code can either clear this or |
lelect | 0:06d9443a018f | 289 | // draw over every pixel. (No effect if double-buffering is not enabled.) |
lelect | 0:06d9443a018f | 290 | void RGBmatrixPanel::swapBuffers(bool copy) |
lelect | 0:06d9443a018f | 291 | { |
lelect | 4:0ff6053c4bb2 | 292 | log_debug("\r\ncall swapBuffers %s","\r\n"); |
lelect | 0:06d9443a018f | 293 | if(matrixbuff[0] != matrixbuff[1]) { |
lelect | 0:06d9443a018f | 294 | // To avoid 'tearing' display, actual swap takes place in the interrupt |
lelect | 0:06d9443a018f | 295 | // handler, at the end of a complete screen refresh cycle. |
lelect | 0:06d9443a018f | 296 | swapflag = true; // Set flag here, then... |
lelect | 2:6136465ffd3a | 297 | while(swapflag == true) wait_ms(1); // wait for interrupt to clear it |
lelect | 3:aa3762e0dfee | 298 | if(copy == true) { |
lelect | 3:aa3762e0dfee | 299 | log_debug("\tmemcpy %s","\r\n"); |
lelect | 0:06d9443a018f | 300 | memcpy(matrixbuff[backindex], matrixbuff[1-backindex], 32 * nRows * 3); |
lelect | 3:aa3762e0dfee | 301 | } else { |
lelect | 3:aa3762e0dfee | 302 | log_debug("\tnot memcpy %s","\r\n"); |
lelect | 3:aa3762e0dfee | 303 | } |
lelect | 0:06d9443a018f | 304 | } |
lelect | 0:06d9443a018f | 305 | } |
lelect | 0:06d9443a018f | 306 | |
lelect | 0:06d9443a018f | 307 | // Dump display contents to the Serial Monitor, adding some formatting to |
lelect | 0:06d9443a018f | 308 | // simplify copy-and-paste of data as a PROGMEM-embedded image for another |
lelect | 0:06d9443a018f | 309 | // sketch. If using multiple dumps this way, you'll need to edit the |
lelect | 0:06d9443a018f | 310 | // output to change the 'img' name for each. Data can then be loaded |
lelect | 0:06d9443a018f | 311 | // back into the display using a pgm_read_byte() loop. |
lelect | 0:06d9443a018f | 312 | void RGBmatrixPanel::dumpMatrix(void) |
lelect | 0:06d9443a018f | 313 | { |
lelect | 4:0ff6053c4bb2 | 314 | #ifdef DEBUG |
lelect | 4:0ff6053c4bb2 | 315 | log_debug("\r\ncall dumpMatrix%s","\r\n"); |
lelect | 3:aa3762e0dfee | 316 | int buffsize=32*nRows*3; |
lelect | 3:aa3762e0dfee | 317 | for(int item=0; item<buffsize; item++) { |
lelect | 3:aa3762e0dfee | 318 | log_debug("0x%02X",matrixbuff[backindex][item]); |
lelect | 3:aa3762e0dfee | 319 | if((item%32)==31) log_debug(",\r\n"); |
lelect | 3:aa3762e0dfee | 320 | else log_debug(","); |
lelect | 0:06d9443a018f | 321 | } |
lelect | 4:0ff6053c4bb2 | 322 | log_debug("%s","\r\n\r\n"); |
lelect | 4:0ff6053c4bb2 | 323 | #endif |
lelect | 0:06d9443a018f | 324 | |
lelect | 0:06d9443a018f | 325 | } |
lelect | 8:6d98c8cd8045 | 326 | void RGBmatrixPanel::setBus(int value) |
lelect | 8:6d98c8cd8045 | 327 | { |
lelect | 8:6d98c8cd8045 | 328 | for (int i=0; i<6; i++) { |
lelect | 8:6d98c8cd8045 | 329 | if (_pin[i] != 0) { |
lelect | 8:6d98c8cd8045 | 330 | _pin[i]->write((value >> i) & 1); |
lelect | 8:6d98c8cd8045 | 331 | } |
lelect | 8:6d98c8cd8045 | 332 | } |
lelect | 8:6d98c8cd8045 | 333 | } |
lelect | 8:6d98c8cd8045 | 334 | int RGBmatrixPanel::readBus() |
lelect | 8:6d98c8cd8045 | 335 | { |
lelect | 8:6d98c8cd8045 | 336 | int v = 0; |
lelect | 8:6d98c8cd8045 | 337 | for (int i=0; i<6; i++) { |
lelect | 8:6d98c8cd8045 | 338 | if (_pin[i] != 0) { |
lelect | 8:6d98c8cd8045 | 339 | v |= _pin[i]->read() << i; |
lelect | 8:6d98c8cd8045 | 340 | } |
lelect | 8:6d98c8cd8045 | 341 | } |
lelect | 8:6d98c8cd8045 | 342 | return v; |
lelect | 8:6d98c8cd8045 | 343 | } |
lelect | 0:06d9443a018f | 344 | |
lelect | 0:06d9443a018f | 345 | void RGBmatrixPanel::updateDisplay(void) |
lelect | 0:06d9443a018f | 346 | { |
lelect | 5:1f8409ee8850 | 347 | uint8_t *ptr; |
lelect | 4:0ff6053c4bb2 | 348 | log_debug("\r\ncall updateDisplay\r\n"); |
lelect | 3:aa3762e0dfee | 349 | _oe=1; |
lelect | 3:aa3762e0dfee | 350 | _latch=1; |
lelect | 3:aa3762e0dfee | 351 | if(++plane >= nPlanes) { // Advance plane counter. Maxed out? |
lelect | 0:06d9443a018f | 352 | plane = 0; // Yes, reset to plane 0, and |
lelect | 0:06d9443a018f | 353 | if(++row >= nRows) { // advance row counter. Maxed out? |
lelect | 3:aa3762e0dfee | 354 | row= 0; // Yes, reset row counter, then... |
lelect | 3:aa3762e0dfee | 355 | if(swapflag == true) { // Swap front/back buffers if requested |
lelect | 0:06d9443a018f | 356 | backindex = 1 - backindex; |
lelect | 3:aa3762e0dfee | 357 | log_debug("\t\treset swapflag%s","\r\n"); |
lelect | 0:06d9443a018f | 358 | swapflag = false; |
lelect | 0:06d9443a018f | 359 | } |
lelect | 3:aa3762e0dfee | 360 | log_debug("\tReset into front buffer[%d]%s",backindex,"\r\n"); |
lelect | 0:06d9443a018f | 361 | buffptr = matrixbuff[1-backindex]; // Reset into front buffer |
lelect | 0:06d9443a018f | 362 | } |
lelect | 0:06d9443a018f | 363 | } else if(plane == 1) { |
lelect | 4:0ff6053c4bb2 | 364 | log_debug("\tupdate row%s","\r\n"); |
lelect | 5:1f8409ee8850 | 365 | _rowBus.write(row); |
lelect | 0:06d9443a018f | 366 | } |
lelect | 8:6d98c8cd8045 | 367 | setBus(0); |
lelect | 3:aa3762e0dfee | 368 | _oe=0; |
lelect | 3:aa3762e0dfee | 369 | _latch=0; |
lelect | 5:1f8409ee8850 | 370 | ptr = (uint8_t *)buffptr; |
lelect | 5:1f8409ee8850 | 371 | |
lelect | 4:0ff6053c4bb2 | 372 | log_debug("\t(row@plane)=(%d,%d)\r\n",row,plane); |
lelect | 4:0ff6053c4bb2 | 373 | int color; |
lelect | 4:0ff6053c4bb2 | 374 | if(plane > 0) { |
lelect | 5:1f8409ee8850 | 375 | //ptr[i]>>2 |
lelect | 3:aa3762e0dfee | 376 | for(int i=0; i<32; i++) { |
lelect | 5:1f8409ee8850 | 377 | color=*(ptr+i); |
lelect | 5:1f8409ee8850 | 378 | color=(color>>2)&0x3F; |
lelect | 8:6d98c8cd8045 | 379 | setBus(color); |
lelect | 3:aa3762e0dfee | 380 | _sclk=1; |
lelect | 3:aa3762e0dfee | 381 | _sclk=0; |
lelect | 8:6d98c8cd8045 | 382 | #if 0 |
lelect | 8:6d98c8cd8045 | 383 | #ifdef DEBUG |
lelect | 8:6d98c8cd8045 | 384 | if(int(readBus)==color) { |
lelect | 8:6d98c8cd8045 | 385 | log_debug(" %02x",int(_dataBus)); |
lelect | 8:6d98c8cd8045 | 386 | } else { |
lelect | 8:6d98c8cd8045 | 387 | _dataBus=color; |
lelect | 8:6d98c8cd8045 | 388 | log_debug(" (%x->%x)%s",color,int(_dataBus),"\0"); |
lelect | 8:6d98c8cd8045 | 389 | } |
lelect | 8:6d98c8cd8045 | 390 | #endif |
lelect | 8:6d98c8cd8045 | 391 | #endif |
lelect | 8:6d98c8cd8045 | 392 | } |
lelect | 8:6d98c8cd8045 | 393 | buffptr += _rawWidth; |
lelect | 8:6d98c8cd8045 | 394 | } else { |
lelect | 8:6d98c8cd8045 | 395 | //((ptr[i]<<4)|((ptr[i+32]<<2)&0x0C)|((ptr[i+64])&0x03)); |
lelect | 8:6d98c8cd8045 | 396 | for(int i=0; i<32; i++) { |
lelect | 8:6d98c8cd8045 | 397 | color=0x3F&((ptr[i]<<4)|((ptr[i+32]<<2)&0x0C)|((ptr[i+64])&0x03)); |
lelect | 8:6d98c8cd8045 | 398 | setBus(color); |
lelect | 8:6d98c8cd8045 | 399 | _sclk=1; |
lelect | 8:6d98c8cd8045 | 400 | _sclk=0; |
lelect | 8:6d98c8cd8045 | 401 | #if 0 |
lelect | 4:0ff6053c4bb2 | 402 | #ifdef DEBUG |
lelect | 4:0ff6053c4bb2 | 403 | if(int(_dataBus)==color) { |
lelect | 4:0ff6053c4bb2 | 404 | log_debug(" %02x",int(_dataBus)); |
lelect | 4:0ff6053c4bb2 | 405 | } else { |
lelect | 4:0ff6053c4bb2 | 406 | _dataBus=color; |
lelect | 4:0ff6053c4bb2 | 407 | log_debug(" (%x->%x)%s",color,int(_dataBus),"\0"); |
lelect | 4:0ff6053c4bb2 | 408 | } |
lelect | 4:0ff6053c4bb2 | 409 | #endif |
lelect | 4:0ff6053c4bb2 | 410 | #endif |
lelect | 0:06d9443a018f | 411 | } |
lelect | 0:06d9443a018f | 412 | } |
lelect | 5:1f8409ee8850 | 413 | |
lelect | 0:06d9443a018f | 414 | } |
lelect | 4:0ff6053c4bb2 | 415 |