cuter

一步步艰难搞定OLED

1
阅读(22380)

凌晨1点半,OLED终于有显示了,唉,SDK总是出现各种错误,导致我反反复复开关SDK,甚至是重启电脑,大多数时候连RUN和Debug都没有办法进行,让我从下午6点一直熬到现在……最后发现是由于OLED复位后没有给足够的延时,导致无法写OLED寄存器,进而导致SDK无法单步调试,估计这一点也影响了SDK的稳定性。

    先上图吧,明天再补OLED软件移植的整个过程~图片效果不是很好,手机不给力啊~

IMG_20121217_012711

关于OLED这块,已经有两篇文章走在前面了,不过,虽然有这两篇文章,我的调试过程还是一波三折,所以我才打算再给出一篇详细教程。

        1、资料准备:

        1.1、通过前辈们的调试经验可以知道,Zed的OLED的驱动芯片是SSD1306,所以SSD1306的datasheet必不可少;

        1.2、ZedBoard开发板的原理图;

        1.3、ZedBoard用的OLED是128*32的UG-2832HSWEG04;网上比较流行的、比较相近的是128*64的一块OLED,型号我也没有细看,MCU是ARM的STM32,OLED的驱动芯片也是SSD1306,网上有很多帖子都在讨论它,其中有一个比较详细的教程,应该是一个STM32开发板的配套资料,有比较详细的程序,基本上可以直接使用。

        这3份文档差不多足够了,ZedBoard的原理图我就不上传了,另外两个资料我会用附件上传上来。

       2、方案选择:

       2.1、使用ARM核的SPI接口

            优点:初始化SPI成功后,就不用关心SPI的并串转换等问题;缺点:ARM核支持的是标准四线SPI,和OLED接口不完全吻合,不仅要控制时钟和数据,同时要控制D/C#,所以即使使用SPI,还是需要其他GPIO控制D/C#的时序,并且要和SPI接口协同工作。

       2.2、老莫老师的方案,使用老莫老师的方法:通过EMIO实现

            具体实现是在XPS中加入一个Xilinx提供的GPIO IP核,然后使能EMIO接口,将PS的GPIO连接到PL内部。截个图看一下:

image             具体如何操作,可以参考官方的ug873《Zynq-7000 EPP Concepts, Tools, and Techniques》,ZedBoard也有一个类似的文档,我一时找不到在哪了,只好给官方的了。

            这个不知道咋说,老莫老师都吐槽过了。这个方法我也试了一下,感觉提供的BSP函数比较复杂,不是太好用。我需要的功能很简单,只需要6个GPIO,输出SSD1306需要的时序就够了,再加上以前有过新建IP核的经验,打算自己新建一个IP核,也就是方案三。

       2.3、新建一个基于AXI-Lite总线的IP核,这个IP核有一个可读写的寄存器slv_reg0,PS软件产生需要的时序,送给slv_reg0,PL直接输出slv_reg0的低6位至SSD1306。这个方案最大的优点就是操作寄存器slv_reg0非常简单,只需要读写IP核的基地址就可以读写slv_reg0。

       3、方案实现

先给出方案的整体框图。

image

        3.1、PL部分

        PL内部的OLED表示我新建的IP核,其实他是一个GPIO的IP核,但是既然是用来控制OLED的,我这里把他命名为OLED。新建IP核的详细教程,前面已经给出了,这里我把OLED的用户逻辑的代码稍微说一下。很简单,只有一行:

leds <= slv_reg0(5 downto 0);//将slv_reg0的值付给leds

        这里没有使用PL产生时序,时序和数据都是由PS控制,PL仅起到了传输作用,其实PL部分所有的工作加起来充当了导线的角色——实现简单的代价是浪费了很多资源。

        3.2、PS部分

        PS部分部分实际上也没有多少好讲的,就把slv_reg0当成一个32bits的IO就可以了,对slv_reg0的低6位进行位操作,就可以写出控制时序了,这里稍微讲一下PS的位操作如何实现吧。


	位操作相关代码#include "xil_io.h"

#define OLED_BASE_ADDR 0X7a800000

// 下面几个宏定义和引脚分配有直接关系,编写ucf文件时要注意
#define OLED_DC 0
#define OLED_RES 1
#define OLED_SCLK 2
#define OLED_SDIN 3
#define OLED_VBAT 4
#define OLED_VDD 5

// 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))))

       这里用到了BSP中的两个函数分别为Xil_In32()和Xil_Out32(),这两个函数分别实现对某个地址的读写,置位和清零的操作,大家自己看一下吧,用到了移位和取反,为了不影响其他位,才用了Xil_In32()读取寄存器的原状态,按位操作完毕后再送回寄存器。

除此之外,比较重要的就是OLED的初始化了,先看一下OLED的工作流程:

image

我在编写初始化代码的时候,POWER ON和初始化代码都放到一个oled_init的函数里了,所做的工作有:

1)POWER ON

image         在这里,我没有找到可以用程序控制的Vcc,我猜测是Vbat,因为Vbat是电荷泵的电源,Vcc的升压是通过电荷泵实现的,所以,勉强可以用Vbat代替Vcc,想不到其他解释了。

        也就是这张时序图害苦了我,在这里它说将RES#引脚拉低3us之后就可以给Vcc上电,所以我也就没给很久的延时,最后发现问题就出在这里,估计是没有足够的时间完成复位操作,导致软硬件无法交互。

2) SoftWare Initialization

image

上面这两幅图都出自SSD1306的datasheet 。

在PowerOn的时候要注意看电路图:

image

pin7 VDD和pin5 VBAT是高电平有效的,所以上电的时候,需要将OLED_VBAT和OLED-VDD清零,3.3V的电压才会送到VBAT和VDD。 网上大多数电路都是直接给VDD和VBAT加电压,而zed选择用软件控制,虽然稍微增加了软件的工作,但却达到了降低功耗的目的,这个细节要赞一下!

        其他接口函数的编写我就不一一讲了,1.3里的教程讲得很清楚了,我暂时还没有修改这些函数,待会把这些接口函数修改成128*32的。

        后面还是有工作要做的,比如现在显示的字符是翻转180°显示的,看着不舒服,要翻过来等等。

        附件里会把所有源文件打包发上来,附件能自己命名吗,谁知道?


版权声明:

本文由博主“cuter”发布。欢迎转载,但不得擅自更改博文内容,也不得用于任何盈利目的。转载时不得删除作者简介和版权声明。如有盗用而不说明出处引起的版权纠纷,由盗用者自负。

博客官方地址:

ChinaAET:http://blog.chinaaet.com/cuter521

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