打印

这个i2c程序错在哪了?渴盼火眼金睛中......

[复制链接]
2365|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
andyany|  楼主 | 2010-11-5 09:51 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 andyany 于 2010-11-5 15:10 编辑

module i2c(
   input                 clk,
   input                 rst_n,
   input                enable,
   output reg[3:0] state,
   output reg[2:0] cmd,
   output reg[4:0] i_state,
   output reg[4:0] i_next_state,
   output reg        r_w,
   output reg        next,
   output reg[3:0] bit_num
);

reg           ack_data;
reg           bit_num_check;
reg           bit_false;
reg [19:0]  delay_num;
reg [  3:0]  next_state;

parameter idle                 = 4'd0;    parameter start_1             = 4'd1;  
parameter sla_w              = 4'd2;    parameter sla_w_ack        = 4'd3;  
parameter sec_addr        = 4'd4;    parameter sec_addr_ack  = 4'd5;
parameter start_2            = 4'd6;    parameter sla_r                = 4'd7;  
parameter sla_r_ack        = 4'd8;    parameter sec_data         = 4'd9;  
parameter sec_data_ack = 4'd10;  parameter stop                 = 4'd11;
parameter delay               = 4'd12;

parameter i_idle     = 5'd0;      parameter start_a = 5'd1;  
parameter start_b  = 5'd2;      parameter start_c = 5'd3;  
parameter bit_a     = 5'd4;      parameter bit_b    = 5'd5;
parameter bit_c     = 5'd6;      parameter ack_a   = 5'd7;  
parameter ack_b   = 5'd8;      parameter ack_c   = 5'd9;  
parameter stop_a  = 5'd10;    parameter stop_b  = 5'd11;
parameter stop_c  = 5'd12;    parameter stop_d  = 5'd13;
parameter stop_e  = 5'd14;    parameter stop_f  = 5'd15;
parameter i_delay = 5'd16;

parameter cmd_start = 3'd0;     
parameter cmd_byte  = 3'd1;
parameter cmd_ack   = 3'd2;
parameter cmd_stop  = 3'd3;
parameter cmd_delay = 3'd4;

待续

相关帖子

沙发
andyany|  楼主 | 2010-11-5 09:53 | 只看该作者
本帖最后由 andyany 于 2010-11-5 15:17 编辑


always@(posedge clk)
if(!rst_n)        begin state <= idle;             i_state <= idle;              end
else if(enable) begin state <= next_state;  i_state <= i_next_state;  end

always@(posedge clk)
if(enable)
case(state)
idle: begin           cmd <= cmd_start;
                          r_w <= 0;
                next_state <= start_1;        end

start_1: if(next) begin cmd <= cmd_byte;
                       next_state <= sla_w; end

sla_w: begin if(!bit_num_check) next_state <= idle;
                   if(next) begin           cmd <= cmd_ack;
                                                 r_w <= 1'b1;
                                       next_state <= sla_w_ack; end end

sla_w_ack: if(ack_data) next_state <= idle;
                else begin              cmd <= cmd_byte;
                                            r_w <= 1'b0;
                                  next_state <= sec_addr; end

sec_addr: begin if(!bit_num_check) next_state <= idle;
                        if(next) begin cmd <= cmd_ack;
                                            r_w <= 1'b1;
                                   next_state <= sec_addr_ack; end
end
sec_addr_ack: if(ack_data) next_state <= idle;
                     else begin             cmd <= cmd_start;
                                      next_state <= start_2; end

start_2: if(next) begin cmd <= cmd_byte;
                                 r_w <= 1'b0;
                       next_state <= sla_r; end

sla_r: begin if(!bit_num_check) next_state <= idle;
                  if(next) begin                 cmd <= cmd_ack;
                                                      r_w <= 1'b1;
                                            next_state <= sla_r_ack; end end
sla_r_ack: if(ack_data) next_state <= idle;
               else begin             cmd <= cmd_byte;
                                next_state <= sec_data; end

sec_data: begin if(!bit_num_check) next_state <= idle;
                       if(next) begin                  cmd <= cmd_ack;
                                                            r_w <= 1'b0;
                                                 next_state <= sec_data_ack; end end
sec_data_ack: if(next) begin cmd <= cmd_stop; next_state <= stop; end
stop:              if(next) begin cmd <= cmd_delay; next_state <= delay; end
delay:             if(next) begin cmd <= cmd_start; next_state <= start_1;end
default:           next_state <= start_1;
endcase

always@(posedge clk)
if(enable)
case(i_state)
i_idle: begin bit_num_check <= 1'b1;
                  next <= 1'b0;
                  case(cmd)
cmd_start:          i_next_state <= start_a;
cmd_byte: begin  i_next_state <= bit_a;     bit_num <= 4'd8; end
cmd_ack:            i_next_state <= ack_a;
cmd_stop:          i_next_state <= stop_a;
cmd_delay: begin i_next_state <= i_delay;  delay_num <= 20'hf4240; end
default:              i_next_state <= i_idle;
endcase
end
start_a:         i_next_state <= start_b;
start_b:         i_next_state <= start_c;
start_c: begin i_next_state <= i_idle;         next <= 1'b1; end

bit_a:    begin i_next_state <= bit_b;    bit_num <= bit_num - 4'b1; end
bit_b:            i_next_state <= bit_c;
bit_c:    begin if(!bit_false) begin i_next_state <= i_idle; bit_num_check <= 1'b0; end
                     else if(bit_num != 4'd0) i_next_state <= bit_a;
                     else begin                     i_next_state <= i_idle; next <= 1'b1; end end

ack_a:          i_next_state <= ack_b;
ack_b:          i_next_state <= ack_c;
ack_c:           i_next_state <= i_idle;

stop_a:         i_next_state <= stop_b;
stop_b:         i_next_state <= stop_c;
stop_c:         i_next_state <= stop_d;
stop_d:         i_next_state <= stop_e;
stop_e:         i_next_state <= stop_f;
stop_f: begin i_next_state <= i_idle;        next <= 1'b1; end

i_delay: begin delay_num <= delay_num -1;
                     if(delay_num != 20'd0) i_next_state <= i_delay;
                    else begin                     i_next_state <= i_idle; next <= 1'b1; end
end

default:        i_next_state <= i_idle;
endcase

endmodule

使用特权

评论回复
板凳
andyany|  楼主 | 2010-11-5 10:08 | 只看该作者
本帖最后由 andyany 于 2010-11-5 10:18 编辑

由于网络问题,稍后我会上传仿真波形。请见谅!
谢谢!

使用特权

评论回复
地板
andyany|  楼主 | 2010-11-5 10:19 | 只看该作者
本帖最后由 andyany 于 2010-11-5 15:12 编辑

testbench——

module test_v;

reg clk;
reg rst_n;
reg enable;
wire [3:0] state;
wire [4:0] i_state;
wire [4:0] i_next_state;
wire [2:0] cmd;
wire r_w;
wire next;
wire [3:0] bit_num;

i2c uut (
.clk(clk),
.rst_n(rst_n),
.enable(enable),
.state(state),
.i_state(i_state),
.i_next_state(i_next_state),
.cmd(cmd),
.r_w(r_w),
.next(next),
.bit_num(bit_num)
);

initial begin
clk = 0;
rst_n = 0;
enable = 0;
#100 rst_n = 1;
end

always #10 clk = !clk;
always #10 enable = !enable;

endmodule

使用特权

评论回复
5
andyany|  楼主 | 2010-11-5 15:08 | 只看该作者
本帖最后由 andyany 于 2010-11-5 15:13 编辑

目前仿真的问题是bit_num在i_state为bit_b时也减1了。
不知道错在哪。原意是bit_num仅在i_state为bit_a时减1。

使用特权

评论回复
6
半个苹果| | 2010-11-5 17:59 | 只看该作者

状态机在bit_a这个状态停留了2个时钟周期才跳转到bit_b这个状态,楼主的代码中描述了当状态机在bit_a这个状态时,bit_num就减一,因此当状态机从状态bit_a跳转到bit_b的时候,bit_num就自然减2了。

楼主说状态机在bit_b的时候,bit_num也减一的原因估计是楼主把波形看错了,我在仿真的时候给阻塞复制加了延迟,这样看就清晰多了。

另外建议楼主写代码的时候不要嵌套case语句,也许这样写可能比较简洁,但是别人读起来可能会多用些时间

使用特权

评论回复
7
wxfxwk1986| | 2010-11-5 21:31 | 只看该作者
看不懂,帮顶。。。

使用特权

评论回复
8
andyany|  楼主 | 2010-11-8 09:32 | 只看该作者
谢谢半个苹果!你说的很对!
我看了很久,最终发现了这个问题。最后把第二个always语句改成了状态机,把问题解决了。
读程序肯定费了你时间,不好意思。还有仿真分析......,谢谢!
不过,请教你一个问题,对于我的程序,如果第二个always语句不用case嵌套,有什么办法?
当初我对case嵌套也有疑问,但看到罗力凡和常春藤老师的《基于VHDL的FPGA开发 快速入门.技巧.实例》用了case嵌套,我也就没有再犹豫了。这个程序也参考了这本书,对他们也表示感谢!

使用特权

评论回复
9
andyany|  楼主 | 2010-11-8 09:35 | 只看该作者
第二个always语句改成状态机是把
always@(posedge clk)
if(enable)
改成
always@(i_state,cmd)

使用特权

评论回复
10
半个苹果| | 2010-11-8 16:28 | 只看该作者
具体怎么改,我也说不好,我也写过一些HDL的代码,都没有用到case嵌套
我觉得可以从设计上避免吧
把状态机的状态切换,下一个状态计算和状态译码输出分开写,可能会好点

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

62

主题

664

帖子

3

粉丝