Forum Discussion
I2C read of De0 nano accelerometer
Hello everyone,
I am using de0 nano and would like to try I2C read of accelerometer(ADXL345) that embedded in de0 nano. So I take it that I2C read has the following sequence: 1) generate start signal 2) write slave address(0011101) + write bit(0) 3) receive acknowledge from slave 4) write memory location(register with add 00110000 has reset value of 00000010) 5) receive acknowledge from slave 6) generate repeated start signal 7) write slave address + read bit(1) 8) receive acknowledge from slave 9) read byte from slave 10) write no acknowledge (NACK) to slave, indicating end of transfer 11) generate stop signal Everything's going fine until step 9.The value ,that was read at step 9, is 11111111. I expect the data value to be 00000010 because it is the reset value of register 00110000. I generate clock of 100 hz for the whole operation because the default/reset value of register BW_Rate is 00001010 (this register control the "output data rate") which translate that output data rate is 100hz. Could someone give me an advice to be able to read the correct data? Your help is fully appreciated.21 Replies
- Altera_Forum
Honored Contributor
I have tried to generate I2C_sclk and I2C_sdat in the same always block. And also I use state machine code. The data I get is 0 instead of 0000 0010. Can anyone help me?
- Altera_Forum
Honored Contributor
I still use signal tap2 and use clock "clk_signaltap" as the clock for signaltap. My trigger is rising edge of "q" to check node "sclk", "sdat" and "q". I have no idea what's wrong. The slave DO acknowledge everything but it just transmit wrong data.
- Altera_Forum
Honored Contributor
I wonder why with the first program(at page 1), I could read(display at signaltap2) the register of eeprom in my de0 nano without any problem. But the same code can't work with adxl
- Altera_Forum
Honored Contributor
I think you should read I2C_sdat instead of sdat in your code, on steps 20, 38, 62 and 63-78. sdat is an internal signal and it is only used to control the output. To read the data pin, place sdat at 1'bz and read the value from I2C_sdat.
When you read the data you should only read it on the rising edge of the clock, the slave will change the data line on the falling edge and you may miss a bit if you read it on both edges. To simplify the code a bit (once it's working ;) ), it seems that most of the time you pull the clock low when step has an odd value and high when it is even. Also in most of the cases you increase step by one. I think you should be able to have those two rules as general ones before the case and just override those on the specific steps that need overriding. Now I'm not a Verilog expert, I'm more a VHDL guy myself, but I think it could be done. As for the register value, did you try to read different registers and see what value you got back? - Altera_Forum
Honored Contributor
Thanks Daixiwen.
I will try it right away. Yeah I have tried to read different reg and I always got 0000 0000. Thank you. - Altera_Forum
Honored Contributor
"When you read the data you should only read it on the rising edge of the clock, the slave will change the data line on the falling edge and you may miss a bit if you read it on both edges."
How about if I read the I2C_sdat when the I2C_sclk high (instead of the moment of rising edge I2C_sclk)? I am asking because I am not sure how to do it on the rising edge. - Altera_Forum
Honored Contributor
// ADXL clock= 500,000samples of 50Mhz/100Hz
// ADXL address= 0x1D/11101 (alt address pin grounded) module ADXL_Read(clk_50, I2C_sclk, I2C_sdat, key0, key1, clk_st, data1); input clk_50; output I2C_sclk; output data1; inout I2C_sdat; input key0; //Trigger0 to reset input key1; //Trigger1 to begin output clk_st; reg [30:0] a; reg [30:0] b; reg clk; //Clk for slave reg clk_signaltap; //Clk for signaltap2 reg q; //Register for Trigger reg [10:0] step; reg [6:0] sl_ad = 7'b0011101; // Slave Address reg [7:0] reg_ad = 8'h2D; // Register Address reg [7:0] data1; // Databyte#1 reg sclk; reg sdat; initial begin step = 0; q = 0; end always @(posedge clk_50) begin if(a == 1000000) //Clock for Slave with sample 2a begin clk = ~clk; a = 1; end else a = a + 1; //Signaltap begin if(b == 500000) //Clock for Signaltap2 begin clk_signaltap = ~clk_signaltap; b = 1; end else b = b + 1; end //Signaltap end always @(posedge clk_50) //Trigger Condition case({!key1, !key0}) //Active low 2'b00 : q <= q; 2'b10 : q <= 1; //Set 2'b01 : q <= 0; //Reset endcase always @(posedge clk) begin if (q == 1) begin case(step) //Initial 0: begin sclk = 1; sdat = 1; step = 1; end //1.Start 1: begin sclk = 1; sdat = 0; step = 2; end 2: begin sclk = 0; sdat = 0; step = 3; end //2.Slave add 3: begin sclk = 0; sdat = sl_ad[6]; step = 4; end 4: begin sclk = 1; sdat = sl_ad[6]; step = 5; end 5: begin sclk = 0; sdat = sl_ad[5]; step = 6; end 6: begin sclk = 1; sdat = sl_ad[5]; step = 7; end 7: begin sclk = 0; sdat = sl_ad[4]; step = 8; end 8: begin sclk = 1; sdat = sl_ad[4]; step = 9; end 9: begin sclk = 0; sdat = sl_ad[3]; step = 10; end 10: begin sclk =1; sdat = sl_ad[3]; step = 11; end 11: begin sclk = 0; sdat = sl_ad[2]; step = 12; end 12: begin sclk = 1; sdat = sl_ad[2]; step = 13; end 13: begin sclk = 0; sdat = sl_ad[1]; step = 14; end 14: begin sclk = 1; sdat = sl_ad[1]; step = 15; end 15: begin sclk = 0; sdat = sl_ad[0]; step = 16; end 16: begin sclk = 1; sdat = sl_ad[0]; step = 17; end //3.sdat = 0 17: begin sclk = 0; sdat = 0; step = 18; end 18: begin sclk = 1; sdat = 0; step = 19; end //4.Acknowledge 19: begin sclk = 0; sdat = 1'bz; step = 20; end 20: begin sclk = 1; sdat = 1'bz; if (I2C_sdat == 1) step = 20; else step = 21; end //5.Reg add 21: begin sclk = 0; sdat = reg_ad[7]; step = 22; end //7 22: begin sclk = 1; sdat = reg_ad[7]; step = 23; end 23: begin sclk = 0; sdat = reg_ad[6]; step = 24; end //6 24: begin sclk = 1; sdat = reg_ad[6]; step = 25; end 25: begin sclk = 0; sdat = reg_ad[5]; step = 26; end //5 26: begin sclk = 1; sdat = reg_ad[5]; step = 27; end 27: begin sclk = 0; sdat = reg_ad[4]; step = 28; end //4 28: begin sclk = 1; sdat = reg_ad[4]; step = 29; end 29: begin sclk = 0; sdat = reg_ad[3]; step = 30; end //3 30: begin sclk = 1; sdat = reg_ad[3]; step = 31; end 31: begin sclk = 0; sdat = reg_ad[2]; step = 32; end //2 32: begin sclk = 1; sdat = reg_ad[2]; step = 33; end 33: begin sclk = 0; sdat = reg_ad[1]; step = 34; end //1 34: begin sclk = 1; sdat = reg_ad[1]; step = 35; end 35: begin sclk = 0; sdat = reg_ad[0]; step = 36; end //0 36: begin sclk = 1; sdat = reg_ad[0]; step = 37; end //6.Acknowledge 37: begin sclk = 0; sdat = 1'bz; step = 38; end 38: begin sclk = 1; sdat = 1'bz; if (I2C_sdat == 1) step = 38; else step = 39; end //7.Start 39: begin sclk = 0; sdat = 0; step = 40; end //sclk= 0, sdat= 0 40: begin sclk = 1; sdat = 1; step = 41; end //sclk= 1, sdat= 1 41: begin sclk = 1; sdat = 0; step = 42; end //sclk= 1, sdat= 0 42: begin sclk = 0; sdat = 0; step = 45; end //sclk= 0, sdat= 0 --------------- //8.Slave Add 45: begin sclk = 0; sdat = sl_ad[6]; step = 46; end //6 46: begin sclk = 1; sdat = sl_ad[6]; step = 47; end 47: begin sclk = 0; sdat = sl_ad[5]; step = 48; end //5 48: begin sclk = 1; sdat = sl_ad[5]; step = 49; end 49: begin sclk = 0; sdat = sl_ad[4]; step = 50; end //4 50: begin sclk = 1; sdat = sl_ad[4]; step = 51; end 51: begin sclk = 0; sdat = sl_ad[3]; step = 52; end //3 52: begin sclk = 1; sdat = sl_ad[3]; step = 53; end 53: begin sclk = 0; sdat = sl_ad[2]; step = 54; end //2 54: begin sclk = 1; sdat = sl_ad[2]; step = 55; end 55: begin sclk = 0; sdat = sl_ad[1]; step = 56; end //1 56: begin sclk = 1; sdat = sl_ad[1]; step = 57; end 57: begin sclk = 0; sdat = sl_ad[0]; step = 58; end //0 58: begin sclk = 1; sdat = sl_ad[0]; step = 59; end //9.sdat = 1 59: begin sclk = 0; sdat = 1; step = 60; end 60: begin sclk = 1; sdat = 1; step = 61; end //10.Acknowledge 61: begin sclk = 0; sdat = 1'bz; step = 62; end 62: begin sclk = 1; sdat = 1'bz; if (I2C_sdat == 1) step = 62; else step = 63; end //11.Databyte#1 63: begin sclk = 0; sdat = 1'bz; step = 64; end //Databyte#1 bit 7 64: begin sclk = 1; sdat = 1'bz; data1[7] = I2C_sdat; step = 65; end 65: begin sclk = 0; sdat = 1'bz; step = 66; end //6 66: begin sclk = 1; sdat = 1'bz; data1[6] = I2C_sdat; step = 67; end 67: begin sclk = 0; sdat = 1'bz; step = 68; end //5 68: begin sclk = 1; sdat = 1'bz; data1[5] = I2C_sdat; step = 69; end 69: begin sclk = 0; sdat = 1'bz; step = 70; end //4 70: begin sclk = 1; sdat = 1'bz; data1[4] = I2C_sdat; step = 71; end 71: begin sclk = 0; sdat = 1'bz; step = 72; end //3 72: begin sclk = 1; sdat = 1'bz; data1[3] = I2C_sdat; step = 73; end 73: begin sclk = 0; sdat = 1'bz; step = 74; end //2 74: begin sclk = 1; sdat = 1'bz; data1[2] = I2C_sdat; step = 75; end 75: begin sclk = 0; sdat = 1'bz; step = 76; end //1 76: begin sclk = 1; sdat = 1'bz; data1[1] = I2C_sdat; step = 77; end 77: begin sclk = 0; sdat = 1'bz; step = 78; end //0 78: begin sclk = 1; sdat = 1'bz; data1[0] = I2C_sdat; step = 79; end //12.Acknowledge 79: begin sclk = 0; sdat = 1'bz; step = 80; end 80: begin sclk = 1; sdat = 1'bz; if (I2C_sdat == 1) step = 80; else step = 81; end //13.Stop 81: begin sclk = 1; sdat = 0; step = 82; end //sclk= 1, sdat= 0 82: begin sclk = 1; sdat = 1; step = 83; end //sclk= 1, sdat= 1 83: begin sclk = 1; sdat = 1; end endcase end end assign I2C_sclk = sclk; assign I2C_sdat = sdat; assign clk_st = clk_signaltap; endmodule Now problem's solved. I also do some modification so that I feed each new data at sdat when the sclk is low(instead of when it was high) and I read the needed data when the sclk is high. That way I could be sure although if there is any delay when the data is being transmited by the slave, I could still get the right data. Thank you so much Daixiwen. Without your help, I may still stuck in this problem now. - Altera_Forum
Honored Contributor
// ADXL clock= 500,000samples of 50Mhz/100Hz
// ADXL address= 0x1D/11101 (alt address pin grounded) module ADXL_Read(clk_50, I2C_sclk, I2C_sdat, key0, key1, clk_st, data1); input clk_50; output I2C_sclk; output data1; inout I2C_sdat; input key0; //Trigger0 to reset input key1; //Trigger1 to begin output clk_st; reg [30:0] a; reg [30:0] b; reg clk; //Clk for slave reg clk_signaltap; //Clk for signaltap2 reg q; //Register for Trigger reg [10:0] step; reg [6:0] sl_ad = 7'b0011101; // Slave Address reg [7:0] reg_ad = 8'h2D; // Register Address reg [7:0] data1; // Databyte#1 reg sclk; reg sdat; initial begin step = 0; q = 0; end always @(posedge clk_50) begin if(a == 1000000) //Clock for Slave with sample 2a begin clk = ~clk; a = 1; end else a = a + 1; //Signaltap begin if(b == 500000) //Clock for Signaltap2 begin clk_signaltap = ~clk_signaltap; b = 1; end else b = b + 1; end //Signaltap end always @(posedge clk_50) //Trigger Condition case({!key1, !key0}) //Active low 2'b00 : q <= q; 2'b10 : q <= 1; //Set 2'b01 : q <= 0; //Reset endcase always @(posedge clk) begin if (q == 1) begin case(step) //Initial 0: begin sclk = 1; sdat = 1; step = 1; end //1.Start 1: begin sclk = 1; sdat = 0; step = 2; end 2: begin sclk = 0; sdat = 0; step = 3; end //2.Slave add 3: begin sclk = 0; sdat = sl_ad[6]; step = 4; end 4: begin sclk = 1; sdat = sl_ad[6]; step = 5; end 5: begin sclk = 0; sdat = sl_ad[5]; step = 6; end 6: begin sclk = 1; sdat = sl_ad[5]; step = 7; end 7: begin sclk = 0; sdat = sl_ad[4]; step = 8; end 8: begin sclk = 1; sdat = sl_ad[4]; step = 9; end 9: begin sclk = 0; sdat = sl_ad[3]; step = 10; end 10: begin sclk =1; sdat = sl_ad[3]; step = 11; end 11: begin sclk = 0; sdat = sl_ad[2]; step = 12; end 12: begin sclk = 1; sdat = sl_ad[2]; step = 13; end 13: begin sclk = 0; sdat = sl_ad[1]; step = 14; end 14: begin sclk = 1; sdat = sl_ad[1]; step = 15; end 15: begin sclk = 0; sdat = sl_ad[0]; step = 16; end 16: begin sclk = 1; sdat = sl_ad[0]; step = 17; end //3.sdat = 0 17: begin sclk = 0; sdat = 0; step = 18; end 18: begin sclk = 1; sdat = 0; step = 19; end //4.Acknowledge 19: begin sclk = 0; sdat = 1'bz; step = 20; end 20: begin sclk = 1; sdat = 1'bz; if (I2C_sdat == 1) step = 20; else step = 21; end //5.Reg add 21: begin sclk = 0; sdat = reg_ad[7]; step = 22; end //7 22: begin sclk = 1; sdat = reg_ad[7]; step = 23; end 23: begin sclk = 0; sdat = reg_ad[6]; step = 24; end //6 24: begin sclk = 1; sdat = reg_ad[6]; step = 25; end 25: begin sclk = 0; sdat = reg_ad[5]; step = 26; end //5 26: begin sclk = 1; sdat = reg_ad[5]; step = 27; end 27: begin sclk = 0; sdat = reg_ad[4]; step = 28; end //4 28: begin sclk = 1; sdat = reg_ad[4]; step = 29; end 29: begin sclk = 0; sdat = reg_ad[3]; step = 30; end //3 30: begin sclk = 1; sdat = reg_ad[3]; step = 31; end 31: begin sclk = 0; sdat = reg_ad[2]; step = 32; end //2 32: begin sclk = 1; sdat = reg_ad[2]; step = 33; end 33: begin sclk = 0; sdat = reg_ad[1]; step = 34; end //1 34: begin sclk = 1; sdat = reg_ad[1]; step = 35; end 35: begin sclk = 0; sdat = reg_ad[0]; step = 36; end //0 36: begin sclk = 1; sdat = reg_ad[0]; step = 37; end //6.Acknowledge 37: begin sclk = 0; sdat = 1'bz; step = 38; end 38: begin sclk = 1; sdat = 1'bz; if (I2C_sdat == 1) step = 38; else step = 39; end //7.Start 39: begin sclk = 0; sdat = 0; step = 40; end //sclk= 0, sdat= 0 40: begin sclk = 1; sdat = 1; step = 41; end //sclk= 1, sdat= 1 41: begin sclk = 1; sdat = 0; step = 42; end //sclk= 1, sdat= 0 42: begin sclk = 0; sdat = 0; step = 45; end //sclk= 0, sdat= 0 --------------- //8.Slave Add 45: begin sclk = 0; sdat = sl_ad[6]; step = 46; end //6 46: begin sclk = 1; sdat = sl_ad[6]; step = 47; end 47: begin sclk = 0; sdat = sl_ad[5]; step = 48; end //5 48: begin sclk = 1; sdat = sl_ad[5]; step = 49; end 49: begin sclk = 0; sdat = sl_ad[4]; step = 50; end //4 50: begin sclk = 1; sdat = sl_ad[4]; step = 51; end 51: begin sclk = 0; sdat = sl_ad[3]; step = 52; end //3 52: begin sclk = 1; sdat = sl_ad[3]; step = 53; end 53: begin sclk = 0; sdat = sl_ad[2]; step = 54; end //2 54: begin sclk = 1; sdat = sl_ad[2]; step = 55; end 55: begin sclk = 0; sdat = sl_ad[1]; step = 56; end //1 56: begin sclk = 1; sdat = sl_ad[1]; step = 57; end 57: begin sclk = 0; sdat = sl_ad[0]; step = 58; end //0 58: begin sclk = 1; sdat = sl_ad[0]; step = 59; end //9.sdat = 1 59: begin sclk = 0; sdat = 1; step = 60; end 60: begin sclk = 1; sdat = 1; step = 61; end //10.Acknowledge 61: begin sclk = 0; sdat = 1'bz; step = 62; end 62: begin sclk = 1; sdat = 1'bz; if (I2C_sdat == 1) step = 62; else step = 63; end //11.Databyte#1 63: begin sclk = 0; sdat = 1'bz; step = 64; end //Databyte#1 bit 7 64: begin sclk = 1; sdat = 1'bz; data1[7] = I2C_sdat; step = 65; end 65: begin sclk = 0; sdat = 1'bz; step = 66; end //6 66: begin sclk = 1; sdat = 1'bz; data1[6] = I2C_sdat; step = 67; end 67: begin sclk = 0; sdat = 1'bz; step = 68; end //5 68: begin sclk = 1; sdat = 1'bz; data1[5] = I2C_sdat; step = 69; end 69: begin sclk = 0; sdat = 1'bz; step = 70; end //4 70: begin sclk = 1; sdat = 1'bz; data1[4] = I2C_sdat; step = 71; end 71: begin sclk = 0; sdat = 1'bz; step = 72; end //3 72: begin sclk = 1; sdat = 1'bz; data1[3] = I2C_sdat; step = 73; end 73: begin sclk = 0; sdat = 1'bz; step = 74; end //2 74: begin sclk = 1; sdat = 1'bz; data1[2] = I2C_sdat; step = 75; end 75: begin sclk = 0; sdat = 1'bz; step = 76; end //1 76: begin sclk = 1; sdat = 1'bz; data1[1] = I2C_sdat; step = 77; end 77: begin sclk = 0; sdat = 1'bz; step = 78; end //0 78: begin sclk = 1; sdat = 1'bz; data1[0] = I2C_sdat; step = 79; end //12.Acknowledge 79: begin sclk = 0; sdat = 1'bz; step = 80; end 80: begin sclk = 1; sdat = 1'bz; if (I2C_sdat == 1) step = 80; else step = 81; end //13.Stop 81: begin sclk = 1; sdat = 0; step = 82; end //sclk= 1, sdat= 0 82: begin sclk = 1; sdat = 1; step = 83; end //sclk= 1, sdat= 1 83: begin sclk = 1; sdat = 1; end endcase end end assign I2C_sclk = sclk; assign I2C_sdat = sdat; assign clk_st = clk_signaltap; endmodule Now problem's solved. I also do some modification so that I feed each new data at sdat when the sclk is low(instead of when it was high) and I read the needed data when the sclk is high. That way I could be sure although if there is any delay when the data is being transmited by the slave, I could still get the right data. Thank you so much Daixiwen. Without your help, I may still stuck in this problem now. - Altera_Forum
Honored Contributor
I'm glad you managed to solve your problem! I was about to suggest to use a scope just to be sure the signals outside the FPGA where the ones you expected.
Solving those kind of problems sure can be painful, but you also learn a lot in the process. The I2C protocol indeed only says that the data line should be stable when the clock signal is high, and one way to do it is to write to sda on the falling edge of the clock (or when you put yourself the clock to 0) and read from sda on the rising edge of the clock (or when you put yourself the clock to 1). It's not 100% compliant when you control yourself the clock because of the delay on the line but in practise it works well. - Altera_Forum
Honored Contributor
What was your final code on this project?