数字电路期末课程设计总结(三)IIC总线调用
首先介绍一下IIC总线。高速设备为了抗干扰,大多数都用低压差分信号(LVDS)。差分线路由于传递差模信号,可以有效抑制共模噪声和串扰。IIC总线虽然由于速度限制不能驱动高速设备,多用于KHz级别的信号传递,不过依然有着比较广泛的用途。
IIC网上资料繁多,我就不再赘述。
写数据分三步:
1.主机发送地址位(写),从机应答。
2.主机发送控制字,从机应答。
3.主机发送数据。
读数据分四步:
1.主机发送地址位(写),从机应答。
2.主机发送控制字,从机应答。
3.主机发送地址位(读),从机应答。
3.主机接收数据。
这次主要实现的功能:
根据工作状态控制字决定AOUT端输出波形(波形控制字控制波形),
或是AIN0,AIN1,AIN3端读入不同传感器的数据。
顶层模块图:
IIC模块读(写)完毕后Done_Sig产生1个高脉冲,驱动RomAddressCtrl模块和StateToCtrlByte模块改变工作状态,
外部的State控制信号由StateToCtrlByte模块处理后产生对应的IIC控制字,
Done_Sig信号与State控制信号通过控制Start_Sig信号决定IIC模块读写状态。
顶层代码如下:
1 module I2C4In1 2 ( 3 input clock, // 时钟线 4 input reset, // 复位线 5 input[4:0] State, // 工作状态控制字 6 7 8 9 inout SDA, // IIC数据线 10 input[2:0] WaveChoose, // 波形控制字 11 input[7:0] FreqChoose, // 相位控制字 12 13 output SCL, // IIC时钟线 14 output[7:0] ReadDataOut // 读数据输出 15 ); 16 17 /***************************/ 18 RomAddressCtrl U1( // ROM地址控制模块 19 .Done_Sig(Done_Sig), // IIC结束信号 20 .clock(clock), // 时钟线 21 .reset(reset), // 复位线 22 .FreqChoose(FreqChoose), // 相位控制字 23 .isStart(isStart), // ROM输出IIC使能 24 .RomAddress(RomAddress) // ROM地址 25 ); 26 27 WaveRomChoose U4( // ROM选择模块,选择输出波形对应的ROM 28 .WaveChoose(WaveChoose), // 波形控制字 29 .address(RomAddress), // ROM地址 30 .clock(clock), // 时钟线 31 .q(RomData) // ROM数据输出 32 ); 33 wire[7:0] RomData; // 模块间连线 34 wire[10:0] RomAddress; // 模块间连线 35 wire[1:0] isStart; // 模块间连线 36 wire[1:0] Start_Sig; // 模块间连线 37 // IIC控制字输出模块 38 StateToCtrlByte U3(clock,reset,State,IICCtrlByte,isStart,Start_Sig,Done_Sig,RdData,ReadDataOut); 39 /***************************/ 40 wire[7:0] IICCtrlByte; // 模块间连线 41 wire[7:0] RdData; // 模块间连线 42 wire Done_Sig; // 模块间连线 43 44 iic_func_module U2 // IIC模块 45 ( 46 .clock( clock ), 47 .reset( reset ), 48 .Start_Sig(Start_Sig ), 49 .Addr_Sig( IICCtrlByte ), 50 .WrData( RomData ), 51 .RdData( RdData ), 52 .Done_Sig( Done_Sig ), 53 .SCL( SCL ), 54 .SDA( SDA ) 55 ); 56 57 58 endmodule
地址:1001000(0/1)
A2A1A0见下图,都连了地,所以都是0.
IIC代码如下(源于黑金FPGA社区):
1 module iic_func_module 2 ( 3 input clock, 4 input reset, 5 6 input [1:0]Start_Sig, // IIC使能信号,10为读,01为写 7 input [7:0]Addr_Sig, // 控制字 8 input [7:0]WrData, // 写数据 9 output [7:0]RdData, // 读数据 10 output Done_Sig, // 转换完成信号,一个高脉冲 11 12 output SCL, // IIC时钟线 13 inout SDA // IIC数据线 14 15 16 ); 17 18 /*************************/ 19 20 parameter FREQ14 = 11'd85; 21 parameter FREQ24 = 11'd170; 22 parameter FREQ34 = 11'd255; 23 parameter FREQ = 11'd341; // 时间参量,对应50MHz时钟 24 25 /*************************/ 26 27 reg [4:0]i; 28 reg [4:0]Go; 29 reg [10:0]C1; 30 reg [7:0]rData; 31 reg rSCL; 32 reg rSDA; 33 reg isAck; 34 reg isDone; 35 reg isOut; 36 37 always @ ( posedge clock or negedge reset ) 38 if( !reset ) 39 begin 40 i <= 5'd0; 41 Go <= 5'd0; 42 C1 <= 11'd0; 43 rData <= 8'd0; 44 rSCL <= 1'b1; 45 rSDA <= 1'b1; 46 isAck <= 1'b1; 47 isDone <= 1'b0; 48 isOut <= 1'b1; 49 end 50 else if( Start_Sig[0] ) 51 case( i ) 52 53 0: // Start 54 begin 55 isOut = 1; 56 57 rSCL <= 1'b1; 58 59 if( C1 == 0 ) rSDA <= 1'b1; 60 else if( C1 == FREQ24 ) rSDA <= 1'b0; 61 62 if( C1 == FREQ -1) begin C1 <= 11'd0; i <= i + 1'b1; end 63 else C1 <= C1 + 1'b1; 64 end 65 66 1: // Write Device Addr 67 begin rData <= {4'b1001, 3'b000, 1'b0}; i <= 5'd7; Go <= i + 1'b1; end 68 69 2: // Wirte Word Addr 70 begin rData <= Addr_Sig; i <= 5'd7; Go <= i + 1'b1; end 71 72 3: // Write Data 73 begin rData <= WrData; i <= 5'd7; Go <= i + 1'b1; end 74 75 /*************************/ 76 77 4: // Stop 78 begin 79 isOut = 1'b1; 80 81 if( C1 == 0 ) rSCL <= 1'b0; 82 else if( C1 == FREQ14 ) rSCL <= 1'b1; 83 84 if( C1 == 0 ) rSDA <= 1'b0; 85 else if( C1 == FREQ34 ) rSDA <= 1'b1; 86 87 if( C1 == FREQ14 + FREQ -1 ) begin C1 <= 11'd0; i <= i + 1'b1; end 88 else C1 <= C1 + 1'b1; 89 end 90 91 5: 92 begin isDone <= 1'b1; i <= i + 1'b1; end 93 94 6: 95 begin isDone <= 1'b0; i <= 5'd0; end 96 97 /*******************************/ //function 98 99 7,8,9,10,11,12,13,14: 100 begin 101 isOut = 1'b1; 102 rSDA <= rData[14-i]; 103 104 if( C1 == 0 ) rSCL <= 1'b0; 105 else if( C1 == FREQ24 ) rSCL <= 1'b1; 106 107 if( C1 == FREQ -1 ) begin C1 <= 11'd0; i <= i + 1'b1; end 108 else C1 <= C1 + 1'b1; 109 end 110 111 15: // waiting for acknowledge 112 begin 113 isOut = 1'b0; 114 if( C1 == FREQ34 ) isAck <= SDA; 115 116 if( C1 == 0 ) rSCL <= 1'b0; 117 else if( C1 == FREQ24 ) rSCL <= 1'b1; 118 119 if( C1 == FREQ -1 ) begin C1 <= 11'd0; i <= i + 1'b1; end 120 else C1 <= C1 + 1'b1; 121 end 122 123 16: 124 if( isAck != 0 ) i <= 5'd0; 125 else i <= Go; 126 127 /*******************************/ // end function 128 129 endcase 130 131 else if( Start_Sig[1] ) 132 case( i ) 133 134 0: // Start 135 begin 136 isOut = 1; 137 138 rSCL <= 1'b1; 139 140 if( C1 == 0 ) rSDA <= 1'b1; 141 else if( C1 == FREQ24 ) rSDA <= 1'b0; 142 143 if( C1 == FREQ -1 ) begin C1 <= 11'd0; i <= i + 1'b1; end 144 else C1 <= C1 + 1'b1; 145 end 146 147 1: // Write Device Addr 148 begin rData <= {4'b1001, 3'b000, 1'b0}; i <= 5'd9; Go <= i + 1'b1; end 149 150 2: // Wirte Word Addr 151 begin rData <= Addr_Sig; i <= 5'd9; Go <= i + 1'b1; end 152 153 3: // Start again 154 begin 155 isOut = 1'b1; 156 157 if( C1 == 0 ) rSCL <= 1'b0; 158 else if( C1 == FREQ14 ) rSCL <= 1'b1; 159 else if( C1 == FREQ14 + FREQ ) rSCL <= 1'b0; 160 161 if( C1 == 0 ) rSDA <= 1'b0; 162 else if( C1 == FREQ14 ) rSDA <= 1'b1; 163 else if( C1 == FREQ34 ) rSDA <= 1'b0; 164 165 if( C1 == FREQ + FREQ24 -1 ) begin C1 <= 11'd0; i <= i + 1'b1; end 166 else C1 <= C1 + 1'b1; 167 end 168 169 4: // Write Device Addr ( Read ) 170 begin rData <= {4'b1001, 3'b000, 1'b1}; i <= 5'd9; Go <= i + 1'b1; end 171 172 5: // Read Data 173 begin rData <= 8'd0; i <= 5'd19; Go <= i + 1'b1; end 174 175 6: // Stop 176 begin 177 isOut = 1'b1; 178 179 if( C1 == 0 ) rSCL <= 1'b0; 180 else if( C1 == FREQ14 ) rSCL <= 1'b1; 181 182 if( C1 == 0 ) rSDA <= 1'b0; 183 else if( C1 == FREQ34 ) rSDA <= 1'b1; 184 185 if( C1 == 50 + FREQ -1 ) begin C1 <= 11'd0; i <= i + 1'b1; end 186 else C1 <= C1 + 1'b1; 187 end 188 189 7: 190 begin isDone <= 1'b1; i <= i + 1'b1; end 191 192 8: 193 begin isDone <= 1'b0; i <= 5'd0; end 194 195 /*******************************/ //function 196 197 9,10,11,12,13,14,15,16: 198 begin 199 isOut = 1'b1; 200 201 rSDA <= rData[16-i]; 202 203 if( C1 == 0 ) rSCL <= 1'b0; 204 else if( C1 == FREQ24 ) rSCL <= 1'b1; 205 206 if( C1 == FREQ -1 ) begin C1 <= 11'd0; i <= i + 1'b1; end 207 else C1 <= C1 + 1'b1; 208 end 209 210 17: // waiting for acknowledge 211 begin 212 isOut = 1'b0; 213 214 if( C1 == FREQ34 ) isAck <= SDA; 215 216 if( C1 == 0 ) rSCL <= 1'b0; 217 else if( C1 == FREQ24 ) rSCL <= 1'b1; 218 219 if( C1 == FREQ -1 ) begin C1 <= 11'd0; i <= i + 1'b1; end 220 else C1 <= C1 + 1'b1; 221 end 222 223 18: 224 if( isAck != 0 ) i <= 5'd0; 225 else i <= Go; 226 227 /*****************************/ 228 229 19,20,21,22,23,24,25,26: // Read 230 begin 231 isOut = 1'b0; 232 if( C1 == FREQ34 ) rData[26-i] <= SDA; 233 234 if( C1 == 0 ) rSCL <= 1'b0; 235 else if( C1 == FREQ24 ) rSCL <= 1'b1; 236 237 if( C1 == FREQ -1 ) begin C1 <= 11'd0; i <= i + 1'b1; end 238 else C1 <= C1 + 1'b1; 239 end 240 241 27: // no acknowledge 242 begin 243 isOut = 1'b1; 244 //if( C1 == 100 ) isAck <= SDA; 245 246 if( C1 == 0 ) rSCL <= 1'b0; 247 else if( C1 == FREQ24 ) rSCL <= 1'b1; 248 249 if( C1 == FREQ -1 ) begin C1 <= 11'd0; i <= Go; end 250 else C1 <= C1 + 1'b1; 251 end 252 253 /*************************************/ // end fucntion 254 255 endcase 256 257 /***************************************/ 258 259 assign Done_Sig = isDon; 260 assign RdData = rData; 261 assign SCL = rSCL; 262 assign SDA = isOut ? rSDA : 1'bz; 263 264 /***************************************/ 265 266 267 endmodule 268
StateToCtrlByte模块:
State决定IICCtrlByte(IIC控制字)。针对27-41行的写法,我做了一些思考。最初用的是锁存器写法。
1 always@(State) 2 case(State) 3 5'b00001: RegIICCtrlByte <= 8'b00000000; 4 5'b00010: RegIICCtrlByte <= 8'b00000001; 5 5'b00100: RegIICCtrlByte <= 8'b01000000; 6 5'b01000: RegIICCtrlByte <= 8'b00000011; 7 endcase
后来发现存在bug,信号有时会过不去。于是改成了组合逻辑式写法
1 assign IICCtrlByte = State[0]==1?8'd0:(State[1]==1?8'd1:(State[2]==1?8'd64:8'd3));
StateToCtrlByte:
1 module StateToCtrlByte(clock,reset,State,IICCtrlByte,isStart,Start_Sig,Done_Sig,RdData,ReadDataOut); 2 input[4:0] State; 3 input[1:0] isStart; 4 input Done_Sig; 5 input clock,reset; 6 input[7:0] RdData; //IIC模块读操作数据输入 7 8 output[1:0] Start_Sig; 9 output[7:0] IICCtrlByte; 10 output[7:0] ReadDataOut; // IIC模块读操作数据输出 11 12 reg[1:0] RegStart; 13 reg[7:0] RegReadDataOut; 14 // reg[7:0] RegIICCtrlByte; 15 16 always @ ( posedge clock or negedge reset ) 17 if( !reset ) 18 begin 19 RegStart <= 2'b00; 20 end 21 else 22 case( Done_Sig ) 23 0: if(State==5'b00100)RegStart <= 2'b01;else RegStart <= 2'b10; 24 1: begin RegStart <= 2'b00; RegReadDataOut <= RdData;end 25 endcase 26 27 // always@(State) 28 // case(State) 29 // 5'b00001: RegIICCtrlByte <= 8'b00000000; 30 // 5'b00010: RegIICCtrlByte <= 8'b00000001; 31 // 5'b00100: RegIICCtrlByte <= 8'b01000000; 32 // 5'b01000: RegIICCtrlByte <= 8'b00000011; 33 // endcase 34 35 assign IICCtrlByte = State[0]==1?8'd0:(State[1]==1?8'd1:(State[2]==1?8'd64:8'd3)); 36 assign ReadDataOut = RegReadDataOut; 37 assign Start_Sig = RegStart; 38 //光照 AIN0 8'b00000000; 00001 39 //温度 AIN1 8'b00000001; 00010 40 //频率输出 8'b01000000; 00100 41 //内部电阻分压 AIN3 8'b00000011; 01000 42 endmodule
1 // 相位累加模块 2 module RomAddressCtrl(Done_Sig,clock,reset,FreqChoose,isStart,RomAddress); 3 4 input Done_Sig; 5 input clock; 6 input reset; 7 input[7:0] FreqChoose; 8 9 output[1:0] isStart; // 输出使能。01写操作,00中止 10 output[10:0] RomAddress; // ROM地址 11 12 reg [3:0] i; // 状态变量 i 13 reg [1:0] RegisStart; // 输出使能寄存器 14 reg[10:0] RegRomAddress; // ROM地址寄存器 15 16 // 相位累加模块 17 // 收到IIC结束信号Done_Sig后 18 always @ ( posedge clock or negedge reset ) 19 if( !reset ) 20 begin 21 i <= 4'd0; 22 RegisStart <= 2'b00; 23 end 24 else 25 case( Done_Sig ) 26 27 0: RegisStart <= 2'b01; 28 29 1: begin RegisStart <= 2'b00; i <= 4'd0; RegRomAddress <= RegRomAddress + FreqChoose;end 30 31 endcase 32 33 assign isStart = RegisStart; 34 assign RomAddress = RegRomAddress; 35 36 endmodule
1 module WaveRomChoose(WaveChoose,address,clock,q); 2 3 input clock; 4 input[2:0] WaveChoose; 5 input[10:0] address; 6 7 output[7:0] q; 8 9 wire[7:0] SinData; 10 wire[7:0] SquData; 11 wire[7:0] TriData; 12 13 rom_sin U1( 14 .address(address), 15 .clock(clock), 16 .q(SinData) 17 ); 18 19 rom_squ U2( 20 .address(address), 21 .clock(clock), 22 .q(SquData) 23 ); 24 25 rom_tri U3( 26 .address(address), 27 .clock(clock), 28 .q(TriData) 29 ); 30 31 assign q = WaveChoose[0]?SinData:(WaveChoose[1]?SquData:TriData); 32 endmodule