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 wonder if ADXL support clock stretching? If yes, in what condition should we apply it.
I personally think that clock stretching is not needed in my case because there is no sign that the adxl has ever hold the I2C clock low. It can be seen because I am using signaltap2 with clock 200hz(2 times of the clock that I generated for the reading of ADXL) - Altera_Forum
Honored Contributor
This is my coding. Please somebody out there help me.
// ADXL clock= 500,000samples of 50Mhz/100Hz // ADXL address= 0x1D/11101 module ADXL_Read( clk_50, //clock 50Mhz// key, I2C_sclk, I2C_sdat, ); input clk_50; input [1:0] key; inout I2C_sclk; inout I2C_sdat; reg I2C_sdat; reg [18:0] counter; reg [18:0] counter2; reg [1:0] q; reg [1:0] q2; wire reset_n; reg GO; reg sclk; reg [6:0] sd_counter; reg [6:0] slave_add = 7'b0011101; // DEFINE SLAVE ADDRESS reg [7:0] register_add = 8'b110000; // DEFINE REGISTER ADDRESS reg [7:0] data; //Data that is read initial begin counter = 3'b0; data = 8'b0; end assign reset_n= key[0]; // 50MHz clock is too fast for the our devive // therefore slower clk need to be generated always @(posedge clk_50) begin if (counter == 18'b0) // if counter is 0 begin q = 2'b01; end else if (counter == 19'b111101000010010000) // if counter is the desired value(has the same priority as earlier if) begin q = 2'b00; end else begin q<= q; end end always @(posedge clk_50) begin if (q == 2'b00) begin counter <= counter -1; end if (q == 2'b01) begin counter <= counter +1; end end //Clk for the Signaltap2 // Notify the moment counter is at the desired value or at 0 always @(posedge clk_50) begin if (counter2 == 18'b0) // if counter is 0 begin q2 = 2'b01; end else if (counter2 == 19'b11110100001001000) // if counter is the desired value(has the same priority as earlier if) begin q2 = 2'b00; end else begin q2<= q2; end end always @(posedge clk_50) begin if (q2 == 2'b00) begin counter2 <= counter2 -1; end if (q2 == 2'b01) begin counter2 <= counter2 +1; end end // key[0] is to reset the whole operation // key[1] is to give a start signal always@(posedge q[0] or negedge reset_n) begin if (!reset_n) GO <= 0; else if (!key[1]) GO <= 1; end always@ (posedge q[0] or negedge reset_n) begin if(!reset_n) sd_counter <= 6'b0; else begin if (!GO) sd_counter <= 0; else if (sd_counter < 44) //sd_counter maximum sd_counter <= sd_counter + 1; end end always@ (posedge q[0] or negedge reset_n) begin if (!reset_n) begin sclk <= 1; I2C_sdat <= 1; end else case (sd_counter) 6'd0 : begin I2C_sdat<=1; sclk<=1;end //START 6'd1 : I2C_sdat <= 0; 6'd2 : sclk <= 0; //SLAVE ADDR+Write(Control Byte)7'b0011101 6'd3 : I2C_sdat <= slave_add[6]; 6'd4 : I2C_sdat <= slave_add[5]; 6'd5 : I2C_sdat <= slave_add[4]; 6'd6 : I2C_sdat <= slave_add[3]; 6'd7 : I2C_sdat <= slave_add[2]; 6'd8 : I2C_sdat <= slave_add[1]; 6'd9 : I2C_sdat <= slave_add[0]; 6'd10 : I2C_sdat <= 0; //Write(0) 6'd11 : I2C_sdat <= 1'bz;//Slave ACK //SUB ADDR(WORD ADDRESS)8'b110000 6'd12 : I2C_sdat <= register_add[7]; 6'd13 : I2C_sdat <= register_add[6]; 6'd14 : I2C_sdat <= register_add[5]; 6'd15 : I2C_sdat <= register_add[4]; 6'd16 : I2C_sdat <= register_add[3]; 6'd17 : I2C_sdat <= register_add[2]; 6'd18 : I2C_sdat <= register_add[1]; 6'd19 : I2C_sdat <= register_add[0]; 6'd20 : I2C_sdat <= 1'bz;//Slave ACK //START 6'd21 : begin I2C_sdat <= 1; sclk<=1; end 6'd22 : I2C_sdat <= 0; //SLAVE ADDR+Read(CONTROL BYTE) 6'd23 : I2C_sdat <= slave_add[6]; 6'd24 : I2C_sdat <= slave_add[5]; 6'd25 : I2C_sdat <= slave_add[4]; 6'd26 : I2C_sdat <= slave_add[3]; 6'd27 : I2C_sdat <= slave_add[2]; 6'd28 : I2C_sdat <= slave_add[1]; 6'd29 : I2C_sdat <= slave_add[0]; 6'd30 : I2C_sdat <= 1; //Read(1) 6'd31 : I2C_sdat <= 1'bz;//Slave ACK //Data read(DATA) //Data byte 1 6'd32 : I2C_sdat <= 1'bz; 6'd33 : I2C_sdat <= 1'bz; 6'd34 : I2C_sdat <= 1'bz; 6'd35 : I2C_sdat <= 1'bz; 6'd36 : I2C_sdat <= 1'bz; 6'd37 : I2C_sdat <= 1'bz; 6'd38 : I2C_sdat <= 1'bz; 6'd39 : I2C_sdat <= 1'bz; 6'd40 : I2C_sdat <= 1'b1;//Master ACK //stop 6'd41 : begin I2C_sdat <= 1'b0; sclk <= 1'b1; end 6'd42 : I2C_sdat <= 1'b1; endcase end assign I2C_sclk = (((sd_counter >= 4)&(sd_counter <= 20))|((sd_counter >=24)&(sd_counter <=42)))? ~q[0] : sclk; endmodule - Altera_Forum
Honored Contributor
Too bad:( nobody's willing to help me in my thesis project.
Come on anyone help me:D - Altera_Forum
Honored Contributor
First using generated logic signals inside FPGAs isn't a good idea. If you have glitches on the signal the FPGA logic could interpret it as a new clock cycle and you would loose some cycles.
It is best to do everything in a single always block and use a counter to generate both the clock and data signals from the same place, changing them only when the counter reaches specific values. Do you actually try to read the acknowledge pulse from the I2C slave? You should read it to be sure it has actually recognized its address on the I2C bus first. - Altera_Forum
Honored Contributor
Thank you very much for your reply, Daixiwen.
I don't really get it. Do you mean the "generated clock" when you say "generated logic signal"("First using generated logic signals inside FPGAs isn't a good idea.")? I need to generate slower clock because the accelerometer output data rate is 100hz(by default) and my fpga has 50Mhz clock. I will try to remake my program by trying to use always block as less as possible(although I am not sure that I can do it with only a single always block). "Do you actually try to read the acknowledge pulse from the I2C slave? You should read it to be sure it has actually recognized its address on the I2C bus first." Yeah I am actually trying to read ack pulse from ADXL to make sure that the ADXL has already listened the data from master(at 6'd11, 6'd20, 6'd31) and at 6'd40 the master send the ack pulse to the slave.(I believe this is the standard timing diagram for I2C read protocol) Could you give more hint to solve this problem? Thank you so much for your help. - Altera_Forum
Honored Contributor
Yes sorry, I forgot to finish my sentence. I meant "using generated logic signals as a clock inside FPGAs isn't a good idea". You should generate both I2C_sclk and I2C_sdat in the same always block, clocked with clk_50. You can use a counter to gerenate the I2C_sclk signal and only execute your state machine code when the counter reaches a specific value.
I've asked about acknowledge read because I don't see anything in your code that does that. Sure you put the I2C_sdat in high impedance mode, but you don't seem to do anything to read back the signal value and check that the slave indeed acknowledged its address. Did you check it with signaltap? - Altera_Forum
Honored Contributor
Thanks again Daixiwen.
Yeah I use signaltap2 to check my coding. It shows that the slave grounded the pulse at 6'd11, 6'd20, 6'd31(low pulse instead of high pulse). If the slave do not acknowledge the master, it will give the high pulse at 6'd11, 6'd20, 6'd31. If you think I am wrong at the acknowledge read pulse, how do you suggest me to get the right acknowledge read? Thank you so much for your quick response, Daixiwen. - Altera_Forum
Honored Contributor
Yes you are right, this means the slave is acknowledging properly. But if in your application you need to know if the slave answered properly without having to use SignalTap, it could be a good idea to read this value in your code and change an output pin such as "SlaveOK" or "SlaveError" depending on the results.
The next thing to check is that you are reading the correct register, and indep check if the slave is doing any clock stretching. For that you can change your code so that the clock output is set to 'z' instead of '1' (you do have external pull-ups on both the I2C clock and data, don't you?) and see with signaltap if the slave is keeping scl low for any reason. - Altera_Forum
Honored Contributor
Thanks Daixiwen.
Now I am remaking my program and trying to follow your suggestion. Tomorrow I will have finished it and will post it here. Thank you. - Altera_Forum
Honored Contributor
Here is my new code:
// 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); input clk_50; output I2C_sclk; inout I2C_sdat; input key0; //Trigger0 to reset input key1; //Trigger1 to begin output clk_st; reg [18:0] a; reg [18: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'b110000; // 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 == 250000) //Clock for Slave with sample 2a begin clk = ~clk; a = 1; end else a = a + 1; //Signaltap begin if(b == 125000) //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({key0, key1}) 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 = 1; sdat = sl_ad[6]; step = 4; end 4: begin sclk = 0; sdat = sl_ad[6]; step = 5; end 5: begin sclk = 1; sdat = sl_ad[5]; step = 6; end 6: begin sclk = 0; sdat = sl_ad[5]; step = 7; end 7: begin sclk = 1; sdat = sl_ad[4]; step = 8; end 8: begin sclk = 0; sdat = sl_ad[4]; step = 9; end 9: begin sclk = 1; sdat = sl_ad[3]; step = 10; end 10: begin sclk = 0; sdat = sl_ad[3]; step = 11; end 11: begin sclk = 1; sdat = sl_ad[2]; step = 12; end 12: begin sclk = 0; sdat = sl_ad[2]; step = 13; end 13: begin sclk = 1; sdat = sl_ad[1]; step = 14; end 14: begin sclk = 0; sdat = sl_ad[1]; step = 15; end 15: begin sclk = 1; sdat = sl_ad[0]; step = 16; end 16: begin sclk = 0; sdat = sl_ad[0]; step = 17; end //3.sdat = 0 17: begin sclk = 1; sdat = 0; step = 18; end 18: begin sclk = 0; sdat = 0; step = 19; end //4.Acknowledge 19: begin sclk = 1; sdat = 1'bz; step = 20; end 20: begin sclk = 0; sdat = 1'bz; if (sdat == 1) step = 19; else step = 21; end //5.Reg add 21: begin sclk = 1; sdat = reg_ad[7]; step = 22; end //7 22: begin sclk = 0; sdat = reg_ad[7]; step = 23; end 23: begin sclk = 1; sdat = reg_ad[6]; step = 24; end //6 24: begin sclk = 0; sdat = reg_ad[6]; step = 25; end 25: begin sclk = 1; sdat = reg_ad[5]; step = 26; end //5 26: begin sclk = 0; sdat = reg_ad[5]; step = 27; end 27: begin sclk = 1; sdat = reg_ad[4]; step = 28; end //4 28: begin sclk = 0; sdat = reg_ad[4]; step = 29; end 29: begin sclk = 1; sdat = reg_ad[3]; step = 30; end //3 30: begin sclk = 0; sdat = reg_ad[3]; step = 31; end 31: begin sclk = 1; sdat = reg_ad[2]; step = 32; end //2 32: begin sclk = 0; sdat = reg_ad[2]; step = 33; end 33: begin sclk = 1; sdat = reg_ad[1]; step = 34; end //1 34: begin sclk = 0; sdat = reg_ad[1]; step = 35; end 35: begin sclk = 1; sdat = reg_ad[0]; step = 36; end //0 36: begin sclk = 0; sdat = reg_ad[0]; step = 37; end //6.Acknowledge 37: begin sclk = 1; sdat = 1'bz; step = 38; end 38: begin sclk = 0; sdat = 1'bz; if (sdat == 1) step = 37; else step = 39; end //7.Start 39: begin sclk = 1; sdat = 1; step = 40; end //sclk= 1, sdat= 1 40: begin sclk = 1; sdat = 1; step = 41; end 41: begin sclk = 1; sdat = 0; step = 42; end //sclk= 1, sdat= 0 42: begin sclk = 1; sdat = 0; step = 43; end 43: begin sclk = 0; sdat = 0; step = 44; end //sclk= 0, sdat= 0 44: begin sclk = 0; sdat = 0; step = 45; end //8.Slave Add 45: begin sclk = 1; sdat = sl_ad[6]; step = 46; end //6 46: begin sclk = 0; sdat = sl_ad[6]; step = 47; end 47: begin sclk = 1; sdat = sl_ad[5]; step = 48; end //5 48: begin sclk = 0; sdat = sl_ad[5]; step = 49; end 49: begin sclk = 1; sdat = sl_ad[4]; step = 50; end //4 50: begin sclk = 0; sdat = sl_ad[4]; step = 51; end 51: begin sclk = 1; sdat = sl_ad[3]; step = 52; end //3 52: begin sclk = 0; sdat = sl_ad[3]; step = 53; end 53: begin sclk = 1; sdat = sl_ad[2]; step = 54; end //2 54: begin sclk = 0; sdat = sl_ad[2]; step = 55; end 55: begin sclk = 1; sdat = sl_ad[1]; step = 56; end //1 56: begin sclk = 0; sdat = sl_ad[1]; step = 57; end 57: begin sclk = 1; sdat = sl_ad[0]; step = 58; end //0 58: begin sclk = 0; sdat = sl_ad[0]; step = 59; end //9.sdat = 1 59: begin sclk = 1; sdat = 1; step = 60; end 60: begin sclk = 0; sdat = 1; step = 61; end //10.Acknowledge 61: begin sclk = 1; sdat = 1'bz; step = 62; end 62: begin sclk = 0; sdat = 1'bz; if (sdat == 1) step = 61; else step = 63; end //11.Databyte#1 63: begin sclk = 1; data1[7] = sdat; step = 64; end //Databyte#1 bit 7 64: begin sclk = 0; data1[7] = sdat; step = 65; end 65: begin sclk = 1; data1[6] = sdat; step = 66; end //6 66: begin sclk = 0; data1[6] = sdat; step = 67; end 67: begin sclk = 1; data1[5] = sdat; step = 68; end //5 68: begin sclk = 0; data1[5] = sdat; step = 69; end 69: begin sclk = 1; data1[4] = sdat; step = 70; end //4 70: begin sclk = 0; data1[4] = sdat; step = 71; end 71: begin sclk = 1; data1[3] = sdat; step = 72; end //3 72: begin sclk = 0; data1[3] = sdat; step = 73; end 73: begin sclk = 1; data1[2] = sdat; step = 74; end //2 74: begin sclk = 0; data1[2] = sdat; step = 75; end 75: begin sclk = 1; data1[1] = sdat; step = 76; end //1 76: begin sclk = 0; data1[1] = sdat; step = 77; end 77: begin sclk = 1; data1[0] = sdat; step = 78; end //0 78: begin sclk = 0; data1[0] = sdat; step = 79; end //12.Acknowledge 79: begin sclk = 1; sdat = 1'bz; step = 80; end 80: begin sclk = 0; sdat = 1'bz; if (sdat == 1) step = 79; else step = 81; end //13.Stop 81: begin sclk = 1; sdat = 0; step = 82; end //sclk= 1, sdat= 0 82: begin sclk = 1; sdat = 0; step = 83; end 83: begin sclk = 1; sdat = 1; step = 84; end //sclk= 1, sdat= 1 84: begin sclk = 1; sdat = 1; end endcase end end assign I2C_sclk = sclk; assign I2C_sdat = sdat; assign clk_st = clk_signaltap; endmodule