Adafruit Led Matrix 64x32 Lib

Dependents:   Adafruit-64x32-PWM-Demo

LedMatrix.cpp

Committer:
davidr99
Date:
2017-10-24
Revision:
1:99abd7449a45
Parent:
0:cdc5e3a73147
Child:
2:e37a437cf602

File content as of revision 1:99abd7449a45:

#include "LedMatrix.h"
#include "FastIO.h"
#include "rtos.h"

#if (defined(TARGET_STM32F303K8))

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

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

#elif (defined(TARGET_STM32F767ZI))

BusOut ABCD(A0,A1,A2,A3); // Row address.
FastOut<PD_2> OE;     //  Output enable - active low (hold high during data load, bring low after LAT pulse)
FastOut<PG_2> LAT;    //  Data latch    - active low (pulse up after data load)
FastOut<PG_3> CLK;    //  Data clock    - rising edge

FastOut<PD_7> R1;     //  RED   Serial in for upper half
FastOut<PD_6> G1;      //  GREEN Serial in for upper half
FastOut<PD_5> B1;      //  BLUE  Serial in for upper half
FastOut<PD_4> R2;     //  RED   Serial in for lower half
FastOut<PD_3> G2;      //  GREEN Serial in for lower half
FastOut<A4> B2;      //  BLUE  Serial in for lower half

#endif

LedMatrix::LedMatrix() : Adafruit_GFX(WIDTH, HEIGHT)
{
    tickCount = 0;
    shownBuffer = 0;
    drawBuffer = 0;
    refreshed = false;
}

// 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 c)
{
    int r, g, b;
    
    r =  (c >> 10) & 0x1F;        // RRRRRgggggbbbbb
    g = (c >>  5) & 0x1F; // rrrrrGGGGGbbbbb
    b = c & 0x1F; // rrrrrgggggBBBBB
     
    for(int p=0;p<PLANES;p++)
    {
        if (y >= HEIGHT_DEV_2)
        {
            // Keep last 3 bits (B2G2R2b1g1r1)
            gm[drawBuffer][p][y - HEIGHT_DEV_2][x] = (gm[drawBuffer][p][y - HEIGHT_DEV_2][x] & 0b111000) + ((r >> p) & 1) + (((g >> p) & 1) << 1) + (((b >> p) & 1) << 2);
        }
        else
        {
            // keep first 3 bits (b2g2r2B1G1R1)
            gm[drawBuffer][p][y][x] = (gm[drawBuffer][p][y][x] & 0b000111) + ((((r >> p) & 1) + (((g << 1) >> p) & 2) + (((b << 2) >> p) & 4)) << 3);
        }            
    }
}

void LedMatrix::Init()
{
    // Set up things to a known state
    CLK = LOW;
    LAT = LOW;
    OE = HIGH; //display off
    ABCD = 0;
    plane=0;
    currRow=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
    char *val = (char *) &gm[shownBuffer][plane][Row][WIDTH-1];
    
    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.
        int value = *val;
        
        R1 = (value & 1); // Red bit, upper half
        G1 = (value & 2); // Green bit, upper half
        B1 = (value & 4); // Blue bit, upper half
        
        R2 = (value & 8); // Red bit, lower half
        G2 = (value & 16); // Green bit, lower half
        B2 = (value & 32); // Blue bit, lower half
        CLK = HIGH;                 // tick (clock bit in)
        for(int h=0;h<5;h++);
        CLK = LOW;                  // tock
        for(int h=0;h<5;h++);
        val--;
    }
    LAT = HIGH; // Latch entire row
    for(int h=0;h<5;h++);
    LAT = LOW;
}

void LedMatrix::CopyBuffer(char oldBuffer, char newBuffer)
{
    char *oldBuff = (char *) &gm[oldBuffer][0][0][0];
    char *newBuff = (char *) &gm[newBuffer][0][0][0];
    
    for(uint32_t buf = 0;buf<(PLANES * HEIGHT_DEV_2 * WIDTH);buf++)
    {
        *newBuff = *oldBuff;
        newBuff++;
        oldBuff++;
    }
}

void LedMatrix::SetDoubleBuffer(bool setDoubleBuffer)
{
    if (setDoubleBuffer)
    {
        shownBuffer = 1;
        drawBuffer = 0;   
    }
    else
    {
        shownBuffer = 0;
        drawBuffer = 0;
    }
}

void LedMatrix::Swap(bool copyBuffer)
{
    if (shownBuffer == 0)
    {
        shownBuffer = 1;
        drawBuffer = 0;
    }
    else
    {
        drawBuffer = 1;
        shownBuffer = 0;
    }
    
    if (copyBuffer)
    {
        CopyBuffer(shownBuffer, drawBuffer);
    }
}

// Break painting up into 8 rows to keep CPU int time down
void LedMatrix::Paint()
{      
    if ((plane >= 1 && tickCount >= (1 << (plane - 1)) && currRow == 0 && !refreshed)
        || (refreshed && tickCount >= (1 << (PLANES - 1))))
    {
        OE = HIGH; // Disable output
        if (refreshed)
        {
            tickCount = 0;
            refreshed = false;
        }
    }
    
    // Write graphics memory to display
    if (tickCount >= (1 << plane) && !refreshed)
    {
        tickCount = 0;
        OE = HIGH; // Disable output
        WrRow(currRow);
        OE = LOW; // Enable output
        currRow++;
    
        if (currRow >= HEIGHT_DEV_2)
        {
            currRow = 0;
            
            if (plane >= (PLANES - 1))
            {
                plane = 0;
                refreshed = true;
            }
            else
            {
                plane++;
            }
        }
    }
    else
    {
        tickCount++;
    }
}