在完成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。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
`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