IIC系列文章:
(1)I2C 接口控制器理论讲解
(2)I2C接口控制设计与实现
(3)I2C连续读写实现
文章目录
- 前言
- 一、 i2c_bit_shift 模块分析
- 二、 i2c_control 模块实现
- 三、 i2c_control 模块仿真测试
前言
上文的 i2c_bit_shift 模块说完了,我们发现实现一个字节的写操作还是可以实现的,实际的应用中我们不可能只写一个字节的数据,那么此时这个 i2c_bit_shift 模块用来连续写就有些不方便了,从上面的仿真代码就能看出来,这时就需要一个上层模块来控制这个i2c_bit_shift 模块去连续写,这样就方便一些。
提示:以下是本篇文章正文内容,下面案例可供参考
一、 i2c_bit_shift 模块分析
还是用一个实际的例子来说明。例如往 1 字节器件地址的 EEPROM 中的 0C 地址写数据 0A 呢?我们来看一下上面说的单字节写时序图。
首先我们按照 i2c_bit_shift 模块的操作来拆分一下,这里面可以分成三次操作:
第一次,起始位+写数据(7 位器件 ID + 1 位读写控制位(这里是 0,表示写)),等待从机应答。
第二次,写数据(8 位 EEPROM 的寄存器地址),等待从机应答。
第三次,写数据(写 8 位数据到 EEPROM 中),等待从机应答,然后给出停止位信号。
我们要从一个 1 字节器件地址的 EEPROM 中的 0C地址读取数据。我们来看一下上面说的单字节读时序图。
首先我们按照 i2c_bit_shift 模块的操作来拆分一下,这里面可以分成四次操作:
第一次,起始位+写数据(7 位器件 ID + 1 位读写控制位(这里是 0,表示写)),等待从机应答。
第二次,写数据(8 位 EEPROM 的寄存器地址),等待从机应答。
第三次,起始位+写数据(7 位器件 ID + 1 位读写控制位(这里是 1,表示读)),等待从机应答。
第四次,读数据(从 EEPROM 中读出 8 位数据)+ 应答位(根据需要给出应答(0)或者无应答(1))+ 停止位。
总的来说就是写了三次 1 字节的数据,读了一次 1 字节的数据。
二、 i2c_control 模块实现
原理图展示:
模块接口功能描述:
状态转移图,如下图所示:
为了让代码更简洁这里就用到了两个 task 一个是用来写字节(write_byte),另一个是读字节(read_byte)。写字节的 task 里面就将要写的字节数据准备好(赋值给 i2c_bit_shift 模块的 Tx_DATA 端口),同时涉及到的传给 i2c_bit_shift 模块的 Cmd 命令也准备好,同时触发 Go 信号,这样就可以通过i2c_bit_shift 模块将要写的数据发送到总线上了。同理,读字节的 task 里面将涉及到的传给i2c_bit_shift 模块的 Cmd 命令也准备好,同时触发 Go 信号,这样就可以通过 i2c_bit_shift 模块将总线上的数据读取出来了。代码如下:
task read_byte;
input [5:0]Ctrl_Cmd;
begin
Cmd <= Ctrl_Cmd;
Go <= 1'b1;
end
endtask
task write_byte;
input [5:0]Ctrl_Cmd;
input [7:0]Wr_Byte_Data;
begin
Cmd <= Ctrl_Cmd;
Tx_DATA <= Wr_Byte_Data;
Go <= 1'b1;
end
endtask
这样的话读代码就可以简化成下面这样了,
write_byte(WR | STA, device_id);
write_byte(WR, reg_addr[15:8]);
write_byte(WR, reg_addr[7:0]);
write_byte(WR | STO, wrdata);
写代码简化为
write_byte(WR | STA, device_id);
write_byte(WR | STO,8'h0C);
write_byte(WR | STA, device_id |8'd1);
read_byte(RD | ACK | STO);
第三行的 device_id | 8’d1 是因为后面要进行读操作,所以用这个小技巧就可以把原本的写改成读了。
那么上面的代码还是有问题,怎么就判断第一行的这个 write_byte 的 task 把数据写成功了呢,这个就需要判断 i2c_bit_shift 模块返回的 Trans_Done 的握手信号,这样就可以接着发送第二行的 write_byte 的 task,以此类推的执行完这四行的 task 就可以实现从 EEPROM 中的 0C 地址读取数据。可以分成 3 个状态来控制这个过程,第一个是写寄存器状态(WR_REG),这里面有这个写数据操作的四个 task(第