You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

654 lines
17 KiB
C

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
******************************************************************************
* @file driver_ST7735S.c
* @author <20>Ϻ<EFBFBD><CFBA><EFBFBD><EFBFBD><EFBFBD>
* @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<LCD_W*LCD_H;i++)
{
gImage_test_[i*2]=DataSend[0];
gImage_test_[i*2+1]=DataSend[1];
}
LCDDrawImage(&gImage_test_[0]);
#endif
#if 0
uint16_t i,j;
st7735s_set_window(0,79,0,159);
LCD_CS_0();
for(i=0; i<=80; i++)
{
for (j=0; j<=160; j++)
{
LCD_WR_DATA2(Color);
}
}
co_delay_100us(100);
LCD_CS_1();
#endif
}
void LCD_Show16BYTE(uint16_t *In,uint32_t len)
{
uint8_t DataSend[2];
uint8_t gImage_test_[LCD_W*LCD_H*2];
for(int i =0;i<len;i++)
{
gImage_test_[i*2] = *(In+i);
gImage_test_[i*2+1] = *(In+i);
}
LCDDrawImage(&gImage_test_[0]);
}
void st7735s_display_wait_transfer_done(void)
{
//while(dma_transfer_done == false);
}
/******************************************************************************
Function: Set point color
******************************************************************************/
void LCDSetPointColor(uint8_t XPoint,uint8_t YPoint,uint16_t Color)
{
st7735s_set_window(XPoint,XPoint,YPoint,YPoint);
LCD_CS_0();
LCD_WR_DATAHalfWord(Color);
LCD_CS_1();
}
// 获取字符数据
const uint8_t *get_char_data(char c) {
if(c < 32 || c > 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*********************************************/