在完成iic_cmd 层设计后,就需要上层应用程序发送操作给cmd层。在结构化设计中, 我们需要将iic_cmd,iic_phy,scl_en 等模块封装一起,称为iic_engine 模块,这样iic_engine 模块就可以独立使用了, 应用层有多种多样,但都是可以调用iic_engine 。本文中使用iic_app 模块作为i2c 的应用层。在iic_app 中,只有数据包的发送和接收, 再没有和i2c phy相关的具体操作了,完全是数据的传输。在结构化设计中,结构框图如下:

图1
从图1中可以看出, iic_app层与数据相关,只是安装接口协议写入或者读取相应的数据到iic_engine,不负责i2c 的具体操作。 iic_engine 负责i2c 的具体操作,但是命令是由上层(iic_app)来提供的。
1 iic_app 层代码:

图2
状态0:初始化, 等待65535 个时钟周期,主要用于仿真,方便观察,跳转到状态1
状态1:读取二维数值中的数据,如果数组不为0, 表示当前命令有效,发送数据到cmd 层,跳转到状态2
状态2:等待cmd 层返回pkg_din_ack 信号, 发送下一笔数据,直到发送的数据个数等于 pkg_len,跳转到状态3
状态3:等待cmd 层返回pkg_end, 指针指向下一条命令, 跳转到状态1。
`timescale 1ns / 1ps
module iic_app
(
input sys_clk,
output reg [7:0] pkg_din = 0,
output reg pkg_din_vld = 0,
input pkg_din_ack,
input pkg_end,
input [7:0] pkg_dout,
input pkg_dout_vld,
input rst
);
localparam CMD_LEN = 12;
reg [CMD_LEN*8 - 1: 0] cmd_list[9:0];
initial
begin
// length delay addr data/rd leng data
cmd_list[0] = {8'h0c,8'h05,8'ha0, 8'h00, 8'h00,8'h01,8'h02,8'h03,8'h04,8'h05,8'h06,8'h07};
cmd_list[1] = {8'h0b,8'h05,8'ha0, 8'h08, 8'h08,8'h09,8'h0a,8'h0b,8'h0c,8'h0d,8'h0e,8'h0f};
cmd_list[2] = {8'h05,8'h01,8'ha1, 8'h03, 8'h06,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00};
cmd_list[3] = {8'h04,8'h01,8'ha1, 8'h02, 8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00};
cmd_list[4] = {8'h04,8'h01,8'ha1, 8'h00, 8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00};
cmd_list[5] = {8'h05,8'h01,8'ha1, 8'h0b, 8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00};
cmd_list[6] = 0;
end
reg [7:0] pkg_len = 0;
reg [3:0] app_st;
reg [15:0] cnt;
reg [4:0] cmd_idx = 0;
always@(posedge sys_clk or posedge rst)
if(rst)
begin
pkg_din_vld <= 0;
cmd_idx <= 0;
cnt <= 1;
app_st <= 0;
end
else
case(app_st)
0:
begin
cmd_idx <= 0;
pkg_din_vld <= 0;
cnt <= cnt + 1;
if(&cnt[15:0])
begin
cnt <= 1;
app_st <= 1;
end
end
1:
begin
cnt <= 1;
if(cmd_list[cmd_idx] != 0)
begin
pkg_din_vld <= 1;
pkg_len <= cmd_list[cmd_idx][CMD_LEN*8-1 -:8];
pkg_din <= cmd_list[cmd_idx][CMD_LEN*8-1 -:8];
app_st <= 2;
end
else $stop;
end
2:
begin
if(pkg_len == cnt)
app_st <= 3;
else
begin
if(pkg_din_ack)
begin
pkg_din <= cmd_list[cmd_idx][(CMD_LEN - cnt)*8-1 -:8];
cnt <= cnt + 1;
end
end
end
3:
begin
if(pkg_end)
begin
pkg_din_vld <= 0;
cmd_idx <= cmd_idx + 1;
#50000;
app_st <= 1;
end
end
default:app_st <= 0;
endcase
endmodule
仿真

图3