/******************************************************************************/ /* Spark Fun Electronics, Owen Osborn 1-22-05 */ /* Nokia 6100 LCD with Epson S1D15G10 Cntroller Test Program */ /******************************************************************************/ /* Written for Philips ARM LPC2138 */ /* Change SPI functions to suit your MCU */ /* */ /* */ /******************************************************************************/ #include "LPC21xx.h" // LPC I/O definitions // 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 // LCD Chip Select #define LCD_CS 0x00200000; #define LCD_RESET 0x00400000; #define LCD_SCK 0x00020000; #define LCD_DI 0x00080000; // these are for the LPC2138 internal initialization void Initialize(void); void feed(void); // general purpose void delay_ms(int); // spi functions use whatever method you want void spi_command(int); void spi_data(int); void spi_init(void); // this can be the basis for more complex graphics void LCD_put_pixel(unsigned char color, unsigned char x, unsigned char y); int main (void) { unsigned int i = 0; // Initialize the MCU Initialize(); spi_init(); delay_ms(10); IODIR0 |= LCD_SCK; IODIR0 |= LCD_DI; IOSET0 |= LCD_SCK; IOCLR0 |= LCD_DI; // reset display IODIR0 |= LCD_RESET; IOCLR0 |= LCD_RESET; delay_ms(1); IOSET0 |= LCD_RESET; delay_ms(20); spi_command(DISCTL); // display control spi_data(0x03); spi_data(32); spi_data(12); spi_data(0x00); spi_command(COMSCN); // comscn spi_data(0x01); spi_command(OSCON); // oscon spi_command(SLPOUT); // sleep out spi_command(VOLCTR); // electronic volume, this is kinda contrast/brightness spi_data(5);//ff); // this might be different for individual LCDs spi_data(0x01);//01); // spi_command(PWRCTR); // power ctrl spi_data(0x0f); //everything on, no external reference resistors delay_ms(100); spi_command(DISINV); // display mode spi_command(DATCTL); // datctl spi_data(0x00); spi_data(0); spi_data(0x01); spi_data(0x00); spi_command(RGBSET8); // setup color lookup table // color table //RED spi_data(0); spi_data(2); spi_data(4); spi_data(6); spi_data(8); spi_data(10); spi_data(12); spi_data(15); // GREEN spi_data(0); spi_data(2); spi_data(4); spi_data(6); spi_data(8); spi_data(10); spi_data(12); spi_data(15); //BLUE spi_data(0); spi_data(4); spi_data(9); spi_data(15); spi_command(NOP); // nop spi_command(PASET); // page start/end ram spi_data(2); // for some reason starts at 2 spi_data(131); spi_command(CASET); // column start/end ram spi_data(0); spi_data(131); spi_command(RAMWR); // write some stuff (background) for (i = 0; i < 18000; i++){ spi_data(28); // 28 is green } spi_command(DISON); // display on delay_ms(200); for (i = 0; i < 160; i++){ // this loop adjusts the contrast, change the number of iterations to get spi_command(VOLUP); // desired contrast. This might be different for individual LCDs delay_ms(2); } // draw a multi-colored square in the center of screen for (i = 0; i < 4096; i++){ LCD_put_pixel(i, (i % 64) + 32, (i / 64) + 32); } for(;;){ } } // main() // a stupid delay void delay_ms(int count){ int i; count *= 2600; for (i = 0; i < count; i++){ asm volatile ("nop"); } } void LCD_put_pixel(unsigned char color, unsigned char x, unsigned char y){ x += 2; // for some reason starts at 2 spi_command(0x75); // page start/end ram spi_data(x); spi_data(132); spi_command(0x15); // column start/end ram spi_data(y); // for some reason starts at 2 spi_data(131); spi_command(0x5C); // write some shit spi_data(color); } void spi_init(void){ PINSEL1 |= 0x00000088; IODIR0 |= LCD_CS; IOSET0 |= LCD_CS; SSPCR0 = 0x08C8; // cpol = 1, cpha = 1 SSPCPSR = 32; // prescale SSPCR1 = 2; // enable } void spi_command(int dat){ int temp; IOCLR0 |= LCD_CS; SSPDR = dat & ~0x0100;// & ~0x00000100; // send next SPI channel 0 data while ((SSPSR & 0x10)) ; // wait for transfer completed IOSET0 |= LCD_CS; } void spi_data(int dat){ IOCLR0 |= LCD_CS; SSPDR = dat | 0x0100;// & ~0x00000100; // send next SPI channel 0 data while ((SSPSR & 0x10)) ; // wait for transfer completed IOSET0 |= LCD_CS; } /********************************************************** Initialize **********************************************************/ #define PLOCK 0x400 void Initialize(void) { // Setting the Phased Lock Loop (PLL) // ---------------------------------- // // Olimex LPC-P2106 has a 14.7456 mhz crystal // // We'd like the LPC2106 to run at 53.2368 mhz (has to be an even multiple of crystal) // // According to the Philips LPC2106 manual: M = cclk / Fosc where: M = PLL multiplier (bits 0-4 of PLLCFG) // cclk = 53236800 hz // Fosc = 14745600 hz // // Solving: M = 53236800 / 14745600 = 3.6103515625 // M = 4 (round up) // // Note: M - 1 must be entered into bits 0-4 of PLLCFG (assign 3 to these bits) // // // The Current Controlled Oscilator (CCO) must operate in the range 156 mhz to 320 mhz // // According to the Philips LPC2106 manual: Fcco = cclk * 2 * P where: Fcco = CCO frequency // cclk = 53236800 hz // P = PLL divisor (bits 5-6 of PLLCFG) // // Solving: Fcco = 53236800 * 2 * P // P = 2 (trial value) // Fcco = 53236800 * 2 * 2 // Fcc0 = 212947200 hz (good choice for P since it's within the 156 mhz to 320 mhz range // // From Table 19 (page 48) of Philips LPC2106 manual P = 2, PLLCFG bits 5-6 = 1 (assign 1 to these bits) // // Finally: PLLCFG = 0 01 00011 = 0x23 // // Final note: to load PLLCFG register, we must use the 0xAA followed 0x55 write sequence to the PLLFEED register // this is done in the short function feed() below // // Setting Multiplier and Divider values PLLCFG=0x23; feed(); // Enabling the PLL */ PLLCON=0x1; feed(); // Wait for the PLL to lock to set frequency while(!(PLLSTAT & PLOCK)) ; // Connect the PLL as the clock source PLLCON=0x3; feed(); // Enabling MAM and setting number of clocks used for Flash memory fetch (4 cclks in this case) MAMCR=0x2; MAMTIM=0x4; // Setting peripheral Clock (pclk) to System Clock (cclk) VPBDIV=0x1; } void feed(void) { PLLFEED=0xAA; PLLFEED=0x55; }