如何使用FPGA驱动OLED屏幕

一. 简介
    这是fpga之旅设计的第九例啦!!!本例将介绍如何使用fpga驱动oled屏幕,并在接下来的几例中,配合其它模块,进行一些有趣的综合实验。由于使用的oled屏是iic接口的,对iic接口不是很清楚的,可以参考第五例的设计,同时使用第五例写好的iic模块,驱动oled屏。let's do it!
二. 0.96寸oled屏介绍
    这里就只介绍最常用的0.96寸屏,其它的一样。oled共支持8080并口、spi和iic三种接口,同样也只介绍iic接口的用法。0.96寸oled屏幕的分辨率为128×64,内部有一块gram用来存储显示的数据。
1oled的存储区域
这块存储区域分为8个page,每个page下面共有128bit,如下图所示
这就难免会有些疑问了,128×8,不应该是128×64嘛?8个page,为什么是64行呢?数据写入的呢?
每一个page包括8行,所以说8个page共有64行。iic每次发送数据的时候,是发送一个byte的,也就是8bit,这8bit数据会存储到某一列的八行中,例如图中seg0区域,是第一列的头八行。这样gram的存储区域就弄懂了。
2
oled的数据存储模式
当我们向oled的gram发送显示数据的过程中,oled内部共有三种处理模式。
模式一: 当我们指定了一个page和某一列的时候,每写一个数据,列会自动加一,当写到page的最后一列的时候,列数,会自动跳转到第零列,需要手动的切换page。
模式二:与模式一不同的时候,当写达到page的最后一列的时候,列数跳转到第零列的同时,page数也会加一。
模式三: 与前两个模式不同,模式三,是一列一列的写,每写完一个数据,page数加一,当加到最后一个page的时候,列数加一,page跳转到第一个page。
在实际的使用中,具体使用那一种模式,可以根据自己的子模软件或者项目来,怎么方便怎么来!
了解了上面两个部分后,基本就可以编写驱动程序啦,不要问为什么,(#^.^#),初始化oled就是配置一些列命令的过程,而这些寄存器和配置的值一般都是copy现成的。然后了解一下关键的一两个命令就可以啦。想要深入的了解oled的功能的话,可以阅读对应的芯片手册哦!在后面的例程中也会介绍部分功能强大的命令。
三. oled关键命令介绍
    0xae/0xaf: 对应着开启oled显示和关闭oled显示
0x20-0x22: 对应着上面的三种oled数据存储模式,默认为0x22,模式一
0x00-0x0f: 设置列地址的低四位,默认为0x00
0x10-0x1f: 设置列地址的高四位,默认为0x10
0xb0-0xb7: 设置page,第四位表示page
暂时差不多只需要了解上面的这些寄存器。
四. iic驱动oled数据格式
    驱动oled分为写数据和写命令(读暂时不考虑)。写命令就是配置的过程,写数据就是写入gram中进行显示的过程。
iic数据格式  :oled地址 + 命令 / 数据 +  值。
oled地址,就是iic协议中的从机地址,我这里是0x78。
命令/数据中,0x00表示接下来的值代表命令,0x40表示接下的值表示数据,存入grma。
值,具体的命令或者数据
也就是说每一次iic需要传输24bit,3个字节的数据,和第五例的iic模块完美对应,那事情就好办啦!
五. oled初始化
    直接copy某例程提供的配置参数,共需要配置26个命令,第一个是上面介绍的0xae命令,关闭oled显示。最后一个也是介绍的0xaf命令,开启oled显示,没有配置模式,直接使用的默认的模式一,配置完成后,可以看到oled屏被点亮,内容是杂乱的
                                                                    always@(*)begin  case(init_index)        'd0:    init_data_reg <= {8'h78,8'h00,8'hae};  //oled地址 + 命令  +  值。**    'd1:    init_data_reg <= {8'h78,8'h00,8'h00};    'd2:    init_data_reg <= {8'h78,8'h00,8'h10};    'd3:    init_data_reg <= {8'h78,8'h00,8'h40};    'd4:    init_data_reg <= {8'h78,8'h00,8'hb0};    'd5:    init_data_reg <= {8'h78,8'h00,8'h81};    'd6:    init_data_reg <= {8'h78,8'h00,8'hff};    'd7:    init_data_reg <= {8'h78,8'h00,8'ha1};    'd8:    init_data_reg <= {8'h78,8'h00,8'ha6};    'd9:    init_data_reg <= {8'h78,8'h00,8'ha8};    'd10:    init_data_reg <= {8'h78,8'h00,8'h3f};    'd11:    init_data_reg <= {8'h78,8'h00,8'hc8};    'd12:    init_data_reg <= {8'h78,8'h00,8'hd3};    'd13:    init_data_reg <= {8'h78,8'h00,8'h00};    'd14:    init_data_reg <= {8'h78,8'h00,8'hd5};    'd15:    init_data_reg <= {8'h78,8'h00,8'h80};    'd16:    init_data_reg <= {8'h78,8'h00,8'hd8};    'd17:    init_data_reg <= {8'h78,8'h00,8'h05};    'd18:    init_data_reg <= {8'h78,8'h00,8'hd9};    'd19:    init_data_reg <= {8'h78,8'h00,8'hf1};    'd20:    init_data_reg <= {8'h78,8'h00,8'hda};    'd21:    init_data_reg <= {8'h78,8'h00,8'h12};    'd22:    init_data_reg <= {8'h78,8'h00,8'hdb};    'd23:    init_data_reg <= {8'h78,8'h00,8'h30};    'd24:    init_data_reg <= {8'h78,8'h00,8'h8d};    'd25:    init_data_reg <= {8'h78,8'h00,8'h14};    'd26:    init_data_reg <= {8'h78,8'h00,8'haf};    default:      init_data_reg <= {8'h78,8'h00,8'hae};    endcaseend  
六. 向gram中写入数据
    初始化后,就可以显示内容啦,仅仅只需要配置page和起始列三个命令,然后写入数据即可,配置页和列地址,只有在模式一有效,也就是上电默认的模式。
这样就可以显示数据啦,亲测可用哦!
        'd0:show_data_reg <= {8'h78,8'h00,8'hb0 + show_pag};        //配置页'd1:show_data_reg <= {8'h78,8'h00,8'h00 +start_x[3:0]};     //配置列的低四位'd2:show_data_reg <= {8'h78,8'h00,8'h10 + start_x[6:4]};    //配置列的高四位,128列只需要配置高三位即可。'd3:show_data_reg <= {8'h78,8'h40, data};            //向配置的地址中,写入显示的数据 其实驱动oled也没有那么复杂嘛。
七. 上板验证
    先来编写个简单的模块,用来初始化oled。下载程序后,我的oled是亮起来了,你的呢!
                                                                                                                                      //oled顶层模块module oled_top(  input      sys_clk,  input      rst_n,  //oled iic  output    oled_scl,  inout      oled_sda);localparam  oled_init = 'd0;      //初始化localparam  oled_idle = 'd1;      //空闲reg[4:0]  state , next_state;wire      init_finish;wire[23:0]  init_data;wire       init_req;wire      iicwritedone;assign init_req = (state == oled_init) ? 1'b1 : 1'b0;always@(posedge sys_clk or negedge rst_n)begin  if(rst_n == 1'b0)    state <= oled_init;  else    state <= next_state;endalways@(*)begin  case(state)  oled_init:    if(init_finish == 1'b1)      next_state <= oled_idle;    else      next_state <= oled_init;  oled_idle:    next_state <= oled_idle;  default: next_state <= oled_init;  endcaseendoled_init oled_init(    .sys_clk        (sys_clk),  .rst_n        (rst_n),    .init_req      (init_req),        //初始化请求  .write_done      (iicwritedone),      //一组初始化数据完成信号    .init_finish    (init_finish),      //初始化完成输出  .init_data      (init_data)//初始化的数据);iic_driver iic_driverhp_oled(   .sys_clk        (sys_clk),           /*系统时钟*/   .rst_n        (rst_n),             /*系统复位*/    .iicscl        (oled_scl),            /*iic 时钟输出*/    .iicsda        (oled_sda),             /*iic 数据线*/    .iicslave      ({init_data[15:8],init_data[23:16]}),           /*从机 8bit的寄存器地址 + 8bit的从机地址*/    .iicwritereq    (init_req),       /*iic写寄存器请求*/    .iicwritedone    (iicwritedone),      /*iic写寄存器完成*/    .iicwritedata    (init_data[7:0]),       /*iic发送数据  8bit的数据*/    .iicreadreq      (1'b0),        /*iic读寄存器请求*/    .iicreaddone      (),       /*iic读寄存器完成*/    .iicreaddata        ()    /*iic读取数据*/);endmodule fpga驱动oled就结束啦!


移植Linux内核ramfs和ramdisk文件系统
什么是阻抗,阻抗是什么意思?
人工智能能为酒店带来什么
怎么查看MySQL语句有没有用到索引
2012年中国MCU市场研判:嵌入式应用全面起飞
如何使用FPGA驱动OLED屏幕
可用于PLC数字输入模块的方案设计
SAE International宣布NACS连接器、充电PKI和基础设施可靠性标准
氢燃料电池汽车销量超6000辆 商业化应用仍在起步阶段
intel第八代处理器依旧采用14nm 今年下半年亮相
pcb设计逻辑芯片功能测试
阿里、腾讯及科大讯飞相继在地铁语音购票发力,期能搭上“快车”赢占商机
索尼电子公司成立 整合并优化三大业务
最美小米6?3月即将发布的小米新机颜值超高!
usb-c接口是什么意思 pd接口和usb接口哪个更好
王欣入局区块链前途未卜 能否东山再起?
高效边缘计算解决方案:研华工业内存 SQRAM DDR5 5600 系列
为何内部开放文化的 Facebook 很少有泄密新闻?
保姆教程:YOLOv5在建筑工地中安全帽佩戴检测的应用
无线传输将决定未来VR的走向