FPGA驱动0.96寸OLED(SSD1306)

目录 

一、七针0.96寸OLED驱动原理

二、SSD1306驱动时序

1、GDDRAM内部结构:

(1)页寻址

 (2)水平寻址

 (3)垂直寻址

2、初始化

3、清屏

4、发送数据

三、子模块源码

1、初始化

2、清屏

3、数据

四、top源码

五、仿真结果

六、板级验证


SPI主机写模式FPGA实现详细请见:FPGA实现SPI写模式(用于SSD1603的0.91寸OLED驱动)_LionelZhao的博客-CSDN博客https://blog.csdn.net/LionelZhao/article/details/128553379

一、七针0.96寸OLED驱动原理

        本实验所使用的七针OLED结构图和电路原理图如下:FPGA驱动0.96寸OLED(SSD1306)_第1张图片

FPGA驱动0.96寸OLED(SSD1306)_第2张图片

         所使用的驱动芯片为SSD1306,通讯协议为4线SPI,七针名称与对应的功能列表如下:

FPGA驱动0.96寸OLED(SSD1306)_第3张图片

 七根管脚分别为:GND、VCC、CS(片选 低电平有效)、DC(数据/命令控制 1数据,0命令)、D0(同步时钟信号sck)、D1(从机接收端MOSI)、RES(OLED清屏信号 低电平有效):

        时序图如下:

FPGA驱动0.96寸OLED(SSD1306)_第4张图片

二、SSD1306驱动时序

1、GDDRAM内部结构:

        GDDRAM(Graphic Display Data RAM )内部结构如下所示:

FPGA驱动0.96寸OLED(SSD1306)_第5张图片

         将128*64个像素按8行一个PAGE分为8个PAGE,列SEG0~SEG127,这样通过PAGE和SEG的数值就能将8位长的数据显示在对应的位置上,从上到下为低位到高位,如下图所示。

FPGA驱动0.96寸OLED(SSD1306)_第6张图片

         GDDRAM三种寻址模式如下所示:

(1)页寻址

        SSD1306默认页寻址模式,通过“20H,02H”命令可以设置寻址模式为页寻址。
  页寻址模式下,寻址只在一页内进行,地址指针不会跳到其他页。每次向GDDRAM写入1Byte显示数据后,列指针会自动+1。当128列都寻址完之后,列指针会重新指向SEG0而页指针仍然保持不变。通过页寻址模式我们可以方便地对一个小区域内数据进行修改。

FPGA驱动0.96寸OLED(SSD1306)_第7张图片

FPGA驱动0.96寸OLED(SSD1306)_第8张图片

 (2)水平寻址

       水平寻址模式可以通过指令“20H,00H”来设置。
  水平寻址模式下,每次向GDDRAM写入1Byte数据后,列地址指针自动+1。列指针到达结束列之后会被重置到起始列,而页指针将会+1。页地址指针达到结束页之后,将会自动重置到起始页。

FPGA驱动0.96寸OLED(SSD1306)_第9张图片

 (3)垂直寻址

       垂直寻址模式可以通过指令“20H,01H”来设置。
  垂直寻址模式下,每次向GDDRAM写入1byte数据之后,页地址指针将会自动+1。页指针到达结束页之后会被重置到0,而列指针将会+1。列地址指针达到结束页之后,将会自动重置到起始列。

FPGA驱动0.96寸OLED(SSD1306)_第10张图片

2、初始化

        SSD1306驱动过程为:初始化->清屏->发送数据,常见命令如下:

FPGA驱动0.96寸OLED(SSD1306)_第11张图片

        在上电开始就需要发送控制命令来初始化OLED。

3、清屏

        在发送这一帧数据之前需要先清楚上一帧的数据,只需要遍历PAGE和SEG的所有地址并发送数据8'h00就能实现清屏。

4、发送数据

        与清屏同理,在对应的PAGE和SEG选中的Byte发送相应的数据,这样就能拼凑出想要的图案。

三、子模块源码

1、初始化

        三段式状态机实现,需要配置多少个命令就添加对应数量的状态,在每一个状态发送响应的命令即可。

module OLED_initial(
    input clk,//输入时钟
    input rst_n,//系统复位
    input SPI_done,//SPI发送完成通知
    output DC,//1数据 0命令
    output initial_done,//初始化完成标志
    output SPI_send,//通过SPI发送数据
    output reg [7:0] SPI_data//SPI发送的数据
    );
    //定义初始化所需命令参数
    parameter Display_on  = 8'haf;//开启显示
    parameter Display_off = 8'hae;//关闭显示
    parameter Set_display_clk_0 = 8'hd5;//显示时钟分频控制 命令头
    parameter Set_display_clk_1 = 8'h80;//100帧/秒
    parameter Set_charge_pump_0 = 8'h8d;//电荷泵 命令头
    parameter Set_charge_pump_1 = 8'h14;//开启charge pump
    parameter Set_contrast_0 = 8'h81;//对比度控制 命令头
    parameter Set_contrast_1 = 8'hcf;//207
    parameter Set_precharge_0 = 8'hd9;//预充电周期控制
    parameter Set_precharge_1 = 8'hf1;//预充电15clk 放电1clk
    parameter Set_normal  = 8'ha6;//正常显示
    parameter Set_inverse = 8'ha7;//反转显示
    //状态机参数定义
    localparam S0  = 5'd0;
    localparam S1  = 5'd1;
    localparam S2  = 5'd2;
    localparam S3  = 5'd3;
    localparam S4  = 5'd4;
    localparam S5  = 5'd5;
    localparam S6  = 5'd6;
    localparam S7  = 5'd7;
    localparam S8  = 5'd8;
    localparam S9  = 5'd9;
    localparam S10 = 5'd10;
    localparam S11 = 5'd11;

    //状态寄存器
    reg [4:0] cstate,nstate;

    assign DC = 0;//发送恒为命令
    assign initial_done = (cstate==S11)?1:0;//初始化完成
    assign SPI_send = (cstate==S11)?0:1;//通过SPI发送数据

    //状态转移同步逻辑
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            cstate <= S0;
        end
        else if(SPI_done)begin
            cstate <= nstate;
        end
        else begin
            cstate <= cstate;
        end
    end
    //产生下一个状态组合逻辑
    always @(*) begin
        case(cstate)
            S0:nstate = S1;
            S1:nstate = S2;
            S2:nstate = S3;
            S3:nstate = S4;
            S4:nstate = S5;
            S5:nstate = S6;
            S6:nstate = S7;
            S7:nstate = S8;
            S8:nstate = S9;
            S9:nstate = S10;
            S10:nstate= S11;
            S11:nstate= S11;
            default:nstate = S0;
        endcase
    end
    //产生输出组合逻辑
    always @(*) begin
        case(cstate)
            S0:SPI_data = Display_off;
            S1:SPI_data = Set_display_clk_0;
            S2:SPI_data = Set_display_clk_1;
            S3:SPI_data = Set_charge_pump_0;
            S4:SPI_data = Set_charge_pump_1;
            S5:SPI_data = Set_contrast_0;
            S6:SPI_data = Set_contrast_1;
            S7:SPI_data = Set_precharge_0;
            S8:SPI_data = Set_precharge_1;
            S9:SPI_data = Set_inverse;
            S10:SPI_data= Display_on;
            S11:SPI_data= 0;
            default:SPI_data= 0;
        endcase
    end
    
endmodule

2、清屏

        需要定义x_tmp和y_tmp计数器来遍历所有PAGE和SEG选中的一共8*128个Byte发送8'h00。

        发送数据的顺序是先发送PAGE,再发送列高地址然后列低地址,最后发送这一个位置的数据。

module OLED_clear(
    input clk,
    input rst_n,
    input clear_en,//清零使能信号
    input SPI_done,//SPI发送完成通知
    output DC,//1数据 0命令
    output clear_done,//清零完成信号
    output reg SPI_send,//通过SPI发送数据
    output reg [7:0]SPI_data//SPI发送数据
    );
    //状态机状态编码
    localparam S0 = 3'd0;
    localparam S1 = 3'd1;
    localparam S2 = 3'd2;
    localparam S3 = 3'd3;
    localparam S4 = 3'd4;
    localparam S5 = 3'd5;
    localparam S6 = 3'd6;
    //状态寄存器定义
    reg [2:0] cstate,nstate;
    //内部寄存器和信号线声明
    reg [7:0] x_tmp,y_tmp;
    wire [7:0] Set_pos_0,Set_pos_1,Set_pos_2;

    assign Set_pos_0 = 8'hb0 | y_tmp;//PAGE地址
    assign Set_pos_1 = (x_tmp[7:4] & 4'hf) | 8'h10;//高位列地址
    assign Set_pos_2 = (x_tmp[3:0] & 4'hf);//低位列地址
    assign DC = (cstate == S4)?1:0;
    assign clear_done = (cstate == S6)?1:0;

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            x_tmp <= 8'd0;
            y_tmp <= 8'd0;
        end
        else begin
            case (cstate)
                S0:begin
                    x_tmp <= 8'd0;
                    y_tmp <= 8'd0;
                end
                S5:begin
                    if(x_tmp == 130)begin
                        x_tmp <= 8'd0;
                        y_tmp <= y_tmp + 8'd1;
                    end
                    else begin
                        x_tmp <= x_tmp + 8'd1;
                        y_tmp <= y_tmp;
                    end
                end
                default:begin
                    x_tmp <= x_tmp;
                    y_tmp <= y_tmp;
                end
            endcase
        end
    end
    //状态转移同步逻辑
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            cstate <= S0;
        end
        else begin
            case (cstate)
                S1,
                S2,
                S3,
                S4:cstate <= SPI_done?nstate:cstate;
                default:cstate <= nstate;
            endcase
        end
    end
    //产生下一个状态组合逻辑
    always @(*) begin
        nstate = cstate;
        case(cstate)
            S0:nstate = clear_en?S1:S0;
            S1:nstate = S2;
            S2:nstate = S3;
            S3:nstate = S4;
            S4:nstate = S5;
            S5:nstate = (x_tmp==127 && y_tmp==7)?S6:S1;
            S6:nstate = S0;
            default:nstate = S0;
        endcase
    end
    //产生输出组合逻辑
    always @(*) begin
        if(!rst_n)begin
            SPI_data = 0;
            SPI_send = 0;
        end
        else begin
            case(cstate)
                S1:begin
                    SPI_data = Set_pos_0;
                    SPI_send = 1;
                end
                S2:begin
                    SPI_data = Set_pos_1;
                    SPI_send = 1;
                end
                S3:begin
                    SPI_data = Set_pos_2;
                    SPI_send = 1;
                end
                S4:begin
                    SPI_data = 0;
                    SPI_send = 1;
                end
                default:begin
                    SPI_data = 0;
                    SPI_send = 0;
                end
            endcase
        end
    end
endmodule

3、数据

        这里要显示图片:

        需要先取模然后存放到ROM中,将取模软件得到的字模使用coe文件初始化ROM:

; This .COE file specifies the contents for a block memory of depth=64, and width=128.
memory_initialization_radix=16;
memory_initialization_vector=
0000000000000000,0000000000000000,
0000000000000000,0000000000000000,
0000000000000000,000000001E1E3E3E,
7CFCF8F0E08080E0,F8F8FC7E3E1F1F1F,
1F1F3E3E7EFCF8F0,E080000000000000,
000000001E3E3E7E,FCFCF8F0E0000000,
0000000000000000,0000000000000000,
0000000000000000,0000000000000000,
0000000000000000,0000000000000000,
0000000000000000,0000000000000000,
00003CFCFCFCF0C0,8000000000000080,
C0F3FFFFFF3F3FFF,FFFFF1C080000000,
0000000000030707,07077CFCFCFCF0C0,
8000000000000080,C0FFFFFFFF3F0000,
0000000000000000,0000000000000000,
0000000000000000,0000000000000000,
0000000000000000,0000000000000000,
0000000000000000,0000000000000000,
000000000103070F,0F0F1FDFDFDFCFCF,
8F87030100000000,0307070F0F0F1FDF,
E0E0E0C0C0800000,000000010387C7CF,
CFFFFFFFFFFFCFCF,8F87030100000000,
0000000000000000,0000000000000000,
0000000000000000,0000000000000000,
0000000000000000,0000000000000000,
0000000000000000,0000000000000000,
0000808080800000,000000030307070F,
1FFFFFFEF8E08080,8080000000000001,
030303070FFFFFFE,FCF0F8FEFFFF1F0F,
070303030303070F,1FFFFFFEF8000000,
0000000000000000,0000000000000000,
0000000000000000,0000000000000000,
0000000000000000,0000000000000000,
0000000000000000,0000000000000000,
00000F3F7FFFFEF8,F0E0E0C0C0E0E0F0,
F8FFFF7F1F070F1F,3F7FFCF8F0F0E0E0,
E0E0F0F8FCFF7F3F,0F030F3F7FFFFCF8,
F0E0E0E000000000,0000000000000000
0000000000000000,0000000000000000,
0000000000000000,0000000000000000,
0000000000000000,0000000000000000,
0000000000000000,0000000000000000,
00000080C0E0F1F1,FBFB7B7B03030303,
0100000000000000,C0E0E0F1F1F9F9F9,
F9F9F9F1F0E0E0C0,00000080C0E0F0F1,
F9F97B7B00000000,0000000000000000,
0000000000000000,0000000000000000,
0000000000000000,0000000000000000,
0000000000000000,0000000000000000,
0000000000000000,0000000000000000,
0000FEFFFFFFC701,0000000000000000,
00C0F0F0F0E0FCFF,FFFFDF0301000000,
00000001031F3F3F,3F3CFEFFFFFF8701,
0000000000000000,00E0F0F0F0E00000,
0000000000000000,0000000000000000,
0000000000000000,0000000000000000,
0000000000000000,0000000000000000,
0000000000000000,0000000000000000,
000001070F1F3F3F,7E7C7C7C7C7C7C7E,
3F3F1F0F07010003,0F1F3F3F7C7C7878,
3000000000000000,000001070F1F3F3F,
7E7C7C7C7C7C7C7E,3F1F1F0F03000000,
0000000000000000,0000000000000000,
0000000000000000,0000000000000000;

        例化一个 ROM的IP,配置如下:

FPGA驱动0.96寸OLED(SSD1306)_第12张图片

FPGA驱动0.96寸OLED(SSD1306)_第13张图片         将coe文件添加并初始化:

FPGA驱动0.96寸OLED(SSD1306)_第14张图片

         数据发送模块,每次从ROM中读取64位数据分8次发送:

module OLED_write_data(
    input clk,
    input rst_n,
    input write_en,
    input SPI_done,
    input [63:0]write_data,//需要发送的数据
    input [6:0]set_pos_x,
    input [2:0]set_pos_y,
    output DC,
    output write_done,//写数据完成标志
    output reg SPI_send,//SPI传输使能
    output reg [7:0] SPI_data//需要SPI发送的字节数据
    );
    //状态机状态编码
    localparam IDLE = 3'd0;//空闲状态
    localparam POS0 = 3'd1;//设置页地址
    localparam POS1 = 3'd2;//设置列高地址
    localparam POS2 = 3'd3;//设置列低地址
    localparam DATA = 3'd4;//发送对应的数据
    localparam JUDGE= 3'd5;//判断是否发送完成
    localparam STOP = 3'd6;//停止发送
    //状态寄存器
    reg [2:0] cstate,nstate;
    //内部寄存器和信号线声明
    reg [2:0] count;//发送循环数计数器
    reg [63:0] write_data_reg;//暂存需要发送的数据
    reg [7:0] x_tmp,y_tmp;
    wire [7:0] Set_pos_0,Set_pos_1,Set_pos_2;

    assign Set_pos_0 = 8'hb0 | y_tmp;              //页地址
    assign Set_pos_1 = (x_tmp[7:4] & 4'hf) | 8'h10;//高位列地址
    assign Set_pos_2 = (x_tmp[3:0] & 4'hf);        //低位列地址
    
    assign DC = (cstate == DATA)?1:0;
    assign write_done = (cstate == STOP)?1:0;

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            x_tmp <= 8'd0;
            y_tmp <= 8'd0;
            write_data_reg <= 0;
            count <= 0;
        end
        else begin
            case (cstate)
                IDLE:begin
                    x_tmp <= {1'b0,set_pos_x};
                    y_tmp <= {5'd0,set_pos_y};
                    write_data_reg <= write_data;
                    count <= 0;
                end
                JUDGE:begin
                    x_tmp <= x_tmp + 8'd1;
                    // y_tmp <= y_tmp;
                    // if(x_tmp>122) y_tmp<=y_tmp+1;
                    write_data_reg <= (write_data_reg<<8);
                    count <= count + 1;
                end
                default:begin
                    x_tmp <= x_tmp;
                    y_tmp <= y_tmp;
                    write_data_reg <= write_data_reg;
                    count <= count;
                end
            endcase
        end
    end

    //状态转移同步逻辑
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            cstate <= IDLE;
        end
        else begin
            case (cstate)
                POS0,
                POS1,
                POS2,
                DATA:cstate <= SPI_done?nstate:cstate;
                default:cstate <= nstate;
            endcase
        end
    end

    //产生下一个状态组合逻辑
    always @(*) begin
        case(cstate)
            IDLE:nstate = write_en?POS0:IDLE;
            POS0:nstate = POS1;
            POS1:nstate = POS2;
            POS2:nstate = DATA;
            DATA:nstate = JUDGE;
            JUDGE:nstate = (&count)?STOP:POS0;
            STOP:nstate = IDLE;
            default:nstate = IDLE;
        endcase
    end
    
    //产生输出组合逻辑
    always @(*)begin
        if(!rst_n)begin
            SPI_data = 0;
            SPI_send = 0;
        end
        else begin
            case(cstate)
                IDLE:begin
                    SPI_data = 0;
                    SPI_send = 0;
                end
                POS0:begin
                    SPI_data = Set_pos_0;
                    SPI_send = 1;
                end
                POS1:begin
                    SPI_data = Set_pos_1;
                    SPI_send = 1;
                end
                POS2:begin
                    SPI_data = Set_pos_2;
                    SPI_send = 1;
                end
                DATA:begin
                    SPI_data = write_data_reg[63:56];
                    SPI_send = 1;
                end
                JUDGE:begin
                    SPI_data = SPI_data;
                    SPI_send = 0;
                end
                STOP:begin
                    SPI_data = SPI_data;
                    SPI_send = SPI_send;
                end
                default:begin
                    SPI_data = 0;
                    SPI_send = 0;
                end
            endcase
        end
    end
    
endmodule

四、top源码

        由于需要发送8*128=1024个Byte的数据,而发送数据模块一次从ROM中读取1*8个Byte,因此需要读取ROM128次,这就需要128个读数据状态和一个初始化状态、一个清屏状态和一个停止发送状态,使用格雷码来编码状态机并使用脚本来生成top代码。

module top(
    input sys_clk,//系统时钟 100MHz
    input sys_rst_n,//系统复位

    output sclk,//同步时钟 
    output sck,
    output reg res=0,//OLED清屏信号 低电平有效
    output MOSI,//主机输出 从机输入
    output CS,//片选信号 低电平有效
    output DC//1数据 0命令
    );
    //状态编码
    localparam INIT= 9'b000000000;//初始化
    localparam CLR = 9'b000000001;//清屏
    localparam D0  = 9'b000000011;//发送数据周期
    localparam D1  = 9'b000000010;
    localparam D2  = 9'b000000110;
    localparam D3  = 9'b000000111;
    localparam D4  = 9'b000000101;
    localparam D5  = 9'b000000100;
    localparam D6  = 9'b000001100;
    localparam D7  = 9'b000001101;
    localparam D8  = 9'b000001111;
    localparam D9  = 9'b000001110;
    localparam D10 = 9'b000001010;
    localparam D11 = 9'b000001011;
    localparam D12 = 9'b000001001;
    localparam D13 = 9'b000001000;
    localparam D14 = 9'b000011000;
    localparam D15 = 9'b000011001;
    localparam D16 = 9'b000011011;
    localparam D17 = 9'b000011010;
    localparam D18 = 9'b000011110;
    localparam D19 = 9'b000011111;
    localparam D20 = 9'b000011101;
    localparam D21 = 9'b000011100;
    localparam D22 = 9'b000010100;
    localparam D23 = 9'b000010101;
    localparam D24 = 9'b000010111;
    localparam D25 = 9'b000010110;
    localparam D26 = 9'b000010010;
    localparam D27 = 9'b000010011;
    localparam D28 = 9'b000010001;
    localparam D29 = 9'b000010000;
    localparam D30 = 9'b000110000;
    localparam D31 = 9'b000110001;
    localparam D32 = 9'b000110011;
    localparam D33 = 9'b000110010;
    localparam D34 = 9'b000110110;
    localparam D35 = 9'b000110111;
    localparam D36 = 9'b000110101;
    localparam D37 = 9'b000110100;
    localparam D38 = 9'b000111100;
    localparam D39 = 9'b000111101;
    localparam D40 = 9'b000111111;
    localparam D41 = 9'b000111110;
    localparam D42 = 9'b000111010;
    localparam D43 = 9'b000111011;
    localparam D44 = 9'b000111001;
    localparam D45 = 9'b000111000;
    localparam D46 = 9'b000101000;
    localparam D47 = 9'b000101001;
    localparam D48 = 9'b000101011;
    localparam D49 = 9'b000101010;
    localparam D50 = 9'b000101110;
    localparam D51 = 9'b000101111;
    localparam D52 = 9'b000101101;
    localparam D53 = 9'b000101100;
    localparam D54 = 9'b000100100;
    localparam D55 = 9'b000100101;
    localparam D56 = 9'b000100111;
    localparam D57 = 9'b000100110;
    localparam D58 = 9'b000100010;
    localparam D59 = 9'b000100011;
    localparam D60 = 9'b000100001;
    localparam D61 = 9'b000100000;
    localparam D62 = 9'b001100000;
    localparam D63 = 9'b001100001;
    localparam D64 = 9'b001100011;
    localparam D65 = 9'b001100010;
    localparam D66 = 9'b001100110;
    localparam D67 = 9'b001100111;
    localparam D68 = 9'b001100101;
    localparam D69 = 9'b001100100;
    localparam D70 = 9'b001101100;
    localparam D71 = 9'b001101101;
    localparam D72 = 9'b001101111;
    localparam D73 = 9'b001101110;
    localparam D74 = 9'b001101010;
    localparam D75 = 9'b001101011;
    localparam D76 = 9'b001101001;
    localparam D77 = 9'b001101000;
    localparam D78 = 9'b001111000;
    localparam D79 = 9'b001111001;
    localparam D80 = 9'b001111011;
    localparam D81 = 9'b001111010;
    localparam D82 = 9'b001111110;
    localparam D83 = 9'b001111111;
    localparam D84 = 9'b001111101;
    localparam D85 = 9'b001111100;
    localparam D86 = 9'b001110100;
    localparam D87 = 9'b001110101;
    localparam D88 = 9'b001110111;
    localparam D89 = 9'b001110110;
    localparam D90 = 9'b001110010;
    localparam D91 = 9'b001110011;
    localparam D92 = 9'b001110001;
    localparam D93 = 9'b001110000;
    localparam D94 = 9'b001010000;
    localparam D95 = 9'b001010001;
    localparam D96 = 9'b001010011;
    localparam D97 = 9'b001010010;
    localparam D98 = 9'b001010110;
    localparam D99 = 9'b001010111;
    localparam D100 = 9'b001010101;
    localparam D101 = 9'b001010100;
    localparam D102 = 9'b001011100;
    localparam D103 = 9'b001011101;
    localparam D104 = 9'b001011111;
    localparam D105 = 9'b001011110;
    localparam D106 = 9'b001011010;
    localparam D107 = 9'b001011011;
    localparam D108 = 9'b001011001;
    localparam D109 = 9'b001011000;
    localparam D110 = 9'b001001000;
    localparam D111 = 9'b001001001;
    localparam D112 = 9'b001001011;
    localparam D113 = 9'b001001010;
    localparam D114 = 9'b001001110;
    localparam D115 = 9'b001001111;
    localparam D116 = 9'b001001101;
    localparam D117 = 9'b001001100;
    localparam D118 = 9'b001000100;
    localparam D119 = 9'b001000101;
    localparam D120 = 9'b001000111;
    localparam D121 = 9'b001000110;
    localparam D122 = 9'b001000010;
    localparam D123 = 9'b001000011;
    localparam D124 = 9'b001000001;
    localparam D125 = 9'b001000000;
    localparam D126 = 9'b011000000;
    localparam D127 = 9'b011000001;
    localparam STOP = 9'b011000011;//发送结束

    //从ROM中读取需要发送的数据
    reg [6:0]ROM_addr=0;//ROM访问地址
    wire [63:0]ROM_data;//ROM输出数据

    blk_mem_gen_0 rom(
        .clka(sys_clk),   // input wire clka
        .addra(ROM_addr), // input wire [6 : 0] addra
        .douta(ROM_data)  // output wire [63 : 0] douta
    );
    
    //状泰寄存器
    reg [8:0] cstate,nstate=0;
    reg [31:0]reset_cnt=0;//复位控制计数�??
    reg rst_n=0;

    //上电复位逻辑
    always @(posedge sys_clk) begin
      if(reset_cnt >= 30000)
            reset_cnt <= 30000;
        else
            reset_cnt <= reset_cnt + 1;
    end

    always @(posedge sys_clk) begin
        if(reset_cnt == 10)begin
            res <= 1;
            rst_n <= 1;
        end
        else if(reset_cnt == 10000)begin
            res <= 0;
            rst_n <= 0;
        end
        else if(reset_cnt == 20000)begin
            res <= 1;
            rst_n <= rst_n;
        end
        else if(reset_cnt == 30000)begin
            res <= res;
            rst_n <= 1;
        end
        else begin
            res <= res;
            rst_n <= rst_n;
        end
    end

    //SPI主机例化
    reg SPI_send=0;//SPI发�?�使能信�??
    reg [7:0] SPI_data=0;//SPI�??要发送的字节数据
    wire SPI_done;//SPI发�?�完成标�??
    reg DC_in=0;//数据/命令控制�??

    SPI_Master SPI_Master_(
        .sys_clk (sys_clk),
        .rst_n(1'b1),
        .SPI_send (SPI_send),
        .SPI_data (SPI_data),
        .DC_in (DC_in),
        .DC_out (DC),
        .sclk (sclk),
        .MOSI (MOSI),
        .CS (CS),
        .SPI_done (SPI_done),
        .sck (sck)
    );
  
    //OLED初始化模块实例化
    wire SPI_send_init;
    wire DC_init;
    wire [7:0] SPI_data_init;
    wire initial_done;
                                    
    OLED_initial OLED_initial_(
        .clk (sclk),
        .rst_n (rst_n),
        .SPI_done (SPI_done),
        .DC (DC_init),
        .initial_done (initial_done),
        .SPI_send (SPI_send_init),
        .SPI_data (SPI_data_init)
    );

    //OLED写信号模块实例化,讲输入的64位向量拆分发送
    reg [6:0]set_pos_x=0;//列的索引 0->127
    reg [2:0]set_pos_y=0;//PAGE的索引 0->7
    wire write_en;
    wire DC_write;
    wire write_done;
    reg [63:0]write_data=0;
    wire SPI_send_write;
    wire [7:0] SPI_data_write;

    assign write_en = (cstate==INIT || cstate == CLR || cstate == STOP)?0:1;

    OLED_write_data OLED_write_(
        .clk (sclk),
        .rst_n (rst_n),
        .write_en (write_en),
        .SPI_done (SPI_done),
        .write_data (write_data),
        .set_pos_x (set_pos_x),
        .set_pos_y (set_pos_y),
        .DC (DC_write),
        .write_done (write_done),
        .SPI_send (SPI_send_write),
        .SPI_data  (SPI_data_write)
    );

    //OLED清屏模块实例化
    wire clear_en;
    wire DC_clear;
    wire clear_done;
    wire SPI_send_clear;
    wire [7:0]SPI_data_clear;

    assign clear_en = (cstate==CLR)?1:0;

    OLED_clear OLED_clear_(
        .clk (sclk),
        .rst_n (rst_n),
        .clear_en (clear_en),
        .SPI_done (SPI_done),
        .DC (DC_clear),
        .clear_done (clear_done),
        .SPI_send (SPI_send_clear),
        .SPI_data (SPI_data_clear)
    );

    //状态转移同步逻辑
    always @(posedge sclk) begin
        if(!rst_n)begin
            cstate <= INIT;
        end
        else begin
            cstate <= nstate;
        end
    end
    //产生下一个状态组合逻辑
    always @(*) begin
        case(cstate)
            INIT:nstate = initial_done?CLR:INIT;
            CLR :nstate = clear_done?D0:CLR;
            D0:nstate = write_done?D1:D0;
            D1:nstate = write_done?D2:D1;
            D2:nstate = write_done?D3:D2;
            D3:nstate = write_done?D4:D3;
            D4:nstate = write_done?D5:D4;
            D5:nstate = write_done?D6:D5;
            D6:nstate = write_done?D7:D6;
            D7:nstate = write_done?D8:D7;
            D8:nstate = write_done?D9:D8;
            D9:nstate = write_done?D10:D9;
            D10:nstate = write_done?D11:D10;
            D11:nstate = write_done?D12:D11;
            D12:nstate = write_done?D13:D12;
            D13:nstate = write_done?D14:D13;
            D14:nstate = write_done?D15:D14;
            D15:nstate = write_done?D16:D15;
            D16:nstate = write_done?D17:D16;
            D17:nstate = write_done?D18:D17;
            D18:nstate = write_done?D19:D18;
            D19:nstate = write_done?D20:D19;
            D20:nstate = write_done?D21:D20;
            D21:nstate = write_done?D22:D21;
            D22:nstate = write_done?D23:D22;
            D23:nstate = write_done?D24:D23;
            D24:nstate = write_done?D25:D24;
            D25:nstate = write_done?D26:D25;
            D26:nstate = write_done?D27:D26;
            D27:nstate = write_done?D28:D27;
            D28:nstate = write_done?D29:D28;
            D29:nstate = write_done?D30:D29;
            D30:nstate = write_done?D31:D30;
            D31:nstate = write_done?D32:D31;
            D32:nstate = write_done?D33:D32;
            D33:nstate = write_done?D34:D33;
            D34:nstate = write_done?D35:D34;
            D35:nstate = write_done?D36:D35;
            D36:nstate = write_done?D37:D36;
            D37:nstate = write_done?D38:D37;
            D38:nstate = write_done?D39:D38;
            D39:nstate = write_done?D40:D39;
            D40:nstate = write_done?D41:D40;
            D41:nstate = write_done?D42:D41;
            D42:nstate = write_done?D43:D42;
            D43:nstate = write_done?D44:D43;
            D44:nstate = write_done?D45:D44;
            D45:nstate = write_done?D46:D45;
            D46:nstate = write_done?D47:D46;
            D47:nstate = write_done?D48:D47;
            D48:nstate = write_done?D49:D48;
            D49:nstate = write_done?D50:D49;
            D50:nstate = write_done?D51:D50;
            D51:nstate = write_done?D52:D51;
            D52:nstate = write_done?D53:D52;
            D53:nstate = write_done?D54:D53;
            D54:nstate = write_done?D55:D54;
            D55:nstate = write_done?D56:D55;
            D56:nstate = write_done?D57:D56;
            D57:nstate = write_done?D58:D57;
            D58:nstate = write_done?D59:D58;
            D59:nstate = write_done?D60:D59;
            D60:nstate = write_done?D61:D60;
            D61:nstate = write_done?D62:D61;
            D62:nstate = write_done?D63:D62;
            D63:nstate = write_done?D64:D63;
            D64:nstate = write_done?D65:D64;
            D65:nstate = write_done?D66:D65;
            D66:nstate = write_done?D67:D66;
            D67:nstate = write_done?D68:D67;
            D68:nstate = write_done?D69:D68;
            D69:nstate = write_done?D70:D69;
            D70:nstate = write_done?D71:D70;
            D71:nstate = write_done?D72:D71;
            D72:nstate = write_done?D73:D72;
            D73:nstate = write_done?D74:D73;
            D74:nstate = write_done?D75:D74;
            D75:nstate = write_done?D76:D75;
            D76:nstate = write_done?D77:D76;
            D77:nstate = write_done?D78:D77;
            D78:nstate = write_done?D79:D78;
            D79:nstate = write_done?D80:D79;
            D80:nstate = write_done?D81:D80;
            D81:nstate = write_done?D82:D81;
            D82:nstate = write_done?D83:D82;
            D83:nstate = write_done?D84:D83;
            D84:nstate = write_done?D85:D84;
            D85:nstate = write_done?D86:D85;
            D86:nstate = write_done?D87:D86;
            D87:nstate = write_done?D88:D87;
            D88:nstate = write_done?D89:D88;
            D89:nstate = write_done?D90:D89;
            D90:nstate = write_done?D91:D90;
            D91:nstate = write_done?D92:D91;
            D92:nstate = write_done?D93:D92;
            D93:nstate = write_done?D94:D93;
            D94:nstate = write_done?D95:D94;
            D95:nstate = write_done?D96:D95;
            D96:nstate = write_done?D97:D96;
            D97:nstate = write_done?D98:D97;
            D98:nstate = write_done?D99:D98;
            D99:nstate = write_done?D100:D99;
            D100:nstate = write_done?D101:D100;
            D101:nstate = write_done?D102:D101;
            D102:nstate = write_done?D103:D102;
            D103:nstate = write_done?D104:D103;
            D104:nstate = write_done?D105:D104;
            D105:nstate = write_done?D106:D105;
            D106:nstate = write_done?D107:D106;
            D107:nstate = write_done?D108:D107;
            D108:nstate = write_done?D109:D108;
            D109:nstate = write_done?D110:D109;
            D110:nstate = write_done?D111:D110;
            D111:nstate = write_done?D112:D111;
            D112:nstate = write_done?D113:D112;
            D113:nstate = write_done?D114:D113;
            D114:nstate = write_done?D115:D114;
            D115:nstate = write_done?D116:D115;
            D116:nstate = write_done?D117:D116;
            D117:nstate = write_done?D118:D117;
            D118:nstate = write_done?D119:D118;
            D119:nstate = write_done?D120:D119;
            D120:nstate = write_done?D121:D120;
            D121:nstate = write_done?D122:D121;
            D122:nstate = write_done?D123:D122;
            D123:nstate = write_done?D124:D123;
            D124:nstate = write_done?D125:D124;
            D125:nstate = write_done?D126:D125;
            D126:nstate = write_done?D127:D126;
            D127:nstate = write_done?STOP:D127;
            STOP:nstate = sys_rst_n?STOP:INIT;
            default:nstate = INIT;
        endcase
    end

    //根据状态提供相应的输出
    wire PAGE_inc_flag = (&set_pos_x)?1:0;
    always @(*) begin
        if(!rst_n)begin
            set_pos_x = 0;
            set_pos_y = 0;
            write_data= 64'd0;
        end
        else begin
            case (cstate)
//PAGE0
                D0:begin
                    set_pos_x = 0;
                    set_pos_y = 0;
                    write_data  = ROM_data;
                    ROM_addr = 0;
                end
                D1:begin
                    set_pos_x = 8;
                    set_pos_y = 0;
                    write_data  = ROM_data;
                    ROM_addr = 1;
                end
                D2:begin
                    set_pos_x = 16;
                    set_pos_y = 0;
                    write_data  = ROM_data;
                    ROM_addr = 2;
                end
                D3:begin
                    set_pos_x = 24;
                    set_pos_y = 0;
                    write_data  = ROM_data;
                    ROM_addr = 3;
                end
                D4:begin
                    set_pos_x = 32;
                    set_pos_y = 0;
                    write_data  = ROM_data;
                    ROM_addr = 4;
                end
                D5:begin
                    set_pos_x = 40;
                    set_pos_y = 0;
                    write_data  = ROM_data;
                    ROM_addr = 5;
                end
                D6:begin
                    set_pos_x = 48;
                    set_pos_y = 0;
                    write_data  = ROM_data;
                    ROM_addr = 6;
                end
                D7:begin
                    set_pos_x = 56;
                    set_pos_y = 0;
                    write_data  = ROM_data;
                    ROM_addr = 7;
                end
                D8:begin
                    set_pos_x = 64;
                    set_pos_y = 0;
                    write_data  = ROM_data;
                    ROM_addr = 8;
                end
                D9:begin
                    set_pos_x = 72;
                    set_pos_y = 0;
                    write_data  = ROM_data;
                    ROM_addr = 9;
                end
                D10:begin
                    set_pos_x = 80;
                    set_pos_y = 0;
                    write_data  = ROM_data;
                    ROM_addr = 10;
                end
                D11:begin
                    set_pos_x = 88;
                    set_pos_y = 0;
                    write_data  = ROM_data;
                    ROM_addr = 11;
                end
                D12:begin
                    set_pos_x = 96;
                    set_pos_y = 0;
                    write_data  = ROM_data;
                    ROM_addr = 12;
                end
                D13:begin
                    set_pos_x = 104;
                    set_pos_y = 0;
                    write_data  = ROM_data;
                    ROM_addr = 13;
                end
                D14:begin
                    set_pos_x = 112;
                    set_pos_y = 0;
                    write_data  = ROM_data;
                    ROM_addr = 14;
                end
                D15:begin
                    set_pos_x = 120;
                    set_pos_y = 0;
                    write_data  = ROM_data;
                    ROM_addr = 15;
                end
//PAGE1
                D16:begin
                    set_pos_x = 0;
                    set_pos_y = 1;
                    write_data  = ROM_data;
                    ROM_addr = 16;
                end
                D17:begin
                    set_pos_x = 8;
                    set_pos_y = 1;
                    write_data  = ROM_data;
                    ROM_addr = 17;
                end
                D18:begin
                    set_pos_x = 16;
                    set_pos_y = 1;
                    write_data  = ROM_data;
                    ROM_addr = 18;
                end
                D19:begin
                    set_pos_x = 24;
                    set_pos_y = 1;
                    write_data  = ROM_data;
                    ROM_addr = 19;
                end
                D20:begin
                    set_pos_x = 32;
                    set_pos_y = 1;
                    write_data  = ROM_data;
                    ROM_addr = 20;
                end
                D21:begin
                    set_pos_x = 40;
                    set_pos_y = 1;
                    write_data  = ROM_data;
                    ROM_addr = 21;
                end
                D22:begin
                    set_pos_x = 48;
                    set_pos_y = 1;
                    write_data  = ROM_data;
                    ROM_addr = 22;
                end
                D23:begin
                    set_pos_x = 56;
                    set_pos_y = 1;
                    write_data  = ROM_data;
                    ROM_addr = 23;
                end
                D24:begin
                    set_pos_x = 64;
                    set_pos_y = 1;
                    write_data  = ROM_data;
                    ROM_addr = 24;
                end
                D25:begin
                    set_pos_x = 72;
                    set_pos_y = 1;
                    write_data  = ROM_data;
                    ROM_addr = 25;
                end
                D26:begin
                    set_pos_x = 80;
                    set_pos_y = 1;
                    write_data  = ROM_data;
                    ROM_addr = 26;
                end
                D27:begin
                    set_pos_x = 88;
                    set_pos_y = 1;
                    write_data  = ROM_data;
                    ROM_addr = 27;
                end
                D28:begin
                    set_pos_x = 96;
                    set_pos_y = 1;
                    write_data  = ROM_data;
                    ROM_addr = 28;
                end                
                D29:begin
                    set_pos_x = 104;
                    set_pos_y = 1;
                    write_data  = ROM_data;
                    ROM_addr = 29;
                end
                D30:begin
                    set_pos_x = 112;
                    set_pos_y = 1;
                    write_data  = ROM_data;
                    ROM_addr = 30;
                end
                D31:begin
                    set_pos_x = 120;
                    set_pos_y = 1;
                    write_data  = ROM_data;
                    ROM_addr = 31;
                end
//PAGE2
                D32:begin
                    set_pos_x = 0;
                    set_pos_y = 2;
                    write_data  = ROM_data;
                    ROM_addr = 32;
                end
                D33:begin
                    set_pos_x = 8;
                    set_pos_y = 2;
                    write_data  = ROM_data;
                    ROM_addr = 33;
                end
                D34:begin
                    set_pos_x = 16;
                    set_pos_y = 2;
                    write_data  = ROM_data;
                    ROM_addr = 34;
                end
                D35:begin
                    set_pos_x = 24;
                    set_pos_y = 2;
                    write_data  = ROM_data;
                    ROM_addr = 35;
                end
                D36:begin
                    set_pos_x = 32;
                    set_pos_y = 2;
                    write_data  = ROM_data;
                    ROM_addr = 36;
                end
                D37:begin
                    set_pos_x = 40;
                    set_pos_y = 2;
                    write_data  = ROM_data;
                    ROM_addr = 37;
                end
                D38:begin
                    set_pos_x = 48;
                    set_pos_y = 2;
                    write_data  = ROM_data;
                    ROM_addr = 38;
                end
                D39:begin
                    set_pos_x = 56;
                    set_pos_y = 2;
                    write_data  = ROM_data;
                    ROM_addr = 39;
                end
                D40:begin
                    set_pos_x = 64;
                    set_pos_y = 2;
                    write_data  = ROM_data;
                    ROM_addr = 40;
                end
                D41:begin
                    set_pos_x = 72;
                    set_pos_y = 2;
                    write_data  = ROM_data;
                    ROM_addr = 41;
                end
                D42:begin
                    set_pos_x = 80;
                    set_pos_y = 2;
                    write_data  = ROM_data;
                    ROM_addr = 42;
                end
                D43:begin
                    set_pos_x = 88;
                    set_pos_y = 2;
                    write_data  = ROM_data;
                    ROM_addr = 43;
                end
                D44:begin
                    set_pos_x = 96;
                    set_pos_y = 2;
                    write_data  = ROM_data;
                    ROM_addr = 44;
                end
                D45:begin
                    set_pos_x = 104;
                    set_pos_y = 2;
                    write_data  = ROM_data;
                    ROM_addr = 45;
                end
                D46:begin
                    set_pos_x = 112;
                    set_pos_y = 2;
                    write_data  = ROM_data;
                    ROM_addr = 46;
                end
                D47:begin
                    set_pos_x = 120;
                    set_pos_y = 2;
                    write_data  = ROM_data;
                    ROM_addr = 47;
                end
//PAGE3
                D48:begin
                    set_pos_x = 0;
                    set_pos_y = 3;
                    write_data  = ROM_data;
                    ROM_addr = 48;
                end
                D49:begin
                    set_pos_x = 8;
                    set_pos_y = 3;
                    write_data  = ROM_data;
                    ROM_addr = 49;
                end
                D50:begin
                    set_pos_x = 16;
                    set_pos_y = 3;
                    write_data  = ROM_data;
                    ROM_addr = 50;
                end
                D51:begin
                    set_pos_x = 24;
                    set_pos_y = 3;
                    write_data  = ROM_data;
                    ROM_addr = 51;
                end
                D52:begin
                    set_pos_x = 32;
                    set_pos_y = 3;
                    write_data  = ROM_data;
                    ROM_addr = 52;
                end
                D53:begin
                    set_pos_x = 40;
                    set_pos_y = 3;
                    write_data  = ROM_data;
                    ROM_addr = 53;
                end
                D54:begin
                    set_pos_x = 48;
                    set_pos_y = 3;
                    write_data  = ROM_data;
                    ROM_addr = 54;
                end
                D55:begin
                    set_pos_x = 56;
                    set_pos_y = 3;
                    write_data  = ROM_data;
                    ROM_addr = 55;
                end
                D56:begin
                    set_pos_x = 64;
                    set_pos_y = 3;
                    write_data  = ROM_data;
                    ROM_addr = 56;
                end
                D57:begin
                    set_pos_x = 72;
                    set_pos_y = 3;
                    write_data  = ROM_data;
                    ROM_addr = 57;
                end
                D58:begin
                    set_pos_x = 80;
                    set_pos_y = 3;
                    write_data  = ROM_data;
                    ROM_addr = 58;
                end
                D59:begin
                    set_pos_x = 88;
                    set_pos_y = 3;
                    write_data  = ROM_data;
                    ROM_addr = 59;
                end
                D60:begin
                    set_pos_x = 96;
                    set_pos_y = 3;
                    write_data  = ROM_data;
                    ROM_addr = 60;
                end
                D61:begin
                    set_pos_x = 104;
                    set_pos_y = 3;
                    write_data  = ROM_data;
                    ROM_addr = 61;
                end
                D62:begin
                    set_pos_x = 112;
                    set_pos_y = 3;
                    write_data  = ROM_data;
                    ROM_addr = 62;
                end
                D63:begin
                    set_pos_x = 120;
                    set_pos_y = 3;
                    write_data  = ROM_data;
                    ROM_addr = 63;
                end
//PAGE4
                D64:begin
                    set_pos_x = 0;
                    set_pos_y = 4;
                    write_data  = ROM_data;
                    ROM_addr = 64;
                end
                D65:begin
                    set_pos_x = 8;
                    set_pos_y = 4;
                    write_data  = ROM_data;
                    ROM_addr = 65;
                end
                D66:begin
                    set_pos_x = 16;
                    set_pos_y = 4;
                    write_data  = ROM_data;
                    ROM_addr = 66;
                end
                D67:begin
                    set_pos_x = 24;
                    set_pos_y = 4;
                    write_data  = ROM_data;
                    ROM_addr = 67;
                end                
                D68:begin
                    set_pos_x = 32;
                    set_pos_y = 4;
                    write_data  = ROM_data;
                    ROM_addr = 68;
                end
                D69:begin
                    set_pos_x = 40;
                    set_pos_y = 4;
                    write_data  = ROM_data;
                    ROM_addr = 69;
                end
                D70:begin
                    set_pos_x = 48;
                    set_pos_y = 4;
                    write_data  = ROM_data;
                    ROM_addr = 70;
                end
                D71:begin
                    set_pos_x = 56;
                    set_pos_y = 4;
                    write_data  = ROM_data;
                    ROM_addr = 71;
                end
                D72:begin
                    set_pos_x = 64;
                    set_pos_y = 4;
                    write_data  = ROM_data;
                    ROM_addr = 72;
                end
                D73:begin
                    set_pos_x = 72;
                    set_pos_y = 4;
                    write_data  = ROM_data;
                    ROM_addr = 73;
                end
                D74:begin
                    set_pos_x = 80;
                    set_pos_y = 4;
                    write_data  = ROM_data;
                    ROM_addr = 74;
                end
                D75:begin
                    set_pos_x = 88;
                    set_pos_y = 4;
                    write_data  = ROM_data;
                    ROM_addr = 75;
                end                
                D76:begin
                    set_pos_x = 96;
                    set_pos_y = 4;
                    write_data  = ROM_data;
                    ROM_addr = 76;
                end
                D77:begin
                    set_pos_x = 104;
                    set_pos_y = 4;
                    write_data  = ROM_data;
                    ROM_addr = 77;
                end
                D78:begin
                    set_pos_x = 112;
                    set_pos_y = 4;
                    write_data  = ROM_data;
                    ROM_addr = 78;
                end
                D79:begin
                    set_pos_x = 120;
                    set_pos_y = 4;
                    write_data  = ROM_data;
                    ROM_addr = 79;
                end
//PAGGE5
                D80:begin
                    set_pos_x = 0;
                    set_pos_y = 5;
                    write_data  = ROM_data;
                    ROM_addr = 80;
                end
                D81:begin
                    set_pos_x = 8;
                    set_pos_y = 5;
                    write_data  = ROM_data;
                    ROM_addr = 81;
                end
                D82:begin
                    set_pos_x = 16;
                    set_pos_y = 5;
                    write_data  = ROM_data;
                    ROM_addr = 82;
                end
                D83:begin
                    set_pos_x = 24;
                    set_pos_y = 5;
                    write_data  = ROM_data;
                    ROM_addr = 83;
                end
                D84:begin
                    set_pos_x = 32;
                    set_pos_y = 5;
                    write_data  = ROM_data;
                    ROM_addr = 84;
                end
                D85:begin
                    set_pos_x = 40;
                    set_pos_y = 5;
                    write_data  = ROM_data;
                    ROM_addr = 85;
                end
                D86:begin
                    set_pos_x = 48;
                    set_pos_y = 5;
                    write_data  = ROM_data;
                    ROM_addr = 86;
                end
                D87:begin
                    set_pos_x = 56;
                    set_pos_y = 5;
                    write_data  = ROM_data;
                    ROM_addr = 87;
                end
                D88:begin
                    set_pos_x = 64;
                    set_pos_y = 5;
                    write_data  = ROM_data;
                    ROM_addr = 88;
                end
                D89:begin
                    set_pos_x = 72;
                    set_pos_y = 5;
                    write_data  = ROM_data;
                    ROM_addr = 89;
                end
                D90:begin
                    set_pos_x = 80;
                    set_pos_y = 5;
                    write_data  = ROM_data;
                    ROM_addr = 90;
                end
                D91:begin
                    set_pos_x = 88;
                    set_pos_y = 5;
                    write_data  = ROM_data;
                    ROM_addr = 91;
                end
                D92:begin
                    set_pos_x = 96;
                    set_pos_y = 5;
                    write_data  = ROM_data;
                    ROM_addr = 92;
                end
                D93:begin
                    set_pos_x = 104;
                    set_pos_y = 5;
                    write_data  = ROM_data;
                    ROM_addr = 93;
                end
                D94:begin
                    set_pos_x = 112;
                    set_pos_y = 5;
                    write_data  = ROM_data;
                    ROM_addr = 94;
                end
                D95:begin
                    set_pos_x = 120;
                    set_pos_y = 5;
                    write_data  = ROM_data;
                    ROM_addr = 95;
                end
//PAGE6
                D96:begin
                    set_pos_x = 0;
                    set_pos_y = 6;
                    write_data  = ROM_data;
                    ROM_addr = 96;
                end
                D97:begin
                    set_pos_x = 8;
                    set_pos_y = 6;
                    write_data  = ROM_data;
                    ROM_addr = 97;
                end
                D98:begin
                    set_pos_x = 16;
                    set_pos_y = 6;
                    write_data  = ROM_data;
                    ROM_addr = 98;
                end
                D99:begin
                    set_pos_x = 24;
                    set_pos_y = 6;
                    write_data  = ROM_data;
                    ROM_addr = 99;
                end
                D100:begin
                    set_pos_x = 32;
                    set_pos_y = 6;
                    write_data  = ROM_data;
                    ROM_addr = 100;
                end
                D101:begin
                    set_pos_x = 40;
                    set_pos_y = 6;
                    write_data  = ROM_data;
                    ROM_addr = 101;
                end
                D102:begin
                    set_pos_x = 48;
                    set_pos_y = 6;
                    write_data  = ROM_data;
                    ROM_addr = 102;
                end
                D103:begin
                    set_pos_x = 56;
                    set_pos_y = 6;
                    write_data  = ROM_data;
                    ROM_addr = 103;
                end
                D104:begin
                    set_pos_x = 64;
                    set_pos_y = 6;
                    write_data  = ROM_data;
                    ROM_addr = 104;
                end
                D105:begin
                    set_pos_x = 72;
                    set_pos_y = 6;
                    write_data  = ROM_data;
                    ROM_addr = 105;
                end
                D106:begin
                    set_pos_x = 80;
                    set_pos_y = 6;
                    write_data  = ROM_data;
                    ROM_addr = 106;
                end
                D107:begin
                    set_pos_x = 88;
                    set_pos_y = 6;
                    write_data  = ROM_data;
                    ROM_addr = 107;
                end
                D108:begin
                    set_pos_x = 96;
                    set_pos_y = 6;
                    write_data  = ROM_data;
                    ROM_addr = 108;
                end
                D109:begin
                    set_pos_x = 104;
                    set_pos_y = 6;
                    write_data  = ROM_data;
                    ROM_addr = 109;
                end
                D110:begin
                    set_pos_x = 112;
                    set_pos_y = 6;
                    write_data  = ROM_data;
                    ROM_addr = 110;
                end
                D111:begin
                    set_pos_x = 120;
                    set_pos_y = 6;
                    write_data  = ROM_data;
                    ROM_addr = 111;
                end
//PAGE7
                D112:begin
                    set_pos_x = 0;
                    set_pos_y = 7;
                    write_data  = ROM_data;
                    ROM_addr = 112;
                end
                D113:begin
                    set_pos_x = 8;
                    set_pos_y = 7;
                    write_data  = ROM_data;
                    ROM_addr = 113;
                end
                D114:begin
                    set_pos_x = 16;
                    set_pos_y = 7;
                    write_data  = ROM_data;
                    ROM_addr = 114;
                end
                D115:begin
                    set_pos_x = 24;
                    set_pos_y = 7;
                    write_data  = ROM_data;
                    ROM_addr = 115;
                end
                D116:begin
                    set_pos_x = 32;
                    set_pos_y = 7;
                    write_data  = ROM_data;
                    ROM_addr = 116;
                end
                D117:begin
                    set_pos_x = 40;
                    set_pos_y = 7;
                    write_data  = ROM_data;
                    ROM_addr = 117;
                end
                D118:begin
                    set_pos_x = 48;
                    set_pos_y = 7;
                    write_data  = ROM_data;
                    ROM_addr = 118;
                end
                D119:begin
                    set_pos_x = 56;
                    set_pos_y = 7;
                    write_data  = ROM_data;
                    ROM_addr = 119;
                end
                D120:begin
                    set_pos_x = 64;
                    set_pos_y = 7;
                    write_data  = ROM_data;
                    ROM_addr = 120;
                end
                D121:begin
                    set_pos_x = 72;
                    set_pos_y = 7;
                    write_data  = ROM_data;
                    ROM_addr = 121;
                end
                D122:begin
                    set_pos_x = 80;
                    set_pos_y = 7;
                    write_data  = ROM_data;
                    ROM_addr = 122;
                end
                D123:begin
                    set_pos_x = 88;
                    set_pos_y = 7;
                    write_data  = ROM_data;
                    ROM_addr = 123;
                end
                D124:begin
                    set_pos_x = 96;
                    set_pos_y = 7;
                    write_data  = ROM_data;
                    ROM_addr = 124;
                end
                D125:begin
                    set_pos_x = 104;
                    set_pos_y = 7;
                    write_data  = ROM_data;
                    ROM_addr = 125;
                end
                D126:begin
                    set_pos_x = 112;
                    set_pos_y = 7;
                    write_data  = ROM_data;
                    ROM_addr = 126;
                end
                D127:begin
                    set_pos_x = 120;
                    set_pos_y = 7;
                    write_data  = ROM_data;
                    ROM_addr = 127;
                end
                default: begin
                    set_pos_x = 0;
                    set_pos_y = 0;
                    write_data= 64'd0;
                end
            endcase
        end
    end

    //初始化写使能、发送的数据控制
    always @(*) begin
        if(!rst_n)begin
            DC_in = 0;
            SPI_data = 0;
            SPI_send = 0;
        end
        else begin
            case(cstate)
                INIT:begin
                    DC_in    = DC_init;
                    SPI_data = SPI_data_init;
                    SPI_send = SPI_send_init;
                end
                CLR:begin
                    DC_in    = DC_clear;
                    SPI_data = SPI_data_clear;
                    SPI_send = SPI_send_clear;
                end
                D0,D1,D2,D3,D4,D5,D6,D7,D8,D9,
                D10,D11,D12,D13,D14,D15,D16,D17,D18,D19,
                D20,D21,D22,D23,D24,D25,D26,D27,D28,D29,
                D30,D31,D32,D33,D34,D35,D36,D37,D38,D39,
                D40,D41,D42,D43,D44,D45,D46,D47,D48,D49,
                D50,D51,D52,D53,D54,D55,D56,D57,D58,D59,
                D60,D61,D62,D63,D64,D65,D66,D67,D68,D69,
                D70,D71,D72,D73,D74,D75,D76,D77,D78,D79,
                D80,D81,D82,D83,D84,D85,D86,D87,D88,D89,
                D90,D91,D92,D93,D94,D95,D96,D97,D98,D99,
                D100,D101,D102,D103,D104,D105,D106,D107,D108,D109,
                D110,D111,D112,D113,D114,D115,D116,D117,D118,D119,
                D120,D121,D122,D123,D124,D125,D126,D127:begin
                    DC_in    = DC_write;
                    SPI_data = SPI_data_write;
                    SPI_send = SPI_send_write;
                end
                default:begin
                    DC_in = 0;
                    SPI_data = 0;
                    SPI_send = 0;
                end
            endcase
        end 
    end

endmodule

五、仿真结果

初始化

FPGA驱动0.96寸OLED(SSD1306)_第15张图片

 清屏后发送数据

FPGA驱动0.96寸OLED(SSD1306)_第16张图片

 testbench:

module top_tb;

    // Ports
    reg sys_clk = 0;
    reg sys_rst_n = 0;
    wire sclk;
    wire sck;
    wire res;
    wire MOSI;
    wire CS;
    wire DC;

    top top_dut(
        .sys_clk(sys_clk),
        .sys_rst_n(sys_rst_n),
        .sclk(sclk),
        .sck(sck),
        .res(res),
        .MOSI(MOSI),
        .CS(CS),
        .DC(DC)
    );

    initial begin
    begin
        #10000;
        sys_rst_n = 1;
        // $finish;
    end
    end
   always #5 sys_clk = ! sys_clk ;

endmodule

六、板级验证

FPGA驱动0.96寸OLED(SSD1306)_第17张图片

你可能感兴趣的:(FPGA动手项目,fpga开发)