|
|
View previous topic :: View next topic |
Author |
Message |
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
PIC24 I2C slave sometimes setting first data bit high? |
Posted: Wed Jul 24, 2024 10:18 am |
|
|
We have some well-tested I2C code that has been in use for years, but while trying something new, I observed something:
My Master program tries to read a few bytes from a PIC24 Slave device. Normally, we respond with a 0xAA (10101010) byte as a start code, followed by the rest of a header and then any data plus a checksum at the end.
Using a Saleae Logic Analyzer, and having the PIC24 return "0x01" for the first byte, shows this most of the time:
Good:
I see the correct clock pulses, and the Master writes out the address with the read bit set (0x65 in this case).
I then see the data line drop LOW until the next set of clock pulses to read the 0x01.
Bad:
I see the correct clock pulses, and the Master writes out the address with the read bit set (0x64).
I then see the data line remain HIGH. When the next set of clock pulses happen, it is still high and is seen as a "1" bit, then it drops and gets the "1" at the end, representing 0x81.
The PIC code is being done in an ISR, and I am manually clearing the IRQ so I can check for the P stop bit or IRQ for next incoming byte in my routine.
The code that is running in the ISR for this case ("first read") is basically this:
Code: | // Get a byte of data which is the address of the board.
i2c_read (SYSTEM_BUS); // NO CLOCK STRETCHING.
// Write out first data byte.
i2c_write (SYSTEM_BUS, 0x01); |
In this case, this code runs when I am not expecting the Master to read (normally the Master writes a message as a command or request, and a buffer is prepared for the ISR to pull bytes from when the Master reads the response).
Has this "data line being held high" thing been observed elsewhere? We use several PIC24 variants, and I see this on a 24FJ64GA002. I have not checked our other boards.
If this happens during normal operation, we never "see" it because we use that 0xAA start code (10101010) so if a fake high bit is read, it still matches that code. Had we chosen 0x55 (01010101) then I bet we would have encountered this years ago.[/code] _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19495
|
|
Posted: Wed Jul 24, 2024 11:02 am |
|
|
I suspect that is caused by erratum 38.
The TBF bit is set, so the peripheral thinks it already has a byte to send,
which just happens to be 0xFF. Suggests some slight timing issue on the
bus is causing this error. |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Wed Jul 24, 2024 11:17 am |
|
|
Ttelmah wrote: | I suspect that is caused by erratum 38.
The TBF bit is set, so the peripheral thinks it already has a byte to send,
which just happens to be 0xFF. Suggests some slight timing issue on the
bus is causing this error. |
I see:
Quote: | The Transmit Buffer Full flag, TBF (I2CxSTAT<0>),
may not be cleared by hardware if a collision on
the I2C bus occurs before the first falling clock
edge during a transmission. |
Any thoughts on what the source of a collision be? I am using the FTDI DLL on Windows and just telling it to:
Code: | ft4222Status = FT4222_I2CMaster_ReadEx (ftHandle,
deviceAddress,
START,
&buffer[0],
1,
&sizeTransferred); |
That causes it to write out the address and then do the read but NOT do the STOP at that time. The Saleae capture shows this sequence -- with over 504 uS before the operation. _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ? |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Wed Jul 24, 2024 12:10 pm |
|
|
As a workaround, I did a few tests. I found that if I just read one extra byte than what I really am expecting, the problem goes away.
The only thing special my code is doing is making a decision whether to write a byte from a transmit buffer, OR send a hard-coded "you read when I was not expecting it". That shouldn't have changed anything, unless that timing was enough to change the outcome.
Then I just tried enabling clock stretching on the address read, and that also made the problem seem to go away:
Code: | // Get a byte of data which is the address of the board.
i2c_read (SYSTEM_BUS, 2); // CLOCK STRETCH
// Write out first data byte.
i2c_write (SYSTEM_BUS, 0x01); |
...so... maybe? _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19495
|
|
Posted: Wed Jul 24, 2024 12:21 pm |
|
|
That makes total sense.
What is happening, is that without the stretch, the master is intermittently
starting it's read _before_ the byte has been loaded. The clock must be
held till the byte is loaded. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|