cuter

[Zynq]ZedBoard OLED驱动方法改进

1
阅读(3081) 评论(5)

一、声明

【声明】本文由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引脚。

ImprovedOled.png


软件驱动程序关键代码:

驱动就是配合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

EDN China: http://bbs.ednchina.com/BLOG_cuter521_356737.HTM

  1. 一万楼赞。。

  2. 这个算是回归到FPGA了?

  3. 绝对是原创,赞一个。

  4. 赞!!感谢老师的分享!!!

  5. 沙发~~~~~

    大赞~~~