RH850F1KS1点亮京东方/和辉1.32圆形显示屏(驱动IC:集创北方ICAN3311/ICNA3310B接口通信:QSPI)
最近使用了一款驱动IC为集创北方ICNA3311的显示屏,通信IC接口类型为QSPI,第一次使用此类显示屏,简单记录一下相关知识。
概述
1、使用MCU:RH850F1KS1
2、通信协议:模拟QSPI
3、显示屏自带电源管理芯片,不需要对芯片额外的供电。
通信协议选择
本人使用的显示屏厂家在设计的时候将IM【1:0】选则为10,则使用的是QAD-SPI,即QSPI协议。datasheet中有其他协议的相关描述,有兴趣的可以自行阅读。
QSPI有单线(standart spi)、双线(qual spi)和四线(quad spi)三种模式。ICNA3311切换这三种模式可以通过下图方式:
读取显示屏ID
为了确保屏幕能正常的使用和验证自己写的时序的正确性,往往通过read ID来验证。先看下图ICNA3311的datasheet提供的QSPI读时序的图。
1、QSP读时序
2、读ID的addr = 0x04
代码
/************************
芯片初始化,RST脚拉低100ms在拉高,注意:显示屏的SO3脚和EN脚要拉高不然屏幕无法点亮
*************************/
void chip_init()
{
OLED_RST_CLR();
delay_ms(100);
OLED_RST_SET();
OLED_CS_CLR();
OLED_SO0_CLR();
OLED_SO1_CLR();
OLED_SO2_SET();
OLED_SO3_SET();
OLED_EN_SET();
}
void QSPI_Single_Write(u8 data)
{
for(i=0; i<8; i++)
{
OLED_SCL_CLR();
delay_us(1);
if(data & 0x80)
{
OLED_SO0_SET();
}
else
{
OLED_SO0_CLR();
}
OLED_SCL_SET();
delay_us(1);
data <<= 1;
}
}
u8 QSPI_Single_Read()
{
for(i=0; i<8; i++)
{
if(!(!OLED_SO0_IN()))
{
data |= 1;
}
data <<=1;
}
return data;
}
void QSPI_Write_Cmd(u8 cmd)
{
int i;
OLED_CS_CLR();
delay_us(1);
QSPI_Single_Write(cmd);
OLED_SCL_CLR();
delay_us(1);
OLED_CS_SET();
}
int Read_ID(u8 cmd, u8 addr, u8 id[], u8 len)
{
int i;
OLED_CS_CLR();
delay_us(1);
QSPI_Single_Write(cmd);
QSPI_Single_Write(0x00);
QSPI_Single_Write(addr);
QSPI_Single_Write(0x00);
for(i = 0; i<3; i++)
{
id[i] = QSPI_Single_Read(); //QSPI的每根线是单向传输的,在写的时候IO被配置为输出模式,如果要读取ID,记得要在此时把ID配置为输入模式,如果不需要把ID输入,可以不用再去配置IO为输入模式,可以只提供24个空时钟(3字节),在逻辑分析仪上看芯片返回的ID。
}
OLED_SCL_CLR();
delay_us(1);
OLED_CS_SET();
}
int main()
{
u8 ID[3] = {0};
chip_init(); //芯片复位和初始化
QSPI_Write_Cmd(0xFF); //单线QSPI模式
Read_ID(0x03, 0x04, ID, 3); //读取ID,注意:芯片返回的ID数据和写命令的共用的是SO0脚(QSPI是半双工通信)
uart_send("id = %d, %id, %d", ID[0],ID[1],ID[2]);
return 0;
}
点亮屏幕(RGB565)
为提高写数据的速度,本人接下来使用4线QSPI的方式来实现屏幕点亮。
void QSPI_4Wire_Write(u8 data)
{
int i;
for(i = 0; i<8; i += 4)
{
OLED_SCL_CLR();
delay_us(1);
if(data & 0x80)
{
OLED_SO3_SET();
}
else
{
OLED_SO3_CLR();
}
if(data & 0x40)
{
OLED_SO2_SET();
}
else
{
OLED_SO2_CLR();
}
if(data & 0x20)
{
OLED_SO1_SET();
}
else
{
OLED_SO1_CLR();
}
if(data & 0x10)
{
OLED_SO0_SET();
}
else
{
OLED_SO0_CLR();
}
OLED_SCL_SET();
delay_us(1);
data <<= 4;
}
}
void QSPII_4Wrie_Write_Cmd(u8 cmd)
{
OLED_CS_CLR();
delay_us(1);
QSPI_4Wire_Write(cmd);
OLED_SCL_CLR();
delay_us(1);
OLED_CS_SET();
}
void QSPI_4Wrie_Write_Cmd_0data(u8 cmd, u8 addr)
{
OLED_CS_CLR();
delay_us(1);
QSPI_4Wire_Write(cmd);
QSPI_4Wire_Write(0x00);
QSPI_4Wire_Write(addr);
QSPI_4Wire_Write(0x00);
OLED_SCL_CLR();
delay_us(1);
OLED_CS_SET();
}
void QSPI_4Wrie_Write_Cmd_1data(u8 cmd, u8 addr, u8 pam)
{
OLED_CS_CLR();
delay_us(1);
QSPI_4Wire_Write(cmd);
QSPI_4Wire_Write(0x00);
QSPI_4Wire_Write(addr);
QSPI_4Wire_Write(0x00);
QSPI_4Wire_Write(pam);
OLED_SCL_CLR();
delay_us(1);
OLED_CS_SET();
}
void QSPI_4Wrie_Write_Cmd_4data(u8 cmd, u8 addr, u8 pam1, u8 pam2, u8 pam3, u8 pam4)
{
OLED_CS_CLR();
delay_us(1);
QSPI_4Wire_Write(cmd);
QSPI_4Wire_Write(0x00);
QSPI_4Wire_Write(addr);
QSPI_4Wire_Write(0x00);
QSPI_4Wire_Write(pam1);
QSPI_4Wire_Write(pam2);
QSPI_4Wire_Write(pam3);
QSPI_4Wire_Write(pam4);
OLED_SCL_CLR();
delay_us(1);
OLED_CS_SET();
}
void set_window_XY(u16 xstart, u16 xend, u16 ystart, u16 yend)
{
u8 x1 = (xstart>>8);
u8 x2 = xstart;
u8 xlen1 = (xend>>8);
u8 xlen2 = xend;
u8 y1 = (ystart>>8);
u8 y2 = ystart;
u8 ylen1 = (yend>>8);
u8 ylen2 = yend;
QSPI_4Wrie_Write_Cmd_4data(0x02, 0x2A, x1, x2, xlen1, xlen2);
QSPI_4Wrie_Write_Cmd_4data(0x02, 0x2B, y1, y2, ylen1, ylen2);
}
void set_Color(u8 cmd, u8 addr, u8 color, int len)
{
int i;
OLED_CS_CLR();
delay_us(1);
QSPI_4Wire_Write(cmd);
QSPI_4Wire_Write(0x00);
QSPI_4Wire_Write(addr);
QSPI_4Wire_Write(0x00);
for(i =0; i<len; i++)
{
QSPI_4Wire_Write(color);
}
OLED_SCL_CLR();
delay_us(1);
OLED_CS_SET();
}
void main()
{
chip_init();
QSPI_4Wrie_Write_Cmd(0xFF);
delay_ms(10);
QSPI_4Wrie_Write_Cmd(0x38);
QSPI_4Wrie_Write_Cmd_1data(0x02, 0xFE, 0x00);
QSPI_4Wrie_Write_Cmd_1data(0x02, 0xC4, 0x80); //spi setting, mipi remove
QSPI_4Wrie_Write_Cmd_1data(0x02, 0x3A, 0x55); //55 RGB565, 77 RGB888
QSPI_4Wrie_Write_Cmd_1data(0x02, 0x35, 0x00);
QSPI_4Wrie_Write_Cmd_1data(0x02, 0x53, 0x20);
QSPI_4Wrie_Write_Cmd_1data(0x02, 0x51, 0xFF);
QSPI_4Wrie_Write_Cmd_1data(0x02, 0x63, 0xFF);
QSPI_4Wrie_Write_Cmd_4data(0x02, 0x2A, 0x00, 0x08, 0x01, 0xD9);
QSPI_4Wrie_Write_Cmd_4data(0x02, 0x2B, 0x00, 0x00, 0x01, 0xD1);
QSPI_4Wrie_Write_Cmd_0data(0x11); //sleep out
delay_ms(120);
QSPI_4Wrie_Write_Cmd_0data(0x29); //display on
set_window_XY(0, 0, 476, 466); //设置要点亮的区域
set_Color(0x32, 0x2C, 0xFF, (115200*5));//注意:写的像素长度要全部覆盖点亮的区域屏幕才会亮起,所以设置len = 115200*5。
}
效果图如下:
总结
这个驱动代码适用于京东方和和辉的1.32寸的圆形显示屏,驱动IC为ICNA3311和ICNA3310B,通信协议为QSPI。模拟QSPI写数据的速度对刷屏速度来说太慢了,如果有显示图片和文字等开发需求建议使用硬件QSPI来提高写的速度,如果MCU不支持硬件QSPI,可以用硬件SPI来做单线QSPI的时序。