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
System Block Diagram
Diff: NokiaLCD.cpp
- 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 ) ); +} +*/