/* * This file is part of Espruino, a JavaScript interpreter for Microcontrollers * * Copyright (C) 2013 Gordon Williams * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * ---------------------------------------------------------------------------- * Graphics Backend for 16 bit parallel LCDs (ILI9325 and similar) * * Loosely based on example code that comes with 'HY' branded STM32 boards, * original Licence unknown. * ---------------------------------------------------------------------------- */ #include "platform_config.h" #include "jshardware.h" #include "jsinteractive.h" // for debug #include "graphics.h" const unsigned int DELAY_SHORT = 10; void LCD_DELAY(__IO uint32_t nCount) { for(; nCount != 0; nCount--) ;//n++; } static inline void delay_ms(__IO uint32_t mSec) { jshDelayMicroseconds(mSec*1000); } static uint8_t LCD_Code; #define ILI9320 0 /* 0x9320 */ #define ILI9325 1 /* 0x9325 */ #define ILI9328 2 /* 0x9328 */ #define ILI9331 3 /* 0x9331 */ #define SSD1298 4 /* 0x8999 */ #define SSD1289 5 /* 0x8989 */ #define ST7781 6 /* 0x7783 */ #define LGDP4531 7 /* 0x4531 */ #define SPFD5408B 8 /* 0x5408 */ #define R61505U 9 /* 0x1505 0x0505 */ #define HX8346A 10 /* 0x0046 */ #define HX8347D 11 /* 0x0047 */ #define HX8347A 12 /* 0x0047 */ #define LGDP4535 13 /* 0x4535 */ #define SSD2119 14 /* 3.5 LCD 0x9919 */ static inline void LCD_WR_CMD(unsigned int index,unsigned int val); static inline unsigned int LCD_RD_CMD(unsigned int index); #ifdef ILI9325_BITBANG #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) #define MEM_ADDR(addr) *((volatile unsigned long *)(addr)) #define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum)) #define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C #define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C #define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C #define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C #define GPIOE_ODR_Addr (GPIOE_BASE+12) //0x4001180C #define GPIOF_ODR_Addr (GPIOF_BASE+12) //0x40011A0C #define GPIOG_ODR_Addr (GPIOG_BASE+12) //0x40011E0C #define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) #define LCD_CS PCout(8) #define LCD_RS PCout(9) #define LCD_WR PCout(10) #define LCD_RD PCout(11) static inline void LCD_WR_REG(unsigned int index) { LCD_CS = 0; LCD_RS = 0; GPIOC->ODR = (GPIOC->ODR&0xff00)|(index&0x00ff); GPIOB->ODR = (GPIOB->ODR&0x00ff)|(index&0xff00); LCD_WR = 0; LCD_WR = 1; LCD_CS = 1; } static inline unsigned int LCD_RD_Data(void) { uint16_t temp; GPIOB->CRH = (GPIOB->CRH & 0x00000000) | 0x44444444; GPIOC->CRL = (GPIOC->CRL & 0x00000000) | 0x44444444; LCD_CS = 0; LCD_RS = 1; LCD_RD = 0; temp = ((GPIOB->IDR&0xff00)|(GPIOC->IDR&0x00ff)); LCD_RD = 1; LCD_CS = 1; GPIOB->CRH = (GPIOB->CRH & 0x00000000) | 0x33333333; GPIOC->CRL = (GPIOC->CRL & 0x00000000) | 0x33333333; return temp; } static inline void LCD_WR_Data(unsigned int val) { LCD_CS = 0; LCD_RS = 1; GPIOC->ODR = (GPIOC->ODR&0xff00)|(val&0x00ff); GPIOB->ODR = (GPIOB->ODR&0x00ff)|(val&0xff00); LCD_WR = 0; LCD_WR = 1; LCD_CS = 1; } static inline void LCD_WR_Data_multi(unsigned int val, unsigned int count) { LCD_CS = 0; LCD_RS = 1; GPIOC->ODR = (GPIOC->ODR&0xff00)|(val&0x00ff); GPIOB->ODR = (GPIOB->ODR&0x00ff)|(val&0xff00); unsigned int i; for (i=0;i>0 )&1)!=0); jshPinSetValue(LCD_FSMC_D1 , ((d>>1 )&1)!=0); jshPinSetValue(LCD_FSMC_D2 , ((d>>2 )&1)!=0); jshPinSetValue(LCD_FSMC_D3 , ((d>>3 )&1)!=0); jshPinSetValue(LCD_FSMC_D4 , ((d>>4 )&1)!=0); jshPinSetValue(LCD_FSMC_D5 , ((d>>5 )&1)!=0); jshPinSetValue(LCD_FSMC_D6 , ((d>>6 )&1)!=0); jshPinSetValue(LCD_FSMC_D7 , ((d>>7 )&1)!=0); jshPinSetValue(LCD_FSMC_D8 , ((d>>8 )&1)!=0); jshPinSetValue(LCD_FSMC_D9 , ((d>>9 )&1)!=0); jshPinSetValue(LCD_FSMC_D10, ((d>>10)&1)!=0); jshPinSetValue(LCD_FSMC_D11, ((d>>11)&1)!=0); jshPinSetValue(LCD_FSMC_D12, ((d>>12)&1)!=0); jshPinSetValue(LCD_FSMC_D13, ((d>>13)&1)!=0); jshPinSetValue(LCD_FSMC_D14, ((d>>14)&1)!=0); jshPinSetValue(LCD_FSMC_D15, ((d>>15)&1)!=0); } static unsigned int _LCD_RD() { unsigned int d = 0; if (jshPinGetValue(LCD_FSMC_D0 )) d|=1<<0 ; if (jshPinGetValue(LCD_FSMC_D1 )) d|=1<<1 ; if (jshPinGetValue(LCD_FSMC_D2 )) d|=1<<2 ; if (jshPinGetValue(LCD_FSMC_D3 )) d|=1<<3 ; if (jshPinGetValue(LCD_FSMC_D4 )) d|=1<<4 ; if (jshPinGetValue(LCD_FSMC_D5 )) d|=1<<5 ; if (jshPinGetValue(LCD_FSMC_D6 )) d|=1<<6 ; if (jshPinGetValue(LCD_FSMC_D7 )) d|=1<<7 ; if (jshPinGetValue(LCD_FSMC_D8 )) d|=1<<8 ; if (jshPinGetValue(LCD_FSMC_D9 )) d|=1<<9 ; if (jshPinGetValue(LCD_FSMC_D10)) d|=1<<10; if (jshPinGetValue(LCD_FSMC_D11)) d|=1<<11; if (jshPinGetValue(LCD_FSMC_D12)) d|=1<<12; if (jshPinGetValue(LCD_FSMC_D13)) d|=1<<13; if (jshPinGetValue(LCD_FSMC_D14)) d|=1<<14; if (jshPinGetValue(LCD_FSMC_D15)) d|=1<<15; return d; } static void _LCD_STATE(JshPinState state) { jshPinSetState(LCD_FSMC_D0 , state); jshPinSetState(LCD_FSMC_D1 , state); jshPinSetState(LCD_FSMC_D2 , state); jshPinSetState(LCD_FSMC_D3 , state); jshPinSetState(LCD_FSMC_D4 , state); jshPinSetState(LCD_FSMC_D5 , state); jshPinSetState(LCD_FSMC_D6 , state); jshPinSetState(LCD_FSMC_D7 , state); jshPinSetState(LCD_FSMC_D8 , state); jshPinSetState(LCD_FSMC_D9 , state); jshPinSetState(LCD_FSMC_D10, state); jshPinSetState(LCD_FSMC_D11, state); jshPinSetState(LCD_FSMC_D12, state); jshPinSetState(LCD_FSMC_D13, state); jshPinSetState(LCD_FSMC_D14, state); jshPinSetState(LCD_FSMC_D15, state); } static inline void LCD_WR_REG(unsigned int index) { jshPinSetValue(LCD_FSMC_CS, 0); jshPinSetValue(LCD_FSMC_RS, 0); _LCD_WR(index); jshPinSetValue(LCD_FSMC_WR, 0); jshPinSetValue(LCD_FSMC_WR, 1); jshPinSetValue(LCD_FSMC_CS, 1); } static inline unsigned int LCD_RD_Data(void) { _LCD_STATE(JSHPINSTATE_GPIO_IN); jshPinSetValue(LCD_FSMC_CS, 0); jshPinSetValue(LCD_FSMC_RS, 1); jshPinSetValue(LCD_FSMC_RD, 0); uint16_t temp = (uint16_t)_LCD_RD(); jshPinSetValue(LCD_FSMC_RD, 1); jshPinSetValue(LCD_FSMC_CS, 1); _LCD_STATE(JSHPINSTATE_GPIO_OUT); return temp; } static inline void LCD_WR_Data(unsigned int val) { jshPinSetValue(LCD_FSMC_CS, 0); jshPinSetValue(LCD_FSMC_RS, 1); _LCD_WR(val); jshPinSetValue(LCD_FSMC_WR, 0); jshPinSetValue(LCD_FSMC_WR, 1); jshPinSetValue(LCD_FSMC_CS, 1); } static inline void LCD_WR_Data_multi(unsigned int val, unsigned int count) { jshPinSetValue(LCD_FSMC_CS, 0); jshPinSetValue(LCD_FSMC_RS, 1); _LCD_WR(val); unsigned int i; for (i=0;idata.width-1)-x; switch( LCD_Code ) { default: /* 0x9320 0x9325 0x9328 0x9331 0x5408 0x1505 0x0505 0x7783 0x4531 0x4535 */ LCD_WR_CMD(0x0020, y ); LCD_WR_CMD(0x0021, x ); break; #ifndef SAVE_ON_FLASH case SSD1298: /* 0x8999 */ case SSD1289: /* 0x8989 */ LCD_WR_CMD(0x004e, y ); LCD_WR_CMD(0x004f, x ); break; case HX8346A: /* 0x0046 */ case HX8347A: /* 0x0047 */ case HX8347D: /* 0x0047 */ LCD_WR_CMD(0x02, y>>8 ); LCD_WR_CMD(0x03, y ); LCD_WR_CMD(0x06, x>>8 ); LCD_WR_CMD(0x07, x ); break; case SSD2119: /* 3.5 LCD 0x9919 */ break; #endif } } static inline void lcdSetWindow(JsGraphics *gfx, unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2) { // x1>=x2 and y1>=y2 x2 = (gfx->data.width-1)-x2; x1 = (gfx->data.width-1)-x1; switch (LCD_Code) { default: LCD_WR_CMD(0x50, y1); LCD_WR_CMD(0x51, y2); LCD_WR_CMD(0x52, x2); LCD_WR_CMD(0x53, x1); break; #ifndef SAVE_ON_FLASH case SSD1289: /* 0x8989 */ LCD_WR_CMD(0x44, y1 | (y2<<8)); LCD_WR_CMD(0x45, x2); LCD_WR_CMD(0x46, x1); break; case HX8346A: case HX8347A: case HX8347D: LCD_WR_CMD(0x02,y1>>8); LCD_WR_CMD(0x03,y1); LCD_WR_CMD(0x04,y2>>8); LCD_WR_CMD(0x05,y2); LCD_WR_CMD(0x06,x2>>8); LCD_WR_CMD(0x07,x2); LCD_WR_CMD(0x08,x1>>8); LCD_WR_CMD(0x09,x1); break; #endif } } static inline void lcdSetFullWindow(JsGraphics *gfx) { lcdSetWindow(gfx,0,0,gfx->data.width-1,gfx->data.height-1); } void lcdFillRect_FSMC(JsGraphics *gfx, short x1, short y1, short x2, short y2) { // finally! if (x1==x2) { // special case for single vertical line - no window needed lcdSetCursor(gfx,x2,y1); LCD_WR_REG(0x22); // start data tx unsigned int i=0, l=(1+y2-y1); LCD_WR_Data_multi(gfx->data.fgColor, l); } else { lcdSetWindow(gfx,x1,y1,x2,y2); lcdSetCursor(gfx,x2,y1); LCD_WR_REG(0x22); // start data tx unsigned int i=0, l=(1+x2-x1)*(1+y2-y1); LCD_WR_Data_multi(gfx->data.fgColor, l); lcdSetFullWindow(gfx); } } unsigned int lcdGetPixel_FSMC(JsGraphics *gfx, short x, short y) { lcdSetCursor(gfx,x,y); LCD_WR_REG(0x22); // start data tx return LCD_RD_Data(); } void lcdSetPixel_FSMC(JsGraphics *gfx, short x, short y, unsigned int col) { lcdSetCursor(gfx,x,y); LCD_WR_REG(34); LCD_WR_Data(col); } void lcdInit_FSMC(JsGraphics *gfx) { assert(gfx->data.bpp == 16); LCD_init_hardware(); LCD_init_panel(); lcdSetFullWindow(gfx); } void lcdSetCallbacks_FSMC(JsGraphics *gfx) { gfx->setPixel = lcdSetPixel_FSMC; gfx->getPixel = lcdGetPixel_FSMC; gfx->fillRect = lcdFillRect_FSMC; }