Adafruit Led Matrix 64x32 Lib

Dependents:   Adafruit-64x32-PWM-Demo

LedMatrix.cpp

Committer:
davidr99
Date:
2017-10-11
Revision:
0:cdc5e3a73147
Child:
1:99abd7449a45

File content as of revision 0:cdc5e3a73147:

#include "LedMatrix.h"

BusOut ABCD(D5,D6,D7,D8); // Row address.
DigitalOut LAT(D3);    //  Data latch    - active low (pulse up after data load)
DigitalOut OE(D4);     //  Output enable - active low (hold high during data load, bring low after LAT pulse)

DigitalOut CLK(D9);    //  Data clock    - rising edge
DigitalOut R1(D10);     //  RED   Serial in for upper half
DigitalOut G1(D11);      //  GREEN Serial in for upper half
DigitalOut B1(D12);      //  BLUE  Serial in for upper half
DigitalOut R2(D13);     //  RED   Serial in for lower half
DigitalOut G2(A0);      //  GREEN Serial in for lower half
DigitalOut B2(A1);      //  BLUE  Serial in for lower half

LedMatrix::LedMatrix() : Adafruit_GFX(WIDTH, HEIGHT)
{
}

// Promote 3/3/3 RGB to Adafruit_GFX 5/6/5
uint16_t LedMatrix::Color333(uint8_t r, uint8_t g, uint8_t b) {
  // RRRrrGGGgggBBBbb
  return ((r & 0x7) << 13) | ((r & 0x6) << 10) |
         ((g & 0x7) <<  8) | ((g & 0x7) <<  5) |
         ((b & 0x7) <<  2) | ((b & 0x6) >>  1);
}

// Promote 4/4/4 RGB to Adafruit_GFX 5/6/5
uint16_t LedMatrix::Color444(uint8_t r, uint8_t g, uint8_t b) {
  // RRRRrGGGGggBBBBb
  return ((r & 0xF) << 12) | ((r & 0x8) << 8) |
         ((g & 0xF) <<  7) | ((g & 0xC) << 3) |
         ((b & 0xF) <<  1) | ((b & 0x8) >> 3);
}

// Demote 8/8/8 to Adafruit_GFX 5/6/5
// If no gamma flag passed, assume linear color
uint16_t LedMatrix::Color888(uint8_t r, uint8_t g, uint8_t b) {
  return ((uint16_t)(r & 0xF8) << 8) | ((uint16_t)(g & 0xFC) << 3) | (b >> 3);
}

// 8/8/8 -> gamma -> 5/6/5
uint16_t LedMatrix::Color888(
  uint8_t r, uint8_t g, uint8_t b, bool gflag) {
  if(gflag) { // Gamma-corrected color?
    r = gamma[r]; // Gamma correction table maps
    g = gamma[g]; // 8-bit input to 4-bit output
    b = gamma[b];
    return ((uint16_t)r << 12) | ((uint16_t)(r & 0x8) << 8) | // 4/4/4->5/6/5
           ((uint16_t)g <<  7) | ((uint16_t)(g & 0xC) << 3) |
           (          b <<  1) | (           b        >> 3);
  } // else linear (uncorrected) color
  return ((uint16_t)(r & 0xF8) << 8) | ((uint16_t)(g & 0xFC) << 3) | (b >> 3);
}

uint16_t LedMatrix::ColorHSV(
  long hue, uint8_t sat, uint8_t val, bool gflag) {

  uint8_t  r, g, b, lo;
  uint16_t s1, v1;

  // Hue
  hue %= 1536;             // -1535 to +1535
  if(hue < 0) hue += 1536; //     0 to +1535
  lo = hue & 255;          // Low byte  = primary/secondary color mix
  switch(hue >> 8) {       // High byte = sextant of colorwheel
    case 0 : r = 255     ; g =  lo     ; b =   0     ; break; // R to Y
    case 1 : r = 255 - lo; g = 255     ; b =   0     ; break; // Y to G
    case 2 : r =   0     ; g = 255     ; b =  lo     ; break; // G to C
    case 3 : r =   0     ; g = 255 - lo; b = 255     ; break; // C to B
    case 4 : r =  lo     ; g =   0     ; b = 255     ; break; // B to M
    default: r = 255     ; g =   0     ; b = 255 - lo; break; // M to R
  }

  // Saturation: add 1 so range is 1 to 256, allowig a quick shift operation
  // on the result rather than a costly divide, while the type upgrade to int
  // avoids repeated type conversions in both directions.
  s1 = sat + 1;
  r  = 255 - (((255 - r) * s1) >> 8);
  g  = 255 - (((255 - g) * s1) >> 8);
  b  = 255 - (((255 - b) * s1) >> 8);

  // Value (brightness) & 16-bit color reduction: similar to above, add 1
  // to allow shifts, and upgrade to int makes other conversions implicit.
  v1 = val + 1;
  if(gflag) { // Gamma-corrected color?
    r = gamma[(r * v1) >> 8]; // Gamma correction table maps
    g = gamma[(g * v1) >> 8]; // 8-bit input to 4-bit output
    b = gamma[(b * v1) >> 8];
  } else { // linear (uncorrected) color
    r = (r * v1) >> 12; // 4-bit results
    g = (g * v1) >> 12;
    b = (b * v1) >> 12;
  }
  return (r << 12) | ((r & 0x8) << 8) | // 4/4/4 -> 5/6/5
         (g <<  7) | ((g & 0xC) << 3) |
         (b <<  1) | ( b        >> 3);
}


void LedMatrix::drawPixel(int16_t x, int16_t y, uint16_t color)
{
    Pset(x, y, color);
}

void LedMatrix::Init()
{
    // Set up things to a known state
    CLK = LOW;
    LAT = LOW;
    OE = HIGH; //display off
    ABCD = 0;
    plane=0;
}

void LedMatrix::WrRow(unsigned char Row)
{
    // Write specified row (and row+8) to display. Valid input: 0 to 7.
    ABCD=(HEIGHT_DEV_2-1)-Row; // Set row address
    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.
        char val = gm[col][Row][plane];
        
        R1 = (val & 1); // Red bit, upper half
        G1 = (val & 2); // Green bit, upper half
        B1 = (val & 4); // Blue bit, upper half
        
        R2 = (val & 8); // Red bit, lower half
        G2 = (val & 16); // Green bit, lower half
        B2 = (val & 32); // Blue bit, lower half
        CLK = HIGH;                 // tick (clock bit in)
        CLK = LOW;                  // tock
    }
    LAT = HIGH; // Latch entire row
    LAT = LOW;
}

void LedMatrix::Pset(int16_t x, int16_t y, uint16_t c)
{
    int r, g, b;
    
    r =  c >> 12;        // RRRRrggggggbbbbb
    g = (c >>  7) & 0xF; // rrrrrGGGGggbbbbb
    b = (c >>  1) & 0xF; // rrrrrggggggBBBBb
    
    for(int p=0;p<PLANES;p++)
    {
        if (y >= HEIGHT_DEV_2)
        {
            // Keep last 3 bits
            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);
        }
        else
        {
            // keep first 3 bits
            gm[x][y][p] = (gm[x][y][p] & 0b000111) + ((((r >> p) & 1) + (((g << 1) >> p) & 2) + (((b << 2) >> p) & 4)) << 3);
        }            
    }
}

void LedMatrix::Paint()
{
    if (plane >= (PLANES - 1))
    {
        plane = 0;
    }
    else
    {
        plane++;
    }
        
    // Write graphics memory to display
    for(int Row=0; Row<HEIGHT_DEV_2; Row++) {
        OE = HIGH; // Disable output
        WrRow(Row);
        OE = LOW; // Enable output
        wait_us(2 * (1 << plane)); // Wasting some time. Use for whatever else. Probably better with a ticker for the display refresh.
    }
    OE = HIGH; // Disable output
}