Mercurial > ~darius > hgwebdir.cgi > stm32test
diff lcd.c @ 4:2c87e30c982d
Add LCD init, touch screen writing etc..
PWM of LCD backlight doesn't work yet though..
author | Daniel O'Connor <darius@dons.net.au> |
---|---|
date | Tue, 03 Jan 2012 22:37:18 +1030 |
parents | 74e9b3baac1e |
children | efa2c22266e3 |
line wrap: on
line diff
--- a/lcd.c Sun Jan 01 11:01:13 2012 +1030 +++ b/lcd.c Tue Jan 03 22:37:18 2012 +1030 @@ -55,14 +55,185 @@ 40 D15 PD10/FSMC_D15 */ +#include <stdio.h> #include "stm32f10x.h" #include "lcd.h" +#define Bank1_LCD_C ((uint32_t)0x60000000) /* Register Address */ +#define Bank1_LCD_D ((uint32_t)0x60020000) /* Data Address */ + +unsigned long colour1 = 0; + +void +LCD_WR_Reg(uint16_t index, uint16_t val) { + *(__IO uint16_t *)(Bank1_LCD_C) = index; + *(__IO uint16_t *)(Bank1_LCD_D) = val; +} + +uint16_t +LCD_RD_Reg(uint16_t index) { + *(__IO uint16_t *)(Bank1_LCD_C) = index; + return(*(__IO uint16_t *)(Bank1_LCD_D)); +} + +uint16_t +LCD_RD_Data(int first) { + uint16_t a = 0; + if (first) + a = *(__IO uint16_t *) (Bank1_LCD_D); /* Dummy */ + a = *(__IO uint16_t *) (Bank1_LCD_D); /* Read */ + + return (a); +} + +void +LCD_WR_Data(uint16_t val) { + *(__IO uint16_t *)(Bank1_LCD_D) = val; +} + +/* Callers imply this is in milliseconds but that seems unlikely */ +void +Delay(__IO uint32_t nCount) { + for(; nCount != 0; nCount--) + ; +} + +uint8_t +SPI_WriteByte(uint8_t out) { + uint8_t in = 0; + + /* Wait until the transmit buffer is empty */ + while (SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET) + ; + + /* Send the byte */ + SPI_I2S_SendData(SPI1, out); + + /* Wait until a data is received */ + while (SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE) == RESET) + ; + + /* Get the received data */ + in = SPI_I2S_ReceiveData(SPI1); + + /* Return the shifted data */ + return (in); +} + +#define TP_SELECT() GPIO_ResetBits(GPIOB, GPIO_Pin_7) +#define TP_DESELECT() GPIO_SetBits(GPIOB, GPIO_Pin_7) +uint16_t +TPRead(uint8_t type) { + uint16_t x = 0; + + /* Select device */ + TP_SELECT(); + + /* Do conversion */ + Delay(10); + SPI_WriteByte(type); + + /* Read result */ + Delay(10); + x = SPI_WriteByte(0x00); + x <<= 8; + x |= SPI_WriteByte(0x00); + Delay(10); + + /* De-select device */ + TP_DESELECT(); + + /* Right justify 12 bit result */ + x = x >> 3; + return (x); +} + +#define FL_SELECT() GPIO_ResetBits(GPIOA, GPIO_Pin_4) +#define FL_DESELECT() GPIO_SetBits(GPIOA, GPIO_Pin_4) + +#define FL_READ 0x03 +#define FL_HSREAD 0x0b +#define FL_32KERASE 0x52 +#define FL_64KERASE 0xd8 +#define FL_CHIPERASE 0x60 +#define FL_BYTEPROG 0x02 +#define FL_AAIWP 0xad +#define FL_RDSR 0x05 +#define FL_EWSR 0x50 +#define FL_WRSR 0x01 +#define FL_WREN 0x06 +#define FL_WRDI 0x04 +#define FL_RDID 0x90 +#define FL_JEDECID 0x9f +#define FL_EBSY 0x70 +#define FL_DBSY 0x80 + +uint16_t +FlashReadID(void) { + uint8_t fac, dev; + + FL_SELECT(); /* Select device */ + + SPI_WriteByte(FL_RDID); /* Send command */ + SPI_WriteByte(0x00); /* Send address cycles (ID data starts at 0) */ + SPI_WriteByte(0x00); + SPI_WriteByte(0x00); + fac = SPI_WriteByte(0x00); /* Read ID */ + dev = SPI_WriteByte(0x00); + + FL_DESELECT(); /* De-select device */ + + return fac << 8 | dev; +} + +uint8_t +FlashReadStatus(void) { + uint8_t status; + + FL_SELECT(); /* Select device */ + + SPI_WriteByte(FL_RDSR); /* Send command */ + SPI_WriteByte(0x00); /* Send dummy byte for address cycle */ + status = SPI_WriteByte(0x00); /* Read status */ + + FL_DESELECT(); /* De-select device */ + + return status; +} + +void +FlashWriteStatus(uint8_t status) { + /* Enable status write */ + FL_SELECT(); /* Select device */ + SPI_WriteByte(FL_EWSR); /* Send command */ + SPI_WriteByte(0x00); /* Send data byte */ + FL_DESELECT(); + + /* Actually write status */ + FL_SELECT(); /* Re-select device for new command */ + SPI_WriteByte(FL_WRSR); /* Send command */ + SPI_WriteByte(status); /* Send data byte */ + FL_DESELECT(); /* De-select device */ +} + void LCD_init(void) { GPIO_InitTypeDef GPIO_InitStructure; + SPI_InitTypeDef SPI_InitStructure; FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure; FSMC_NORSRAMTimingInitTypeDef p; +#if 0 + TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; + TIM_OCInitTypeDef TIM_OCInitStructure; + TIM_BDTRInitTypeDef TIM_BDTRInitStructure; +#endif + uint16_t id; + + /* Enable FSMC clock */ + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE); + + /* Enable GPIOD clock */ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE); /* Configures LCD Control lines (FSMC Pins) in alternate function Push-Pull mode. * @@ -82,6 +253,69 @@ GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; GPIO_Init(GPIOE, &GPIO_InitStructure); + /* Configure backlight control (PD13/FSMC_A18 remapped to TIM4_CH2) */ +#if 0 + /* Enable TIM4 clock */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); + + /* Enable timer function */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; + GPIO_Init(GPIOD, &GPIO_InitStructure); + + /* Remap TIM4_CH2 to PD13 */ + GPIO_PinRemapConfig(GPIO_Remap_TIM4, ENABLE); + + /* Reset TIM4 */ + TIM_DeInit(TIM4); + + /* Time Base configuration */ + TIM_TimeBaseStructure.TIM_Prescaler = 0x00; + TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; + TIM_TimeBaseStructure.TIM_Period = 0x8000; + TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; + TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0; + TIM_TimeBaseInit(TIM4 ,&TIM_TimeBaseStructure); + + /* Channel 1, 2, 3 and 4 Configuration in PWM mode */ + TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; + TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; + TIM_OCInitStructure.TIM_Pulse = 0; + TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; + TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low; + TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; + TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset; + TIM_OC2Init(TIM4, &TIM_OCInitStructure); + + /* Automatic Output enable, Break, dead time and lock configuration*/ + TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; + TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; + TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1; + TIM_BDTRInitStructure.TIM_DeadTime = 0x75; + TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable; + TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; + TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; + + TIM_BDTRConfig(TIM4, &TIM_BDTRInitStructure); + + /* TIM1 counter enable */ + TIM_Cmd(TIM4,ENABLE); +#else + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(GPIOD, &GPIO_InitStructure); + + GPIO_SetBits(GPIOD, GPIO_Pin_13); +#endif + + /* Configure reset pin (PE1) as GPIO out PP */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(GPIOE, &GPIO_InitStructure); + /* Configures the Parallel interface (FSMC) for LCD (Parallel mode) */ /* FSMC_Bank1_NORSRAM4 timing configuration */ p.FSMC_AddressSetupTime = 1; @@ -119,4 +353,148 @@ /* Enable FSMC_Bank1_NORSRAM4 */ FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM4, ENABLE); + + /* Initialise LCD panel */ + + /* Pull reset pin low */ + GPIO_ResetBits(GPIOE, GPIO_Pin_1); + Delay(0xafff); + GPIO_SetBits(GPIOE, GPIO_Pin_1); + Delay(0xafff); + + id = LCD_RD_Reg(0x00); + if (id != 0x9325) { + printf("LCD ID doesn't match, expected 0x9325 got 0x%x\r\n", id); + return; + } + + LCD_WR_Reg(0x00e3, 0x3008); /* Set internal timing */ + LCD_WR_Reg(0x00e7, 0x0012); /* Set internal timing */ + LCD_WR_Reg(0x00ef, 0x1231); /* Set internal timing */ + LCD_WR_Reg(0x0000, 0x0001); /* Start Oscillation */ + LCD_WR_Reg(0x0001, 0x0100); /* set SS and SM bit */ + LCD_WR_Reg(0x0002, 0x0700); /* set 1 line inversion */ + + LCD_WR_Reg(0x0003, 0x1030); /* set GRAM write direction and BGR = 0, 262K colours, 1 transfers/pixel. */ + LCD_WR_Reg(0x0004, 0x0000); /* Resize register */ + LCD_WR_Reg(0x0008, 0x0202); /* set the back porch and front porch */ + LCD_WR_Reg(0x0009, 0x0000); /* set non-display area refresh cycle ISC[3:0] */ + LCD_WR_Reg(0x000a, 0x0000); /* FMARK function */ + LCD_WR_Reg(0x000c, 0x0000); /* RGB interface setting */ + LCD_WR_Reg(0x000d, 0x0000); /* Frame marker Position */ + LCD_WR_Reg(0x000f, 0x0000); /* RGB interface polarity */ + + /* Power On sequence */ + LCD_WR_Reg(0x0010, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ + LCD_WR_Reg(0x0011, 0x0007); /* DC1[2:0], DC0[2:0], VC[2:0] */ + LCD_WR_Reg(0x0012, 0x0000); /* VREG1OUT voltage */ + LCD_WR_Reg(0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ + Delay(200); /* Dis-charge capacitor power voltage */ + LCD_WR_Reg(0x0010, 0x1690); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ + LCD_WR_Reg(0x0011, 0x0227); /* R11h = 0x0221 at VCI = 3.3V, DC1[2:0], DC0[2:0], VC[2:0] */ + Delay(50); /* Delay 50ms */ + LCD_WR_Reg(0x0012, 0x001c); /* External reference voltage= Vci; */ + Delay(50); /* Delay 50ms */ + LCD_WR_Reg(0x0013, 0x1800); /* R13 = 1200 when R12 = 009D; VDV[4:0] for VCOM amplitude */ + LCD_WR_Reg(0x0029, 0x001c); /* R29 = 000C when R12 = 009D; VCM[5:0] for VCOMH */ + LCD_WR_Reg(0x002b, 0x000d); /* Frame Rate = 91Hz */ + Delay(50); /* Delay 50ms */ + LCD_WR_Reg(0x0020, 0x0000); /* GRAM horizontal Address */ + LCD_WR_Reg(0x0021, 0x0000); /* GRAM Vertical Address */ + + /* Adjust the Gamma Curve */ + LCD_WR_Reg(0x0030, 0x0007); + LCD_WR_Reg(0x0031, 0x0302); + LCD_WR_Reg(0x0032, 0x0105); + LCD_WR_Reg(0x0035, 0x0206); + LCD_WR_Reg(0x0036, 0x0808); + LCD_WR_Reg(0x0037, 0x0206); + LCD_WR_Reg(0x0038, 0x0504); + LCD_WR_Reg(0x0039, 0x0007); + LCD_WR_Reg(0x003c, 0x0105); + LCD_WR_Reg(0x003d, 0x0808); + + /* Set GRAM area */ + LCD_WR_Reg(0x0050, 0x0000); /* Horizontal GRAM Start Address */ + LCD_WR_Reg(0x0051, 0x00ef); /* Horizontal GRAM End Address */ + LCD_WR_Reg(0x0052, 0x0000); /* Vertical GRAM Start Address */ + LCD_WR_Reg(0x0053, 0x013f); /* Vertical GRAM Start Address */ + LCD_WR_Reg(0x0060, 0xa700); /* Gate Scan Line */ + LCD_WR_Reg(0x0061, 0x0001); /* NDL,VLE, REV */ + LCD_WR_Reg(0x006a, 0x0000); /* set scrolling line */ + + /* Partial Display Control */ + LCD_WR_Reg(0x0080, 0x0000); + LCD_WR_Reg(0x0081, 0x0000); + LCD_WR_Reg(0x0082, 0x0000); + LCD_WR_Reg(0x0083, 0x0000); + LCD_WR_Reg(0x0084, 0x0000); + LCD_WR_Reg(0x0085, 0x0000); + + /* Panel Control */ + LCD_WR_Reg(0x0090, 0x0010); + LCD_WR_Reg(0x0092, 0x0000); + LCD_WR_Reg(0x0093, 0x0003); + LCD_WR_Reg(0x0095, 0x0110); + LCD_WR_Reg(0x0097, 0x0000); + LCD_WR_Reg(0x0098, 0x0000); + LCD_WR_Reg(0x0007, 0x0133); /* 262K colour and display ON */ + + /* Fill panel with white */ + LCD_WR_Reg(0x20, 0); + LCD_WR_Reg(0x21, 0x013f); + *(__IO uint16_t *)(Bank1_LCD_C) = 34; + for (colour1 = 0; colour1 < 76800; colour1++) { + LCD_WR_Data(0xffff); + } + colour1 = 0; + + /* Configure touch screen controller + * + * Connected to SPI1 which is shared with the AT45DB161D. + * + * The touch screen is selected with PB7. + * The flash chip is selected with PA4. + */ + + /* Enable SPI1 clock */ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); + + /* Configure MOSI, MISO and SCLK as alternate function PP */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + /* Configure flash chip select pin (PA4) as GPIO out PP */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + /* Configure touch chip select pin (PB7) as GPIO out PP */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(GPIOB, &GPIO_InitStructure); + + /* De-select touch & flash */ + GPIO_SetBits(GPIOA, GPIO_Pin_4); + GPIO_SetBits(GPIOB, GPIO_Pin_7); + + /* SPI1 Config */ + SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; + SPI_InitStructure.SPI_Mode = SPI_Mode_Master; + SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; + SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; + SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; + SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; + SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64; + SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; + SPI_InitStructure.SPI_CRCPolynomial = 7; + SPI_Init(SPI1, &SPI_InitStructure); + + /* SPI1 enable */ + SPI_Cmd(SPI1, ENABLE); + }