Source code for the Curilights Controller. See http://www.saccade.com/writing/projects/CuriController/ for details.

Dependencies:   FatFileSystem mbed

This is the source code for the Curilights controller. This lets you interactively control a string of Curilights. It provides a simple click-wheel user interface for changing colors, brightness and behavior. It responds to movement and lighting.

Finished Controller

/media/uploads/isonno/nxp3872_controllerclose.jpg

System Block Diagram

/media/uploads/isonno/blockdiagram.png

NokiaLCD.cpp

Committer:
isonno
Date:
2013-02-11
Revision:
4:cfef06d8bb96
Parent:
0:6da5625a6946

File content as of revision 4:cfef06d8bb96:

/*
  NokiaLCD.cpp - Library for a Nokia LCD with the epson driver.
  Created by Thomas Jespersen, July 2009 (Originally Arduino Sketch by Gravitech.us)
  Released into the public domain.
  Reworked by J. P------- for the TI LM3S9B96
  Reworked again by J. P------- for the mbed

*/

#include "NokiaLCD.h"

// Define Software SPI Pin Signal

// Epson S1D15G10 Command Set 
#define DISON       0xaf
#define DISOFF      0xae
#define DISNOR      0xa6
#define DISINV      0xa7
#define COMSCN      0xbb
#define DISCTL      0xca
#define SLPIN       0x95
#define SLPOUT      0x94
#define PASET       0x75
#define CASET       0x15
#define DATCTL      0xbc
#define RGBSET8     0xce
#define RAMWR       0x5c
#define RAMRD       0x5d
#define PTLIN       0xa8
#define PTLOUT      0xa9
#define RMWIN       0xe0
#define RMWOUT      0xee
#define ASCSET      0xaa
#define SCSTART     0xab
#define OSCON       0xd1
#define OSCOFF      0xd2
#define PWRCTR      0x20
#define VOLCTR      0x81
#define VOLUP       0xd6
#define VOLDOWN     0xd7
#define TMPGRD      0x82
#define EPCTIN      0xcd
#define EPCOUT      0xcc
#define EPMWR       0xfc
#define EPMRD       0xfd
#define EPSRRD1     0x7c
#define EPSRRD2     0x7d
#define NOP         0x25

#include "SmallText.h"
#include "Splash.h"
#include "ColorWheel.h"
#include "NumSprites.h"
#include "f18TextData.h"

const sprite_data_t * NumSprites[] = {&N0_sprt, &N1_sprt,
                                      &N2_sprt, &N3_sprt,
                                      &N4_sprt, &N5_sprt,
                                      &N6_sprt, &N7_sprt,
                                      &N8_sprt, &N9_sprt };



CheapLCD::CheapLCD( PinName mosi, PinName sclk, PinName cs, PinName rst )
    :fSPI( mosi, NC, sclk ),
     fReset( rst ),
     fCS( cs ),
     fCSLevel( 0 ),
     fBacklight( p21 )
{
    init();
}

void CheapLCD::init()
{
    // Initialize the LCD display

    // Hardware Reset LCD
    fCS = 1;
    fReset = 0;
    fSPI.format( 9 );
    fSPI.frequency( 5000000 );
    wait_ms( 1 );
    fReset = 1;
    wait_ms( 1 );
    fCS = 0;

    // Display control
    sendCMD(DISCTL);
    sendData(0x0C);                // 2 divisions, Field swithcing period
    sendData(32);                // 132 lines to be display
    sendData(0);                // Inversely hightlighted lines - 1
    sendData(0);

    sendCMD(COMSCN);            // comscn
    sendData(0x00);

    sendCMD(OSCON);                // oscon

    sendCMD(SLPOUT);            // sleep out

    sendCMD(PWRCTR);            // power ctrl
    sendData(0x0f);                // everything on, no external reference resistors
    wait_ms( 1 );

    sendCMD(VOLCTR);            // electronic volume, this is kinda contrast/brightness
    sendData(0x24);                // this might be different for individual LCDs
    sendData(0x03);    

                                //  sendCMD(DISINV);      // display mode

    sendCMD(DATCTL);            // datctl
    sendData(0x02);   // Set
    sendData(0);                // RGB (not BGR) LCD
    sendData(0x02);                // 16 bit grayscale type A

    sendCMD(DISON);                // display on
    fCS = 1;
}

void CheapLCD::sendCMD( byte data )
{
    fSPI.write( data & 0xFF );
}

void CheapLCD::sendData( byte data )
{
    fSPI.write( data | 0x100 );
}

// Chip select must be asserted low while talking to the display.
// We use this class to keep track of nested calls, so it's done
// once per operation.

class ChipSelect {
 public:
    ChipSelect( CheapLCD * lcd ): fLCD( lcd )
    {
        if (fLCD->fCSLevel == 0)
            fLCD->fCS = 0;
        fLCD->fCSLevel++;
    }


    ~ChipSelect()
    {
        fLCD->fCSLevel--;
        if (fLCD->fCSLevel < 0)
            printf("WTF?? fLCD level negative\r\n");
        if (fLCD->fCSLevel == 0)
            fLCD->fCS = 1;
    }

 private:
    CheapLCD * fLCD;
};


/**************************************/
/*        Put pixel to LCD            */
/**************************************/

void CheapLCD::put_pixel(byte color, byte x, byte y)
{
    ChipSelect cs(this);

    sendCMD(CASET);                // page start/end ram
    sendData(x);                // for some reason starts at 2
    sendData(x+1);

    sendCMD(PASET);                // column start/end ram
    sendData(y);
    sendData(y+1);
    sendCMD(RAMWR);
    sendData(color);
}

void CheapLCD::set_box(byte x1, byte y1, byte x2, byte y2)
{
    ChipSelect cs(this);
    /*
      sendCMD(CASET);   // page start/end ram
      sendData(x1);     // for some reason starts at 2
      sendData(x2);

      sendCMD(PASET);   // column start/end ram
      sendData(y1);
      sendData(y2);
    */

    sendCMD(CASET);                // page start/end ram
    sendData(131-x2);            // for some reason starts at 2
    sendData(131-x1);

    sendCMD(PASET);                // column start/end ram
    sendData(131-y2);
    sendData(131-y1);
}

#define MEMPIXEL(color)    sendData( (color>>4) & 0x00FF);\
    sendData( ((color & 0x0F) << 4) | (color >> 8));\
    sendData( color & 0xFF );


void CheapLCD::clear(uint32_t color, byte x1, byte y1, byte x2, byte y2)
{
    ChipSelect cs(this);

    uint32_t i;
    uint32_t total_bytes1;
    uint32_t total_bytes2;
    uint32_t total_bytes;
    
    CheapLCD::set_box(x1, y1, x2, y2);
    
    sendCMD(RAMWR);
    total_bytes1 = (x2 - x1) +1; 
    total_bytes2 = (y2 - y1) +1;
    total_bytes = total_bytes1 * total_bytes2;
    for (i = 0; i < total_bytes/2; i++)
    {
        MEMPIXEL( color )
    }
}

void CheapLCD::copy_screen( const image_data_t * screenData )
{
    ChipSelect cs(this);

    int i, start, row, num;
//    clear( BLACK, 0, 0, 131, 131 );

    sendCMD(CASET);                // page start/end ram
    sendData(0);                // for some reason starts at 2
    sendData(131);
    
    sendCMD(PASET);                // column start/end ram
    sendData(0);
    sendData(131);

    sendCMD(RAMWR);
    for (row = 0; row <= 131; ++row)
    {
        start = (((row + 2) % 131)) * (132/2)*3;
//        start = row * (132/2)*3;
        num = (132/2)*3;
        for (i = 0; i < num; ++i)
            sendData( screenData->pixel_data[start + i] );
    }
}

/*
// NOTE! (x1-x0)+1 must be even!
void CheapLCD::copy_screen_section( byte x0, byte y0, byte x1, byte y1,
                              const image_data_t * screenData )
{
    int row, i, num, start;
//    set_box( x0, y0, x1, y1 );
    sendCMD(CASET);   // page start/end ram
    sendData((131-x1));     
    sendData((131-x0));
    
    sendCMD(PASET);   // column start/end ram
    if (y0 == 0)
        sendData(2);
    else
        sendData(y0);
    y1++;
    sendData(y1);

    sendCMD(RAMWR);
    for (row = y0; row <= y1; ++row)
    {
        if (y0 == 0)
            start = (((row + 2) % y1)) * (132/2)*3;
        else
            start = (row) * (132/2)*3;
        start += (x0/2) * 3;
        num = ((x1 - x0)+1)/2 * 3;
        for (i = 0; i < num; ++i)
            sendData( screenData->pixel_data[start + i] );
    }
}
*/

void CheapLCD::splash(int demo)
{
    switch (demo)
    {
    case 1:
        copy_screen( &ColorWheel_img );
        break;
/*
*/
    default:
    case 0: 
        copy_screen( &Splash_img );
        break;
    }
}

void CheapLCD::ramp( uint32_t color, uint32_t y, uint32_t height )
{
    ChipSelect cs(this);

    int i, j;
    uint32_t red = (color >> 8);
    uint32_t grn = (color & 0xFF) >> 4;
    uint32_t blu = (color & 0x0F);
    uint32_t c = color, scanline[132/2];
    
    for (i = 0; i < 132/2; ++i)
    {
        if (((i+1) % 4) == 0)    
        {
            if (red > 0) red--; 
            if (grn > 0) grn--; 
            if (blu > 0) blu--;
            c = (red << 8) | (grn << 4) | blu;
        }
        scanline[i] = c;
    }
    
    set_box( 0, y, 131, y+height );

    sendCMD(RAMWR);

    for (i = 0; i < height; ++i)
    {
        for (j = 0; j < 132/2; ++j)    
        {
            c = scanline[j];
            MEMPIXEL( c );
        }
    }
}

void CheapLCD::draw_color_bar()
{
    ChipSelect cs(this);

    clear(RED,0,0,131,33);
    clear(GREEN,0,34,131,66);
    clear(BLUE,0,67,131,99);
    clear(WHITE,0,100,131,131);

    ramp( RED, 0, 15 );
    ramp( GREEN, 34, 15 );
    ramp( BLUE, 67, 15 );
    ramp( WHITE, 100, 15 );
}

void CheapLCD::erase()
{
    clear( BLACK, 0, 0, 131, 131 );
}

void CheapLCD::send_packed_pixels( uint32_t pixel_data[], unsigned int numPixels )
{
    ChipSelect cs(this);

    uint32_t c0, c1;
    unsigned char d;
    unsigned int i;

    sendCMD(RAMWR);

    for (i = 0; i < numPixels/2; ++i)
    {
        c0 = pixel_data[i*2];
        c1 = pixel_data[i*2+1];
        d = (c0 >> 4) | ((c0 >> 4) & 0xF);
        sendData( d );
        d = ((c0 & 0xF) << 4) | (c1 >> 8);
        sendData( d );
        d = c1 & 0xFF;
        sendData( d );
    }
}

void CheapLCD::draw_text_line(uint32_t fcolor, uint32_t bcolor,byte x, byte y,char c)
{
    ChipSelect cs(this);

    unsigned int i;
    uint32_t text_pixels[8];

    set_box(x,y,x,y+7);

    for(i=0;i<8;i++)
    {
        if ((1<<(7-i)) & c)
            text_pixels[i] = fcolor;
        else
            text_pixels[i] = bcolor;
    }

    send_packed_pixels( text_pixels, 8 );
}

void unpack_color( short * r, short * g, short * b, uint32_t color )
{
    *r = color>>8;
    *g = (color>>4) & 0x0F;
    *b = color & 0x0F;
}

void CheapLCD::draw_mask( uint32_t fcolor, uint32_t bcolor,
                          byte x, byte y, 
                          uint32_t numRows, uint32_t numCols,
                          const unsigned char * pixel_data )
{                                                                                       
    ChipSelect cs(this);

    uint32_t sline[132];    // Worse case scanline buffer
    short rf = 0, gf = 0, bf = 0, rb, gb, bb, spixel;
    short r, g, b;
    int row, col, ypos;

    unpack_color( &rf, &gf, &bf, fcolor );
    unpack_color( &rb, &gb, &bb, bcolor );

    // Whacky epson driver chip:  The width of the line must
    // be odd, and the first and last pixels are tossed when
    // filling the display
//    uint32_t oddNumCols = (numCols & 1) ? numCols : numCols + 1;
    sline[0] = bcolor;
    for (row = 0; row < numRows; row++)
    {
        for (col = 0; col < numCols; col++)
        {
            spixel = pixel_data[row * (numCols/2 + (numCols & 1)) + col/2];
            spixel = (col & 1) ? spixel & 0x0F : (spixel >> 4);

            // Note f*t + b*(1-t) reduces to t*(f-b) + b
            r = ((spixel * (rf - rb)) >> 4) + rb;
            g = ((spixel * (gf - gb)) >> 4) + gb;
            b = ((spixel * (bf - bb)) >> 4) + bb;

            sline[col+1] = (uint32_t) ( (r << 8) | (g << 4) | b );
        }
        sline[col+1] = bcolor;

        ypos = (y + numRows-1) - row;
        set_box( x, ypos, x + numCols-1, ypos );
        
        send_packed_pixels( sline, numCols+2 );
    }
}

void CheapLCD::draw_glyph_text( uint32_t fcolor, uint32_t bcolor,
                                int x, int y, const char * str )
{
    const char * p = str;
    int xpos = x;
    while (*p)
    {
        if (*p == ' ')
            xpos += 8;
        else
        {
            const glyph_data_t * g = f18_glyph_array[((*p) & 0x7f) - 0x21];
            draw_glyph( fcolor, bcolor, xpos, y, g );
            xpos += (g->numCols + 1);
        }
        p++;
    }
}

// Note "y" in this case refers to the baseline origin, not top left
void CheapLCD::draw_glyph( uint32_t fcolor, uint32_t bcolor,
                           byte x, byte y,
                           const glyph_data_t * glyph )
{
    int y1 = (int)y - (int)(glyph->numRows) + glyph->baseline;
    draw_mask( fcolor, bcolor, x, (byte) y1,
               glyph->numRows, glyph->numCols, glyph->pixel_data );
}

void CheapLCD::draw_sprite( uint32_t fcolor, uint32_t bcolor,
                            byte x, byte y, 
                            const sprite_data_t * sprite )
{
    draw_mask( fcolor, bcolor, x, y,
               sprite->numRows, sprite->numCols, sprite->pixel_data );                                                                                 
}

void CheapLCD::draw_number( uint32_t fcolor,
                            uint32_t bcolor, byte x, byte y,
                            int number )
{
    ChipSelect cs( this );

    char digits[10];
    int i, numDigits = 0;
    const sprite_data_t * sprite;
    
    // Store digits
    sprintf( digits, "%d", number );

    numDigits = strlen( digits );

    for (i = 0; i < numDigits; ++i)
    {
        sprite = NULL;
        switch (digits[i])
        {
        case '-':
            sprite = &minus_sprt;    
            break;

        default:
            if ((digits[i] >= '0') && (digits[i] <= '9'))
                sprite = NumSprites[digits[i] - '0'];
            break;
        }

        if (sprite)
        {
            draw_sprite( fcolor, bcolor, x, y, sprite );
            x += sprite->numCols;
            clear( bcolor, x, y, x, y + (sprite->numRows - 1) );
            x++;
        }
    }
}

#define SHADE 0xB
#define DKRED (SHADE << 8)
#define DKGRN (SHADE << 4)
#define DKBLU (SHADE)

#define LABELOFF 8
#define NUMBEROFF 52

/*
void CheapLCD::backlight( tBoolean backlight_on )
{
    if (backlight_on) BL0 else BL1;
}

void CheapLCD::draw_RGB( int r, int g, int b )
{
    ChipSelect cs( this );

    clear( BLACK, 0, 0, 131, 59 );
    clear( DKRED, 0, 60, 131, 83 );
    clear( DKGRN, 0, 84, 131, 107 );
    clear( DKBLU, 0, 108, 131, 131 );

    draw_sprite( WHITE, BLACK, 6, 13, &RGBColor_sprt );
    draw_sprite( WHITE, DKRED, LABELOFF, 65, &Red_sprt );
    draw_sprite( WHITE, DKGRN, LABELOFF, 89, &Grn_sprt );
    draw_sprite( WHITE, DKBLU, LABELOFF, 111,&Blu_sprt );

    draw_number( WHITE, DKRED, NUMBEROFF, 65, r );
    draw_number( WHITE, DKGRN, NUMBEROFF, 89, g );
    draw_number( WHITE, DKBLU, NUMBEROFF, 112,b );
}

void CheapLCD::demo_sprite( void )
{
    draw_sprite( WHITE, RED, 10, 10, &OddAt_sprt );
}
*/

void CheapLCD::demo_number( int num )
{
    draw_number( RED, WHITE, 10, 10, num );
}


void CheapLCD::draw_text(uint32_t fcolor, uint32_t bcolor, byte x, byte y,char *text)
{
    ChipSelect cs( this );
    byte c;
    byte t;
    unsigned int i;
    unsigned int j;
    while(*text != 0)
    {
        t = *text;
        i = t - 32;
        i = i * 5;
        for(j = i; j < i+5; j++)
        {
            c = font[j];
            draw_text_line(fcolor, bcolor, x++, y, c);
        }
        draw_text_line(fcolor, bcolor, x++, y, 0);
        text++;
    }
}

#define DATALINE(name, y, reg)\
 draw_data_line( name, y, (int)(reg[0]), (int)(reg[1]), (int)(reg[2]), (int)(reg[3]) );

char *
convert_float( const char * msg, float H )
{
    static char digits[15];

    if (H * 1000 == 1000)
        sprintf( digits, "%s1.0", msg );
    else
    if (H * 1000 > 100)
        sprintf( digits, "%s0.%d", msg, (int) (H * 1000) );
    else
    if (H * 1000 > 10)
        sprintf( digits, "%s0.0%d", msg, (int) (H * 1000) );
    else
        sprintf( digits, "%s0.00%d", msg, (int) (H * 1000) );
    return digits;
}

/*
void CheapLCD::draw_HSL( float H, float S, float L )
{
    byte x = (byte) (H * 131.0);
    byte y = (byte) (S * 131.0);

    copy_screen( &hslImage_img );

    clear( WHITE, x-2, y-2, x+2, y+2 );

    draw_text( WHITE, 0x0888, 10, 120, convert_float( "H=", H ) );
    draw_text( WHITE, 0x0888, 65, 120, convert_float( "S=", S ) );
}        
*/