|
发表于 2012-4-24 11:20:19
|
显示全部楼层
你这程序是什么东西呀,看不懂。你需要一个I2C_Host来读取数据。我给你一个测试过的代码,目前挂在我的3个设备的I2C总线上,正常工作。
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 22:01:45 04/18/2012
// Design Name:
// Module Name: I2CHost
// Project Name:
// Target Devices:
// Tool versions:
// Description:
// Formal I2C host module. Note that Start signal will only be send
// if there's a data write operation after Start bit is set.
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module I2CHost(
input int_in_GCLK,
input int_in_GRST,
// Bus definition
input [7:0] int_in_Control,
input int_in_Validate_Ctrl,
output [7:0] int_out_Status,
input [7:0] int_in_Data,
input int_in_Validate_Data,
output [7:0] int_out_Data,
// If to input one byte, assert this wire to initiate a read cycle.
input int_in_Read_Probe,
// Port definition
output port_out_SCL,
inout port_io_SDA
);
// 100KHz -- 100MHz
reg [11:0] rc_I2C_SCK_Counter_Threshold = 12'd999;
// The following two signals are used to tell Clock generator whether to generate clock.
reg r_I2C_Transmit_Enable = 1'b0;
wire w_I2C_Transmit_Clock;
wire w_I2C_Start_Stop_Clock;
// SDA output control register.
reg r_SDA_Assert_Zero = 1'b0;
reg r_SCL_Assert_Zero = 1'b0;
// Configure register. b7-Start b6-Stop b5-LastRD b1-ACK b0-Done.
// External write should not affect except b7 to b5.
// Because LastRD has no actual effect, we just skip it and set to zero every ACK period.
reg [7:0] r_I2C_Control = 8'h00;
wire w_Start = r_I2C_Control[7];
wire w_Stop = r_I2C_Control[6];
wire w_LastRD = r_I2C_Control[5];
// Status routed directly to Control register.
assign int_out_Status = r_I2C_Control;
// Data will be latched only when controller is IDLE and int_in_Validate_Data is asserted HIGH.
reg [7:0] r_I2C_Data_In;
reg [7:0] r_I2C_Data_Out;
// Output data is routed to r_I2C_To_Parallel_Data_Out, which will be affected after one transaction.
reg [7:0] r_I2C_To_Parallel_Data_Out;
assign int_out_Data = r_I2C_To_Parallel_Data_Out;
reg [3:0] rs_I2C_Transceive;
reg [3:0] rc_I2C_Transceive;
wire [3:0] ws_I2C_Transceive_IDLE = 0;
wire [3:0] ws_I2C_Transceive_Start_Begin = 1;
wire [3:0] ws_I2C_Transceive_Start_SCL_Transition = 2;
wire [3:0] ws_I2C_Transceive_Send_Begin = 3;
wire [3:0] ws_I2C_Transceive_Send_Transition = 4;
wire [3:0] ws_I2C_Transceive_Read_Begin = 5;
wire [3:0] ws_I2C_Transceive_Read_Latch = 6;
wire [3:0] ws_I2C_Transceive_Read_ACK = 7;
wire [3:0] ws_I2C_Transceive_ACK = 8;
wire [3:0] ws_I2C_Transceive_Stop_Begin = 9;
wire [3:0] ws_I2C_Transceive_Stop_SCL_Transition = 10;
wire [3:0] ws_I2C_Transceive_SCL_Low_Last_Cycle = 11;
always @(posedge int_in_GCLK or negedge int_in_GRST)
begin
if(~int_in_GRST)
begin
r_I2C_Control <= 0;
r_I2C_Data_In <= 0;
r_I2C_Data_Out <= 0;
rs_I2C_Transceive <= ws_I2C_Transceive_IDLE;
rc_I2C_Transceive <= 0;
r_I2C_Transmit_Enable <= 0;
r_SDA_Assert_Zero <= 0;
r_SCL_Assert_Zero <= 1;
rc_I2C_SCK_Counter_Threshold <= 12'd999;
end
else
begin
// Control register is updated whenever a write operation occurs.
// We assume this command's only executed serially (not parallelly).
if(int_in_Validate_Ctrl)
r_I2C_Control[7:5] <= int_in_Control[7:5];
else
begin
case (rs_I2C_Transceive)
ws_I2C_Transceive_IDLE:
begin
// Idle state. Wait for any changes in Control Register.
// When Stop is asserted, then generate a stop condition.
// Else wait for Data Validate command.
if(w_Stop)
begin
// State 14 is used for Stop condition.
r_I2C_Transmit_Enable <= 1;
r_SDA_Assert_Zero <= 1;
rs_I2C_Transceive <= ws_I2C_Transceive_Stop_Begin;
r_I2C_Control[0] <= 0;
// Clear Stop bit.
r_I2C_Control[6] <= 0;
end
else if(int_in_Validate_Data)
begin
// Load data;
r_I2C_Data_In <= int_in_Data;
r_I2C_Control[0] <= 0;
rc_I2C_Transceive <= 0;
r_I2C_Transmit_Enable <= 1;
if(w_Start)
begin
// State 1 is the state for initial transmission.
rs_I2C_Transceive <= ws_I2C_Transceive_Start_Begin;
// SDA is set to 1 ahead of other operation.
r_SDA_Assert_Zero <= 0;
// Clear Start bit.
r_I2C_Control[7] <= 0;
end
else
begin
// Just goto State 3 to send data.
rs_I2C_Transceive <= ws_I2C_Transceive_Send_Begin;
end
end
else if(int_in_Read_Probe)
begin
// Read data. First load internal register to output register.
r_I2C_To_Parallel_Data_Out <= r_I2C_Data_Out;
r_I2C_Control[0] <= 0;
// Goto State 5 for read operation. ACK to device.
rs_I2C_Transceive <= ws_I2C_Transceive_Read_Begin;
r_SDA_Assert_Zero <= 0;
rc_I2C_Transceive <= 0;
r_I2C_Transmit_Enable <= 1;
end
else
begin
r_SDA_Assert_Zero <= 0;
r_SCL_Assert_Zero <= 1;
r_I2C_Transmit_Enable <= 0;
r_I2C_Control[0] <= 1;
end
end
ws_I2C_Transceive_Start_Begin:
begin
// Start condition. Assume SDA is previously set to 1.
r_SCL_Assert_Zero <= 0;
// Wait for w_I2C_Transmit_Clock becomes high to change pole.
if(w_I2C_Start_Stop_Clock)
begin
r_SDA_Assert_Zero <= 1;
// Goto state 15 so that after this send cycle return to IDLE.
rs_I2C_Transceive <= ws_I2C_Transceive_Start_SCL_Transition;
end
else
rs_I2C_Transceive <= rs_I2C_Transceive;
end
ws_I2C_Transceive_Start_SCL_Transition:
begin
if(w_I2C_Transmit_Clock)
begin
r_SCL_Assert_Zero <= 1;
rs_I2C_Transceive <= ws_I2C_Transceive_Send_Begin;
end
else
rs_I2C_Transceive <= rs_I2C_Transceive;
end
ws_I2C_Transceive_Send_Begin:
begin
// After start condition. Begin transmit data (MSB first).
// First set data, then goto State 3.
if(~w_I2C_Transmit_Clock)
begin
// Set data first if rc_I2C_Transceive is not 7.
// If rc_I2C_Transceive is 7, then it means 8 bits are sent, and next to receive ACK.
rc_I2C_Transceive <= rc_I2C_Transceive + 1;
r_I2C_Data_In <= {r_I2C_Data_In[6:0],1'b0};
if(rc_I2C_Transceive == 8)
begin
// Receive ACK bit.
rs_I2C_Transceive <= ws_I2C_Transceive_ACK;
r_SDA_Assert_Zero <= 0;
end
else
begin
rs_I2C_Transceive <= ws_I2C_Transceive_Send_Transition;
r_SDA_Assert_Zero <= (r_I2C_Data_In[7]?1'b0:1'b1);
end
end
else
rs_I2C_Transceive <= rs_I2C_Transceive;
end
ws_I2C_Transceive_Send_Transition:
begin
// Write data wait w_I2C_Transmit_Clock High.
if(w_I2C_Transmit_Clock)
begin
r_SCL_Assert_Zero <= 1;
rs_I2C_Transceive <= ws_I2C_Transceive_Send_Begin;
end
else
begin
r_SCL_Assert_Zero <= 0;
rs_I2C_Transceive <= rs_I2C_Transceive;
end
end
ws_I2C_Transceive_Read_Begin:
begin
// Read data.
r_SDA_Assert_Zero <= 0;
if(~w_I2C_Transmit_Clock)
begin
// Begin receive data.
rc_I2C_Transceive <= rc_I2C_Transceive + 1;
if(rc_I2C_Transceive == 8)
begin
rs_I2C_Transceive <= ws_I2C_Transceive_Read_ACK;
end
else
begin
rs_I2C_Transceive <= ws_I2C_Transceive_Read_Latch;
end
end
else
begin
rs_I2C_Transceive <= rs_I2C_Transceive;
end
end
ws_I2C_Transceive_Read_Latch:
begin
if(w_I2C_Transmit_Clock)
begin
r_SCL_Assert_Zero <= 1;
r_I2C_Data_Out <= {r_I2C_Data_Out[6:0],port_io_SDA};
rs_I2C_Transceive <= ws_I2C_Transceive_Read_Begin;
end
else
begin
rs_I2C_Transceive <= rs_I2C_Transceive;
r_SCL_Assert_Zero <= 0;
end
end
ws_I2C_Transceive_Read_ACK:
begin
if(w_LastRD)
begin
// High-Z SDA
r_SDA_Assert_Zero <= 0;
end
else
begin
r_SDA_Assert_Zero <= 1;
end
// Wait for w_I2C_Transmit_Clock High.
if(w_I2C_Transmit_Clock)
begin
r_I2C_Control[1] <= port_io_SDA;
// Goto state 15 so that after this send cycle return to IDLE.
rs_I2C_Transceive <= ws_I2C_Transceive_SCL_Low_Last_Cycle;
r_SCL_Assert_Zero <= 1;
r_I2C_Control[5] <= 0;
end
else
begin
r_SCL_Assert_Zero <= 0;
end
end
ws_I2C_Transceive_ACK:
begin
// ACK period. First set SCL high, then read at w_I2C_Transmit_Clock.
// Assert SCL high. Assume SDA is previously set to float.
r_SDA_Assert_Zero <= 0;
if(w_I2C_Transmit_Clock)
begin
r_I2C_Control[1] <= port_io_SDA;
// Goto state 15 so that after this send cycle return to IDLE.
rs_I2C_Transceive <= ws_I2C_Transceive_SCL_Low_Last_Cycle;
r_SCL_Assert_Zero <= 1;
end
else
begin
r_SCL_Assert_Zero <= 0;
end
end
ws_I2C_Transceive_Stop_Begin:
begin
// Stop condition.
// Assert SCL high. Assume SDA is previously set to zero.
r_SCL_Assert_Zero <= 0;
// Wait for w_I2C_Transmit_Clock becomes high to change pole.
if(w_I2C_Start_Stop_Clock)
begin
r_SDA_Assert_Zero <= 0;
// Goto state 15 so that after this send cycle return to IDLE.
rs_I2C_Transceive <= ws_I2C_Transceive_Stop_SCL_Transition;
end
else
begin
rs_I2C_Transceive <= rs_I2C_Transceive;
end
end
ws_I2C_Transceive_Stop_SCL_Transition:
begin
if(w_I2C_Transmit_Clock)
begin
r_SCL_Assert_Zero <= 1;
rs_I2C_Transceive <= ws_I2C_Transceive_SCL_Low_Last_Cycle;
end
else
begin
rs_I2C_Transceive <= rs_I2C_Transceive;
end
end
ws_I2C_Transceive_SCL_Low_Last_Cycle:
begin
// Last active cycle. After w_I2C_Transmit_Clock low, goto IDLE.
if(~w_I2C_Transmit_Clock)
rs_I2C_Transceive <= ws_I2C_Transceive_IDLE;
else
rs_I2C_Transceive <= rs_I2C_Transceive;
end
default:
begin
rs_I2C_Transceive <= ws_I2C_Transceive_IDLE;
end
endcase
end
end
end
BaudGenerator clk_I2C_Transmit(
.int_in_GCLK(int_in_GCLK),
.port_in_RXD(1'b1),
.int_out_RcvCLK(w_I2C_Transmit_Clock),
.int_in_CountEnable(r_I2C_Transmit_Enable), // Enable when 1
.int_in_CountValue({4'h0,rc_I2C_SCK_Counter_Threshold[11:0]})
);
BaudGenerator clk_I2C_StartStopBitClk(
.int_in_GCLK(int_in_GCLK),
.port_in_RXD(1'b1),
.int_out_RcvCLK(w_I2C_Start_Stop_Clock),
.int_in_CountEnable(r_I2C_Transmit_Enable), // Enable when 1
.int_in_CountValue({5'h0,rc_I2C_SCK_Counter_Threshold[11:1]})
);
assign port_io_SDA = r_SDA_Assert_Zero?1'b0:1'bz;
assign port_out_SCL = r_SCL_Assert_Zero?1'b0:1'bz;
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 08:07:48 04/08/2012
// Design Name:
// Module Name: BaudGenerator
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module BaudGenerator(
input int_in_GCLK,
input port_in_RXD,
output int_out_RcvCLK,
input int_in_CountEnable, // Enable when 1
input [15:0] int_in_CountValue
);
reg [1:0] r_port_in_RXD_delay;
always @(posedge int_in_GCLK)
r_port_in_RXD_delay <= {r_port_in_RXD_delay[0],port_in_RXD};
wire w_int_RXD_edge = ^r_port_in_RXD_delay; // Edge detect.
wire w_int_CountReset = ~w_int_RXD_edge & int_in_CountEnable; // Reset counter on edge or count enable.
reg [15:0] r_Counter;
reg r_int_out_RcvCLK;
assign int_out_RcvCLK = r_int_out_RcvCLK;
always @(posedge int_in_GCLK or negedge w_int_CountReset)
begin
if(~w_int_CountReset)
begin
r_Counter <= 0;
r_int_out_RcvCLK <= 0;
end
else
begin
if(r_Counter == int_in_CountValue)
begin
r_Counter <= 0;
r_int_out_RcvCLK <= 0;
end
else
begin
r_Counter <= r_Counter + 1;
if(r_Counter == {1'b0,int_in_CountValue[15:1]})
begin
r_int_out_RcvCLK <= 1;
end
else
begin
r_int_out_RcvCLK <= r_int_out_RcvCLK;
end
end
end
end
endmodule
注意这个是I2CHost,操作方式同EZ-USB FX2的I2C总线寄存器操作,写寄存器bmSTART,bmSTOP,读bmACK,bmDONE,写I2DAT,读I2DAT。100KHz。注意你读超过8位数据时,需要每读一个字节后要回应设备nACK,要不然设备就认为传输结束,而停止继续输出数据。 |
|