友达1.2寸圆形显示器,使用SPI或MIPI驱动.........啊!有好大个坑!
1.2寸的AMOLED,看到这个OLED,好高大上,结果是MIPI+SPI驱动,第一反应是要两种协议同时用,MIPI在STM32上好难实现,就想用SPI,看完整个手册,也没有找到初始化demo或者说也没有驱动芯片手册,这个显示驱动芯片就是我认为的巨坑:AUO W0222 ASIC,找遍某娘,问遍某服,都没听过,找了大半年,总感觉浪费了我三块屏,150大洋啊。
经过不懈努力,加上我能编会说(pian),最终在半年后的今天(2020年5月1号),发现了,这个显示器使用的驱动芯片型号“应该可能是”RM67162
所以必须要试一下!!!!!
根据手册上的SPI驱动方式,请看下图,写了一个驱动文件,还用了他给我的初始化demo"片段",结果没成功在使劲想不通,有不断修改SPI的驱动时,终于,我还是放弃了一下驱动成功,转而先确认我的资料是否有误。就是有坑好多坑。
第一个坑:我自己丢失了原本的资料,从屏幕上无法确认这个屏的真实型号,在网上搜罗了一堆型号,最相近的就是X20BLN01和X120BLN02以及一个H120BLN01。长得都差不多,驱动IC都是AUO W022 ASIC。
第二个坑:就是这个驱动时序了,STM32基本没有MIPI,所以在我使用SPI一下驱动不成功时,就搁置了大半年,然而如今却发现手册上的SPI不适合这个屏!!!
第三个坑:驱动IC:AUO W022???从上文就知道,现在大概确认驱动型号时RM67162了,所以终于可以找到驱动IC的手册了,注意这里找到的时驱动IC的手册,不是屏幕的手册,这个驱动手册里包含了寄存器等深层的资料。有他才真的找到了驱动时序。
下面来说一下如何正确从0开始,使用正确的资料,确定这些坑。
首先:要确定屏幕手册,浏览了多个手册,FPC排线都时24Pins,当然引脚名时不一样的,所以我就用火眼金睛(睁的比牛眼睛还大)仔细的看实际屏幕的引脚,对比手册上的可能排序,尤其时电源和GND,发现这个屏时X120BLN02的,这样才能确认如何接线。我使用如下硬件电路:还有一点这个屏FPC排线上自带电源处理器,所以无需担心AMOLED的驱动电源问题。
硬件接线可以不看驱动IC,但要写软件,就离不开驱动IC的手册了。这个可是排坑最多的。一般而言,肯定是用屏幕手册上的时序,对应找驱动IC上的驱动时序,然后用这个时序驱动。但毕竟是排坑:这个屏幕手册上的时序不一定对。
软件上使用keil_v5加STM32F10x,我使用的是103VET6。如前面所说,直接驱动,屏幕没有反应,那就需要先确认硬件和时序,硬件确认了如何确认时序呢,不能使用直接驱动,结合以往经验,先读取驱动IC的ID,读出来就表示时序没有问题。
按照屏幕手册,读取了一个星期,一直是输出0xFF 0xFF 0xFF,使用逻辑器发现时序是有的。在不断修改硬件和软件时,发现驱动IC手册上还有好几种SPI时序,然后就一一测试,终于找到了正确的时序:
注意看这个时序图,是四线SPI加命令数据线,,,而屏幕手册上命令数据线(DCX)根本没用。还有时序图在DCX上拉以后会多出一个空时钟,如果没有这个空时钟,ID会是:80 81 05,否则是01 02 A0。这里居然有一个坑:我也不知道这个ID哪个对,手册上两个都不是:看下面00 80 00,什么鬼
为了确认这个空时钟到底有没有用,我又找了一个多数据的寄存器去读,读出的结果:没有哪个空时钟时90 88 8B 8B 7F有了空时钟时21 11 17 16 FF ,从这个最后一个字节看,基本可以确认了,时必须要这个空时钟的。所以屏幕的ID是01 02 A0,但也不是手册上的00 80 00,是不是坑!!!
现在确认了时序,可以读取ID了,就继续配置其他寄存器,但没有准确的初始化demo片段,所以也是举步维艰。
以下就是正确的软件了:SPI时序和普通的SPI没有太大区别,唯一就是时钟可以很快,快到200ns
uint8_t SPI_ReadWriteByte(uint8_t TxData)
{
uint8_t cnt;
uint8_t RxData=0;
for(cnt=0; cnt <8; cnt++)
{
SPI_SCL_RESET(); //时钟 - 低
RxData <<= 1;
if(SPI_MISO_READ()) //读取数据
{
RxData |= 0x01;
}
if(TxData & 0x80) //发送数据
{
SPI_MOSI_SET();
}
else
{
SPI_MOSI_RESET();
}
spi_delay_ns(1);
SPI_SCL_SET();
spi_delay_ns(1);
TxData <<= 1;
}
return RxData;
}
屏幕的驱动代码:(读取到正确的id)
//写命令
void lcd_write_cmd(uint8_t cmd)
{
SPI_CS_RESET();
delay_us(1);
LCD_DCX_RESET();
SPI_ReadWriteByte(cmd);//1st
LCD_DCX_SET();
delay_us(1);
SPI_CS_SET();
}
//写数据
void lcd_write_cmd_data(uint8_t cmd, uint8_t *data, uint8_t len)
{
uint8_t cnt;
SPI_CS_RESET();
delay_us(1);
LCD_DCX_RESET();
SPI_ReadWriteByte(cmd);//1st
LCD_DCX_SET();
for(cnt=0;cnt<len;cnt++)
SPI_ReadWriteByte(data[cnt]);//2st
delay_us(1);
SPI_CS_SET();
}
//读数据
void lcd_read_cmd_data(uint16_t cmd, uint8_t *data, uint8_t len)
{
uint8_t cnt;
SPI_CS_RESET();
delay_us(1);
LCD_DCX_RESET();
SPI_ReadWriteByte(cmd);//1st
LCD_DCX_SET();//2st
if(len>1)
{
SPI_SCL_RESET();
SPI_SCL_SET();
for(cnt=0;cnt<len;cnt++)
data[cnt]=SPI_ReadWriteByte(0xFF);//2st
}
else
{
*data = SPI_ReadWriteByte(0xFF);//2st
}
delay_us(1);
SPI_CS_SET();
}
void lcd_reset(void)
{
LCD_XRES_RESET();
delay_ms(1);
LCD_XRES_SET();
delay_ms(10);
}
void lcd_Init(void)
{
uint8_t id[3];
lcd_reset();
lcd_read_cmd_data(0x04, id, 3);
USART1_SendData(id, 3);
}
OK,基本上有眉目了剩下的最后一个坑就是初始化demo片段了,下一个文章再见。