diff --git a/target/stm32f429i-disco/include/target/lcd.h b/target/stm32f429i-disco/include/target/lcd.h new file mode 100644 index 00000000..046e8ad0 --- /dev/null +++ b/target/stm32f429i-disco/include/target/lcd.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2025 Luka Panio + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#pragma once + +#include + +/* LCD Size (Width and Height) */ +#define LCD_SIZE_PIXEL_WIDTH ((uint16_t)240) +#define LCD_SIZE_PIXEL_HEIGHT ((uint16_t)320) + +#define LCD_FRAME_BUFFER ((uint32_t)0xD0000000) +#define BUFFER_OFFSET ((uint32_t)0x50000) + +#define LCD_BACKGROUND_LAYER 0x0000 + +/** + * @brief LCD Control pin + */ +#define LCD_NCS_PIN GPIO_Pin_2 +#define LCD_NCS_GPIO_PORT GPIOC +#define LCD_NCS_GPIO_CLK RCC_AHB1Periph_GPIOC + +/** + * @brief LCD Command/data pin + */ +#define LCD_WRX_PIN GPIO_Pin_13 +#define LCD_WRX_GPIO_PORT GPIOD +#define LCD_WRX_GPIO_CLK RCC_AHB1Periph_GPIOD + +/** + * @brief LCD SPI Interface pins + */ +#define LCD_SPI_SCK_PIN GPIO_Pin_7 /* PF.07 */ +#define LCD_SPI_SCK_GPIO_PORT GPIOF /* GPIOF */ +#define LCD_SPI_SCK_GPIO_CLK RCC_AHB1Periph_GPIOF +#define LCD_SPI_SCK_SOURCE GPIO_PinSource7 +#define LCD_SPI_SCK_AF GPIO_AF_SPI5 +#define LCD_SPI_MISO_PIN GPIO_Pin_8 /* PF.08 */ +#define LCD_SPI_MISO_GPIO_PORT GPIOF /* GPIOF */ +#define LCD_SPI_MISO_GPIO_CLK RCC_AHB1Periph_GPIOF +#define LCD_SPI_MISO_SOURCE GPIO_PinSource8 +#define LCD_SPI_MISO_AF GPIO_AF_SPI5 +#define LCD_SPI_MOSI_PIN GPIO_Pin_9 /* PF.09 */ +#define LCD_SPI_MOSI_GPIO_PORT GPIOF /* GPIOF */ +#define LCD_SPI_MOSI_GPIO_CLK RCC_AHB1Periph_GPIOF +#define LCD_SPI_MOSI_SOURCE GPIO_PinSource9 +#define LCD_SPI_MOSI_AF GPIO_AF_SPI5 +#define LCD_SPI SPI5 +#define LCD_SPI_CLK RCC_APB2Periph_SPI5 + +/** + * @brief LCD Registers + */ +#define LCD_SLEEP_OUT 0x11 /* Sleep out register */ +#define LCD_GAMMA 0x26 /* Gamma register */ +#define LCD_DISPLAY_OFF 0x28 /* Display off register */ +#define LCD_DISPLAY_ON 0x29 /* Display on register */ +#define LCD_COLUMN_ADDR 0x2A /* Colomn address register */ +#define LCD_PAGE_ADDR 0x2B /* Page address register */ +#define LCD_GRAM 0x2C /* GRAM register */ +#define LCD_MAC 0x36 /* Memory Access Control register*/ +#define LCD_PIXEL_FORMAT 0x3A /* Pixel Format register */ +#define LCD_WDB 0x51 /* Write Brightness Display register */ +#define LCD_WCD 0x53 /* Write Control Display register*/ +#define LCD_RGB_INTERFACE 0xB0 /* RGB Interface Signal Control */ +#define LCD_FRC 0xB1 /* Frame Rate Control register */ +#define LCD_BPC 0xB5 /* Blanking Porch Control register*/ +#define LCD_DFC 0xB6 /* Display Function Control register*/ +#define LCD_POWER1 0xC0 /* Power Control 1 register */ +#define LCD_POWER2 0xC1 /* Power Control 2 register */ +#define LCD_VCOM1 0xC5 /* VCOM Control 1 register */ +#define LCD_VCOM2 0xC7 /* VCOM Control 2 register */ +#define LCD_POWERA 0xCB /* Power control A register */ +#define LCD_POWERB 0xCF /* Power control B register */ +#define LCD_PGAMMA 0xE0 /* Positive Gamma Correction register*/ +#define LCD_NGAMMA 0xE1 /* Negative Gamma Correction register*/ +#define LCD_DTCA 0xE8 /* Driver timing control A */ +#define LCD_DTCB 0xEA /* Driver timing control B */ +#define LCD_POWER_SEQ 0xED /* Power on sequence register */ +#define LCD_3GAMMA_EN 0xF2 /* 3 Gamma enable register */ +#define LCD_INTERFACE 0xF6 /* Interface control register */ +#define LCD_PRC 0xF7 /* Pump ratio control register */ + diff --git a/target/stm32f429i-disco/init.c b/target/stm32f429i-disco/init.c index d5e2c150..1a932a33 100644 --- a/target/stm32f429i-disco/init.c +++ b/target/stm32f429i-disco/init.c @@ -13,12 +13,15 @@ #include #include #include +#include #include #include #include #include #include +extern uint8_t STM_LCD_Init(void); + void target_early_init(void) { #ifdef DEBUG_UART #if DEBUG_UART == 1 @@ -38,6 +41,7 @@ void target_early_init(void) { gpio_config(GPIO_LED1, GPIO_OUTPUT); gpio_config(GPIO_LED2, GPIO_OUTPUT); gpio_config(GPIO_LED3, GPIO_OUTPUT); + STM_LCD_Init(); } void target_init(void) { diff --git a/target/stm32f429i-disco/lcd.c b/target/stm32f429i-disco/lcd.c new file mode 100644 index 00000000..2d98cba5 --- /dev/null +++ b/target/stm32f429i-disco/lcd.c @@ -0,0 +1,683 @@ +/* + * Copyright (c) 2015 Travis Geiselbrecht + * Copyright (c) 2022 Luka Panio + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +/* + * COPYRIGHT(c) 2015 STMicroelectronics + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * lcd initialization sequence, taken from + * STM32F429I-Discovery_FW_V1.0.3/Utilities/STM32F429I-Discovery/stm32f429i_discovery_lcd.[ch] + */ + +/** + * @brief Controls LCD Chip Select (CS) pin + * @param NewState CS pin state + * @retval None + */ +void STM_LCD_ChipSelect(FunctionalState NewState) +{ + if (NewState == DISABLE) + { + GPIO_ResetBits(LCD_NCS_GPIO_PORT, LCD_NCS_PIN); /* CS pin low: LCD disabled */ + } + else + { + GPIO_SetBits(LCD_NCS_GPIO_PORT, LCD_NCS_PIN); /* CS pin high: LCD enabled */ + } +} + +/** + * @brief Configures the LCD_SPI interface. + * @param None + * @retval None + */ +void STM_LCD_SPIConfig(void) +{ + SPI_InitTypeDef SPI_InitStructure; + GPIO_InitTypeDef GPIO_InitStructure; + + /* Enable LCD_SPI_SCK_GPIO_CLK, LCD_SPI_MISO_GPIO_CLK and LCD_SPI_MOSI_GPIO_CLK clock */ + RCC_AHB1PeriphClockCmd(LCD_SPI_SCK_GPIO_CLK | LCD_SPI_MISO_GPIO_CLK | LCD_SPI_MOSI_GPIO_CLK, ENABLE); + + /* Enable LCD_SPI and SYSCFG clock */ + RCC_APB2PeriphClockCmd(LCD_SPI_CLK, ENABLE); + + /* Configure LCD_SPI SCK pin */ + GPIO_InitStructure.GPIO_Pin = LCD_SPI_SCK_PIN; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; + GPIO_Init(LCD_SPI_SCK_GPIO_PORT, &GPIO_InitStructure); + + /* Configure LCD_SPI MISO pin */ + GPIO_InitStructure.GPIO_Pin = LCD_SPI_MISO_PIN; + GPIO_Init(LCD_SPI_MISO_GPIO_PORT, &GPIO_InitStructure); + + /* Configure LCD_SPI MOSI pin */ + GPIO_InitStructure.GPIO_Pin = LCD_SPI_MOSI_PIN; + GPIO_Init(LCD_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure); + + /* Connect SPI SCK */ + GPIO_PinAFConfig(LCD_SPI_SCK_GPIO_PORT, LCD_SPI_SCK_SOURCE, LCD_SPI_SCK_AF); + + /* Connect SPI MISO */ + GPIO_PinAFConfig(LCD_SPI_MISO_GPIO_PORT, LCD_SPI_MISO_SOURCE, LCD_SPI_MISO_AF); + + /* Connect SPI MOSI */ + GPIO_PinAFConfig(LCD_SPI_MOSI_GPIO_PORT, LCD_SPI_MOSI_SOURCE, LCD_SPI_MOSI_AF); + + SPI_I2S_DeInit(LCD_SPI); + + /* SPI configuration -------------------------------------------------------*/ + /* If the SPI peripheral is already enabled, don't reconfigure it */ + if ((LCD_SPI->CR1 & SPI_CR1_SPE) == 0) + { + 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 baudrate is set to 5.6 MHz (PCLK2/SPI_BaudRatePrescaler = 90/16 = 5.625 MHz) + to verify these constraints: + - ILI9341 LCD SPI interface max baudrate is 10MHz for write and 6.66MHz for read + - l3gd20 SPI interface max baudrate is 10MHz for write/read + - PCLK2 frequency is set to 90 MHz + */ + SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; + SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; + SPI_InitStructure.SPI_CRCPolynomial = 7; + SPI_Init(LCD_SPI, &SPI_InitStructure); + + /* Enable L3GD20_SPI */ + SPI_Cmd(LCD_SPI, ENABLE); + } +} + +static void STM_LCD_AF_GPIOConfig(void) +{ + GPIO_InitTypeDef GPIO_InitStruct; + + /* Enable GPIOA, GPIOB, GPIOC, GPIOD, GPIOF, GPIOG AHB Clocks */ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | \ + RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | \ + RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOG, ENABLE); + +/* GPIOs Configuration */ +/* + +------------------------+-----------------------+----------------------------+ + + LCD pins assignment + + +------------------------+-----------------------+----------------------------+ + | LCD_TFT R2 <-> PC.10 | LCD_TFT G2 <-> PA.06 | LCD_TFT B2 <-> PD.06 | + | LCD_TFT R3 <-> PB.00 | LCD_TFT G3 <-> PG.10 | LCD_TFT B3 <-> PG.11 | + | LCD_TFT R4 <-> PA.11 | LCD_TFT G4 <-> PB.10 | LCD_TFT B4 <-> PG.12 | + | LCD_TFT R5 <-> PA.12 | LCD_TFT G5 <-> PB.11 | LCD_TFT B5 <-> PA.03 | + | LCD_TFT R6 <-> PB.01 | LCD_TFT G6 <-> PC.07 | LCD_TFT B6 <-> PB.08 | + | LCD_TFT R7 <-> PG.06 | LCD_TFT G7 <-> PD.03 | LCD_TFT B7 <-> PB.09 | + ------------------------------------------------------------------------------- + | LCD_TFT HSYNC <-> PC.06 | LCDTFT VSYNC <-> PA.04 | + | LCD_TFT CLK <-> PG.07 | LCD_TFT DE <-> PF.10 | + ----------------------------------------------------- + +*/ + + /* GPIOA configuration */ + GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_LTDC); + GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_LTDC); + GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_LTDC); + GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_LTDC); + GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_LTDC); + + GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_6 | \ + GPIO_Pin_11 | GPIO_Pin_12; + + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; + GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(GPIOA, &GPIO_InitStruct); + + /* GPIOB configuration */ + GPIO_PinAFConfig(GPIOB, GPIO_PinSource0, 0x09); + GPIO_PinAFConfig(GPIOB, GPIO_PinSource1, 0x09); + GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_LTDC); + GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_LTDC); + GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_LTDC); + GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_LTDC); + + GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_8 | \ + GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11; + + GPIO_Init(GPIOB, &GPIO_InitStruct); + + /* GPIOC configuration */ + GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_LTDC); + GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_LTDC); + GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_LTDC); + + GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_10; + + GPIO_Init(GPIOC, &GPIO_InitStruct); + + /* GPIOD configuration */ + GPIO_PinAFConfig(GPIOD, GPIO_PinSource3, GPIO_AF_LTDC); + GPIO_PinAFConfig(GPIOD, GPIO_PinSource6, GPIO_AF_LTDC); + + GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_6; + + GPIO_Init(GPIOD, &GPIO_InitStruct); + + /* GPIOF configuration */ + GPIO_PinAFConfig(GPIOF, GPIO_PinSource10, GPIO_AF_LTDC); + + GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; + + GPIO_Init(GPIOF, &GPIO_InitStruct); + + /* GPIOG configuration */ + GPIO_PinAFConfig(GPIOG, GPIO_PinSource6, GPIO_AF_LTDC); + GPIO_PinAFConfig(GPIOG, GPIO_PinSource7, GPIO_AF_LTDC); + GPIO_PinAFConfig(GPIOG, GPIO_PinSource10, 0x09); + GPIO_PinAFConfig(GPIOG, GPIO_PinSource11, GPIO_AF_LTDC); + GPIO_PinAFConfig(GPIOG, GPIO_PinSource12, 0x09); + + GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_10 | \ + GPIO_Pin_11 | GPIO_Pin_12; + + GPIO_Init(GPIOG, &GPIO_InitStruct); +} + +/** + * @brief Sets or reset LCD control lines. + * @param GPIOx: where x can be B or D to select the GPIO peripheral. + * @param CtrlPins: the Control line. + * This parameter can be: + * @arg LCD_NCS_PIN: Chip Select pin + * @arg LCD_NWR_PIN: Read/Write Selection pin + * @arg LCD_RS_PIN: Register/RAM Selection pin + * @param BitVal: specifies the value to be written to the selected bit. + * This parameter can be: + * @arg Bit_RESET: to clear the port pin + * @arg Bit_SET: to set the port pin + * @retval None + */ +void STM_LCD_CtrlLinesWrite(GPIO_TypeDef* GPIOx, uint16_t CtrlPins, BitAction BitVal) +{ + /* Set or Reset the control line */ + GPIO_WriteBit(GPIOx, (uint16_t)CtrlPins, (BitAction)BitVal); +} + +/** + * @brief Configures LCD control lines in Output Push-Pull mode. + * @note The LCD_NCS line can be configured in Open Drain mode + * when VDDIO is lower than required LCD supply. + * @param None + * @retval None + */ +void STM_LCD_CtrlLinesConfig(void) +{ + GPIO_InitTypeDef GPIO_InitStructure; + + /* Enable GPIOs clock*/ + RCC_AHB1PeriphClockCmd(LCD_NCS_GPIO_CLK | LCD_WRX_GPIO_CLK, ENABLE); + + /* Configure NCS in Output Push-Pull mode */ + GPIO_InitStructure.GPIO_Pin = LCD_NCS_PIN; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(LCD_NCS_GPIO_PORT, &GPIO_InitStructure); + + /* Configure WRX in Output Push-Pull mode */ + GPIO_InitStructure.GPIO_Pin = LCD_WRX_PIN; + GPIO_Init(LCD_WRX_GPIO_PORT, &GPIO_InitStructure); + + /* Set chip select pin high */ + STM_LCD_CtrlLinesWrite(LCD_NCS_GPIO_PORT, LCD_NCS_PIN, Bit_SET); +} + + /** + * @brief Writes command to select the LCD register. + * @param LCD_Reg: address of the selected register. + * @retval None + */ +void STM_LCD_WriteCommand(uint8_t LCD_Reg) +{ + /* Reset WRX to send command */ + STM_LCD_CtrlLinesWrite(LCD_WRX_GPIO_PORT, LCD_WRX_PIN, Bit_RESET); + + /* Reset LCD control line(/CS) and Send command */ + STM_LCD_ChipSelect(DISABLE); + SPI_I2S_SendData(LCD_SPI, LCD_Reg); + + /* Wait until a data is sent(not busy), before config /CS HIGH */ + + while(SPI_I2S_GetFlagStatus(LCD_SPI, SPI_I2S_FLAG_TXE) == RESET) ; + + while(SPI_I2S_GetFlagStatus(LCD_SPI, SPI_I2S_FLAG_BSY) != RESET); + + STM_LCD_ChipSelect(ENABLE); +} + +/** + * @brief Writes data to select the LCD register. + * This function must be used after STM_LCD_WriteCommand() function + * @param value: data to write to the selected register. + * @retval None + */ +void STM_LCD_WriteData(uint8_t value) +{ + /* Set WRX to send data */ + STM_LCD_CtrlLinesWrite(LCD_WRX_GPIO_PORT, LCD_WRX_PIN, Bit_SET); + + /* Reset LCD control line(/CS) and Send data */ + STM_LCD_ChipSelect(DISABLE); + SPI_I2S_SendData(LCD_SPI, value); + + /* Wait until a data is sent(not busy), before config /CS HIGH */ + + while(SPI_I2S_GetFlagStatus(LCD_SPI, SPI_I2S_FLAG_TXE) == RESET) ; + + while(SPI_I2S_GetFlagStatus(LCD_SPI, SPI_I2S_FLAG_BSY) != RESET); + + STM_LCD_ChipSelect(ENABLE); +} + +/** + * @brief Configure the LCD controller (Power On sequence as described in ILI9341 Datasheet) + * @param None + * @retval None + */ +void STM_LCD_PowerOn(void) +{ + STM_LCD_WriteCommand(0xCA); + STM_LCD_WriteData(0xC3); + STM_LCD_WriteData(0x08); + STM_LCD_WriteData(0x50); + STM_LCD_WriteCommand(LCD_POWERB); + STM_LCD_WriteData(0x00); + STM_LCD_WriteData(0xC1); + STM_LCD_WriteData(0x30); + STM_LCD_WriteCommand(LCD_POWER_SEQ); + STM_LCD_WriteData(0x64); + STM_LCD_WriteData(0x03); + STM_LCD_WriteData(0x12); + STM_LCD_WriteData(0x81); + STM_LCD_WriteCommand(LCD_DTCA); + STM_LCD_WriteData(0x85); + STM_LCD_WriteData(0x00); + STM_LCD_WriteData(0x78); + STM_LCD_WriteCommand(LCD_POWERA); + STM_LCD_WriteData(0x39); + STM_LCD_WriteData(0x2C); + STM_LCD_WriteData(0x00); + STM_LCD_WriteData(0x34); + STM_LCD_WriteData(0x02); + STM_LCD_WriteCommand(LCD_PRC); + STM_LCD_WriteData(0x20); + STM_LCD_WriteCommand(LCD_DTCB); + STM_LCD_WriteData(0x00); + STM_LCD_WriteData(0x00); + STM_LCD_WriteCommand(LCD_FRC); + STM_LCD_WriteData(0x00); + STM_LCD_WriteData(0x1B); + STM_LCD_WriteCommand(LCD_DFC); + STM_LCD_WriteData(0x0A); + STM_LCD_WriteData(0xA2); + STM_LCD_WriteCommand(LCD_POWER1); + STM_LCD_WriteData(0x10); + STM_LCD_WriteCommand(LCD_POWER2); + STM_LCD_WriteData(0x10); + STM_LCD_WriteCommand(LCD_VCOM1); + STM_LCD_WriteData(0x45); + STM_LCD_WriteData(0x15); + STM_LCD_WriteCommand(LCD_VCOM2); + STM_LCD_WriteData(0x90); + STM_LCD_WriteCommand(LCD_MAC); + STM_LCD_WriteData(0xC8); + STM_LCD_WriteCommand(LCD_3GAMMA_EN); + STM_LCD_WriteData(0x00); + STM_LCD_WriteCommand(LCD_RGB_INTERFACE); + STM_LCD_WriteData(0xC2); + STM_LCD_WriteCommand(LCD_DFC); + STM_LCD_WriteData(0x0A); + STM_LCD_WriteData(0xA7); + STM_LCD_WriteData(0x27); + STM_LCD_WriteData(0x04); + + /* colomn address set */ + STM_LCD_WriteCommand(LCD_COLUMN_ADDR); + STM_LCD_WriteData(0x00); + STM_LCD_WriteData(0x00); + STM_LCD_WriteData(0x00); + STM_LCD_WriteData(0xEF); + /* Page Address Set */ + STM_LCD_WriteCommand(LCD_PAGE_ADDR); + STM_LCD_WriteData(0x00); + STM_LCD_WriteData(0x00); + STM_LCD_WriteData(0x01); + STM_LCD_WriteData(0x3F); + STM_LCD_WriteCommand(LCD_INTERFACE); + STM_LCD_WriteData(0x01); + STM_LCD_WriteData(0x00); + STM_LCD_WriteData(0x06); + + STM_LCD_WriteCommand(LCD_GRAM); + thread_sleep(200); + + STM_LCD_WriteCommand(LCD_GAMMA); + STM_LCD_WriteData(0x01); + + STM_LCD_WriteCommand(LCD_PGAMMA); + STM_LCD_WriteData(0x0F); + STM_LCD_WriteData(0x29); + STM_LCD_WriteData(0x24); + STM_LCD_WriteData(0x0C); + STM_LCD_WriteData(0x0E); + STM_LCD_WriteData(0x09); + STM_LCD_WriteData(0x4E); + STM_LCD_WriteData(0x78); + STM_LCD_WriteData(0x3C); + STM_LCD_WriteData(0x09); + STM_LCD_WriteData(0x13); + STM_LCD_WriteData(0x05); + STM_LCD_WriteData(0x17); + STM_LCD_WriteData(0x11); + STM_LCD_WriteData(0x00); + STM_LCD_WriteCommand(LCD_NGAMMA); + STM_LCD_WriteData(0x00); + STM_LCD_WriteData(0x16); + STM_LCD_WriteData(0x1B); + STM_LCD_WriteData(0x04); + STM_LCD_WriteData(0x11); + STM_LCD_WriteData(0x07); + STM_LCD_WriteData(0x31); + STM_LCD_WriteData(0x33); + STM_LCD_WriteData(0x42); + STM_LCD_WriteData(0x05); + STM_LCD_WriteData(0x0C); + STM_LCD_WriteData(0x0A); + STM_LCD_WriteData(0x28); + STM_LCD_WriteData(0x2F); + STM_LCD_WriteData(0x0F); + + STM_LCD_WriteCommand(LCD_SLEEP_OUT); + thread_sleep(200); + STM_LCD_WriteCommand(LCD_DISPLAY_ON); + /* GRAM start writing */ + STM_LCD_WriteCommand(LCD_GRAM); + } + +/** + * @brief LCD Configuration. + * @note This function Configure tha LTDC peripheral : + * 1) Configure the Pixel Clock for the LCD + * 2) Configure the LTDC Timing and Polarity + * 3) Configure the LTDC Layer 1 : + * - The frame buffer is located at FLASH memory + * - The Layer size configuration : 480x272 + * @retval + * None + */ +static void STM_LCD_Config(void) +{ + LTDC_InitTypeDef LTDC_InitStruct; + + /* Configure the LCD Control pins ------------------------------------------*/ + STM_LCD_CtrlLinesConfig(); + STM_LCD_ChipSelect(DISABLE); + STM_LCD_ChipSelect(ENABLE); + + /* Configure the LCD_SPI interface -----------------------------------------*/ + STM_LCD_SPIConfig(); + + /* Power on the LCD --------------------------------------------------------*/ + STM_LCD_PowerOn(); + + /* Enable the LTDC Clock */ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_LTDC, ENABLE); + + /* Enable the DMA2D Clock */ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2D, ENABLE); + +/* Configure the LCD Control pins --------------------------------------------*/ + STM_LCD_AF_GPIOConfig(); + +/* LTDC Configuration *********************************************************/ + /* Polarity configuration */ + /* Initialize the horizontal synchronization polarity as active low */ + LTDC_InitStruct.LTDC_HSPolarity = LTDC_HSPolarity_AL; + /* Initialize the vertical synchronization polarity as active low */ + LTDC_InitStruct.LTDC_VSPolarity = LTDC_VSPolarity_AL; + /* Initialize the data enable polarity as active low */ + LTDC_InitStruct.LTDC_DEPolarity = LTDC_DEPolarity_AL; + /* Initialize the pixel clock polarity as input pixel clock */ + LTDC_InitStruct.LTDC_PCPolarity = LTDC_PCPolarity_IPC; + + /* Configure R,G,B component values for LCD background color */ + LTDC_InitStruct.LTDC_BackgroundRedValue = 0; + LTDC_InitStruct.LTDC_BackgroundGreenValue = 0; + LTDC_InitStruct.LTDC_BackgroundBlueValue = 0; + + /* Configure PLLSAI prescalers for LCD */ + /* Enable Pixel Clock */ + /* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */ + /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAI_N = 192 Mhz */ + /* PLLLCDCLK = PLLSAI_VCO Output/PLLSAI_R = 192/4 = 48 Mhz */ + /* LTDC clock frequency = PLLLCDCLK / RCC_PLLSAIDivR = 48/8 = 6 Mhz */ + RCC_PLLSAIConfig(192, 7, 4); + RCC_LTDCCLKDivConfig(RCC_PLLSAIDivR_Div8); + + /* Enable PLLSAI Clock */ + RCC_PLLSAICmd(ENABLE); + /* Wait for PLLSAI activation */ + while(RCC_GetFlagStatus(RCC_FLAG_PLLSAIRDY) == RESET) + { + } + + /* Timing configuration */ + /* Configure horizontal synchronization width */ + LTDC_InitStruct.LTDC_HorizontalSync = 9; + /* Configure vertical synchronization height */ + LTDC_InitStruct.LTDC_VerticalSync = 1; + /* Configure accumulated horizontal back porch */ + LTDC_InitStruct.LTDC_AccumulatedHBP = 29; + /* Configure accumulated vertical back porch */ + LTDC_InitStruct.LTDC_AccumulatedVBP = 3; + /* Configure accumulated active width */ + LTDC_InitStruct.LTDC_AccumulatedActiveW = 269; + /* Configure accumulated active height */ + LTDC_InitStruct.LTDC_AccumulatedActiveH = 323; + /* Configure total width */ + LTDC_InitStruct.LTDC_TotalWidth = 279; + /* Configure total height */ + LTDC_InitStruct.LTDC_TotalHeigh = 327; + + LTDC_Init(<DC_InitStruct); + +} + +/** + * @brief Initializes the LCD Layers. + * @param None + * @retval None + */ +void LCD_LayerInit(void) +{ + LTDC_Layer_InitTypeDef LTDC_Layer_InitStruct; + + /* Windowing configuration */ + /* In this case all the active display area is used to display a picture then : + Horizontal start = horizontal synchronization + Horizontal back porch = 30 + Horizontal stop = Horizontal start + window width -1 = 30 + 240 -1 + Vertical start = vertical synchronization + vertical back porch = 4 + Vertical stop = Vertical start + window height -1 = 4 + 320 -1 */ + LTDC_Layer_InitStruct.LTDC_HorizontalStart = 30; + LTDC_Layer_InitStruct.LTDC_HorizontalStop = (LCD_SIZE_PIXEL_WIDTH + 30 - 1); + LTDC_Layer_InitStruct.LTDC_VerticalStart = 4; + LTDC_Layer_InitStruct.LTDC_VerticalStop = (LCD_SIZE_PIXEL_HEIGHT + 4 - 1); + + /* Pixel Format configuration*/ + LTDC_Layer_InitStruct.LTDC_PixelFormat = LTDC_Pixelformat_ARGB8888; + /* Alpha constant (255 totally opaque) */ + LTDC_Layer_InitStruct.LTDC_ConstantAlpha = 255; + /* Default Color configuration (configure A,R,G,B component values) */ + LTDC_Layer_InitStruct.LTDC_DefaultColorBlue = 0; + LTDC_Layer_InitStruct.LTDC_DefaultColorGreen = 0; + LTDC_Layer_InitStruct.LTDC_DefaultColorRed = 0; + LTDC_Layer_InitStruct.LTDC_DefaultColorAlpha = 0; + /* Configure blending factors */ + LTDC_Layer_InitStruct.LTDC_BlendingFactor_1 = LTDC_BlendingFactor1_CA; + + /* the length of one line of pixels in bytes + 3 then : + Line Lenth = Active high width x number of bytes per pixel + 3 + Active high width = LCD_SIZE_PIXEL_WIDTH + number of bytes per pixel = 4 (pixel_format : ARGB8888) + */ + LTDC_Layer_InitStruct.LTDC_CFBLineLength = ((LCD_SIZE_PIXEL_WIDTH * 4) + 3); + /* the pitch is the increment from the start of one line of pixels to the + start of the next line in bytes, then : + Pitch = Active high width x number of bytes per pixel */ + LTDC_Layer_InitStruct.LTDC_CFBPitch = (LCD_SIZE_PIXEL_WIDTH * 4); + + /* Configure the number of lines */ + LTDC_Layer_InitStruct.LTDC_CFBLineNumber = LCD_SIZE_PIXEL_HEIGHT; + + /* Start Address configuration : the LCD Frame buffer is defined on SDRAM */ + LTDC_Layer_InitStruct.LTDC_CFBStartAdress = LCD_FRAME_BUFFER; + + /* Initialize LTDC layer 1 */ + LTDC_LayerInit(LTDC_Layer1, <DC_Layer_InitStruct); + + /* Configure blending factors */ + LTDC_Layer_InitStruct.LTDC_BlendingFactor_1 = LTDC_BlendingFactor1_PAxCA; + + /* LTDC configuration reload */ + LTDC_ReloadConfig(LTDC_IMReload); + + /* Enable foreground & background Layers */ + LTDC_LayerCmd(LTDC_Layer1, ENABLE); + + /* LTDC configuration reload */ + LTDC_ReloadConfig(LTDC_IMReload); + + /* dithering activation */ + LTDC_DitherCmd(ENABLE); +} + +uint8_t STM_LCD_Init(void) { + /*!< At this stage the microcontroller clock setting is already configured, + this is done through SystemInit() function which is called from startup + files (startup_stm32f429_439xx.s) before to branch to application main. + */ + + dprintf(SPEW, "initializing LCD\n"); + + /* Configure LCD : Only one layer is used */ + STM_LCD_Config(); + + /* Enable Layer 1 */ + LTDC_LayerCmd(LTDC_Layer1, ENABLE); + + /* Reload configuration of Layer 1 */ + LTDC_ReloadConfig(LTDC_IMReload); + + /* Enable The LCD */ + LTDC_Cmd(ENABLE); + + /* Setup layers */ + LCD_LayerInit(); + + return 0; +} + +/* LK display api here */ +status_t display_get_framebuffer(struct display_framebuffer *fb) { + /* fb->image.pixels = (void *)hLtdcEval.LayerCfg[ActiveLayer].FBStartAdress; + + if (hLtdcEval.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB8888) { + fb->format = DISPLAY_FORMAT_ARGB_8888; + fb->image.format = IMAGE_FORMAT_ARGB_8888; + fb->image.rowbytes = BSP_LCD_GetXSize() * 4; + } else if (hLtdcEval.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) { + fb->format = DISPLAY_FORMAT_RGB_565; + fb->image.format = IMAGE_FORMAT_RGB_565; + fb->image.rowbytes = BSP_LCD_GetXSize() * 2; + } else { + panic("unhandled pixel format\n"); + return ERR_NOT_FOUND; + } + + fb->image.width = BSP_LCD_GetXSize(); + fb->image.height = BSP_LCD_GetYSize(); + fb->image.stride = BSP_LCD_GetXSize(); + fb->flush = NULL;*/ + + return NO_ERROR; +} + +status_t display_get_info(struct display_info *info) { + info->format = DISPLAY_FORMAT_ARGB_8888; + info->width = LCD_SIZE_PIXEL_WIDTH; + info->height = LCD_SIZE_PIXEL_HEIGHT; + + return NO_ERROR; +} + +status_t display_present(struct display_image *image, uint starty, uint endy) { + TRACEF("display_present - not implemented"); + DEBUG_ASSERT(false); + return NO_ERROR; +} diff --git a/target/stm32f429i-disco/rules.mk b/target/stm32f429i-disco/rules.mk index 7c36aef9..5043ea4a 100644 --- a/target/stm32f429i-disco/rules.mk +++ b/target/stm32f429i-disco/rules.mk @@ -15,7 +15,8 @@ GLOBAL_DEFINES += \ PLL_P_VALUE=2 MODULE_SRCS += \ - $(LOCAL_DIR)/init.c + $(LOCAL_DIR)/init.c \ + $(LOCAL_DIR)/lcd.c include make/module.mk