上一篇我们设计了 I2C Master 的状态机,那麽我们今天要来引用上次完成的状态机模块来实现 I2C Master 模块,但我们先一步一步来,先来完成 write 的部分,也就是先可以把输入的值成功以 I2C 协定传出去,再来完成读入的部分
先来看看这个 I2C Master write 模块该有哪些输入输出脚吧:
输入:
输出:
输入+输出:
module I2C_write_R_W(
clk_sys,
rst_n,
en,
data_R,
data_W,
ACK,
ACK1,
ACK2,
ACK3,
rstACK,
SCLK,
SDA,
ldnACK1,
ldnACK2,
ldnACK3,
R_W,
tick_I2C_neg
);
/*---------ports declaration---------*/
input clk_sys;
input rst_n;
input en;
input R_W;
input [26:0] data_R;//read 27bit
input [17:0] data_W;//write 18bit
output ACK1;
output ACK2;
output ACK3;
output tick_I2C_neg;
output ACK;
output rstACK;
output SCLK;
output ldnACK1;
output ldnACK2;
output ldnACK3;
reg tick_I2C_neg;
reg ACK1;
reg ACK2;
reg ACK3;
wire ACK;
wire rstACK;
wire SCLK;
wire ldnACK1;
wire ldnACK2;
wire ldnACK3;
inout SDA;
宣告变数:
需要用到的变数有:
/*---------variables---------*/
reg [4:0] count;
reg [8:0] cnt_I2C;
reg tick_I2C;
reg SCLK_100k;
reg [26:0] regdata_R;
reg [17:0] regdata_W;
wire SCLK_temp;
wire SHEN;
wire LDEN;
wire SDO;
wire countEN;
wire rstcount;
wire SEL;
/*---------assign wire---------*/
assign SEL = (SHEN)?((!R_W)?(regdata_W[17]):(regdata_R[26])):(SDO);
assign SDA = (SEL)?(1'bz):(1'b0);
assign ACK = ACK1|ACK2|ACK3;
引用状态机模组
/*---------module instantiate---------*/
I2C_control_R_W U0(
.clk_sys(clk_sys),
.SCLK_100k(SCLK_100k),
.tick_I2C(tick_I2C),
.rst_n(rst_n),
.en(en),
.count(count),
.countEN(countEN),
.rstcount(rstcount),
.ACK1(ldnACK1),
.ACK2(ldnACK2),
.ACK3(ldnACK3),
.rstACK(rstACK),
.SCLK(SCLK),
.SCLK_temp(SCLK_temp),
.SHEN(SHEN),
.LDEN(LDEN),
.SDO(SDO),
.R_W(R_W)
);
cnt_I2C
/*---------100k counter---------*/
always@(posedge clk_sys or negedge rst_n)begin
if(!rst_n)cnt_I2C <= 9'd0;
else begin
if(cnt_I2C<9'd499)cnt_I2C <= cnt_I2C + 9'd1;//0-499
else cnt_I2C <= 9'd0;
end
end
tick_I2C
/*---------I2C tick---------*/
always@(posedge clk_sys or negedge rst_n)begin
if(!rst_n)tick_I2C <= 1'b0;
else begin
if(cnt_I2C==9'd498)tick_I2C <= 1'b1;
else tick_I2C <= 1'b0;
end
end
/*---------I2C tick_neg---------*/
always@(posedge clk_sys or negedge rst_n)begin
if(!rst_n)tick_I2C_neg <= 1'b0;
else begin
if(cnt_I2C==9'd249)tick_I2C_neg <= 1'b1;
else tick_I2C_neg <= 1'b0;
end
end
SCLK_100k
/*---------SCLK_100k---------*/
always@(posedge clk_sys or negedge rst_n)begin
if(!rst_n)SCLK_100k <= 1'b0;
else begin
if(cnt_I2C==9'd100) SCLK_100k <= 1'b0;
else if(cnt_I2C==9'd400)SCLK_100k <= 1'b1;
else SCLK_100k <= SCLK_100k;
end
end
这里来解释一下为什麽是 100 跟 400:
还记得前几天的 I2C 的介绍内有提到,SDA 只能在 SCLK 为 "0" 时更动值,因此我们的 SCLK 高电位的部分要抓短一点,所以才会出现 100 时下去 400 上来的情况(咦?这样不是反过来吗?因为我状态机模组里面有反向了,你们也可以 100 上去 400 下来,然後不要反向,当然你想用其他的高电位宽度也都可以!),而 SDA 只会在 cnt_I2C 等於 498 时才更动值,如此一来就可以达到 SDA 只会在 SCLK 等於 "0" 时才更动值的效果!
藉由 rstcount&countEN 来控制 count
/*---------count---------*/
always@(posedge clk_sys or negedge rst_n)begin
if(!rst_n)begin
count <= 5'd0;
end
else begin
if(tick_I2C)begin
if(rstcount) count <= 5'd0;
else if(countEN)count <= count + 5'd1;
else count <= count;
end
else count <= count;
end
end
藉由 LDEN&SHEN&R_W 来控制我们的 regdata_W®data_R
/*---------load data---------*/
always@(posedge clk_sys or negedge rst_n)begin
if(!rst_n)begin
regdata_R <= 27'd0;
regdata_W <= 18'd0;
end
else begin
if(!R_W)begin
if(tick_I2C)begin
if(LDEN) regdata_W <= data_W;
else if(SHEN)regdata_W <= {regdata_W[16:0],1'b0};
else regdata_W <= regdata_W;
end
else regdata_W <= regdata_W;
end
else begin
if(tick_I2C)begin
if(LDEN) regdata_R <= data_R;
else if(SHEN)regdata_R <= {regdata_R[25:0],1'b0};
else regdata_R <= regdata_R;
end
else regdata_R <= regdata_R;
end
end
end
读取 BUS 上的 ACK
/*---------ACK---------*/
always@(posedge clk_sys or negedge rst_n)begin
if(!rst_n)begin
ACK1 <= 1'b0;
ACK2 <= 1'b0;
ACK3 <= 1'b0;
end
else if(rstACK&&tick_I2C)begin
ACK1 <= 1'b0;
ACK2 <= 1'b0;
ACK3 <= 1'b0;
end
else begin
if(ldnACK1&&tick_I2C)ACK1 <= SDA;
else ACK1 <= ACK1;
if(ldnACK2&&tick_I2C)ACK2 <= SDA;
else ACK2 <= ACK2;
if(ldnACK3&&tick_I2C)ACK3 <= SDA;
else ACK3 <= ACK3;
end
end
endmodule
由於这篇的内容也算偏多,可以先让你们消化一下,下一篇我们会继续完成 Read 的部分,并且撰写 TestBench 来验证电路的正确性~~
<<: Day23 - this&Object Prototypes Ch3 Objects - Review
jQuery的基本语法: 1.前面都会有美元 $ 的符号 2. $(CSS选择器).执行的动作() ...
昨天提到了生成模型(Generative Model),要去计算事前机率(Prior Probabi...
在操作元件那天,已经大略谈到在Activity 上架上元件就像在写Windows Form 上的元件...
前言 $emit 让我们可以发送出自订的事件,例如: 触发特定的事件(关闭 popup) 或是 子元...
哈罗~~大家好!!星期五好愉快~~马上进入主题吧!! 今天要介绍的是使用NodeJs建立後端的服务器...