Verilog学习笔记简单功能实现(七)...............接口设计(并行输入串行输出)
利用状态机实现比较复杂的接口设计:
这是一个将并行数据转换为串行输出的变换器,利用双向总线输出。这是由EEPROM读写器的缩减得到的,首先对I2C总线特征介绍:
I2C总线(inter integrated circuit)双向二线制串行总线协议为:只有总线处于“非忙”状态时,数据传输才开始。在数据传输期间,只要时钟线为高电平,数据线都必须保持稳定,否则数据线上的任何变化都被当作“启动”或“停止”信号。
下面介绍A、B、C、D的工作状态:
(1)总线处于非忙状态(A段):该段内的数据线(sda)和时钟线(scl)都保持高电平;
(2)启动数据传输(B段):当时钟线(scl)为高电平时,数据线(sda)由高电平变为低电平的下降沿被认为是“启动”信号;
(3)停止数据传输(C段):当时钟线(scl)为高电平时,数据线(sda)由低电平变为高电平的上升沿被认为是“停止”信号;
(4)数据有效(D段):在出现“启动”信号之后,在时钟线(scl)为高电平时,数据线是稳定的,这是数据线上的数据就是要传送的数据,数据线上的数据改变必须在时钟线(scl)为低电平期间完成,每个数据占用一个时钟;
(5)应答信号:每个正在接受数据的EEPROM在接收到一个字节的数据后,通常需要发出一个应答信号;而每个正在发送数据的EEPROM在发出一个字节的数据后,通常需要接受一个应答信号;EEPROM读写控制器必须提供一个与这个应答信号相联系的二外的始终脉冲。
其控制字节一共有8位:1010xxxW/R 其中1010是I2C总线器件特征编码,xxx表示地址,W/R表示读写状态。
在实现并行输入串行输出时,需要两个状态机:
主状态机主要控制内部存储器和输入端的连接,以及给出应答信号;从状态机主要负责总线连接时,内部寄存器的最高位输出个移位;
状态机的源码如下:
1 module parallel_to_serial(rst,clk,addr,data,sda,ack); 2 input rst,clk; 3 input [7:0]data,addr; 4 5 inout sda; //data bus 6 output ack; //ask for next address/data writting wo eeprm; 7 reg link_write; //whether connect to output 8 reg [2:0]state; //main status, 9 reg [4:0]sh8out_state; //serial output status 10 reg [7:0]sh8out_buf; //output data buffer 11 reg finish_F; //whether finished an operation of main status 12 reg ack; 13 14 parameter idle=0, addr_write=3'd1, data_write=3'd2, stop_ack=3'd4; //main status code 15 parameter bit0=1, bit1=2, bit2=3, bit3=4, bit4=5, bit5=6, bit6=7, bit7=8; //serial output status code 16 17 assign sda=link_write?sh8out_buf[7]:1'bz; //??????????? 18 19 always @(posedge clk) 20 begin 21 if(!rst) //reset 22 begin 23 ack<=0; 24 link_write<=0; //??????? 25 finish_F<=0; 26 state<=idle; 27 sh8out_state<=idle; 28 sh8out_buf<=0; 29 end 30 else 31 case(state) 32 idle:begin 33 link_write<=0; //?????? 34 ack<=0; 35 finish_F<=0; 36 sh8out_buf<=addr; //??????? 37 sh8out_state<=idle; 38 state<=addr_write; //??????? 39 end 40 addr_write:begin 41 if (finish_F==0) begin shift8_out;end //??????? 42 else 43 begin 44 link_write<=0; 45 ack<=0; 46 finish_F<=0; 47 sh8out_buf<=data; //??????? 48 state<=data_write; 49 sh8out_state<=idle; 50 end 51 end 52 data_write:begin 53 if (finish_F==0) begin shift8_out;end //??????? 54 else 55 begin 56 link_write<=0; 57 finish_F<=0; 58 state<=stop_ack; 59 ack<=1; //???????? 60 end 61 end 62 stop_ack:begin //???? 63 ack<=0; 64 state<=idle; 65 end 66 endcase 67 end 68 69 task shift8_out; //??????? 70 begin 71 case(sh8out_state) 72 idle:begin 73 link_write<=1; //?????????????????17?assign sda=link_write?sh8out_buf[7]:1'bz; sda??????????sh8out_buf????? 74 sh8out_state<=bit7; 75 end 76 bit7:begin 77 link_write<=1; 78 sh8out_buf=sh8out_buf<<1; //?????data?????bit6 79 sh8out_state<=bit6; 80 end 81 bit6:begin 82 link_write<=1; 83 sh8out_buf=sh8out_buf<<1; 84 sh8out_state<=bit5; 85 end 86 bit5:begin 87 link_write<=1; 88 sh8out_buf=sh8out_buf<<1; 89 sh8out_state<=bit4; 90 end 91 bit4:begin 92 link_write<=1; 93 sh8out_buf=sh8out_buf<<1; 94 sh8out_state<=bit3; 95 end 96 bit3:begin 97 link_write<=1; 98 sh8out_buf=sh8out_buf<<1; 99 sh8out_state<=bit2; 100 end 101 bit2:begin 102 link_write<=1; 103 sh8out_buf=sh8out_buf<<1; 104 sh8out_state<=bit1; 105 end 106 bit1:begin 107 link_write<=1; 108 sh8out_buf=sh8out_buf<<1; 109 sh8out_state<=bit0; 110 end 111 bit0:begin 112 link_write<=0; 113 finish_F<=1; 114 end 115 endcase 116 end 117 endtask 118 endmodule
测试程序:
1 `timescale 1ns/1ns 2 `define clk_period 50 3 module parallel_to_serial_test; 4 reg rst,clk; 5 reg [7:0]data,addr; 6 wire ack,sda; 7 wire [2:0]state; //main status, 8 wire [4:0]sh8out_state; 9 10 initial 11 begin 12 clk=0; 13 rst=1; 14 data=0; 15 addr=0; 16 #(2*`clk_period) rst=0; 17 #(2*`clk_period) rst=1; 18 #(100*`clk_period) $stop; 19 end 20 21 always #50 clk=~clk; 22 23 24 25 always @(posedge clk) 26 begin data=data+1; addr=addr+1; end 27 28 parallel_to_serial m( 29 .rst(rst), 30 .clk(clk), 31 .addr(addr), 32 .data(data), 33 .sda(sda), 34 .ack(ack) 35 ); 36 37 assign state=m.state; 38 assign sh8out_state=m.sh8out_state; 39 endmodule
波形信号: