[Zynq]ZedBoard OLED驱动方法改进
1赞一、声明
【声明】本文由cuter原创,未经允许,禁止转载。
二、前言
距离第一版OLED驱动的出炉已经3年多了,期间有很多人用过这版驱动,相信以后也会有人尝试用同样的思路去完成设计,这是让人高兴的一件事。《一步步艰难搞定OLED》一文里曾简单的分析过几种方案,最后采用的方案很容易实现,当时主要考虑功能的实现,所以在一定程度上牺牲了效率。三年的时间里有很多人问过各种问题,但基本都是沿着我的老路走,并没有人对我的方案进行改进,觉得有点遗憾。
三、改进思路
这是第一次改进,主要目的是对软件驱动代码进行精简和加速。
后续会进行更加严谨的分析,如果有必要,可以尝试用PL实现底层函数write_data()和write_cmd(),从而更好地平衡PS和PL的工作量。
对驱动程序的各个函数进行追本溯源可以发现,最底层的操作是下面几个宏定义:
---------------------------------------------------------
// DC
#define Set_OLED_DC (Xil_Out32(OLED_BASE_ADDR,Xil_In32(OLED_BASE_ADDR)|(1<<OLED_DC)))
#define Clr_OLED_DC (Xil_Out32(OLED_BASE_ADDR,Xil_In32(OLED_BASE_ADDR)&(~(1<<OLED_DC))))
// RES
#define Set_OLED_RES (Xil_Out32(OLED_BASE_ADDR,Xil_In32(OLED_BASE_ADDR)|(1<<OLED_RES)))
#define Clr_OLED_RES (Xil_Out32(OLED_BASE_ADDR,Xil_In32(OLED_BASE_ADDR)&(~(1<<OLED_RES))))
// SCLK
#define Set_OLED_SCLK (Xil_Out32(OLED_BASE_ADDR,Xil_In32(OLED_BASE_ADDR)|(1<<OLED_SCLK)))
#define Clr_OLED_SCLK (Xil_Out32(OLED_BASE_ADDR,Xil_In32(OLED_BASE_ADDR)&(~(1<<OLED_SCLK))))
// SDIN
#define Set_OLED_SDIN (Xil_Out32(OLED_BASE_ADDR,Xil_In32(OLED_BASE_ADDR)|(1<<OLED_SDIN)))
#define Clr_OLED_SDIN (Xil_Out32(OLED_BASE_ADDR,Xil_In32(OLED_BASE_ADDR)&(~(1<<OLED_SDIN))))
// OLED_VBAT
#define Set_OLED_VBAT (Xil_Out32(OLED_BASE_ADDR,Xil_In32(OLED_BASE_ADDR)|(1<<OLED_VBAT)))
#define Clr_OLED_VBAT (Xil_Out32(OLED_BASE_ADDR,Xil_In32(OLED_BASE_ADDR)&(~(1<<OLED_VBAT))))
// OLED_VDD
#define Set_OLED_VDD (Xil_Out32(OLED_BASE_ADDR,Xil_In32(OLED_BASE_ADDR)|(1<<OLED_VDD)))
#define Clr_OLED_VDD (Xil_Out32(OLED_BASE_ADDR,Xil_In32(OLED_BASE_ADDR)&(~(1<<OLED_VDD))))
---------------------------------------------------------
根据以前开发作图程序的经验,利用Xil_Out32()和Xil_In32()对外设进行写和读所消耗的时间是不同的,读操作耗时要远高于写操作。所以,这一点就可以做文章了,也就是本次改进的核心:干掉读操作。
这种改进从理论上就知道必然可以提高效率,因为原先一次操作需要首先读取OLED引脚状态,然后再计算出需要用的数据,最后将数据送至OLED;改进后就只有一次写操作。
动机和目标都有了,就想想办法吧。既然单纯由PS实现位操作比较麻烦,能不能用PS、PL合作的方式实现呢?HDL实现位操作是十分简单的,所以这种想法是具有很好滴可行性的。
既然大方向定了,接下来就不难了,思路如下:
操作oled IP核的操作码分成两部分:
1、位编号:用于表示要操作的对象是oled的哪个引脚(硬件相关)
2、标志位:用于表示所进行的操作是置位还是清零;1:置位,0:清零
有了这两部分,我们就可以轻松上实现对编号是“位编号”的引脚进行“标志位”操作了。
下面就是干货了,虽然不多,但是是一种精益求精的态度。
四、修改后的关键代码
OLED IP核关键代码:
这一行代码实现了,把slv_reg0的bit3赋值给编号为slv_reg0[2:0]的oled引脚。
软件驱动程序关键代码:
驱动就是配合OLED IP核,将正确的数据送至IP核内的寄存器。
----------------------------------------------------------
// DC
// bit0~2: bit position,当前操作的位编号
// bit3: set or reset,置位还是清零
// 操作码:
/*
* DC: 0 reset; 8 set
* RES: 1 reset; 9 set
* SCLK: 2 reset 8+2 set
* SDIN: 3 reset 8+3 set
* VBAT: 4 reset 8+4 set
* VDD: 5 reset 8+5 set
* */
#define Set_OLED_DC (Xil_Out32(OLED_BASE_ADDR,(8+OLED_DC)))
#define Clr_OLED_DC (Xil_Out32(OLED_BASE_ADDR,OLED_DC))
// RES
#define Set_OLED_RES (Xil_Out32(OLED_BASE_ADDR,(8+OLED_RES)))
#define Clr_OLED_RES (Xil_Out32(OLED_BASE_ADDR,OLED_RES))
// SCLK
#define Set_OLED_SCLK (Xil_Out32(OLED_BASE_ADDR,(8+OLED_SCLK)))
#define Clr_OLED_SCLK (Xil_Out32(OLED_BASE_ADDR,OLED_SCLK))
// SDIN
#define Set_OLED_SDIN (Xil_Out32(OLED_BASE_ADDR,(8+OLED_SDIN)))
#define Clr_OLED_SDIN (Xil_Out32(OLED_BASE_ADDR,OLED_SDIN))
// OLED_VBAT
#define Set_OLED_VBAT (Xil_Out32(OLED_BASE_ADDR,(8+OLED_VBAT)))
#define Clr_OLED_VBAT (Xil_Out32(OLED_BASE_ADDR,OLED_VBAT))
// OLED_VDD
#define Set_OLED_VDD (Xil_Out32(OLED_BASE_ADDR,(8+OLED_VDD)))
#define Clr_OLED_VDD (Xil_Out32(OLED_BASE_ADDR,OLED_VDD))
----------------------------------------------------------
版权声明:
本文由博主“cuter”发布。欢迎转载,但不得擅自更改博文内容,也不得用于任何盈利目的。转载时不得删除作者简介和版权声明。如有盗用而不说明出处引起的版权纠纷,由盗用者自负。
博客官方地址:
ChinaAET:http://blog.chinaaet.com/cuter521