/* ****************************************************************************** * @file driver_ST7735S.c * @author �Ϻ����� * @version V1.0.0 * @date 2023 * @brief ST7735S driver. * This file provides firmware functions to manage gc9c01 * with SPI and DMA. User should set GPIO, dma channel, spi * channel according actual resource allocation. ****************************************************************************** * @attention * * Copyright (c) 2023 Bixdo. * All rights reserved. ****************************************************************************** */ #include "ALLinclude.h" // static DMA_LLI_InitTypeDef Link_Channel[20]; // static DMA_HandleTypeDef ST7735S_DMA_Channel; // static dma_LinkParameter_t LinkParameter; // static volatile bool dma_transfer_done = true; // SPI_HandleTypeDef ST7735S_SPI_Handle; // static void (*dma_trans_done_callback)(void) = NULL; static void co_delay_100us(uint32_t timer) { uint32_t timerdelay =timer*100; while(timerdelay) { timerdelay--; } } void LCD_ENABLE_BACKLIGHTANDVCC(void) { GPIO_InitTypeDef GPIO_InitStruct; /* Enable the GPIO Clock */ __HAL_RCC_GPIOB_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET); } void LCD_DISABLE_BACKLIGHT(void) { } static void st7735s_init_io(void) { GPIO_InitTypeDef GPIO_InitStruct; __HAL_RCC_GPIOB_CLK_ENABLE(); // backlight GPIO_InitStruct.Pin = GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); // reset GPIO_InitStruct.Pin = GPIO_PIN_11; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* CS */ GPIO_InitStruct.Pin = GPIO_PIN_12; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* RS */ GPIO_InitStruct.Pin = GPIO_PIN_14; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); LCD_CS_1(); LCD_RS_1(); LCD_RESET_1(); LCD_ENABLE_BACKLIGHTANDVCC(); //co_delay_100us(100); } /****************************************************************************** 函数说明:LCD串行数据写入函数 入口数据:dat 要写入的串行数据 返回值: 无 ******************************************************************************/ void LCD_Writ_Bus(uint8_t *dat,uint16_t datalenth) { LCD_CS_0(); HAL_SPI_Transmit_DMA(&Spi2Handle, dat, datalenth); LCD_CS_1(); } /****************************************************************************** 函数说明:LCD写入数据 入口数据:dat 写入的数据 返回值: 无 ******************************************************************************/ void LCD_WR_DATA(uint8_t dat) { uint8_t DataSend[2]; DataSend[0]=dat; LCD_Writ_Bus(DataSend,1); } void LCD_WR_DATAHalfWord(uint16_t dat) { uint8_t DataSend[2]; DataSend[0]=dat>>8; DataSend[1]=(uint8_t)dat; LCD_Writ_Bus(DataSend,2); } void LCD_WR_DATA2(uint16_t dat) { uint8_t DataSend[2]; DataSend[0]=dat>>8; DataSend[1]=(uint8_t)dat; HAL_SPI_Transmit_DMA(&Spi2Handle, DataSend, 2); //spi_master_transmit_X1(&ST7735S_SPI_Handle, &dat, 1); } /****************************************************************************** 函数说明:LCD写入命令 入口数据:dat 写入的命令 返回值: 无 ******************************************************************************/ void LCD_WR_REG(uint8_t dat) { uint8_t datsend =dat; LCD_RS_0();//写命令 LCD_Writ_Bus(&datsend,1); LCD_RS_1();//写数据 } void st7735s_init(void) { printf("display init "); st7735s_init_io(); LCD_RESET_0(); co_delay_100us(100); LCD_RESET_1(); co_delay_100us(10000); //************* Start Initial Sequence **********// // LCD_WR_REG(0x3A); //0x05-65k mode 0x06-262k mode // LCD_WR_DATA(0x05); LCD_WR_REG(0x11); //Sleep out co_delay_100us(1000); LCD_WR_REG(0x28); //Display off //------------------------------------ST7735S Frame Rate-----------------------------------------// LCD_WR_REG(0xB1); LCD_WR_DATA(0x05); LCD_WR_DATA(0x3A); LCD_WR_DATA(0x3A); LCD_WR_REG(0xB2); LCD_WR_DATA(0x05); LCD_WR_DATA(0x3A); LCD_WR_DATA(0x3A); LCD_WR_REG(0xB3); LCD_WR_DATA(0x05); LCD_WR_DATA(0x3A); LCD_WR_DATA(0x3A); LCD_WR_DATA(0x05); LCD_WR_DATA(0x3A); LCD_WR_DATA(0x3A); //------------------------------------End ST7735S Frame Rate---------------------------------// LCD_WR_REG(0xB4); //Dot inversion LCD_WR_DATA(0x07); // LCD_WR_DATA(0x03); //2020.3.18 XQC //------------------------------------ST7735S Power Sequence---------------------------------// LCD_WR_REG(0xC0); LCD_WR_DATA(0x0E); //0x62 LCD_WR_DATA(0x0E); //0x02 LCD_WR_DATA(0x04); LCD_WR_REG(0xC1); LCD_WR_DATA(0xC0); LCD_WR_REG(0xC2); LCD_WR_DATA(0x0D); LCD_WR_DATA(0x00); LCD_WR_REG(0xC3); LCD_WR_DATA(0x8D); LCD_WR_DATA(0x2A); //0x6A LCD_WR_REG(0xC4); LCD_WR_DATA(0x8D); LCD_WR_DATA(0xEE); //0x6A //---------------------------------End ST7735S Power Sequence-------------------------------------// LCD_WR_REG(0xC5); //VCOM LCD_WR_DATA(0x0E); //0x0E 0X04 LCD_WR_REG(0x36); //刷新方向 LCD_WR_DATA(0x08); //0x78-横屏 //C8/A8/08/68-竖屏 0X18 //------------------------------------ST7735S Gamma Sequence---------------------------------// LCD_WR_REG(0xE0); LCD_WR_DATA(0x10); LCD_WR_DATA(0x0E); LCD_WR_DATA(0x02); LCD_WR_DATA(0x03); LCD_WR_DATA(0x0E); LCD_WR_DATA(0x07); LCD_WR_DATA(0x02); LCD_WR_DATA(0x07); LCD_WR_DATA(0x0A); LCD_WR_DATA(0x12); LCD_WR_DATA(0x27); LCD_WR_DATA(0x37); LCD_WR_DATA(0x00); LCD_WR_DATA(0x0D); LCD_WR_DATA(0x0E); LCD_WR_DATA(0x10); LCD_WR_REG(0xE1); LCD_WR_DATA(0x10); LCD_WR_DATA(0x0E); LCD_WR_DATA(0x03); LCD_WR_DATA(0x03); LCD_WR_DATA(0x0F); LCD_WR_DATA(0x06); LCD_WR_DATA(0x02); LCD_WR_DATA(0x08); LCD_WR_DATA(0x0A); LCD_WR_DATA(0x13); LCD_WR_DATA(0x26); LCD_WR_DATA(0x36); LCD_WR_DATA(0x00); LCD_WR_DATA(0x0D); LCD_WR_DATA(0x0E); LCD_WR_DATA(0x10); //------------------------------------End ST7735S Gamma Sequence-----------------------------// LCD_WR_REG(0x3A); //0x05-65k mode 0x06-262k mode LCD_WR_DATA(0x05); #if LCD_Maker ==LCD_Maker_B LCD_WR_REG(0x21); //Inversion on #endif st7745s_display_on(); //LCD_Fill(0,160,0,160,&ColorSet); LCD_Clear(BLUE); LCDDrawImage(&gImage_test[0]); LCD_PutStr(10,20,"hello",RED); printf("OK\r\n"); } void st7745s_display_off(void) { LCD_WR_REG(0x28); //Display off } void st7745s_display_on(void) { LCD_WR_REG(0x29); //Display on } void st7735s_set_window(uint16_t x_s, uint16_t x_e, uint16_t y_s, uint16_t y_e) { LCD_WR_REG(0x2a);//列地址设置 #if LCD_Maker ==LCD_Maker_A LCD_WR_DATAHalfWord(x_s+24); LCD_WR_DATAHalfWord(x_e+24); LCD_WR_REG(0x2b);//行地址设置 LCD_WR_DATAHalfWord(y_s); LCD_WR_DATAHalfWord(y_e); #elif LCD_Maker ==LCD_Maker_B LCD_WR_DATAHalfWord(x_s+26); LCD_WR_DATAHalfWord(x_e+26); LCD_WR_REG(0x2b);//行地址设置 LCD_WR_DATAHalfWord(y_s+1); LCD_WR_DATAHalfWord(y_e+1); #endif LCD_WR_REG(0x2c);//储存器写 } /****************************************************************************** 函数说明:区域填充颜色 入口数据:x1,x2,y1,y2,color颜色 返回值: 无 ******************************************************************************/ void LCD_Fill(uint16_t x_s, uint16_t x_e, uint16_t y_s, uint16_t y_e,uint16_t *color) { uint16_t i,j; st7735s_set_window(x_s,x_e,y_s,y_e); LCD_CS_0(); co_delay_100us(1000); for(i=x_s; i<=x_e; i++) { for (j=y_s; j<=y_e; j++) { LCD_WR_DATA2(*color); color++; } } LCD_CS_1(); } /****************************************************************************** 函数说明:全屏刷新颜色 入口数据:color颜色 返回值: 无 ******************************************************************************/ void LCD_Clear(uint16_t Color) { #if 1 uint8_t gImage_test_[LCD_W*LCD_H*2]; uint8_t DataSend[2]; DataSend[0]=Color>>8; DataSend[1]=(uint8_t)Color; for(int i =0;i 126) return NULL; return &Font5x7_Data[(c - 32) * 5]; } // 绘制字符 void draw_char(uint8_t x, uint8_t y, char c, uint16_t color) { const uint8_t *data = get_char_data(c); if(!data) return; for(uint8_t col = 0; col < 5; col++) { uint8_t pixels = data[col]; for(uint8_t row = 0; row < 7; row++) { if(pixels & (1 << row)) { LCDSetPointColor(x + col, y + row, color); } } } } // 绘制字符串 void LCD_PutStr(uint8_t x, uint8_t y, const char *str, uint16_t color) { char c; while(*str) { c = *str; draw_char(x,y,c,color); x += 6; // 字符宽度+1像素间距 str++; } } /****************************************************************************** Function: show one char ******************************************************************************/ void LCDShowChar(uint8_t XPoint,uint8_t YPoint,char c,uint16_t Color) { st7735s_set_window(XPoint,XPoint,YPoint,YPoint); LCD_CS_0(); LCD_WR_DATAHalfWord(Color); LCD_CS_1(); } /****************************************************************************** Function: Set point color ******************************************************************************/ void LCDDrawImage(uint8_t *p) { //LCD_Clear(WHITE);//clean screen st7735s_set_window(0,LCD_W-1,0,LCD_H-1); LCD_CS_0(); HAL_SPI_Transmit_DMA(&Spi2Handle, p, LCD_W*LCD_H*2); // for(i=0; i<=80*160; i++) // { // // for (j=0; j<=160; j++) // { // PicH = *(p+i*2);//data hight byte first // PicL = *(p+i*2+1); // LCD_WR_DATA2(PicH<<8 | PicL); // printf("0x%X ",PicH); // printf("0x%X ",PicL); // //HAL_SPI_Transmit_DMA(&Spi2Handle, p+i*2, 1); // //HAL_SPI_Transmit_DMA(&Spi2Handle, p+i*2+1, 1); // } // } co_delay_100us(1000); LCD_CS_1(); } #if 0 void st7735s_display(uint32_t pixel_count, uint16_t *data, void (*callback)(void)) { uint32_t i; uint32_t total_count = pixel_count / 2; // accoding source width uint8_t link_count = total_count / 4000; if(dma_transfer_done == false) { return; } else { dma_transfer_done = false; } dma_trans_done_callback = callback; if(total_count % 4000) { link_count++; } for (i = 0; i < link_count; i++) { uint8_t all_set = (total_count <= 4000); LinkParameter.SrcAddr = (uint32_t)&data[i * 8000]; LinkParameter.DstAddr = (uint32_t)&SPIM1->DR; if(all_set) { LinkParameter.NextLink = 0; } else { LinkParameter.NextLink = (uint32_t)&Link_Channel[i + 1]; } LinkParameter.Data_Flow = DMA_M2P_DMAC; LinkParameter.Request_ID = ST7735S_DMA_Channel.Init.Request_ID; LinkParameter.Source_Inc = DMA_ADDR_INC_INC; LinkParameter.Desination_Inc = DMA_ADDR_INC_NO_CHANGE; LinkParameter.Source_Width = DMA_TRANSFER_WIDTH_32; LinkParameter.Desination_Width = DMA_TRANSFER_WIDTH_16; LinkParameter.Burst_Len = DMA_BURST_LEN_4; LinkParameter.Size = all_set ? (total_count) : 4000; LinkParameter.gather_enable = 0; LinkParameter.scatter_enable = 0; total_count -= 4000; dma_linked_list_init(&Link_Channel[i], &LinkParameter); } ST7735S_SPI_Handle.Init.Frame_Size = SPI_FRAME_SIZE_16BIT; ST7735S_SPI_Handle.MultWireParam.Wire_X2X4 = Wire_X4; ST7735S_SPI_Handle.MultWireParam.InstructLength = INST_8BIT; ST7735S_SPI_Handle.MultWireParam.Instruct = 0x32; ST7735S_SPI_Handle.MultWireParam.AddressLength = ADDR_24BIT; ST7735S_SPI_Handle.MultWireParam.Address = 0x003C00; LCD_CS_1(); spi_master_transmit_X2X4_DMA(&ST7735S_SPI_Handle); dma_linked_list_start_IT(Link_Channel, &LinkParameter, ST7735S_DMA_Channel.Channel); } #endif #if 0 void st7735s_display_gather(uint32_t pixel_count, uint16_t *data, uint16_t interval, uint16_t count) { #define DMA_TRANSFER_SIZE 4000 uint32_t total_count = pixel_count / 2; // accoding source width uint16_t line_count_in_single_list = DMA_TRANSFER_SIZE/(count/2); uint16_t src_width_count_in_single_list = line_count_in_single_list*(count/2); uint8_t link_count, i; if(dma_transfer_done == false) { return; } else { dma_transfer_done = false; } link_count = total_count / src_width_count_in_single_list; if(total_count % src_width_count_in_single_list) { link_count++; } for (i = 0; i < link_count; i++) { uint8_t all_set = (total_count <= src_width_count_in_single_list); LinkParameter.SrcAddr = (uint32_t)&data[i * interval * line_count_in_single_list]; LinkParameter.DstAddr = (uint32_t)&SPIM1->DR; if(all_set) { LinkParameter.NextLink = 0; } else { LinkParameter.NextLink = (uint32_t)&Link_Channel[i + 1]; } LinkParameter.Data_Flow = DMA_M2P_DMAC; LinkParameter.Request_ID = ST7735S_DMA_Channel.Init.Request_ID; LinkParameter.Source_Inc = DMA_ADDR_INC_INC; LinkParameter.Desination_Inc = DMA_ADDR_INC_NO_CHANGE; LinkParameter.Source_Width = DMA_TRANSFER_WIDTH_32; LinkParameter.Desination_Width = DMA_TRANSFER_WIDTH_16; LinkParameter.Burst_Len = DMA_BURST_LEN_4; LinkParameter.Size = all_set ? (total_count) : src_width_count_in_single_list; LinkParameter.gather_enable = 1; LinkParameter.scatter_enable = 0; total_count -= src_width_count_in_single_list; dma_linked_list_init(&Link_Channel[i], &LinkParameter); } ST7735S_SPI_Handle.Init.Frame_Size = SPI_FRAME_SIZE_16BIT; ST7735S_SPI_Handle.MultWireParam.Wire_X2X4 = Wire_X4; ST7735S_SPI_Handle.MultWireParam.InstructLength = INST_8BIT; ST7735S_SPI_Handle.MultWireParam.Instruct = 0x32; ST7735S_SPI_Handle.MultWireParam.AddressLength = ADDR_24BIT; ST7735S_SPI_Handle.MultWireParam.Address = 0x003C00; LCD_CS_1(); spi_master_transmit_X2X4_DMA(&ST7735S_SPI_Handle); __DMA_GATHER_FUNC_ENABLE(ST7735S_DMA_Channel.Channel); __DMA_GATHER_INTERVAL(ST7735S_DMA_Channel.Channel, (interval-count)/2); __DMA_GATHER_COUNT(ST7735S_DMA_Channel.Channel, count/2); dma_linked_list_start_IT(Link_Channel, &LinkParameter, ST7735S_DMA_Channel.Channel); } __attribute__((section("ram_code"))) void st7735s_dma_isr(void) { void (*callback)(); while(__SPI_IS_BUSY(SPIM1)); // CS Release LCD_CS_1(); /* Clear Transfer complete status */ dma_clear_tfr_Status(ST7735S_DMA_Channel.Channel); /* channel Transfer complete interrupt disable */ dma_tfr_interrupt_disable(ST7735S_DMA_Channel.Channel); __SPI_DISABLE(ST7735S_SPI_Handle.SPIx); __SPI_DATA_FRAME_SIZE(ST7735S_SPI_Handle.SPIx, SPI_FRAME_SIZE_16BIT); dma_transfer_done = true; callback = dma_trans_done_callback; dma_trans_done_callback = NULL; if(callback) { callback(); } } #endif /*********************************************END OF FILE*********************************************/