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

Revision:
0:6da5625a6946
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NokiaLCD.cpp	Thu Dec 29 01:59:53 2011 +0000
@@ -0,0 +1,629 @@
+/*
+  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 ) );
+}        
+*/