用fsmc模拟8080协议来驱动ILI9341的显示
8080协议
8080 时序也叫因特尔总线,一般mcu(mpu)模式的lcd上。
Inter总线控制线有四根:
RD:写使能
WR:读使能
DC(RS):数据/命令
CS:片选
LCD控制及传输数据所需要的管脚:
管脚名称 | 功能描述 |
---|---|
CS | 片选信号 |
DC(RS) | 数据或者命令管脚(1:数据读写,0:命令读写) |
WR | MCU(MPU)向LCD写入数据控制线,上升沿有效,写数据时 RD拉高 |
RD | MCU (MPU) 从LCD读数据控制线,上升沿有效,读数据时,WR拉高 |
DB[x:0] | 8/9/16/18bit 双向数据总线,一般8位MCU接口用的比较多 |
RST | 硬件复位 LCD 信号 |
BL | LCD背光信号 |
IM2/IM1/IM0 | 接口控制. IM2=0 串行,IM2 =1,IM1=0,IM0=0,6800/8080 8bit 并行接口;IM1=0,IM0=1,6800/8080 16bit 并行接口;IM1=1,IM0=0,6800/8080 9bit 并行接口;IM1=1,IM0=1,6800/8080 18bit 并行接口; |
P68 | 6800/8080 选择。0 表示8080,1 表示6800 |
以下是8080时序图
Fsmc
由于 FSMC 外设可以用于控制扩展的外部存储器,而 MCU 对液晶屏的操作实际上就是把显示数据写入到显存中,与控制SRAM 存储器非常类似,且 8080 接口的通讯时序完全可以使用 FSMC 外设产生,因而非常适合使用 FSMC控制液晶屏。
获取官方的sdk
官方在mindsdk中提供了一系列的参考的例程给我们参考,我们通过下载可以获取到这个sdk,打开其中的lcd.c和lcd.h文件查看其中的代码,可以发现其中的代码提供的是官方支持的显示屏其驱动芯片为st7796s,但是手头只有一块ILI9341的显示屏.查看fsmc的驱动代码,能发现其中提供了现成的发送命令、发送数据、读取命令、读取数据.那么只要发送相应的命令即可实现驱动.然后就是查询ILI9341的芯片手册,获取到主要命令.完成初始化,设置窗口,填充色块的代码.然后就完成了最初的代码,其中利用到了delay_us和delay_ms函数主要是参考之前论坛中两位大佬写的systicks系统定时器编写延时器来编写的.这里和这里.
然后就实现了ILI9341芯片显示屏的驱动.
相关代码如下
void LCD_Init(LCD_Init_Type * init)
{
LCD_InitHardware();
GPIO_SetBits(BOARD_LCD_RST_GPIO_PORT, BOARD_LCD_RST_GPIO_PIN);
GPIO_ClearBits(BOARD_LCD_RST_GPIO_PORT, BOARD_LCD_RST_GPIO_PIN);
GPIO_SetBits(BOARD_LCD_RST_GPIO_PORT, BOARD_LCD_RST_GPIO_PIN);
delay_ms(50);
LCD_WriteCmd(0xCF);
LCD_WriteData(0x00);
LCD_WriteData(0xC1);
LCD_WriteData(0X30);
LCD_WriteCmd(0xED);
LCD_WriteData(0x64);
LCD_WriteData(0x03);
LCD_WriteData(0X12);
LCD_WriteData(0X81);
LCD_WriteCmd(0xE8);
LCD_WriteData(0x85);
LCD_WriteData(0x10);
LCD_WriteData(0x7A);
LCD_WriteCmd(0xCB);
LCD_WriteData(0x39);
LCD_WriteData(0x2C);
LCD_WriteData(0x00);
LCD_WriteData(0x34);
LCD_WriteData(0x02);
LCD_WriteCmd(0xF7);
LCD_WriteData(0x20);
LCD_WriteCmd(0xEA);
LCD_WriteData(0x00);
LCD_WriteData(0x00);
LCD_WriteCmd(0xC0); //Power control
LCD_WriteData(0x1B); //VRH[5:0]
LCD_WriteCmd(0xC1); //Power control
LCD_WriteData(0x01); //SAP[2:0];BT[3:0]
LCD_WriteCmd(0xC5); //VCM control
LCD_WriteData(0x30); //3F
LCD_WriteData(0x30); //3C
LCD_WriteCmd(0xC7); //VCM control2
LCD_WriteData(0XB7);
LCD_WriteCmd(0x36); // Memory Access Control
LCD_WriteData(0x48);
LCD_WriteCmd(0x3A);
LCD_WriteData(0x55);
LCD_WriteCmd(0xB1);
LCD_WriteData(0x00);
LCD_WriteData(0x1A);
LCD_WriteCmd(0xB6); // Display Function Control
LCD_WriteData(0x0A);
LCD_WriteData(0xA2);
LCD_WriteCmd(0xF2); // 3Gamma Function Disable
LCD_WriteData(0x00);
LCD_WriteCmd(0x26); //Gamma curve selected
LCD_WriteData(0x01);
LCD_WriteCmd(0xE0); //Set Gamma
LCD_WriteData(0x0F);
LCD_WriteData(0x2A);
LCD_WriteData(0x28);
LCD_WriteData(0x08);
LCD_WriteData(0x0E);
LCD_WriteData(0x08);
LCD_WriteData(0x54);
LCD_WriteData(0XA9);
LCD_WriteData(0x43);
LCD_WriteData(0x0A);
LCD_WriteData(0x0F);
LCD_WriteData(0x00);
LCD_WriteData(0x00);
LCD_WriteData(0x00);
LCD_WriteData(0x00);
LCD_WriteCmd(0XE1); //Set Gamma
LCD_WriteData(0x00);
LCD_WriteData(0x15);
LCD_WriteData(0x17);
LCD_WriteData(0x07);
LCD_WriteData(0x11);
LCD_WriteData(0x06);
LCD_WriteData(0x2B);
LCD_WriteData(0x56);
LCD_WriteData(0x3C);
LCD_WriteData(0x05);
LCD_WriteData(0x10);
LCD_WriteData(0x0F);
LCD_WriteData(0x3F);
LCD_WriteData(0x3F);
LCD_WriteData(0x0F);
LCD_WriteCmd(0x2B);
LCD_WriteData(0x00);
LCD_WriteData(0x00);
LCD_WriteData(0x01);
LCD_WriteData(0x3f);
LCD_WriteCmd(0x2A);
LCD_WriteData(0x00);
LCD_WriteData(0x00);
LCD_WriteData(0x00);
LCD_WriteData(0xef);
LCD_WriteCmd(0x11); //Exit Sleep
delay_ms(120);
LCD_WriteCmd(0x29); //display on
LCD_Display_Dir(2); //选择--屏幕显示方式
LCD_ClearWindow(0,0,240,320,WHITE);
void LCD_SetWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{
uint16_t x2,y2;
x2=x0+x1-1;
y2=y0+y1-1;
LCD_WriteCmd(0x2a);
LCD_WriteData(x0 >> 8);
LCD_WriteData(x0 & 0xff);
LCD_WriteData(x2 >> 8);
LCD_WriteData(x2 & 0xff);
LCD_WriteCmd(0x2b);
LCD_WriteData(y0 >> 8);
LCD_WriteData(y0 & 0xff);
LCD_WriteData(y2 >> 8);
LCD_WriteData(y2 & 0xff);
}
void LCD_FillWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t * color)
{
LCD_SetWindow(x0, y0, x1, y1);
LCD_WriteCmd(0x2c);
for(uint32_t i = 0; i <= x1 - x0; i++)
{
for(uint32_t j = 0; j <= y1 - y0; j++)
{
LCD_WriteData((* color++));
}
}
}
!
在后来我还用lvgl的demo跑了一下,但是因为非官方屏幕,所以尺寸适配的不是很友好.
总结
mindsdk中提供的示例很好,代码写的很好,但是就是在函数中的注释太少,不便于理解,但是在参数的描述很到位.