xilinx verilog 编写IIC程序,从机TCA6416APW,求高手指导
时间:10-02
整理:3721RD
点击:
最近编写了一个IIC程序,从机是TCA6416APW芯片,sda,scl 均通过10k上拉电阻接到3.3v电源上。如图1
2013-9-12 20:39 上传
下载附件 (67.12 KB)

tca6416的口线通过反相器驱动LED,(只截图两个管脚,其他相同)。sda,scl,reset接到fpga(spartan 3se500)的管脚上。先编写程序驱动led,程序源码如下
2013-9-12 20:39 上传下载附件 (67.12 KB)

tca6416的口线通过反相器驱动LED,(只截图两个管脚,其他相同)。sda,scl,reset接到fpga(spartan 3se500)的管脚上。先编写程序驱动led,程序源码如下
- module iic_com(clk,rst_n,reset_led, scl,sda);
- input clk; // 30MHz
- input rst_n; //复位信号,低有效
- output reset_led;
- output scl; // 时钟端口
- inout sda; // 数据端口
- assign reset_led=1;//tca6416复位信号置高
- //--------------------------------------------
- reg[20:0] cnt_20ms; //20ms计数寄存器
- always @ (posedge clk or negedge rst_n)
- if(!rst_n) cnt_20ms <= 20'd0;
- else if(cnt_20ms == 20'd600000) cnt_20ms <= 20'd0;
- else cnt_20ms <= cnt_20ms+1'b1; //不断计数
- //---------------------------------------------
- //分频部分
- reg[2:0] cnt; // cnt=0:scl上升沿cnt=1:scl高电平中间 cnt=2:scl下降沿 cnt=3:scl低电平中间
- reg[9:0] cnt_delay; //600循环计数,产生iic所需要的时钟 20us
- reg scl_r; //时钟脉冲寄存器
- reg ack_rise;
- reg scl_dir;
- always @ (posedge clk or negedge rst_n)
- if(!rst_n) cnt_delay <= 10'd0;
- else if(cnt_delay == 10'd599) cnt_delay <=10'd0; //计数到20us为scl的周期
- else cnt_delay <= cnt_delay+1'b1; //延时
-
- always @ (posedge clk or negedge rst_n) begin
- if(!rst_n) cnt <= 3'd5;
- else begin
- case (cnt_delay)
- 10'd49: cnt <= 3'd1; //cnt=1:scl高电平中间,用于数据采样
- 10'd299: cnt <= 3'd2; //cnt=2:scl下降沿
- 10'd314: cnt <= 3'd3; //cnt=3:scl低电平中间,
- 10'd599: cnt <= 3'd0; //cnt=0:scl上升沿
- default: cnt <= 3'd5;
- endcase
- end
- end
- `define SCL_POS (cnt==3'd0) //cnt=0:scl上升沿
- `define SCL_HIG (cnt==3'd1) //cnt=1:scl高电平中间,用于数据采样
- `define SCL_NEG (cnt==3'd2) //cnt=2:scl下降沿
- `define SCL_LOW (cnt==3'd3) //cnt=3:scl低电平中间
- always @ (posedge clk or negedge rst_n)begin
- if(!rst_n) begin
- scl_r <= 1'b1;
- end
- else if(cnt==3'd0)
- begin
- scl_r <= 1'b1; //scl信号上升沿
- end
- else if(cnt==3'd2) begin
- scl_r <= 1'b0; //scl信号下降
- end
- end
- assign scl = scl_dir ? scl_r : 1'bz; //iic所需要的时钟信号
- //--------------------------------------------
- //配置TCA6416A
- `define DEVICE_ADDR 8'b01000010 //TCA6416地址
- `define CONFIG_COMMAND 8'b00000110 //P0口配置地址
- `define CONFIG_DATA 8'b00000000 //P0/P1口配置数据,配置为输出口
- `define OUT_COMMAND 8'b00000010 //P0口输出地址
- `define POLARITY_COMMAND 8'b00000100 //p0极性
- `define POLARITY_data 8'b00000000 //p0极性
- wire[7:0] dis_data0; //故障信息的数据
- wire[7:0] dis_data1;
- assign dis_data0=8'b00001111;
- assign dis_data1=8'b00001111;
- reg[7:0] db_r; //在IIC上传送的数据寄存器
- //读、写时序
- parameter IDLE = 5'd0;
- parameter START = 5'd1;
- parameter ADDR_DEVICE = 5'd2;
- parameter ADDR_DEVICE_ACK = 5'd3;
- parameter CONFIG_ADDR = 5'd4;
- parameter CONFIG_ADDR_ACK = 5'd5;
- parameter CONFIG_DATA0 = 5'd6;
- parameter CONFIG_DATA0_ACK = 5'd7;
- parameter CONFIG_DATA1 = 5'd8;
- parameter CONFIG_DATA1_ACK = 5'd9;
- parameter OUT_ADDR = 5'd10;
- parameter OUT_ADDR_ACK = 5'd11;
- parameter OUT_DATA0 = 5'd12;
- parameter OUT_DATA0_ACK = 5'd13;
- parameter OUT_DATA1 = 5'd14;
- parameter OUT_DATA1_ACK = 5'd15;
- parameter POLARITY=5'd16;
- parameter POLARITY_ACK=5'd17;
- parameter POLARITY_DATA0=5'd18;
- parameter POLARITY_DATA0_ACK=5'd19;
- parameter POLARITY_DATA1=5'd20;
- parameter POLARITY_DATA1_ACK=5'd21;
- parameter STOP1 = 5'd22;
- parameter STOP2 = 5'd23;
- parameter WAIT = 5'd24;
- reg[4:0] cstate; //状态寄存器
- reg[3:0] num;
- reg sda_r; //输出数据寄存器
- reg sda_link; //输出sda信号inout方向 1为输出,0为输入
- assign sda = sda_link ? sda_r:1'bZ;//三态口
- always @ (posedge clk or negedge rst_n) begin
- if(!rst_n) begin//复位
- ack_rise<=1'b0;
- cstate <= IDLE;
- sda_link <= 1'b0;
- scl_dir<=1'b0;
- num <= 4'd0;
- db_r <= 8'b00000000; //送器件地址
- end
- else
- case (cstate)
- IDLE: begin
- scl_dir<=1'b1;
- sda_link <= 1'b1; //数据线sda为output
- sda_r <= 1'b1;
- db_r <= `DEVICE_ADDR; //送器件地址
- cstate <= START;
- end
-
- START: begin
- if(cnt_delay==10'd150)begin //scl为高电平期间
- sda_link <= 1'b1; //数据线sda output
- sda_r <= 1'b0; //拉低数据sda,产生下降沿
- cstate <= ADDR_DEVICE;
- num <= 4'd0; //num计数清零
- end
- else cstate <= START; //等待scl高电平中间位置到来
- end
-
- ADDR_DEVICE:begin //发送器件地址
- if(`SCL_LOW) begin
- case (num)
- 4'd0: sda_r <= db_r[7];
- 4'd1: sda_r <= db_r[6];
- 4'd2: sda_r <= db_r[5];
- 4'd3: sda_r <= db_r[4];
- 4'd4: sda_r <= db_r[3];
- 4'd5: sda_r <= db_r[2];
- 4'd6: sda_r <= db_r[1];
- 4'd7: sda_r <= db_r[0];
- default: ;
- endcase
- sda_link <= 1'b1;
- num <= num+1'b1;//并行执行
- if(num == 4'd8) begin
- num <= 4'd0; //num计数清零
- sda_link <= 1'b0; //释放总线
- cstate <=ADDR_DEVICE_ACK;
- end
- end
- else cstate <= ADDR_DEVICE;//等待
- end
-
- ADDR_DEVICE_ACK:begin
- if(scl) begin
- sda_link <= 1'b0;
- if(!sda)begin
- cstate <= CONFIG_ADDR; //从机响应
- db_r <= `CONFIG_COMMAND;// P0配置地址
- end
- end
- else cstate <= ADDR_DEVICE_ACK; //等待下降沿
- end
-
- CONFIG_ADDR:begin
- if(`SCL_LOW) begin
- case (num)
- 4'd0: sda_r <= db_r[7];
- 4'd1: sda_r <= db_r[6];
- 4'd2: sda_r <= db_r[5];
- 4'd3: sda_r <= db_r[4];
- 4'd4: sda_r <= db_r[3];
- 4'd5: sda_r <= db_r[2];
- 4'd6: sda_r <= db_r[1];
- 4'd7: sda_r <= db_r[0];
- default: ;
- endcase
- sda_link <= 1'b1;
- num <= num+1'b1;//并行执行
- if(num == 4'd8) begin
- num <= 4'd0;
- //sda_r <= 1'b1;
- sda_link <= 1'b0;//释放总线
- cstate <=CONFIG_ADDR_ACK;
- end
- end
- else cstate <= CONFIG_ADDR;//等待
- end
-
- CONFIG_ADDR_ACK: begin
- if(scl) begin
- sda_link <= 1'b0;
- if(!sda) begin //从机响应
- cstate <=CONFIG_DATA0; //写P0配置操作
- db_r <= `CONFIG_DATA; //P0口配置数据
- end
- end
- else cstate <= CONFIG_ADDR_ACK; //等待从机响应
- end
-
- CONFIG_DATA0: begin
- if(`SCL_LOW) begin
- case (num)
- 4'd0: sda_r <= db_r[7];
- 4'd1: sda_r <= db_r[6];
- 4'd2: sda_r <= db_r[5];
- 4'd3: sda_r <= db_r[4];
- 4'd4: sda_r <= db_r[3];
- 4'd5: sda_r <= db_r[2];
- 4'd6: sda_r <= db_r[1];
- 4'd7: sda_r <= db_r[0];
- default: ;
- endcase
- sda_link <= 1'b1;
- num <= num+1'b1;//并行执行
- if(num == 4'd8) begin
- num <= 4'd0;
- //sda_r <= 1'b1;
- sda_link <= 1'b0;//释放总线
- cstate <=CONFIG_DATA0_ACK;
- end
- end
- else cstate <= CONFIG_DATA0;//等待
- end
-
- CONFIG_DATA0_ACK: begin
- if(scl) begin
- sda_link <= 1'b0;
- if(!sda) begin //从机响π藕
- cstate <= CONFIG_DATA1; //写P1
- db_r <= `CONFIG_DATA; //P1口配置数据
- end
- end
- else cstate <= CONFIG_DATA0_ACK; //等待从机响应
- end
-
- CONFIG_DATA1: begin
- if(`SCL_LOW) begin
- case (num)
- 4'd0: sda_r <= db_r[7];
- 4'd1: sda_r <= db_r[6];
- 4'd2: sda_r <= db_r[5];
- 4'd3: sda_r <= db_r[4];
- 4'd4: sda_r <= db_r[3];
- 4'd5: sda_r <= db_r[2];
- 4'd6: sda_r <= db_r[1];
- 4'd7: sda_r <= db_r[0];
- default: ;
- endcase
- sda_link <= 1'b1;
- num <= num+1'b1;//并行执行
- if(num == 4'd8) begin
- num <= 4'd0; //num计数清零
- //sda_r <= 1'b1;
- sda_link <= 1'b0;//释放总线
- cstate <=CONFIG_DATA1_ACK;
- end
- end
- else cstate <= CONFIG_DATA1;//等待
- end
-
- CONFIG_DATA1_ACK: begin
- if(scl) begin
- sda_link <= 1'b0;
- if(!sda) begin //从机响应
- cstate <= OUT_ADDR; //写P0输出地址
- db_r <= `OUT_COMMAND; //P0口配置数据
- end
- end
- else cstate <= CONFIG_DATA1_ACK;
- end
-
- OUT_ADDR: begin
- if(`SCL_LOW) begin
- case (num)
- 4'd0: sda_r <= db_r[7];
- 4'd1: sda_r <= db_r[6];
- 4'd2: sda_r <= db_r[5];
- 4'd3: sda_r <= db_r[4];
- 4'd4: sda_r <= db_r[3];
- 4'd5: sda_r <= db_r[2];
- 4'd6: sda_r <= db_r[1];
- 4'd7: sda_r <= db_r[0];
- default: ;
- endcase
- num <= num+1'b1;//并行执行
- if(num == 4'd8) begin
- ack_rise<=1'b1;
- num <= 4'd0; //num计数清零
- //sda_r <= 1'b1;
- sda_link <= 1'b0;
- cstate <=OUT_ADDR_ACK;
- end
- end
- else cstate <= OUT_ADDR;//等待
- end
- OUT_ADDR_ACK: begin
- if(scl) begin
- sda_link <= 1'b0;
- if(!sda) begin //从机响应
- cstate <= OUT_DATA0; //写P0输出数据
- db_r <= dis_data0;
- end
- end
- else cstate <= OUT_ADDR_ACK; //等待从机响应
- end
-
- OUT_DATA0: begin
- if(`SCL_LOW) begin
- case (num)
- 4'd0: sda_r <= db_r[7];
- 4'd1: sda_r <= db_r[6];
- 4'd2: sda_r <= db_r[5];
- 4'd3: sda_r <= db_r[4];
- 4'd4: sda_r <= db_r[3];
- &nb
