From b74eceed5e2d7a31d346e2ba4ad33d511adf9272 Mon Sep 17 00:00:00 2001 From: zhji Date: Sat, 27 Apr 2024 21:38:35 +0800 Subject: [PATCH] [feat] add lcd driver --- stm32f4/driver/CMakeLists.txt | 1 + stm32f4/main.c | 3 + stm32f4/src/CMakeLists.txt | 1 + stm32f4/src/lcd.c | 241 ++++++++++++++++++++++++++++++++++ stm32f4/src/lcd.h | 47 +++++++ 5 files changed, 293 insertions(+) diff --git a/stm32f4/driver/CMakeLists.txt b/stm32f4/driver/CMakeLists.txt index ea337ea..8ae2dcd 100755 --- a/stm32f4/driver/CMakeLists.txt +++ b/stm32f4/driver/CMakeLists.txt @@ -7,6 +7,7 @@ src/stm32f4xx_tim.c src/stm32f4xx_spi.c src/stm32f4xx_usart.c src/stm32f4xx_dma.c +src/stm32f4xx_tim.c ) add_library(driver STATIC ${FILELIST}) diff --git a/stm32f4/main.c b/stm32f4/main.c index 076d1da..2972c8f 100755 --- a/stm32f4/main.c +++ b/stm32f4/main.c @@ -1,5 +1,6 @@ #include "stm32f4xx_rcc.h" #include "led.h" +#include "lcd.h" volatile uint32_t system_tick_cnt; @@ -27,6 +28,7 @@ void system_init(void) { led_init(); system_tick_init(); + lcd_init(); } int main(void) @@ -37,6 +39,7 @@ int main(void) __enable_irq(); while (1) { led_loop(); + lcd_loop(); } return 0; } diff --git a/stm32f4/src/CMakeLists.txt b/stm32f4/src/CMakeLists.txt index 49a5b8d..86416a1 100755 --- a/stm32f4/src/CMakeLists.txt +++ b/stm32f4/src/CMakeLists.txt @@ -1,5 +1,6 @@ file(GLOB FILELIST led.c +lcd.c ) add_library(src STATIC ${FILELIST}) diff --git a/stm32f4/src/lcd.c b/stm32f4/src/lcd.c index e69de29..b754fc0 100644 --- a/stm32f4/src/lcd.c +++ b/stm32f4/src/lcd.c @@ -0,0 +1,241 @@ +#include "stm32f4xx_rcc.h" +#include "stm32f4xx_gpio.h" +#include "stm32f4xx_spi.h" +#include "stm32f4xx_dma.h" +#include "stm32f4xx_tim.h" +#include "lcd.h" + +uint8_t lcd_buffer[LCD_PIX * 2]; +extern volatile uint32_t system_tick_cnt; + +static void lcd_pin_cs_select(void) +{ + GPIO_ResetBits(GPIOB, LCD_PIN_CS); +} + +static void lcd_pin_cs_disselect(void) +{ + GPIO_SetBits(GPIOB, LCD_PIN_CS); +} + +static void lcd_pin_dc_cmd(void) +{ + GPIO_ResetBits(GPIOB, LCD_PIN_DC); +} + +static void lcd_pin_dc_data(void) +{ + GPIO_SetBits(GPIOB, LCD_PIN_DC); +} + +static void lcd_pin_res_reset(void) +{ + GPIO_ResetBits(GPIOC, LCD_PIN_RES); +} + +static void lcd_pin_res_disreset(void) +{ + GPIO_SetBits(GPIOC, LCD_PIN_RES); +} + +void lcd_bl_set(uint8_t percent) +{ + if (percent == 0) { + GPIO_ResetBits(GPIOC, LCD_PIN_BL); + } else { + GPIO_SetBits(GPIOC, LCD_PIN_BL); + } +} + +void lcd_init(void) +{ + GPIO_InitTypeDef GPIO_InitStructure; + SPI_InitTypeDef SPI_InitStructure; + DMA_InitTypeDef DMA_InitStructure; + TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; + uint16_t *p; + + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); + RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); + + /* config pin */ + GPIO_InitStructure.GPIO_Pin = LCD_PIN_RES | LCD_PIN_BL; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_Init(GPIOC, &GPIO_InitStructure); + GPIO_InitStructure.GPIO_Pin = LCD_PIN_CS | LCD_PIN_DC; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_Init(GPIOB, &GPIO_InitStructure); + lcd_pin_cs_disselect(); + GPIO_InitStructure.GPIO_Pin = LCD_PIN_SCL | LCD_PIN_SDA; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_Init(GPIOB, &GPIO_InitStructure); + GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_SPI2); + GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2); + + /* config SPI function */ + SPI_I2S_DeInit(SPI2); + SPI_InitStructure.SPI_Mode = SPI_Mode_Master; + SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; + SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; + SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; + SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; + SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; + SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; + SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; + SPI_InitStructure.SPI_CRCPolynomial = 7; + SPI_Init(SPI2, &SPI_InitStructure); + SPI_Cmd(SPI2, ENABLE); + // SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE); + + /* Configure DMA controller to manage SPI request */ + DMA_InitStructure.DMA_BufferSize = LCD_PIX * 2; + DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; + DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull; + DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; + DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; + DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; + DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; + DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t)(&(SPI2->DR)); + DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; + DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; + DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; + DMA_InitStructure.DMA_Priority = DMA_Priority_Low; + DMA_InitStructure.DMA_Channel = DMA_Channel_0; + DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; + DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)lcd_buffer; + DMA_Init(DMA1_Stream4, &DMA_InitStructure); + + /* TIM3 for delay, unit: 0.1ms */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); + TIM_TimeBaseStructure.TIM_Period = 84 / 100 - 1; /* 0.1ms = 100us */ + TIM_TimeBaseStructure.TIM_Prescaler = 0; + TIM_TimeBaseStructure.TIM_ClockDivision = 0; + TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; + TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); + TIM_PrescalerConfig(TIM3, 0, TIM_PSCReloadMode_Immediate); + TIM_Cmd(TIM3, DISABLE); + + /* ST7735 init */ + lcd_bl_set(100); + lcd_pin_res_reset(); + lcd_delay_100us(1); + lcd_pin_res_disreset(); + lcd_delay_100us(1200); + // lcd_cmd(LCD_CMD_SWRESET); + lcd_cmd(LCD_CMD_SLPOUT); + lcd_buffer[0] = 0x08; + lcd_send_data(LCD_CMD_MADCTL, lcd_buffer, 1); + lcd_buffer[0] = 0x5; /* 16-bit/pixel */ + lcd_send_data(LCD_CMD_COLMOD, lcd_buffer, 1); + lcd_cmd_caset(0, LCD_X - 1); + lcd_cmd_raset(0, LCD_Y - 1); + p = (uint16_t *)lcd_buffer; + for (uint32_t i = 0; i < LCD_PIX; i++) { + p[i] = 0x3800; + } + lcd_cmd_ramwr(lcd_buffer, LCD_PIX * 2); + lcd_cmd(LCD_CMD_DISPON); +} + +void lcd_delay_100us(uint16_t cnt) +{ + TIM_SetCounter(TIM3, 0); + TIM_ClearFlag(TIM3, TIM_FLAG_Update); + TIM_Cmd(TIM3, ENABLE); + for (uint16_t i = 0; i < cnt; i++) { + while (RESET == TIM_GetFlagStatus(TIM3, TIM_FLAG_Update)); + TIM_ClearFlag(TIM3, TIM_FLAG_Update); + } + TIM_Cmd(TIM3, DISABLE); +} + +void lcd_send_data_dma(uint16_t data) +{ + DMA_ClearFlag(DMA1_Stream4, DMA_FLAG_FEIF4 | DMA_FLAG_DMEIF4 | DMA_FLAG_TEIF4 | DMA_FLAG_HTIF4 | DMA_FLAG_TCIF4); + // DMA_SetCurrDataCounter(DMA1_Stream4, LCD_PIX); + DMA_Cmd(DMA1_Stream4, ENABLE); +} + +void lcd_send_data(uint8_t cmd, uint8_t *data, uint32_t length) +{ + uint32_t idx = 0; + + lcd_pin_cs_select(); + lcd_pin_dc_cmd(); + SPI_I2S_SendData(SPI2, cmd); + while (RESET == SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)); + while (SET == SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY)); + lcd_pin_dc_data(); + while (idx < length) { + while (RESET == SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)); + SPI_I2S_SendData(SPI2, data[idx++]); + } + while (RESET == SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)); + while (SET == SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY)); + lcd_pin_cs_disselect(); +} + +void lcd_cmd(uint8_t cmd) +{ + lcd_pin_cs_select(); + lcd_pin_dc_cmd(); + SPI_I2S_SendData(SPI2, cmd); + while (RESET == SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)); + while (SET == SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY)); + lcd_pin_cs_disselect(); +} + +void lcd_cmd_caset(uint16_t xs, uint16_t xe) +{ + uint8_t data[4] = {0}; + + xs += LCD_X_START; + xe += LCD_X_START; + data[0] = (uint8_t)(xs >> 8); + data[1] = (uint8_t)(xs); + data[2] = (uint8_t)(xe >> 8); + data[3] = (uint8_t)(xe); + lcd_send_data(LCD_CMD_CASET, data, sizeof(data)); +} + +void lcd_cmd_raset(uint16_t ys, uint16_t ye) +{ + uint8_t data[4] = {0}; + + ys += LCD_Y_START; + ye += LCD_Y_START; + data[0] = (uint8_t)(ys >> 8); + data[1] = (uint8_t)(ys); + data[2] = (uint8_t)(ye >> 8); + data[3] = (uint8_t)(ye); + lcd_send_data(LCD_CMD_RASET, data, sizeof(data)); +} + +void lcd_cmd_ramwr(uint8_t *data, uint32_t length) +{ + lcd_send_data(LCD_CMD_RAMWR, data, length); +} + +void lcd_loop(void) +{ + static uint32_t tick = 0; + + if (system_tick_cnt - tick > 10) { + tick = system_tick_cnt; + lcd_cmd_caset(0, 0); + lcd_cmd_raset(0, 0); + ((uint16_t *)lcd_buffer)[0] = 0x001F; + ((uint16_t *)lcd_buffer)[1] = 0x001F; + ((uint16_t *)lcd_buffer)[2] = 0x001F; + ((uint16_t *)lcd_buffer)[3] = 0x001F; + lcd_cmd_ramwr(lcd_buffer, 8); + } +} diff --git a/stm32f4/src/lcd.h b/stm32f4/src/lcd.h index e69de29..039ea99 100644 --- a/stm32f4/src/lcd.h +++ b/stm32f4/src/lcd.h @@ -0,0 +1,47 @@ +#ifndef __LCD_H__ +#define __LCD_H__ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "stm32f4xx.h" + +#define LCD_PIN_CS (GPIO_Pin_12) +#define LCD_PIN_SCL (GPIO_Pin_13) +#define LCD_PIN_SDA (GPIO_Pin_15) +#define LCD_PIN_DC (GPIO_Pin_14) +#define LCD_PIN_RES (GPIO_Pin_7) +#define LCD_PIN_BL (GPIO_Pin_6) + +#define LCD_X (128) +#define LCD_Y (160) +#define LCD_PIX (LCD_X * LCD_Y) +#define LCD_X_START (2) +#define LCD_Y_START (1) + +#define LCD_CMD_NOP (0x00) +#define LCD_CMD_SWRESET (0x01) +#define LCD_CMD_SLPOUT (0x11) +#define LCD_CMD_DISPOFF (0x28) +#define LCD_CMD_DISPON (0x29) +#define LCD_CMD_CASET (0x2A) +#define LCD_CMD_RASET (0x2B) +#define LCD_CMD_RAMWR (0x2C) +#define LCD_CMD_MADCTL (0x36) +#define LCD_CMD_COLMOD (0x3A) + +void lcd_init(void); +void lcd_delay_100us(uint16_t cnt); +void lcd_send_data(uint8_t cmd, uint8_t *data, uint32_t length); +void lcd_cmd(uint8_t cmd); +void lcd_cmd_caset(uint16_t xs, uint16_t xe); +void lcd_cmd_raset(uint16_t ys, uint16_t ye); +void lcd_cmd_ramwr(uint8_t *data, uint32_t length); +void lcd_loop(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __LCD_H__ */