|
|
View previous topic :: View next topic |
Author |
Message |
Ttelmah
Joined: 11 Mar 2010 Posts: 19225
|
|
Posted: Mon Nov 18, 2019 12:34 pm |
|
|
No, the clock is held on every transaction.
When you read data this immediately releases the clock.
The point about a master read, is you read data and don't release the
line (this is the '2'), then release it once you have loaded the reply.
Every individual transfer is synchronised by the clock hold. |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 537 Location: Des Moines, Iowa, USA
|
|
Posted: Mon Nov 18, 2019 5:17 pm |
|
|
I have things working "perfectly" on two boards, but then I started testing on a PIC24FJ64GA002 and the behavior changes.
On this board, it initializes I2C with P and S both 0 (good). When the first message comes in, it doesn't seem to toggle S or the IRQ, but I can look in the debugger and see P is 1 (so it saw the stop bit, but not the stat and data). After that, messages process as expected.
It worked on 24FJ256GA106, and a 24EP256GP202, but I'm still working on the 24FJ64GA002 to figure out what is different. _________________ 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 ? |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1317
|
|
Posted: Tue Nov 19, 2019 11:58 am |
|
|
I would check the errata on that chip. We had some troubles with the 44 pin version (24FJ64GA004) that we had to do a lot of workarounds for. |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 537 Location: Des Moines, Iowa, USA
|
|
Posted: Tue Nov 19, 2019 12:26 pm |
|
|
jeremiah wrote: | I would check the errata on that chip. We had some troubles with the 44 pin version (24FJ64GA004) that we had to do a lot of workarounds for. |
Will do. I found some other posts in Microchip (one from 2008) about I2C quirks.
The end result for me was much more robust I2C polled code:
Now, if I am waiting on a Receive (Master Write) and I get a Master Read, I send it back some blank data (so the Master does not hang) and go back to Receive for the next proper message. (Thus, doing a Receive will stay there until it receives something.)
If I am doing a Response (waiting on Master Read) and I get a Master Write, I consume the unexpected data (to clear the receive buffer, etc.) and then return a 0 indicating the response was not sent. (Calling code can handle.)
I need to add some timeouts and make some things a bit more bulletproof (it can still hang if transmission is disrupted, since I rely on seeing a Stop bit which might not come).
But it's great progress. _________________ 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: 537 Location: Des Moines, Iowa, USA
|
|
Posted: Tue Nov 19, 2019 12:30 pm |
|
|
In case anyone wants to eyeball this, here is the work-in-progress polled code I have been working on.
(EDIT: Minor update. A few more still to be posted after I get them tested.)
Read message from Master:
Code: | unsigned int i2cSlaveReceive (void *buffer, size_t size)
{
unsigned int state = 0;
unsigned int value = 0;
unsigned int bytesTransferred = 0;
// NULL check.
if ((buffer == NULL) || (size == 0)) return 0;
// There is a bug in the 24FJ64GA002 which misses the
// first Start bit and Event Interrupt Flag Status.
do
{
// Wait for START bit
while (S == 0);
// Wait for first address byte so we can tell if this is a Read or Write.
while (I2C_SYSTEM_BUS_IRQ_PENDING_BIT == 0);
// Do not clear. We may need it pending for main loop below.
// If this is a Write to Slave, we are done here.
if (RW == 0) break;
// Else, it was unexpected.
i2c_read (SYSTEM_BUS, 2); // Address
i2c_write (SYSTEM_BUS, 0x42);
while (P == 0)
{
if (TBF == 0)
{
i2c_write (SYSTEM_BUS, 0x42);
}
}
I2C_SYSTEM_BUS_IRQ_PENDING_BIT = 0;
} while (1);
// Process INCOMING address and INCOMING data bytes.
while (1)
{
// Wait for I2C interrupt pending.
while (I2C_SYSTEM_BUS_IRQ_PENDING_BIT == 0);
I2C_SYSTEM_BUS_IRQ_PENDING_BIT = 0; // Clear IRQ flag
state = i2c_isr_state(SYSTEM_BUS);
value = (state & ~BIT(7)); // Mask off high bit.
// High bit (1xxxxxxx) indicates READ, else WRITE
if ((state & BIT(7)) == 0) // High bit CLEAR (Read from Master)
{
unsigned int data;
if (value == 0x00)
{
// 0 - Address match received with R/W bit clear, perform
i2c_read (SYSTEM_BUS);
}
else
{
// 1-0x7F - Master has written data; i2c_read() will immediately
// return the data
data = i2c_read (SYSTEM_BUS);
if (bytesTransferred < size)
{
buffer[bytesTransferred] = data;
bytesTransferred++;
}
}
}
else // High bit SET (Slave writing to Master)
{
// Write? We were trying to read!
break;
}
// If Reading, we read however many bytes the Master wrote,
// or up to 'size' bytes.
// If Writing, we send however many bytes the Master reads,
// or up to 'size' bytes.
// Wait for either a stop bit, or another incoming data byte.
while ((P == 0) && (I2C_SYSTEM_BUS_IRQ_PENDING_BIT == 0));
if (P != 0)
{
break;
}
} // end of while (1)
return bytesTransferred;
} // end of i2cSlaveReceive ()
|
Write Message to Master:
Code: |
unsigned int i2cSlaveRespond (void *buffer, size_t size)
{
unsigned int state = 0;
unsigned int value = 0;
unsigned int bytesTransferred = 0;
// NULL check.
if ((buffer == NULL) || (size == 0)) return 0;
do
{
// Wait for START bit
while (S == 0);
// Wait for first address byte so we can tell if this is a Read or Write.
while (I2C_SYSTEM_BUS_IRQ_PENDING_BIT == 0);
// Do not clear. We may need it pending for main loop below.
// If this is a Read from Master, we are done here.
if (RW == 1) break;
// Else, it was unexpected. Master was Writing, not reading.
// Consume incoming message.
while (P == 0)
{
if (RBF == 0)
{
i2c_read (SYSTEM_BUS);
}
}
I2C_SYSTEM_BUS_IRQ_PENDING_BIT = 0;
return 0;
} while (1);
// Process INCOMING address and OUTGOING data bytes.
while (1)
{
// Wait for I2C interrupt pending.
while (I2C_SYSTEM_BUS_IRQ_PENDING_BIT == 0);
I2C_SYSTEM_BUS_IRQ_PENDING_BIT = 0; // Clear IRQ flag
state = i2c_isr_state(SYSTEM_BUS);
value = (state & ~BIT(7)); // Mask off high bit.
// High bit (1xxxxxxx) indicates READ, else WRITE
if ((state & BIT(7)) == 0) // High bit CLEAR (Read from Master)
{
// Read? We were trying to write!
break;
}
else // High bit SET (Slave writing to Master)
{
if (value == 0x00)
{
// 0x80 - Address match received with R/W bit set; perform
// i2c_read( ) to read the I2C address, and use i2c_write( ) to
// pre-load the transmit buffer for the next transaction (next
// I2C read performed by master will read this byte).
i2c_read (SYSTEM_BUS, 2);
i2c_write (SYSTEM_BUS, buffer[0]);
}
else
{
// 0x81-0xFF - Transmission completed and acknowledged; respond
// with i2c_write() to pre-load the transmit buffer for the next
// transition (the next I2C read performed by master will read
// this byte).
i2c_write (SYSTEM_BUS, buffer[bytesTransferred]);
//i2c_write (SYSTEM_BUS, buffer[value]);
}
}
// Done when STOP bit is seen.
// If Reading, we read however many bytes the Master wrote,
// or up to 'size' bytes.
// If Writing, we send however many bytes the Master reads,
// or up to 'size' bytes.
// Wait for either a stop bit, or another incoming data byte.
while ((P == 0) && (I2C_SYSTEM_BUS_IRQ_PENDING_BIT == 0));
if (P != 0)
{
break;
}
// To avoid returining +1, we increment after the Stop bit check.
bytesTransferred++;
} // end of while (1)
return bytesTransferred;
} // end of i2cSlaveRespond () |
_________________ 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 ?
Last edited by allenhuffman on Tue Nov 19, 2019 2:44 pm; edited 1 time in total |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 537 Location: Des Moines, Iowa, USA
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19225
|
|
Posted: Tue Nov 19, 2019 2:11 pm |
|
|
That issue only applies to a six year old revision of the chip.
Assuming you are working with something reasonably recent, this
should not apply to you. |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 537 Location: Des Moines, Iowa, USA
|
|
Posted: Tue Nov 19, 2019 2:13 pm |
|
|
Ttelmah wrote: | That issue only applies to a six year old revision of the chip.
Assuming you are working with something reasonably recent, this
should not apply to you. |
Sadly, it's on a brand new board we just made (PIC from Digi-Key). We (software guys) aren't sure how to check for the revision of the chip. _________________ 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: 19225
|
|
Posted: Tue Nov 19, 2019 2:43 pm |
|
|
The device programmer can read the revision ID. Depends what software
you are using.
If you want to write a program just read the configuration data space.
The revision is in the last word of this. |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 537 Location: Des Moines, Iowa, USA
|
|
Posted: Tue Nov 19, 2019 2:51 pm |
|
|
Ttelmah wrote: | The device programmer can read the revision ID. Depends what software
you are using.
If you want to write a program just read the configuration data space.
The revision is in the last word of this. |
I have the ICD-U80 with the CCS Load program, but I think we have a PICkit-3 around here somewhere. I see Target Device ID, but I'm not sure I am finding revision for the chip here (just for the hardware debugger itself, it looks like). _________________ 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: 537 Location: Des Moines, Iowa, USA
|
|
Posted: Thu Nov 21, 2019 10:49 am |
|
|
I have now moved on to implementing messaging code to make use of my I2C polled receive/respond routines. Once I get to testing those, I am sure I will find more cases where the code can hang.
There are places in my code, and in the CCS i2c_xxx() routines, where they poll for a bit to change. Under normal circumstances, things work fine, but if a signal is disrupted and a state change is missed, we get a hang.
I'll try to post "final" code when I get to that point. _________________ 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 ? |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1902
|
|
Posted: Thu Nov 21, 2019 11:28 am |
|
|
Have you considered launching a timer which is configured to expire in 2x or 3x your maximum anticipated I2C timeout? Then poll for your anticipated I2C state OR the timer expiring. If the timer expires, at least you can break out of your I2C routine and take some sort of remedial action instead of blocking/hanging in a test which will never become true. |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 537 Location: Des Moines, Iowa, USA
|
|
Posted: Thu Nov 21, 2019 4:03 pm |
|
|
newguy wrote: | Have you considered launching a timer which is configured to expire in 2x or 3x your maximum anticipated I2C timeout? Then poll for your anticipated I2C state OR the timer expiring. If the timer expires, at least you can break out of your I2C routine and take some sort of remedial action instead of blocking/hanging in a test which will never become true. |
I hadn't -- and that seems like a good solution. I could read the timer value even without using any interrupts. In earlier test code, I was just doing a loop countdown, which varies in time on different speed processors. _________________ 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 ? |
|
|
jaka
Joined: 04 May 2014 Posts: 35 Location: Finland
|
|
Posted: Fri Nov 22, 2019 8:17 am |
|
|
Just a quick comment. You said that you are using FTDI as a master. At least the MPSSE in FT232H devices doesn't support I2C clock stretching. So it's pretty useless if trying to communicate with a microcontroller based slave device.
We had lots of problems with the FT232H and eventually had to change to another USB-I2C chip which does support clock stretching. |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 537 Location: Des Moines, Iowa, USA
|
|
Posted: Fri Nov 22, 2019 8:57 am |
|
|
jaka wrote: | Just a quick comment. You said that you are using FTDI as a master. At least the MPSSE in FT232H devices doesn't support I2C clock stretching. So it's pretty useless if trying to communicate with a microcontroller based slave device.
We had lots of problems with the FT232H and eventually had to change to another USB-I2C chip which does support clock stretching. |
Wow, thanks! Good to know! Our main PIC24 board has an FTDI chip on it (USB to the PC). We use the FTD2XX dll and LIBFT4222 dll.
These do seem to honor clock stretching. Our production system doesn't do it, but when I went to write there I2C routines, I found it did work. My PIC24 code can do this:
Code: | i2cSlaveReceive( … );
...master writes data...
...slave receives data...
i2cSlaveRespond( … ); // slave will wait.
...wait for seconds at the Master side, before doing a read...
...master does a read...
...slave writes data... |
I was pleased to see it working, since our PC host code does a bunch of sleeps between Writes and Reads to give the PIC24 chain time to respond. It looks like I can update this so the master can just Write/Read and it will wait (in a thread) until the slave responds. Awesome. That will really speed things up. _________________ 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 ? |
|
|
|
|
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
|