Adafruit Led Matrix 64x32 Lib
Dependents: Adafruit-64x32-PWM-Demo
LedMatrix.cpp@0:cdc5e3a73147, 2017-10-11 (annotated)
- Committer:
- davidr99
- Date:
- Wed Oct 11 00:36:17 2017 +0000
- Revision:
- 0:cdc5e3a73147
- Child:
- 1:99abd7449a45
Changed over to use Adafruit GFX
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
davidr99 | 0:cdc5e3a73147 | 1 | #include "LedMatrix.h" |
davidr99 | 0:cdc5e3a73147 | 2 | |
davidr99 | 0:cdc5e3a73147 | 3 | BusOut ABCD(D5,D6,D7,D8); // Row address. |
davidr99 | 0:cdc5e3a73147 | 4 | DigitalOut LAT(D3); // Data latch - active low (pulse up after data load) |
davidr99 | 0:cdc5e3a73147 | 5 | DigitalOut OE(D4); // Output enable - active low (hold high during data load, bring low after LAT pulse) |
davidr99 | 0:cdc5e3a73147 | 6 | |
davidr99 | 0:cdc5e3a73147 | 7 | DigitalOut CLK(D9); // Data clock - rising edge |
davidr99 | 0:cdc5e3a73147 | 8 | DigitalOut R1(D10); // RED Serial in for upper half |
davidr99 | 0:cdc5e3a73147 | 9 | DigitalOut G1(D11); // GREEN Serial in for upper half |
davidr99 | 0:cdc5e3a73147 | 10 | DigitalOut B1(D12); // BLUE Serial in for upper half |
davidr99 | 0:cdc5e3a73147 | 11 | DigitalOut R2(D13); // RED Serial in for lower half |
davidr99 | 0:cdc5e3a73147 | 12 | DigitalOut G2(A0); // GREEN Serial in for lower half |
davidr99 | 0:cdc5e3a73147 | 13 | DigitalOut B2(A1); // BLUE Serial in for lower half |
davidr99 | 0:cdc5e3a73147 | 14 | |
davidr99 | 0:cdc5e3a73147 | 15 | LedMatrix::LedMatrix() : Adafruit_GFX(WIDTH, HEIGHT) |
davidr99 | 0:cdc5e3a73147 | 16 | { |
davidr99 | 0:cdc5e3a73147 | 17 | } |
davidr99 | 0:cdc5e3a73147 | 18 | |
davidr99 | 0:cdc5e3a73147 | 19 | // Promote 3/3/3 RGB to Adafruit_GFX 5/6/5 |
davidr99 | 0:cdc5e3a73147 | 20 | uint16_t LedMatrix::Color333(uint8_t r, uint8_t g, uint8_t b) { |
davidr99 | 0:cdc5e3a73147 | 21 | // RRRrrGGGgggBBBbb |
davidr99 | 0:cdc5e3a73147 | 22 | return ((r & 0x7) << 13) | ((r & 0x6) << 10) | |
davidr99 | 0:cdc5e3a73147 | 23 | ((g & 0x7) << 8) | ((g & 0x7) << 5) | |
davidr99 | 0:cdc5e3a73147 | 24 | ((b & 0x7) << 2) | ((b & 0x6) >> 1); |
davidr99 | 0:cdc5e3a73147 | 25 | } |
davidr99 | 0:cdc5e3a73147 | 26 | |
davidr99 | 0:cdc5e3a73147 | 27 | // Promote 4/4/4 RGB to Adafruit_GFX 5/6/5 |
davidr99 | 0:cdc5e3a73147 | 28 | uint16_t LedMatrix::Color444(uint8_t r, uint8_t g, uint8_t b) { |
davidr99 | 0:cdc5e3a73147 | 29 | // RRRRrGGGGggBBBBb |
davidr99 | 0:cdc5e3a73147 | 30 | return ((r & 0xF) << 12) | ((r & 0x8) << 8) | |
davidr99 | 0:cdc5e3a73147 | 31 | ((g & 0xF) << 7) | ((g & 0xC) << 3) | |
davidr99 | 0:cdc5e3a73147 | 32 | ((b & 0xF) << 1) | ((b & 0x8) >> 3); |
davidr99 | 0:cdc5e3a73147 | 33 | } |
davidr99 | 0:cdc5e3a73147 | 34 | |
davidr99 | 0:cdc5e3a73147 | 35 | // Demote 8/8/8 to Adafruit_GFX 5/6/5 |
davidr99 | 0:cdc5e3a73147 | 36 | // If no gamma flag passed, assume linear color |
davidr99 | 0:cdc5e3a73147 | 37 | uint16_t LedMatrix::Color888(uint8_t r, uint8_t g, uint8_t b) { |
davidr99 | 0:cdc5e3a73147 | 38 | return ((uint16_t)(r & 0xF8) << 8) | ((uint16_t)(g & 0xFC) << 3) | (b >> 3); |
davidr99 | 0:cdc5e3a73147 | 39 | } |
davidr99 | 0:cdc5e3a73147 | 40 | |
davidr99 | 0:cdc5e3a73147 | 41 | // 8/8/8 -> gamma -> 5/6/5 |
davidr99 | 0:cdc5e3a73147 | 42 | uint16_t LedMatrix::Color888( |
davidr99 | 0:cdc5e3a73147 | 43 | uint8_t r, uint8_t g, uint8_t b, bool gflag) { |
davidr99 | 0:cdc5e3a73147 | 44 | if(gflag) { // Gamma-corrected color? |
davidr99 | 0:cdc5e3a73147 | 45 | r = gamma[r]; // Gamma correction table maps |
davidr99 | 0:cdc5e3a73147 | 46 | g = gamma[g]; // 8-bit input to 4-bit output |
davidr99 | 0:cdc5e3a73147 | 47 | b = gamma[b]; |
davidr99 | 0:cdc5e3a73147 | 48 | return ((uint16_t)r << 12) | ((uint16_t)(r & 0x8) << 8) | // 4/4/4->5/6/5 |
davidr99 | 0:cdc5e3a73147 | 49 | ((uint16_t)g << 7) | ((uint16_t)(g & 0xC) << 3) | |
davidr99 | 0:cdc5e3a73147 | 50 | ( b << 1) | ( b >> 3); |
davidr99 | 0:cdc5e3a73147 | 51 | } // else linear (uncorrected) color |
davidr99 | 0:cdc5e3a73147 | 52 | return ((uint16_t)(r & 0xF8) << 8) | ((uint16_t)(g & 0xFC) << 3) | (b >> 3); |
davidr99 | 0:cdc5e3a73147 | 53 | } |
davidr99 | 0:cdc5e3a73147 | 54 | |
davidr99 | 0:cdc5e3a73147 | 55 | uint16_t LedMatrix::ColorHSV( |
davidr99 | 0:cdc5e3a73147 | 56 | long hue, uint8_t sat, uint8_t val, bool gflag) { |
davidr99 | 0:cdc5e3a73147 | 57 | |
davidr99 | 0:cdc5e3a73147 | 58 | uint8_t r, g, b, lo; |
davidr99 | 0:cdc5e3a73147 | 59 | uint16_t s1, v1; |
davidr99 | 0:cdc5e3a73147 | 60 | |
davidr99 | 0:cdc5e3a73147 | 61 | // Hue |
davidr99 | 0:cdc5e3a73147 | 62 | hue %= 1536; // -1535 to +1535 |
davidr99 | 0:cdc5e3a73147 | 63 | if(hue < 0) hue += 1536; // 0 to +1535 |
davidr99 | 0:cdc5e3a73147 | 64 | lo = hue & 255; // Low byte = primary/secondary color mix |
davidr99 | 0:cdc5e3a73147 | 65 | switch(hue >> 8) { // High byte = sextant of colorwheel |
davidr99 | 0:cdc5e3a73147 | 66 | case 0 : r = 255 ; g = lo ; b = 0 ; break; // R to Y |
davidr99 | 0:cdc5e3a73147 | 67 | case 1 : r = 255 - lo; g = 255 ; b = 0 ; break; // Y to G |
davidr99 | 0:cdc5e3a73147 | 68 | case 2 : r = 0 ; g = 255 ; b = lo ; break; // G to C |
davidr99 | 0:cdc5e3a73147 | 69 | case 3 : r = 0 ; g = 255 - lo; b = 255 ; break; // C to B |
davidr99 | 0:cdc5e3a73147 | 70 | case 4 : r = lo ; g = 0 ; b = 255 ; break; // B to M |
davidr99 | 0:cdc5e3a73147 | 71 | default: r = 255 ; g = 0 ; b = 255 - lo; break; // M to R |
davidr99 | 0:cdc5e3a73147 | 72 | } |
davidr99 | 0:cdc5e3a73147 | 73 | |
davidr99 | 0:cdc5e3a73147 | 74 | // Saturation: add 1 so range is 1 to 256, allowig a quick shift operation |
davidr99 | 0:cdc5e3a73147 | 75 | // on the result rather than a costly divide, while the type upgrade to int |
davidr99 | 0:cdc5e3a73147 | 76 | // avoids repeated type conversions in both directions. |
davidr99 | 0:cdc5e3a73147 | 77 | s1 = sat + 1; |
davidr99 | 0:cdc5e3a73147 | 78 | r = 255 - (((255 - r) * s1) >> 8); |
davidr99 | 0:cdc5e3a73147 | 79 | g = 255 - (((255 - g) * s1) >> 8); |
davidr99 | 0:cdc5e3a73147 | 80 | b = 255 - (((255 - b) * s1) >> 8); |
davidr99 | 0:cdc5e3a73147 | 81 | |
davidr99 | 0:cdc5e3a73147 | 82 | // Value (brightness) & 16-bit color reduction: similar to above, add 1 |
davidr99 | 0:cdc5e3a73147 | 83 | // to allow shifts, and upgrade to int makes other conversions implicit. |
davidr99 | 0:cdc5e3a73147 | 84 | v1 = val + 1; |
davidr99 | 0:cdc5e3a73147 | 85 | if(gflag) { // Gamma-corrected color? |
davidr99 | 0:cdc5e3a73147 | 86 | r = gamma[(r * v1) >> 8]; // Gamma correction table maps |
davidr99 | 0:cdc5e3a73147 | 87 | g = gamma[(g * v1) >> 8]; // 8-bit input to 4-bit output |
davidr99 | 0:cdc5e3a73147 | 88 | b = gamma[(b * v1) >> 8]; |
davidr99 | 0:cdc5e3a73147 | 89 | } else { // linear (uncorrected) color |
davidr99 | 0:cdc5e3a73147 | 90 | r = (r * v1) >> 12; // 4-bit results |
davidr99 | 0:cdc5e3a73147 | 91 | g = (g * v1) >> 12; |
davidr99 | 0:cdc5e3a73147 | 92 | b = (b * v1) >> 12; |
davidr99 | 0:cdc5e3a73147 | 93 | } |
davidr99 | 0:cdc5e3a73147 | 94 | return (r << 12) | ((r & 0x8) << 8) | // 4/4/4 -> 5/6/5 |
davidr99 | 0:cdc5e3a73147 | 95 | (g << 7) | ((g & 0xC) << 3) | |
davidr99 | 0:cdc5e3a73147 | 96 | (b << 1) | ( b >> 3); |
davidr99 | 0:cdc5e3a73147 | 97 | } |
davidr99 | 0:cdc5e3a73147 | 98 | |
davidr99 | 0:cdc5e3a73147 | 99 | |
davidr99 | 0:cdc5e3a73147 | 100 | void LedMatrix::drawPixel(int16_t x, int16_t y, uint16_t color) |
davidr99 | 0:cdc5e3a73147 | 101 | { |
davidr99 | 0:cdc5e3a73147 | 102 | Pset(x, y, color); |
davidr99 | 0:cdc5e3a73147 | 103 | } |
davidr99 | 0:cdc5e3a73147 | 104 | |
davidr99 | 0:cdc5e3a73147 | 105 | void LedMatrix::Init() |
davidr99 | 0:cdc5e3a73147 | 106 | { |
davidr99 | 0:cdc5e3a73147 | 107 | // Set up things to a known state |
davidr99 | 0:cdc5e3a73147 | 108 | CLK = LOW; |
davidr99 | 0:cdc5e3a73147 | 109 | LAT = LOW; |
davidr99 | 0:cdc5e3a73147 | 110 | OE = HIGH; //display off |
davidr99 | 0:cdc5e3a73147 | 111 | ABCD = 0; |
davidr99 | 0:cdc5e3a73147 | 112 | plane=0; |
davidr99 | 0:cdc5e3a73147 | 113 | } |
davidr99 | 0:cdc5e3a73147 | 114 | |
davidr99 | 0:cdc5e3a73147 | 115 | void LedMatrix::WrRow(unsigned char Row) |
davidr99 | 0:cdc5e3a73147 | 116 | { |
davidr99 | 0:cdc5e3a73147 | 117 | // Write specified row (and row+8) to display. Valid input: 0 to 7. |
davidr99 | 0:cdc5e3a73147 | 118 | ABCD=(HEIGHT_DEV_2-1)-Row; // Set row address |
davidr99 | 0:cdc5e3a73147 | 119 | for(int col=(WIDTH-1); col >= 0; col--) { // To daisychain more displays, I guess you would have to increase this counter to n*32 columns. Might mirror though. |
davidr99 | 0:cdc5e3a73147 | 120 | char val = gm[col][Row][plane]; |
davidr99 | 0:cdc5e3a73147 | 121 | |
davidr99 | 0:cdc5e3a73147 | 122 | R1 = (val & 1); // Red bit, upper half |
davidr99 | 0:cdc5e3a73147 | 123 | G1 = (val & 2); // Green bit, upper half |
davidr99 | 0:cdc5e3a73147 | 124 | B1 = (val & 4); // Blue bit, upper half |
davidr99 | 0:cdc5e3a73147 | 125 | |
davidr99 | 0:cdc5e3a73147 | 126 | R2 = (val & 8); // Red bit, lower half |
davidr99 | 0:cdc5e3a73147 | 127 | G2 = (val & 16); // Green bit, lower half |
davidr99 | 0:cdc5e3a73147 | 128 | B2 = (val & 32); // Blue bit, lower half |
davidr99 | 0:cdc5e3a73147 | 129 | CLK = HIGH; // tick (clock bit in) |
davidr99 | 0:cdc5e3a73147 | 130 | CLK = LOW; // tock |
davidr99 | 0:cdc5e3a73147 | 131 | } |
davidr99 | 0:cdc5e3a73147 | 132 | LAT = HIGH; // Latch entire row |
davidr99 | 0:cdc5e3a73147 | 133 | LAT = LOW; |
davidr99 | 0:cdc5e3a73147 | 134 | } |
davidr99 | 0:cdc5e3a73147 | 135 | |
davidr99 | 0:cdc5e3a73147 | 136 | void LedMatrix::Pset(int16_t x, int16_t y, uint16_t c) |
davidr99 | 0:cdc5e3a73147 | 137 | { |
davidr99 | 0:cdc5e3a73147 | 138 | int r, g, b; |
davidr99 | 0:cdc5e3a73147 | 139 | |
davidr99 | 0:cdc5e3a73147 | 140 | r = c >> 12; // RRRRrggggggbbbbb |
davidr99 | 0:cdc5e3a73147 | 141 | g = (c >> 7) & 0xF; // rrrrrGGGGggbbbbb |
davidr99 | 0:cdc5e3a73147 | 142 | b = (c >> 1) & 0xF; // rrrrrggggggBBBBb |
davidr99 | 0:cdc5e3a73147 | 143 | |
davidr99 | 0:cdc5e3a73147 | 144 | for(int p=0;p<PLANES;p++) |
davidr99 | 0:cdc5e3a73147 | 145 | { |
davidr99 | 0:cdc5e3a73147 | 146 | if (y >= HEIGHT_DEV_2) |
davidr99 | 0:cdc5e3a73147 | 147 | { |
davidr99 | 0:cdc5e3a73147 | 148 | // Keep last 3 bits |
davidr99 | 0:cdc5e3a73147 | 149 | gm[x][y - HEIGHT_DEV_2][p] = (gm[x][y - HEIGHT_DEV_2][p] & 0b111000) + ((r >> p) & 1) + (((g << 1) >> p) & 2) + (((b << 2) >> p) & 4); |
davidr99 | 0:cdc5e3a73147 | 150 | } |
davidr99 | 0:cdc5e3a73147 | 151 | else |
davidr99 | 0:cdc5e3a73147 | 152 | { |
davidr99 | 0:cdc5e3a73147 | 153 | // keep first 3 bits |
davidr99 | 0:cdc5e3a73147 | 154 | gm[x][y][p] = (gm[x][y][p] & 0b000111) + ((((r >> p) & 1) + (((g << 1) >> p) & 2) + (((b << 2) >> p) & 4)) << 3); |
davidr99 | 0:cdc5e3a73147 | 155 | } |
davidr99 | 0:cdc5e3a73147 | 156 | } |
davidr99 | 0:cdc5e3a73147 | 157 | } |
davidr99 | 0:cdc5e3a73147 | 158 | |
davidr99 | 0:cdc5e3a73147 | 159 | void LedMatrix::Paint() |
davidr99 | 0:cdc5e3a73147 | 160 | { |
davidr99 | 0:cdc5e3a73147 | 161 | if (plane >= (PLANES - 1)) |
davidr99 | 0:cdc5e3a73147 | 162 | { |
davidr99 | 0:cdc5e3a73147 | 163 | plane = 0; |
davidr99 | 0:cdc5e3a73147 | 164 | } |
davidr99 | 0:cdc5e3a73147 | 165 | else |
davidr99 | 0:cdc5e3a73147 | 166 | { |
davidr99 | 0:cdc5e3a73147 | 167 | plane++; |
davidr99 | 0:cdc5e3a73147 | 168 | } |
davidr99 | 0:cdc5e3a73147 | 169 | |
davidr99 | 0:cdc5e3a73147 | 170 | // Write graphics memory to display |
davidr99 | 0:cdc5e3a73147 | 171 | for(int Row=0; Row<HEIGHT_DEV_2; Row++) { |
davidr99 | 0:cdc5e3a73147 | 172 | OE = HIGH; // Disable output |
davidr99 | 0:cdc5e3a73147 | 173 | WrRow(Row); |
davidr99 | 0:cdc5e3a73147 | 174 | OE = LOW; // Enable output |
davidr99 | 0:cdc5e3a73147 | 175 | wait_us(2 * (1 << plane)); // Wasting some time. Use for whatever else. Probably better with a ticker for the display refresh. |
davidr99 | 0:cdc5e3a73147 | 176 | } |
davidr99 | 0:cdc5e3a73147 | 177 | OE = HIGH; // Disable output |
davidr99 | 0:cdc5e3a73147 | 178 | } |