Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: Adafruit-GFX
RGBmatrixPanel.cpp
00001 #define DEBUG 00002 #undef DEBUG 00003 #include "RGBmatrixPanel.h" 00004 #include "gamma.h" 00005 00006 #define nPlanes 4 00007 00008 // The fact that the display driver interrupt stuff is tied to the 00009 // singular Timer1 doesn't really take well to object orientation with 00010 // multiple RGBmatrixPanel instances. The solution at present is to 00011 // allow instances, but only one is active at any given time, via its 00012 // begin() method. The implementation is still incomplete in parts; 00013 // the prior active panel really should be gracefully disabled, and a 00014 // stop() method should perhaps be added...assuming multiple instances 00015 // are even an actual need. 00016 //static RGBmatrixPanel *activePanel = NULL; 00017 00018 // Code common to both the 16x32 and 32x32 constructors: 00019 void RGBmatrixPanel::init(uint8_t rows, bool dbuf) 00020 { 00021 nRows = rows; // Number of multiplexed rows; actual height is 2X this 00022 // Allocate and initialize matrix buffer: 00023 int buffsize = 32*nRows*3, // x3 = 3 bytes holds 4 planes "packed" 00024 allocsize = (dbuf == true) ? (buffsize * 2) : buffsize; 00025 if(NULL == (matrixbuff[0] = (uint8_t *)malloc(allocsize))) return; 00026 memset(matrixbuff[0], 0, allocsize); 00027 // If not double-buffered, both buffers then point to the same address: 00028 matrixbuff[1] = (dbuf == true) ? &matrixbuff[0][buffsize] : matrixbuff[0]; 00029 00030 plane = nPlanes - 1; 00031 row = nRows - 1; 00032 swapflag = false; 00033 backindex = 0; // Array index of back buffer 00034 } 00035 00036 // Constructor for 16x32 panel: 00037 RGBmatrixPanel::RGBmatrixPanel(PinName r1,PinName g1,PinName b1,PinName r2,PinName g2,PinName b2,PinName a,PinName b, PinName c, PinName sclk, PinName latch, PinName oe, bool dbuf) 00038 :Adafruit_GFX(32, 16), 00039 _dataBus(r1,g1,b1,r2,g2,b2), 00040 _rowBus(a,b,c), 00041 _d(NC), 00042 _sclk(sclk), 00043 _latch(latch), 00044 _oe(oe) 00045 { 00046 init(8, dbuf); 00047 } 00048 /* 00049 // Constructor for 32x32 panel: 00050 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) 00051 :Adafruit_GFX(32, 32), 00052 _dataBus(r1,g1,b1,r2,g2,b2), 00053 _rowBus(a,b,c), 00054 _d(d),// Init 32x32-specific elements: 00055 _sclk(sclk), 00056 _latch(latch), 00057 _oe(oe) 00058 { 00059 init(16,dbuf); 00060 } 00061 */ 00062 void RGBmatrixPanel::begin(void) 00063 { 00064 00065 backindex = 0; // Back buffer 00066 buffptr = matrixbuff[1 - backindex]; // -> front buffer 00067 // activePanel = this; // For interrupt hander 00068 00069 // Set up Timer for interrupt: 00070 #ifndef DEBUG 00071 _refresh.attach_us(this,(&RGBmatrixPanel::updateDisplay ),100); //updateDisplay() called every 1ms 00072 #else 00073 _refresh.attach(this,(&RGBmatrixPanel::updateDisplay ),0.5); //updateDisplay() called every 2s 00074 #endif 00075 } 00076 00077 // Original RGBmatrixPanel library used 3/3/3 color. Later version used 00078 // 4/4/4. Then Adafruit_GFX (core library used across all Adafruit 00079 // display devices now) standardized on 5/6/5. The matrix still operates 00080 // internally on 4/4/4 color, but all the graphics functions are written 00081 // to expect 5/6/5...the matrix lib will truncate the color components as 00082 // needed when drawing. These next functions are mostly here for the 00083 // benefit of older code using one of the original color formats. 00084 00085 // Promote 3/3/3 RGB to Adafruit_GFX 5/6/5 00086 uint16_t RGBmatrixPanel::Color333(uint8_t r, uint8_t g, uint8_t b) 00087 { 00088 // RRRrrGGGgggBBBbb 00089 return ((r & 0x7) << 13) | ((r & 0x6) << 10) | 00090 ((g & 0x7) << 8) | ((g & 0x7) << 5) | 00091 ((b & 0x7) << 2) | ((b & 0x6) >> 1); 00092 } 00093 00094 // Promote 4/4/4 RGB to Adafruit_GFX 5/6/5 00095 uint16_t RGBmatrixPanel::Color444(uint8_t r, uint8_t g, uint8_t b) 00096 { 00097 // RRRRrGGGGggBBBBb 00098 return ((r & 0xF) << 12) | ((r & 0x8) << 8) | 00099 ((g & 0xF) << 7) | ((g & 0xC) << 3) | 00100 ((b & 0xF) << 1) | ((b & 0x8) >> 3); 00101 } 00102 00103 // Demote 8/8/8 to Adafruit_GFX 5/6/5 00104 // If no gamma flag passed, assume linear color 00105 uint16_t RGBmatrixPanel::Color888(uint8_t r, uint8_t g, uint8_t b) 00106 { 00107 return ((r & 0xF8) << 11) | ((g & 0xFC) << 5) | (b >> 3); 00108 } 00109 00110 // 8/8/8 -> gamma -> 5/6/5 00111 uint16_t RGBmatrixPanel::Color888(uint8_t r, uint8_t g, uint8_t b, bool gflag) 00112 { 00113 if(gflag) { // Gamma-corrected color? 00114 r = gamma[r]; // Gamma correction table maps 00115 g = gamma[g]; // 8-bit input to 4-bit output 00116 b = gamma[b]; 00117 return (r << 12) | ((r & 0x8) << 8) | // 4/4/4 -> 5/6/5 00118 (g << 7) | ((g & 0xC) << 3) | 00119 (b << 1) | ( b >> 3); 00120 } // else linear (uncorrected) color 00121 return ((r & 0xF8) << 11) | ((g & 0xFC) << 5) | (b >> 3); 00122 } 00123 00124 uint16_t RGBmatrixPanel::ColorHSV(long hue, uint8_t sat, uint8_t val, bool gflag) 00125 { 00126 00127 uint8_t r, g, b, lo; 00128 uint16_t s1, v1; 00129 00130 // Hue 00131 hue %= 1536; // -1535 to +1535 00132 if(hue < 0) hue += 1536; // 0 to +1535 00133 lo = hue & 255; // Low byte = primary/secondary color mix 00134 switch(hue >> 8) { // High byte = sextant of colorwheel 00135 case 0 : 00136 r = 255 ; 00137 g = lo ; 00138 b = 0 ; 00139 break; // R to Y 00140 case 1 : 00141 r = 255 - lo; 00142 g = 255 ; 00143 b = 0 ; 00144 break; // Y to G 00145 case 2 : 00146 r = 0 ; 00147 g = 255 ; 00148 b = lo ; 00149 break; // G to C 00150 case 3 : 00151 r = 0 ; 00152 g = 255 - lo; 00153 b = 255 ; 00154 break; // C to B 00155 case 4 : 00156 r = lo ; 00157 g = 0 ; 00158 b = 255 ; 00159 break; // B to M 00160 default: 00161 r = 255 ; 00162 g = 0 ; 00163 b = 255 - lo; 00164 break; // M to R 00165 } 00166 00167 // Saturation: add 1 so range is 1 to 256, allowig a quick shift operation 00168 // on the result rather than a costly divide, while the type upgrade to int 00169 // avoids repeated type conversions in both directions. 00170 s1 = sat + 1; 00171 r = 255 - (((255 - r) * s1) >> 8); 00172 g = 255 - (((255 - g) * s1) >> 8); 00173 b = 255 - (((255 - b) * s1) >> 8); 00174 00175 // Value (brightness) & 16-bit color reduction: similar to above, add 1 00176 // to allow shifts, and upgrade to int makes other conversions implicit. 00177 v1 = val + 1; 00178 if(gflag) { // Gamma-corrected color? 00179 r = gamma[(r * v1) >> 8]; // Gamma correction table maps 00180 g = gamma[(g * v1) >> 8]; // 8-bit input to 4-bit output 00181 b = gamma[(b * v1) >> 8]; 00182 //before pgm_read_byte(&gamma[(b * v1) >> 8]) 00183 } else { // linear (uncorrected) color 00184 r = (r * v1) >> 12; // 4-bit results 00185 g = (g * v1) >> 12; 00186 b = (b * v1) >> 12; 00187 } 00188 return (r << 12) | ((r & 0x8) << 8) | // 4/4/4 -> 5/6/5 00189 (g << 7) | ((g & 0xC) << 3) | 00190 (b << 1) | ( b >> 3); 00191 } 00192 uint16_t RGBmatrixPanel::ColorHSV(float hue, float sat, float val, bool gflag) 00193 { 00194 int i = floor(hue * 6); 00195 float f = hue*6-i; 00196 float p = val*(1-sat); 00197 float q = val*(1-f*sat); 00198 float t = val*(1-(1-f)*sat); 00199 float r = 0,g=0,b=0; 00200 switch(i % 6) { 00201 case 0: 00202 r = val; 00203 g = t; 00204 b = p; 00205 break; 00206 case 1: 00207 r = q; 00208 g = val; 00209 b = p; 00210 break; 00211 case 2: 00212 r = p; 00213 g = val; 00214 b = t; 00215 break; 00216 case 3: 00217 r = p; 00218 g = q; 00219 b = val; 00220 break; 00221 case 4: 00222 r = t; 00223 g = p; 00224 b = val; 00225 break; 00226 case 5: 00227 r = val; 00228 g = p; 00229 b = q; 00230 break; 00231 } 00232 return Color888(r*255,g*255,b*255,gflag); 00233 } 00234 void RGBmatrixPanel::drawPixel(int16_t x, int16_t y, uint16_t c) 00235 { 00236 uint8_t r, g, b, bit, limit, *ptr; 00237 if((x < 0) || (x >= _width) || (y < 0) || (y >= _height)) return; 00238 switch(rotation) { 00239 case 1: 00240 swap(x, y); 00241 x = _rawWidth - 1 - x; 00242 break; 00243 case 2: 00244 x = _rawWidth - 1 - x; 00245 y = _rawHeight - 1 - y; 00246 break; 00247 case 3: 00248 swap(x, y); 00249 y = _rawHeight - 1 - y; 00250 break; 00251 } 00252 00253 // Adafruit_GFX uses 16-bit color in 5/6/5 format, while matrix needs 00254 // 4/4/4. Pluck out relevant bits while separating into R,G,B: 00255 r = c >> 12; // RRRRrggggggbbbbb 00256 g = (c >> 7) & 0xF; // rrrrrGGGGggbbbbb 00257 b = (c >> 1) & 0xF; // rrrrrggggggBBBBb 00258 // Loop counter stuff 00259 bit = 2; 00260 limit = 1 << nPlanes; 00261 if(y < nRows) { 00262 // Data for the upper half of the display is stored in the lower bits of each byte. 00263 ptr = &matrixbuff[backindex][y*_rawWidth*(nPlanes-1) + x]; // Base addr 00264 // Plane 0 is a tricky case -- its data is spread about, stored in least two bits not used by the other planes. 00265 ptr[64] &= ~(_BV(1)|_BV(0)); // Plane 0 R,G mask(0b11111100) out in one op 00266 if(r & 1) ptr[64] |= _BV(0); // Plane 0 R: 64 bytes ahead, bit 0 00267 if(g & 1) ptr[64] |= _BV(1); // Plane 0 G: 64 bytes ahead, bit 1 00268 if(b & 1) ptr[32] |= _BV(0); // Plane 0 B: 32 bytes ahead, bit 0 00269 else ptr[32] &= ~_BV(0); // Plane 0 B unset; mask out 00270 // The remaining three image planes are more normal-ish. 00271 // Data is stored in the high 6 bits so it can be quickly 00272 // copied to the DATAPORT register w/6 output lines. 00273 for(; bit < limit; bit <<= 1) { 00274 *ptr &= ~(_BV(4)|_BV(3)|_BV(2)) ; // Mask(0b11100011) out R,G,B in one op 00275 if(r & bit) *ptr |= _BV(2); // Plane N R: bit 2 00276 if(g & bit) *ptr |= _BV(3); // Plane N G: bit 3 00277 if(b & bit) *ptr |= _BV(4); // Plane N B: bit 4 00278 ptr += _rawWidth; // Advance to next bit plane 00279 } 00280 } else { 00281 // Data for the lower half of the display is stored in the upper bits, except for the plane 0 stuff, using 2 least bits. 00282 ptr = &matrixbuff[backindex][(y-nRows)*_rawWidth*(nPlanes-1) + x]; 00283 *ptr &= ~(_BV(1)|_BV(0)); // Plane 0 G,B mask out in one op 00284 if(r & 1) ptr[32] |= _BV(1); // Plane 0 R: 32 bytes ahead, bit 1 00285 else ptr[32] &= ~_BV(1); // Plane 0 R unset; mask out 00286 if(g & 1) *ptr |= _BV(0); // Plane 0 G: bit 0 00287 if(b & 1) *ptr |= _BV(1); // Plane 0 B: bit 0 00288 for(; bit < limit; bit <<= 1) { 00289 *ptr &= ~(_BV(7)|_BV(6)|_BV(5)); // Mask out R,G,B in one op 00290 if(r & bit) *ptr |= _BV(5); // Plane N R: bit 5 00291 if(g & bit) *ptr |= _BV(6); // Plane N G: bit 6 00292 if(b & bit) *ptr |= _BV(7); // Plane N B: bit 7 00293 ptr += _rawWidth; // Advance to next bit plane 00294 } 00295 } 00296 } 00297 00298 void RGBmatrixPanel::fillScreen(uint16_t c) 00299 { 00300 if((c == 0x0000) || (c == 0xffff)) { 00301 // For black or white, all bits in frame buffer will be identically 00302 // set or unset (regardless of weird bit packing), so it's OK to just 00303 // quickly memset the whole thing: 00304 memset(matrixbuff[backindex], c, 32 * nRows * 3); 00305 } else { 00306 // Otherwise, need to handle it the long way: 00307 Adafruit_GFX::fillScreen(c); 00308 } 00309 } 00310 00311 // Return address of back buffer -- can then load/store data directly 00312 uint8_t *RGBmatrixPanel::backBuffer() 00313 { 00314 return matrixbuff[backindex]; 00315 } 00316 00317 // For smooth animation -- drawing always takes place in the "back" buffer; 00318 // this method pushes it to the "front" for display. Passing "true", the 00319 // updated display contents are then copied to the new back buffer and can 00320 // be incrementally modified. If "false", the back buffer then contains 00321 // the old front buffer contents -- your code can either clear this or 00322 // draw over every pixel. (No effect if double-buffering is not enabled.) 00323 void RGBmatrixPanel::swapBuffers (bool copy) 00324 { 00325 if(matrixbuff[0] != matrixbuff[1]) { 00326 // To avoid 'tearing' display, actual swap takes place in the interrupt 00327 // handler, at the end of a complete screen refresh cycle. 00328 swapflag = true; // Set flag here, then... 00329 while(swapflag == true) wait_ms(1); // wait for interrupt to clear it 00330 if(copy == true) { 00331 memcpy(matrixbuff[backindex], matrixbuff[1-backindex], 32 * nRows * 3); 00332 } 00333 } 00334 } 00335 00336 // Dump display contents to the Serial Monitor, adding some formatting to 00337 // simplify copy-and-paste of data as a PROGMEM-embedded image for another 00338 // sketch. If using multiple dumps this way, you'll need to edit the 00339 // output to change the 'img' name for each. Data can then be loaded 00340 // back into the display using a pgm_read_byte() loop. 00341 void RGBmatrixPanel::dumpMatrix(void) 00342 { 00343 #ifdef DEBUG 00344 log_debug("\r\ncall dumpMatrix%s","\r\n"); 00345 int buffsize=32*nRows*3; 00346 for(int item=0; item<buffsize; item++) { 00347 log_debug("0x%02X",matrixbuff[backindex][item]); 00348 if((item%32)==31) log_debug(",\r\n"); 00349 else log_debug(","); 00350 } 00351 log_debug("%s","\r\n\r\n"); 00352 #endif 00353 00354 } 00355 00356 void RGBmatrixPanel::updateDisplay (void) 00357 { 00358 _oe=1; 00359 _latch=1; 00360 if(++plane >= nPlanes) { // Advance plane counter. Maxed out? 00361 plane = 0; // Yes, reset to plane 0, and 00362 if(++row >= nRows) { // advance row counter. Maxed out? 00363 row= 0; // Yes, reset row counter, then... 00364 if(swapflag == true) { // Swap front/back buffers if requested 00365 backindex = 1 - backindex; 00366 swapflag = false; 00367 } 00368 buffptr = matrixbuff[1-backindex]; // Reset into front buffer 00369 } 00370 } else if(plane == 1) { 00371 _rowBus.write(row); 00372 } 00373 _oe=0; 00374 _latch=0; 00375 if(plane > 0) { 00376 for(int i=0; i<32; i++) { 00377 _dataBus.write((*(buffptr+i)>>2)); 00378 _sclk=1; 00379 _sclk=0; 00380 } 00381 buffptr += _rawWidth; 00382 } else { 00383 for(int i=0; i<32; i++) { 00384 _dataBus.write(((buffptr[i]<<4)|((buffptr[i+32]<<2)&0x0C)|((buffptr[i+64])&0x03))); 00385 _sclk=1; 00386 _sclk=0; 00387 } 00388 } 00389 00390 } 00391
Generated on Tue Jul 12 2022 15:51:16 by
1.7.2