#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); } }