结合上次的串口和LCD,这次在中间加了一个IIC。
流程图,如下:

看着好像挺复杂的样子。其实,在上次,已经实现了右下角的部分和串口的部分。只需要实现IIC部分,在和已经实现好的模块连接就行了。
首先说下功能:
串口将接收到是数据发送到IIC_FIFO中,然后IIC_FIFO控制器控制IIC控制器,将IIC_FIFO中暂存的数据给写到EEPROM中。当外部有按键按下时,按键检测模块会检测到这个输入,然后控制IIC控制器进行EEPROM的数据读取,读取到的数据发送给FIFO中。后面就和上次的一样,LCD从FIFO中取出数据,然后进行显示。
IIC控制器的程序,之前写过博客介绍过。
这里就列出顶层信号
module AT24C02_module(
            input                   clk,
            input                   rst_n,
             
            input                   start,              
            input       [2:0]           device_address,    //the device AT24C02 address
            input       [7:0]           rom_address,       //the rom address
            input       [7:0]           rom_write_data,    //write 8-bits data to the AT24C02
            input                   write_or_read,       //write mode or read mode   0 write  1 read
             
            input    [7:0]              write_data_number,       // write data number
            input    [7:0]                          read_data_number,  //read  data number
             
             
            output  reg[7:0]                        row_read_data,     //read 8-bits data from AT24C02 in rom_address
             
            output  reg             read_finish,       //read data finish,mean external can read data
            output   reg                write_finish,     //write one byte data finsih.
            output   reg                write_idle,       //write data state, 1 mean external can write new data
             
            inout                           i2c_sda,            //I2C    data   , bidirectional port
            output  reg             i2c_scl,             //I2C    clk   250K
             
            output   reg                operate_busy,     // IIC is or bot busy ,1 mean busy ,0 mean not busy
             
            output                  enable_read         // now state is read or write.  1 mean read, 0 mean write
    );  
可以实现IIC的多数据或单个数据的读写。
下面就是IIC_FIFO控制器。
采用状态机设计。
总共有三个状态。第一个状态是空闲状态,第二个状态是等待fifo接收串口数据状态,第三个状态就是控制写IIC状态。
所以,代码也是比较简单的。
module FIFO_IIC_control(
        input           clk,
        input           rst_n,
     
 
        input           rxd_finish,         // uart receive finish signal . 1 mean read a uart data
         
        input           iic_write_finish,       //IIC write 1 byte data signal. 1 mean write finish
         
         
        input   [5:0]           iFifo_count,            //IIC_FIFO save data number
         
        output  reg         fifo_rd_en,     //fifo read enable, 1 mean read data from fifo
        output  reg             iic_start,      //IIC statt signal, 1 mean start
             
        output  reg  [5:0]      oFifo_count  // output to IIC  show how many data will be write
    );
      
      
     localparam  idle_state             =  'd0;
     localparam  fifo_rxd_state         =   'd1;
     localparam  iic_write_state            =  'd2; 
      
      
     localparam  time_value = 27'b100_0000_0000_0000_0000_0000_0000;
     //localparam  time_value = 27'd2000;
     reg [26:0]   time_counter;
      
      
     reg [1:0] state;
     always@(posedge clk or negedge rst_n) begin
        if(!rst_n)  
            begin
                oFifo_count <= 'd16;
                fifo_rd_en  <= 'd0;
                iic_start <='d0;
                time_counter <= 'd0;
                state <= idle_state;
            end
        else
            case(state)
            //idle state   nothing to do 
            //detect uart reveice siganl ,state go to fifo_rxd_state
            idle_state: begin
               time_counter <= 'd0;
                if(rxd_finish == 1)
                    state <= fifo_rxd_state;
            end
            //fifo_rxd_state   wait uart receive data finsih
            //if exceed time_value ,mean uart receive data is finish, so state go to iic_write_state
            fifo_rxd_state: begin
                if( time_counter >= time_value )
                    begin
                        state <= iic_write_state;
                        oFifo_count <= iFifo_count;
                        iic_start <= 1'b1;
                        fifo_rd_en <= 1'b1;
                    end
                else if(rxd_finish == 1)
                    time_counter <= 'd0;
                else
                    time_counter <= time_counter + 1'b1;
            end
            //iic_write_state   , control IIC write data
            iic_write_state: begin
                iic_start <= 1'b0;
                fifo_rd_en <= iic_write_finish;
                if(iFifo_count == 0)
                    state <= idle_state;
            end
            endcase
     end
endmodule
这里说明一下oFifo_count <= 'd16; 这条语句。
oFifo_count这个是输出给IIC控制器的,指示这次操作读或写是要操作多少个数据。这里复位值是16.因为我们知道EEPROM器件数据是掉电不丢失的。所以上次写的数据在掉电后是不丢失的。所以在给开发板重新上电后,我们可以直接读取数据,而不用串口重新写数据之后才能读。所以这里将这个数据个数给复位为16.意思就在上电复位后,当按下按键后,就读取IIC的16个数据进行显示。
然后将IIC部分的代码给封装成一个模块
module fifo_iic(
        input           clk,
        input           rst_n,
         
        input           iuart_send_flag,  //uart receive finish signal
        input    [7:0]          iuart_data,         //uart receive 8-bits data
         
        input           key,                    //external buttom
         
         
        output          iic_read_finish,    //IIC read 1-byte data finish
        output [7:0]            iic_read_data,      //IIC read 1-byte data
         
        inout           i2c_sda,            //I2C    data   , bidirectional port
        output          i2c_scl ,           //I2C    clk   250K
         
         
        output [7:0]            fifo_data_o,         
        output                  fifo_rd_en
         
    );
      
      
     wire iic_write_idle;
     wire iic_write_finish;
     wire [5:0] data_count;
     wire [5:0] oFifo_count;
     reg write_or_read;
     wire key_down;
      
      
AT24C02_module u1 (
    .clk(clk), 
    .rst_n(rst_n), 
    .start(iic_start | key_down), 
    .device_address(3'b000), 
    .rom_address('d0), 
    .rom_write_data(fifo_data_o), 
    .write_or_read(write_or_read), 
    .write_data_number({2'b0,oFifo_count}), 
    .read_data_number({2'b0,oFifo_count}), 
    .row_read_data(iic_read_data), 
    .read_finish(iic_read_finish), 
    .write_finish(iic_write_finish), 
    .write_idle(iic_write_idle), 
    .i2c_sda(i2c_sda), 
    .i2c_scl(i2c_scl), 
     .operate_busy(),
    .enable_read()
    );
      
 FIFO_IIC_control u2 (
     .clk(clk),
     .rst_n(rst_n),
    .rxd_finish(iuart_send_flag), 
    .iic_write_finish(iic_write_finish), 
    .iFifo_count(data_count), 
    .fifo_rd_en(fifo_rd_en), 
    .iic_start(iic_start), 
    .oFifo_count(oFifo_count)
    );
      
      
 
fifo_module u3 (
    .clk(clk), 
    .rst_n(rst_n), 
    .idata(iuart_data), 
    .ird_en(fifo_rd_en), 
    .iwr_en(iuart_send_flag), 
    .odata(fifo_data_o), 
    .empty(),
     .data_count(data_count) // output [5 : 0] data_count
    );
      
     key_button u4 (
    .clk(clk), 
    .rst_n(rst_n), 
    .key(~key), 
    .key_down(key_down)
    );
      
     always@(posedge clk or negedge rst_n) begin
            if(!rst_n)
                write_or_read <= 1'b0;  //default  IIC is write operate
            else
                if(key_down == 1)
                    write_or_read <= 1'b1;
                else if(iic_write_idle == 1 && write_or_read == 1'b1)
                    write_or_read <= 1'b0;
     end
endmodule
在然后,将串口模块,IIC模块,LCD模块给连接起来。也就是进行封装。
module uart_iic_lcd(
    input               clk,
    input               rst_n,
     
    //uart interface
    input               uart_rxd,     //input  serial rxd data
    output                  uart_txd ,    //output   serial txd data
       
    input                       key,
     
    inout                           i2c_sda,            //I2C    data   , bidirectional port
    output                  i2c_scl,             //I2C    clk   250K
     
     //    LCD Interface
        output [3:0]                    LCD_DATA,    //
        output                          LCD_RW,      //
        output                          LCD_EN,      //
        output                          LCD_RS ,     // 
      
    output       [7:0]              oled     
    );
      
     wire [7:0] iic_read_data;
     wire iic_read_finish;
      
     wire iuart_send_flag;
     wire [7:0] iuart_data;
      
     wire fifo_rd_en;
     wire [7:0] fifo_data_o;
      
     wire clk_50M;
 
 
          
    uart_top u0 (
    .clk(clk_50M), 
    .rst_n(rst_n), 
    .uart_rxd(uart_rxd), 
    .tx_start(fifo_rd_en ), 
    .tx_data(fifo_data_o[7:0]), 
    .tx_finish(), 
    .rx_finish(iuart_send_flag), 
    .uart_txd(uart_txd), 
    .receive_data(iuart_data[7:0])
    );
      
     assign oled = iuart_data[7:0];
      
      
     fifo_iic u1 (
    .clk(clk_50M), 
    .rst_n(rst_n), 
    .iuart_send_flag(iuart_send_flag), 
    .iuart_data(iuart_data), 
    .key(key), 
    .iic_read_finish(iic_read_finish), 
    .iic_read_data(iic_read_data[7:0]), 
    .i2c_sda(i2c_sda), 
    .i2c_scl(i2c_scl),
    .fifo_data_o(),
     .fifo_rd_en()
    );
      
      LCD_top u2 (
    .clk(clk_50M), 
    .rst_n(rst_n), 
    .iuart_data(iic_read_data[7:0]), 
    .iuart_send_flag(iic_read_finish), 
    .LCD_DATA(LCD_DATA[3:0]), 
    .LCD_RW(LCD_RW), 
    .LCD_EN(LCD_EN), 
    .LCD_RS(LCD_RS),
     .fifo_data_o(fifo_data_o[7:0]),
     .fifo_rd_en(fifo_rd_en)
    );
      
     dcm_100_50 u3 (
    .clk(clk), 
    .rst_n(rst_n), 
    .clk_out(clk_50M)
    );
endmodule
这里多一个dcm_100_50模块,因为virtex5的板子的晶振是100M的。而设计的代码是基于50M时钟的,所以需要一个dcm将时钟进行二分频。为什么不自己写一个二分频代码了。因为用dcm分频出来的时钟的质量比直接用代码写生成出来的时钟质量好。
下面就开始测试
首先发送数据。

使用逻辑分析仪抓紧的IIC写数据波形

最前面两个发的是器件地址和写数据的地址。后面是写的数据。
然后读取数据,

逻辑分析仪抓取的IIC读取波形

前两个是器件地址和读取数据的地址。后面一个是重新发送器件地址,但是发送的数据最后一位要为1,表示是读数据。后面就是读取的数据。
设计,还有些小bug。
EEPROM在多字节写入的时候,一次操作最多只能写16个数据,超过16个数据后,写的数据会覆盖之前写的数据,但是在读的时候,是没有限制的。所以,当串口发送的数据超过16个后,之前写入的数据会被覆盖掉,而读取的时候,是读取发送那么多数据的个数的。所以,就会读到无效数据,显示就会出现乱码。
例如,我发送18个数据,那么最后两个数据会覆盖最先写的两个数据。读的时候,会读取18个数据,这样就读到了无效的后两个数据。
这里,在程序中,就需要加入,当写入的数据超过16个的时候,进行写第二次。
我发送

用逻辑分析仪抓波形

然后读取数据

抓取的波形

发送的数据,总共有34个。所以最终写入到IIC的第一个数据是第33个,也就是7.因为被后面写的数据覆盖了。所以读取到的数据的第一个就是7。至于后面读到的乱码,那是因为地址超过16了,而地址超过16的数据,我们都没有写,所以不知道这些数据是什么。就有可能是乱码了。
 畅学电子
畅学电子








