【国民技术N32项目移植】3.天气显示及预报系统之硬件SPI+DAM驱动触摸LCD(ST7789+XPT2046)
本篇文章介绍了如何使用硬件SPI驱动4.3寸LCD触摸电阻屏幕(ST7789+XPT2046),最后加入了DMA来提高SPI的速率最终提高刷新速率。
1、功能介绍
ST7789和XPT2046都采用3.3V供电,LCD尺寸420*380,两个IC都是使用SPI4线进行驱动,所以通过控制片选引脚然后使用一个SPI即可达到通信,只不过由于通信速率不一样。经测试XPT2046的SPI通信速率最高为4M,再高就会有读数误差;使用的SPI2最高 速度为18M,可以正常驱动ST7789。
2、查看手册
SPI部分:
进入RTT官网查看SPI的使用手册,然后根据手册编写程序:https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/spi/spi
更深入的了解RTT的SPI工作模式可以参考这篇文章:https://blog.csdn.net/BLBQ962464/article/details/123485338
DMA:
由于RTT没有提供SPI+DMA的例程,所以需要自己根据国民技术提供的库函数去自行编写程序
3、编写程序
同定时器一样,也是需要使能硬件SPI,然后编写程序。
#define SPI_BUS_NAME "spi2"
#define SPI_ST7789_DEVICE_NAME "spi20"
rt_err_t SPI2_Init(void){
rt_err_t res;
res = rt_spi_bus_attach_device(&spi_dev_st7789,
SPI_ST7789_DEVICE_NAME,
SPI_BUS_NAME,
(void *)0);
if(res != RT_EOK){
rt_kprintf("SPI1 attach error! \r\n");
return res;
}
struct rt_spi_configuration cfg;
cfg.data_width = 8;
cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB;
cfg.max_hz = 18 * 1000 *1000;
rt_spi_configure(&spi_dev_st7789, &cfg);
return RT_EOK;
}
#define SCLK_PIN GET_PIN(B, 13)
#define MOSI_PIN GET_PIN(B, 15)
#define MISO_PIN GET_PIN(B, 14)
#define RES_PIN GET_PIN(B, 10)
#define DC_PIN GET_PIN(B, 11)
#define BLK_PIN GET_PIN(B, 12)
void LCD_GPIO_Init(void){
rt_pin_mode(RES_PIN, PIN_MODE_OUTPUT);
rt_pin_mode(DC_PIN, PIN_MODE_OUTPUT);
rt_pin_mode(BLK_PIN, PIN_MODE_OUTPUT);
rt_pin_mode(ST7789_CS_PIN, PIN_MODE_OUTPUT);
rt_pin_write(RES_PIN, PIN_HIGH);
rt_pin_write(DC_PIN, PIN_HIGH);
rt_pin_write(BLK_PIN, PIN_HIGH);
rt_pin_write(ST7789_CS_PIN, PIN_HIGH);
rt_pin_mode(XPT2046_CS_PIN, PIN_MODE_OUTPUT);
rt_pin_mode(XPT2046_PEN_PIN, PIN_MODE_INPUT_PULLUP);
rt_pin_write(XPT2046_CS_PIN, PIN_HIGH);
}
void LCD_Init(void)
{
SPI2_Init();
LCD_GPIO_Init();
LCD_RES_Clr();
rt_thread_mdelay(100);
LCD_RES_Set();
rt_thread_mdelay(100);
LCD_BLK_Set();
rt_thread_mdelay(100);
LCD_WR_REG(0x11);
rt_thread_mdelay(120);
LCD_WR_REG(0Xf0);
LCD_WR_DATA8(0xc3);
LCD_WR_REG(0Xf0);
LCD_WR_DATA8(0x96);
LCD_WR_REG(0x36);
if(USE_HORIZONTAL==0)LCD_WR_DATA8(0x48);
else if(USE_HORIZONTAL==1)LCD_WR_DATA8(0x88);
else if(USE_HORIZONTAL==2)LCD_WR_DATA8(0x28);
else LCD_WR_DATA8(0xE8);
LCD_WR_REG(0X3a);
LCD_WR_DATA8(0x05);
LCD_WR_REG(0Xe6);
LCD_WR_DATA8(0x0f);
LCD_WR_DATA8(0xf2);
LCD_WR_DATA8(0x3f);
LCD_WR_DATA8(0x4f);
LCD_WR_DATA8(0x4f);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x0e);
LCD_WR_DATA8(0x00);
LCD_WR_REG(0Xc5);
LCD_WR_DATA8(0x2a);
LCD_WR_REG(0Xe0);
LCD_WR_DATA8(0xf0);
LCD_WR_DATA8(0x03);
LCD_WR_DATA8(0x0a);
LCD_WR_DATA8(0x11);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x1c);
LCD_WR_DATA8(0x3b);
LCD_WR_DATA8(0x55);
LCD_WR_DATA8(0x4a);
LCD_WR_DATA8(0x0a);
LCD_WR_DATA8(0x13);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x1c);
LCD_WR_DATA8(0x1f);
LCD_WR_REG(0Xe1);
LCD_WR_DATA8(0xf0);
LCD_WR_DATA8(0x03);
LCD_WR_DATA8(0x0a);
LCD_WR_DATA8(0x0c);
LCD_WR_DATA8(0x0c);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x36);
LCD_WR_DATA8(0x54);
LCD_WR_DATA8(0x49);
LCD_WR_DATA8(0x0f);
LCD_WR_DATA8(0x1b);
LCD_WR_DATA8(0x18);
LCD_WR_DATA8(0x1b);
LCD_WR_DATA8(0x1f);
LCD_WR_REG(0Xf0);
LCD_WR_DATA8(0x3c);
LCD_WR_REG(0Xf0);
LCD_WR_DATA8(0x69);
LCD_WR_REG(0X29);
}
DMA_InitType DMA_InitStructure;
rt_uint16_t DMA1_MEM_LEN;
void LcdFillDMA_Config(DMA_ChannelType* DMA_CHx,rt_uint32_t cpar,rt_uint32_t cmar,rt_uint16_t cndtr){
RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA1, ENABLE);
DMA_DeInit(DMA_CHx);
DMA_InitStructure.PeriphAddr = cpar;
DMA_InitStructure.MemAddr = cmar;
DMA_InitStructure.Direction = DMA_DIR_PERIPH_DST;
DMA_InitStructure.BufSize = cndtr;
DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_DISABLE;
DMA_InitStructure.DMA_MemoryInc = DMA_MEM_INC_DISABLE;
DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_HALFWORD;
DMA_InitStructure.MemDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.CircularMode = DMA_MODE_NORMAL;
DMA_InitStructure.Priority = DMA_PRIORITY_MEDIUM;
DMA_InitStructure.Mem2Mem = DMA_M2M_DISABLE;
DMA_Init(DMA_CHx, &DMA_InitStructure);
}
4、功能验证
不使用DMA进行刷屏
使用触摸屏幕控制DMA刷屏
5、避坑部分
1.SPI的极性以及四种工作模式如何确定:
问题描述: 一开始没有看芯片手册直接使用例程来配置SPI,使用默认的是模式1,半天也没有找到问题。
**解决方案:**查阅资料后,调试半天看手册才发现应该使用模式0!
CPOL 表示时钟信号的初始电平的状态,CPOL 为 0 表示时钟信号初始状态为低电平,为 1 表示时钟信号的初始电平是高电平。CPHA 表示在哪个时钟沿采样数据,CPHA 为 0 表示在首个时钟变化沿采样数据,而 CPHA 为 1 则表示在第二个时钟变化沿采样数据。
**①CPOL=0,CPHA=0、**
**②CPOL=0,CPHA=1、**
**③CPOL=1,CPHA=0、**
**④CPOL=1,CPHA=1。**
2.sConscript的修改和更新
**问题描述:**修改RT-Studio的sConscript文件,并没有实现添加文件功能
**解决方法:**在添加n32g45x_dma.c的时候,需要修改RT-Studio的sConscript文件,修改后需要手动更新一下才能起作用。
3.编码方式的问题(GBK和UTF-8)
**问题描述:**使用LCD显示中文的时候无法显示
**解决方法:**lcd字库.c文件和LCD显示的文件不是同一种编码方式,修改成一样即可。
GBK只验证了两个字节,而UTF-8是需要三个字节的验证。
参考资料:https://blog.csdn.net/qq_47736089/article/details/124854500
最后附上整个过程中使用到的资料:
https://blog.csdn.net/chenhao0568/article/details/99817731
https://blog.csdn.net/BLBQ962464/article/details/123485338
https://bbs.21ic.com/icview-3165424-1-1.html
https://www.elecfans.com/d/663089.html
https://club.rt-thread.org/ask/question/4ba9aad2e4255fea.html
https://bbs.21ic.com/icview-2948020-1-1.html
https://bbs.21ic.com/icview-3259398-2-1.html
http://m.eeworld.com.cn/bbs/forum.php?mod=viewthread&tid=1143661&page=1
https://blog.csdn.net/qq_29505153/article/details/117637481