国产FPGA测评【五】I2C遍历EEPROM寄存器并通过串口打印

yyliu   2023-2-5 18:05 楼主

声明:1.本帖如有对引用其他网站资源,均附上了网址,针对本帖中可能出现的侵权行为,请及时联系本人修改或删除。

2.未经本人允许,请勿转载。若本帖存在错误或不足之处,烦请指正,本人会及时修改。

3.本帖代码根据正点原子代码修改,并给出了源码,若对正点原子构成侵权,请及时联系本人删除。


 

0.说明


本帖根据正点原子的EEPROM模块核串口模块,融合为一个工程文件,来实现特定业务:I2C遍历EEPROM寄存器并通过串口打印。

开始介绍我的工程之前,先来解答几个疑问。

1.为什么使用I2C

I2C是一种在工业控制、消费电子、计算机硬件广泛应用的程序。其仅需SCL和SDA两根数据线,但是在硬件设计中不难发现一个主设备挂载数十个I2C从设备,掌握I2C的硬件设计方法、PCB走线、程序设计是极其重要的。FPGA实现I2C驱动,需要根据I2C的读写时序去设计驱动模块,根据应用场景去实现业务逻辑;像MCU这一类的IC实现I2C就较为简单了,只需要设置相关的寄存器去配置I2C的工作模式即可。MCU自带的I2C总线可能会存在一定的使用局限,MCU的GPIO模拟I2C时序,也是消费电子中经常使用的。

2.为什么通过串口打印寄存器数据

通过对寄存器的写入和读出,并在串口显示,能够方便我们调试,观察写入的数据与读出的数据是否一致。当我们在调试I2C设备发现工作异常时,可以方便的将从器件的寄存器值打印出来,对比datasheet查看是否是配置有误。

另外,根据上一节提到的,我们还可以将I2C设备发送过来的数据存到RAM、FIFO、FLASH中,可供随时查看分析。

3.本帖提供全部源代码,见附件。

 

1.软件总体设计


本帖的硬件设计比较简单,就是FPGA与EEPROM的I2C电路设计,网上相关内容较多,可自行学习。本帖直接介绍软件的设计。

本帖实验目标:开发板上电后,像EEPROM写入256个数据(0~255)后,读取EEPROM的所有寄存器数据(8192个),并通过串口打印到串口助手上。

I2C驱动模块:i2c dri为I2C驱动模块,用来驱动I2C的读写操作

读写EEPROM模块:e2promrw模块通过i2caddr接口向i2cdri模块输入器件字地址,通过i2cdata_w接口向i2c_dri模块输入写的数据,并通过i2c_data_r接口读取i2c_dri模块读到的数据。该模块还例化和串口模块,可以实现将读取到的EEPROM数据打印到串口。

LED显示模块:在EEPROM读写测试完成之前,LED灯处于熄灭状态;如果EEPROM读写测试成功,LED灯处于常亮状态;如果EEPROM读写测试失败,LED灯会不停的闪烁。

image.png  

 

  2.关键代码分析


I2C驱动是本工程最关键的部分,大家可以自行学习正点原子的资源,不再赘述。

本帖只对顶层模块和读写EEPROM模块进行了修改。

串口发送模块例化如下,assign uart_send_en = ((i2c_rh_wl == 1'b1) && i2c_done);当I2C处于读状态且读完成一字节数据后,就通过串口发送出去。这里有几个关键问题,一定要注意:

1.串口的使能信号,uart_en只需要一个周期的高电平去触发,而非一直保持高电平。如果一直保持高电平,就会导致uart_tx_busy信号一直为高,且串口的发送过程无法进行。大家可以自行分析串口发送模块。

2.i2c_done也只是保持一个时钟周期有效。我一开始想要通过定时器cke_1ms,每隔1ms读一次EEPROM数据,并让读取地址增加,并通过串口发送出去再进行下一次EEPROM数据的读取。发现程序执行异常。因为我没有注意到,i2c_done也只是保持一个时钟周期有效,且时钟cke_1ms与I2C读写的时钟属于异步时钟,当i2c_done有效时,cke_1ms可能无效;当i2c_done无效时,ke_1ms可能有效,这是地址增加这条指令永远执行不到,读不到想要的数据。

3.本帖是根据i2c_done信号去写串口数据的,大家可以考虑下,为什么I2C读取的EEPROM数据可以全部通过串口打印出来?什么情况下,会出现串口数据未发送完,I2C读取了多次数据导致串口数据漏掉?并未使用cke_1ms,大家要使用定时器要注意时钟同步的问题。

assign uart_send_en = ((i2c_rh_wl == 1'b1) && i2c_done);

uart_send #(                          
    .CLK_FREQ       (CLK_FREQ),         //设置系统时钟频率
    .UART_BPS       (UART_BPS))         //设置串口发送波特率
u_uart_send(                 
    .sys_clk        (sysclk),
    .sys_rst_n      (rst_n),
     
    .uart_en        (uart_send_en),     //发送使能信号
    .uart_din       (i2c_data_r),   //待发送数据
    .uart_tx_busy   (uart_tx_busy),     //发送忙状态标志    
    .uart_txd       (uart_txd)          //UART发送端口
    );

 

串口数据发送状态机如下:

  2'd2 : begin                 
                    if (1)   begin         // if (cke_1ms),cke_1ms周期小于clk
                        flow_cnt <= flow_cnt + 1'b1;
                        i2c_exec <= 1'b1;
                    end
                    else
                        flow_cnt <= flow_cnt;
            end    
            2'd3 : begin
                if(i2c_done == 1'b1) begin                 //EEPROM单次读出完成
                    //读出的值错误或者I2C未应答,读写测试失败
                    if((i2c_addr <= MAX_BYTE-1) && (i2c_addr[7:0] != i2c_data_r) || (i2c_ack == 1'b1)) begin
                        rw_done <= 1'b1;
                        rw_result <= 1'b0;
                    end
                    //else if(i2c_addr == MAX_BYTE - 1'b1) begin //读写测试成功
                    else if(i2c_addr == 8191) begin //读写测试成功
                        rw_done <= 1'b1;
                        rw_result <= 1'b1;
                        i2c_addr <= i2c_addr;
                    end    
                    else begin
                        flow_cnt <= 2'd2;
                        i2c_addr <= i2c_addr + 1'b1;
                    end

 

3.实物仿真


1.实物连接如下图:包括下载器连接到PC、type-c数据线连接PC和开发板,连接上电源。

image.png

 

红色灯常亮表示我们向地址0-255写入的256个数据,与读出是相同的,证明了I2C数据读写的正确性。

 

串口助手设置:

波特率设置为115200,停止位1,无校验。注意勾选十六进制显示。

串口助手点击清除接收,然后下载程序,串口助手就会出现下列数据,方框中的前256个数据是我们写入的,数据依次为0-255,后面的数据默认值都为FF。箭头表示我们一共读取了EEPROM的8192个数据。

image.png

我在附件给出了源码,大家如果有疑问可以回帖咨询。

 

 

本帖最后由 yyliu 于 2023-2-5 18:07 编辑

    e2prom_top.v (2023-2-5 18:02 上传)

    4.17 KB, 下载次数: 1

    顶层文件

    e2prom_rw.v (2023-2-5 18:02 上传)

    5.73 KB, 下载次数: 3

    根据业务修改

    i2c_dri.v (2023-2-5 18:02 上传)

    22.58 KB, 下载次数: 0

    无需修改

    led_alarm.v (2023-2-5 18:02 上传)

    2.57 KB, 下载次数: 0

    无需修改

    uart_send.v (2023-2-5 18:02 上传)

    5.88 KB, 下载次数: 1

    无需修改

回复评论 (2)

为什么I2C读取的EEPROM数据可以全部通过串口打印出来?这是个问题

点赞  2023-2-5 22:25
引用: 火辣西米秀 发表于 2023-2-5 22:25 为什么I2C读取的EEPROM数据可以全部通过串口打印出来?这是个问题

根据i2c的频率和传输位数,计算出读取一次eepron寄存器所需时间t1,


串口波特率为115200,计算一次传输8bit数据所需时间t2,


t1>t2,因此不会丢数据。你可以实际计算下


点赞  2023-2-6 19:07
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复