View previous topic :: View next topic |
Author |
Message |
robleso7473
Joined: 25 Mar 2009 Posts: 47
|
I2C Read failing |
Posted: Wed Jun 02, 2021 10:06 am |
|
|
Hello Everyone,
I am using the I2C driver in the dsPIC33CK32MC102 acting as a Master to talk to an FPGA. I use the following: #use i2c(MASTER, I2C1, FAST, RESTART_WDT, stream=I2C_PORT1). This is on dedicated I2C ports RB8/RB9.
The goal is to read internal registers in FPGA by executing the following custom Read sequence using slave address 0x56 followed by a 16-bit memory address 0x0034 and a 16-bit Length byte 0x0001 then I want to read back 4 bytes of data from that location:
Start > 0xAD > 0x0034 > 0x0001 > Read Data1 > Read Data2 > Read Data3 > Read Data4
This is the code:
Code: |
i2c_start();
i2c_write(0xAD); // I2C slave address + write address
i2c_write(0x00); // Write high address byte
i2c_write(0x34); // Write low address byte
i2c_write(0x00); // Write Length Field High Byte
i2c_write(0x01); // Write Length Field Low Byte
data3 = i2c_read(TRUE); // Read data byte 3
data2 = i2c_read(TRUE); // Read data byte 2
data1 = i2c_read(TRUE); // Read data byte 1
data0 = i2c_read(TRUE); // Read data byte 0
i2c_stop();
printf("Reading 4 Bytes from address 0x0034: 0xAD>>0X0034>>0X0001>>BYTE1>>BYTE2>>BYTE3>>BYTE4\r\n");
printf("BYTE1 = 0x%X \r\n", data3);
printf("BYTE2 = 0x%X \r\n", data2);
printf("BYTE3 = 0x%X \r\n", data1);
printf("BYTE4 = 0x%X \r\n\r\n", data0);
|
I know normally a Read sequence is done by writing the address then issuing a reStart and then clocking the data back but due to the structure of the FPGA memory we have to do it this way.
What I see is the following: MCU sends Start > 0xAD > 0x00 then FPGA returns ACK after that last byte and the MCU for some reason does NOT send the LSB of the address >0x34 or the Length word 0x0001 but instead tries to clock back the 4 bytes of data. (I wanted to insert an image but don't know how to)
Two questions for the forum:
1. Does the I2C driver in dsPIC33CK family follows this I2C Standard Read protocol
2. If it does follow the I2C standard protocol can I modify it per my custom Read sequence above?
I appreciate if anyone can help me resolve this issue.
Thanks!
Oscar |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 02, 2021 3:05 pm |
|
|
Quote: | data3 = i2c_read(TRUE); // Read data byte 3
data2 = i2c_read(TRUE); // Read data byte 2
data1 = i2c_read(TRUE); // Read data byte 1
data0 = i2c_read(TRUE); // Read data byte 0
i2c_stop(); |
The i2c spec says the last read above should have a parameter of 0.
That's if your FPGA was designed to follow the i2c spec.
It should be like this:
Code: |
data0 = i2c_read(0); // Read data byte 0
|
Also, it's wrong to use 'TRUE' as a parameter. The CCS manual
says the legal parameters are 0, 1, or 2. From the manual:
Quote: |
i2c_read( )
Syntax:
data = i2c_read();
data = i2c_read(ack);
data = i2c_read(stream, ack);
Parameters:
ack -Optional, defaults to 1
0 indicates do not ack
1 indicates to ack
2 slave only, indicates to not release clock at end of read. Use when i2c_isr_state()
returns 0x80 |
|
|
|
robleso7473
Joined: 25 Mar 2009 Posts: 47
|
|
Posted: Wed Jun 02, 2021 3:22 pm |
|
|
Thanks for the response.
I will change out the TRUE's to 1's and last one to 0.
I have another question for you, if you please: If this MCU is the master then wouldn't setting it to 1 generate an ack back to the slave? Or does this mean that the MCU(master) will look for an ack from the slave. It's a bit confusing to me.
thanks again!
Oscar |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Thu Jun 03, 2021 12:45 am |
|
|
I2C, by using an 'open collector' drive, supports transfers in both directions
on each wire.
So the ''slave', can hold the clock from releasing to delay the master
(clock stretch). Then the master can receive data, by commanding the
slave to send, and sending the clocks, while the slave then drives the data
line to give data to the master. In I2C, all transfers have a ACK or NACK,
which is generated by the receiving device. So when the master is receiving,
it is the master that must ACK/NACK.
For transmissions it is the slave that sends this. For reception, it is the
master.
The rmaster device, when receiving, 'ACK's all but the last byte. This byte
has a NACK. This is a marker to the slave device to say that this is the end
of the packet. It is this that releases the toggle in the slave device to switch
it back to receiving.
Many slaves will automatically reset this, when they see a 'stop'. However
a lot do not. On any device where this is not done, not sending this last
NACK, can result in the slave state machine becoming stuck..... |
|
|
robleso7473
Joined: 25 Mar 2009 Posts: 47
|
|
Posted: Thu Jun 03, 2021 7:23 am |
|
|
Thanks for this additional insight.
Much appreciated fellows.
Oscar |
|
|
robleso7473
Joined: 25 Mar 2009 Posts: 47
|
|
Posted: Fri Jun 04, 2021 8:18 am |
|
|
I'm back!
I still have an issue when executing a read command where after the high address byte below the MCU will not send out the next byte 0x34, it simply ignores the next 3 writes to 0x34, 0x00 and 0x01 and goes straight into reading data1 and data0.
Is the I2C Read function designed to only push out one 8-bit address value prior to clocking back data?
i2c_start();
i2c_write(0xAD); // I2C slave address + write address
i2c_write(0x00); // Write high address byte
i2c_write(0x34); // Write low address byte
i2c_write(0x00); // Write Length byte 1
i2c_write(0x01); // Write Length byte 0
data1 = i2c_read(1); // Read data byte 1
data0 = i2c_read(1); // Read data byte 0
i2c_stop();
}
I want to post an image of the I2C transaction from my Saleae logic analyzer but don't know how to paste it on here - can you help?
Thanks for support,
Oscar |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Fri Jun 04, 2021 8:26 am |
|
|
This is where a restart is used.
The sequence has to be:
start
write device address set to write.
write the register addresses (however many bytes are needed)
trigger a 'restart' (send a start without a stop)
write the device address set to read
Now read the bytes nacking the last one.
stop.
The point is that after an address is sent with the 'read' flag, only reads
are allowed. To set a address you have to do a write transaction, then
turn the bus around with the restart, and the read flag.
To your question:
Quote: |
Is the I2C Read function designed to only push out one 8-bit address value prior to clocking back data?
|
The answer is totally 'yes'. This is all I2C allows.
After the read address is sent, only reads can be done. There can be
no transmissions after this. You only turn the bus to 'read', once you have
already sent all transmissions that are needed. |
|
|
|