SmellyNuisance
Newbie level 3
Hello
I am learning FPGA's using a DE0-Nano Cyclone IV board from Terasic.
Using verilog and I2C, I can write to the boards onboard 24LC02B I2C 2K EEPROM, but I cannot read the EEPROM. So I can read but not write.
The reason I know I can write to the EEPROM, is because after writing, I use the DE0_Nano_ControlPanel program included in the kit CDROM to view the EEPROM memory.
The way I have been trying to read the EEPROM was by trying to fill a 8 bit data register with the I2C SDA line, then assigning it to the LED's.
I got the EEPROM writing code from watching a tutorial on Terasics youtube channel.
From what I have seen, the write code takes the DE0-Nano's board 50 mhz clock, and uses the bit number 9 of an internal counter, as the i2c clock, which seems to operate at just below 25 khz.
Then it looks like using this slow clock, a counter for the i2c operations is created.
Then this counter is used to sequence the individual i2c operations.
Here is the EEPROM write code.
The above works, now, here is the read code, which does not work.
I dont know what I am doing wrong, there are a few possibilities.
1) For the random read, it appears, that you send a control byte, then the address, then you restart the i2c communications again, then you send a control byte, then you read. I dont know if I am doing this sequence correctly.
2) Reading the data from the SDA line, to the DATA register, then assigning it to the LEDs.
For example, should I be assigning the I2C_SDAT variable to DATA[n] during the read.
Also, should the assign I2C_SDAT = SDI be disabled during the above read operations?
3) Not using the bi directional pins properly.
Any help is appreciated.
I am learning FPGA's using a DE0-Nano Cyclone IV board from Terasic.
Using verilog and I2C, I can write to the boards onboard 24LC02B I2C 2K EEPROM, but I cannot read the EEPROM. So I can read but not write.
The reason I know I can write to the EEPROM, is because after writing, I use the DE0_Nano_ControlPanel program included in the kit CDROM to view the EEPROM memory.
The way I have been trying to read the EEPROM was by trying to fill a 8 bit data register with the I2C SDA line, then assigning it to the LED's.
I got the EEPROM writing code from watching a tutorial on Terasics youtube channel.
From what I have seen, the write code takes the DE0-Nano's board 50 mhz clock, and uses the bit number 9 of an internal counter, as the i2c clock, which seems to operate at just below 25 khz.
Then it looks like using this slow clock, a counter for the i2c operations is created.
Then this counter is used to sequence the individual i2c operations.
Here is the EEPROM write code.
Code:
module i2c_test (
CLOCK_50,
LED,
KEY,
I2C_SCLK,
I2C_SDAT,
COUNT,
SD_COUNTER_OUT
);
input CLOCK_50;
output [7:0] LED;
input [1:0] KEY;
output I2C_SCLK;
inout I2C_SDAT;
output [6:0] SD_COUNTER_OUT;
output [9:0] COUNT;
wire reset_n;
reg GO;
reg [6:0] SD_COUNTER;
reg SDI;
reg SCLK;
reg [9:0] COUNT;
assign reset_n = KEY[0];
always@(posedge CLOCK_50) COUNT <= COUNT + 1;
always @ (posedge COUNT[9] or negedge reset_n)
begin
if(!reset_n)
GO <= 0;
else
if(!KEY[1])
GO <= 1;
end
// 12C COUNTER
always @(posedge COUNT[9] or negedge reset_n)
begin
if(!reset_n)
SD_COUNTER <= 6'b0;
else
begin
if(!GO)
SD_COUNTER <= 0;
else
if(SD_COUNTER < 33)
SD_COUNTER <= SD_COUNTER + 1;
end
end
// I2C OPERATION
always @(posedge COUNT[9] or negedge reset_n)
begin
if(!reset_n)
begin
SCLK <= 1;
SDI <= 1;
end
else
case (SD_COUNTER)
6'd0 : begin
SDI <= 1;
SCLK <= 1;
end
// START
6'd1 : SDI <= 0;
6'd2 : SCLK <= 0;
// SLAVE ADDRESS
6'd3 : SDI <= 1;
6'd4 : SDI <= 0;
6'd5 : SDI <= 1;
6'd6 : SDI <= 0;
6'd7 : SDI <= 0;
6'd8 : SDI <= 0;
6'd9 : SDI <= 0;
6'd10 : SDI <= 0;
6'd11 : SDI <= 1'bz;
// SUB ADDRESS
6'd12 : SDI <= 0;
6'd13 : SDI <= 0;
6'd14 : SDI <= 0;
6'd15 : SDI <= 0;
6'd16 : SDI <= 0;
6'd17 : SDI <= 0;
6'd18 : SDI <= 0;
6'd19 : SDI <= 0;
6'd20 : SDI <= 1'bz;
// DATA
6'd21 : SDI <= 0;
6'd22 : SDI <= 1;
6'd23 : SDI <= 0;
6'd24 : SDI <= 1;
6'd25 : SDI <= 0;
6'd26 : SDI <= 1;
6'd27 : SDI <= 0;
6'd28 : SDI <= 1;
6'd29 : SDI <= 1'bz;
6'd30 : begin SDI <= 1'b0; SCLK <= 1'b1; end
6'd31 : SDI <= 1'b1;
endcase
end
assign I2C_SCLK = ((SD_COUNTER >= 4) & (SD_COUNTER <= 31))? ~COUNT[9] : SCLK;
assign I2C_SDAT = SDI;
assign SD_COUNTER_OUT = SD_COUNTER;
endmodule
The above works, now, here is the read code, which does not work.
I dont know what I am doing wrong, there are a few possibilities.
1) For the random read, it appears, that you send a control byte, then the address, then you restart the i2c communications again, then you send a control byte, then you read. I dont know if I am doing this sequence correctly.
2) Reading the data from the SDA line, to the DATA register, then assigning it to the LEDs.
For example, should I be assigning the I2C_SDAT variable to DATA[n] during the read.
Also, should the assign I2C_SDAT = SDI be disabled during the above read operations?
3) Not using the bi directional pins properly.
Code:
module i2c_test (
CLOCK_50,
LED,
KEY,
I2C_SCLK,
I2C_SDAT,
COUNT,
SD_COUNTER_OUT
);
input CLOCK_50;
output [7:0] LED;
input [1:0] KEY;
output I2C_SCLK;
inout I2C_SDAT;
output [6:0] SD_COUNTER_OUT;
output [9:0] COUNT;
wire reset_n;
reg GO;
reg [6:0] SD_COUNTER;
reg SDI;
reg SCLK;
reg [9:0] COUNT;
reg [7:0] DATA = 8'b00000000;
assign reset_n = KEY[0];
always@(posedge CLOCK_50) COUNT <= COUNT + 1;
always @ (posedge COUNT[9] or negedge reset_n)
begin
if(!reset_n)
GO <= 0;
else
if(!KEY[1])
GO <= 1;
end
always @(posedge COUNT[9] or negedge reset_n)
begin
if(!reset_n)
SD_COUNTER <= 6'b0;
else
begin
if(!GO)
SD_COUNTER <= 0;
else
if(SD_COUNTER < 45)
SD_COUNTER <= SD_COUNTER + 1;
end
end
// I2C OPERATION
always @(posedge COUNT[9] or negedge reset_n)
begin
if(!reset_n)
begin
SCLK <= 1;
SDI <= 1;
end
else
case (SD_COUNTER)
6'd0 : begin SDI <= 1; SCLK <= 1; end
// START
6'd1 : SDI <= 0;
6'd2 : SCLK <= 0;
// SLAVE ADDRESS
6'd3 : SDI <= 1;
6'd4 : SDI <= 0;
6'd5 : SDI <= 1;
6'd6 : SDI <= 0;
6'd7 : SDI <= 0;
6'd8 : SDI <= 0;
6'd9 : SDI <= 0;
6'd10 : SDI <= 0;
6'd11 : SDI <= 1'bz;
// SUB ADDRESS
6'd12 : SDI <= 0;
6'd13 : SDI <= 0;
6'd14 : SDI <= 0;
6'd15 : SDI <= 0;
6'd16 : SDI <= 0;
6'd17 : SDI <= 0;
6'd18 : SDI <= 0;
6'd19 : SDI <= 0;
6'd20 : SDI <= 1'bz;
// START
6'd21 : begin SDI <= 1; SCLK <= 1; end
6'd22 : SDI <= 0;
6'd23 : SCLK <= 0;
// SLAVE ADDRESS
6'd24 : SDI <= 1;
6'd25 : SDI <= 0;
6'd26 : SDI <= 1;
6'd27 : SDI <= 0;
6'd28 : SDI <= 0;
6'd29 : SDI <= 0;
6'd30 : SDI <= 0;
6'd31 : SDI <= 1;
6'd32 : SDI <= 1'bz;
// DATA is this the right way to read data from the
6'd33 : DATA[7] <= SDI;
6'd34 : DATA[6] <= SDI;
6'd35 : DATA[5] <= SDI;
6'd36 : DATA[4] <= SDI;
6'd37 : DATA[3] <= SDI;
6'd38 : DATA[2] <= SDI;
6'd39 : DATA[1] <= SDI;
6'd40 : DATA[0] <= SDI;
//6'd41 : SDI <= 1'bz; // The datasheet says there is now acknowledge after read.
6'd41 : SDI <= 1;
// END
6'd42 : begin SDI <= 1'b0; SCLK <= 1'b1; end
6'd43 : SDI <= 1'b1;
endcase
end
assign I2C_SCLK = ((SD_COUNTER >= 4) & (SD_COUNTER <= 45))? ~COUNT[9] : SCLK;
assign I2C_SDAT = SDI;
assign SD_COUNTER_OUT = SD_COUNTER;
assign LED = DATA;
endmodule
Any help is appreciated.