|
|
View previous topic :: View next topic |
Author |
Message |
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
PIC24FJ64GA004 - detecting I2C stop bit (P) inside an ISR |
Posted: Fri Oct 30, 2020 1:24 pm |
|
|
Microchip's I2C document shows me that some of their chips can generate an IRQ on the I2C stop bit, allowing code to know when the Master is done with a Write operation. My PIC24FJ64GA004 does not support this.
Inside the ISR, during reading the master, the stop bit is not set yet when the final byte is processed. I am wondering if there is a common way folks deal with this. I am currently observing flags I set and the P bit manually inside a main loop.
One approach I am considering:
1. Stay in the ISR after the first Master write until the stop bit is detected. This blocks the main loop until the message is complete. A timeout should be added in case of a hang from the master or glitch.
Our existing code uses a protocol where there is a byte for how large a message is expected to be. We occasionally get data glitches so that is not reliable.
Cheers. _________________ 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: 19516
|
|
Posted: Fri Oct 30, 2020 1:51 pm |
|
|
As you say some of the PIC24/33's have a PCIE bit (I2CxCONH:6) that
enables this. Others don't.
Without this all you can do is poll the status bit. |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Fri Oct 30, 2020 2:11 pm |
|
|
Ttelmah wrote: | As you say some of the PIC24/33's have a PCIE bit (I2CxCONH:6) that
enables this. Others don't.
Without this all you can do is poll the status bit. |
I ran into an issue where the Master writes a message, then before the main loop can handle it, the Master goes to Read, clearing the stop bit (since last seen is now start). That is what got me going down this rabbit hole ;-) and wanting to do it inside the ISR somehow. _________________ 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 ? |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Fri Oct 30, 2020 2:59 pm |
|
|
I suppose you could tie the SDA line to another pin that supports IRQ on change (or on whichever edge) Work with that somehow.
Just a thought.... _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19516
|
|
Posted: Sat Oct 31, 2020 1:07 am |
|
|
The problem is not actually 'detecting' the bit, but that the ISR won't be
called.
The chip has detection for the stop. But this doesn't trigger the I2C ISR
on chips that don't have the PCIE bit.
Now detecting stop externally to the I2C routines can be done by polling
the bit reflecting stop. Detecting with interrupt on change, would require the
routine to be set to trigger on low to high on the SDA line, and then poll
the SCL line and check this is high. Stop is a low to high on SDA while
SCL is high. With the PIC24, actually quite easy, since there is nothing to
stop you programming an interrupt onto the existing SDA connection.
Setup a capture on every rising edge on this pin. Set this as a lower
hardware priority than the I2C routine. Then have it's handler poll SCL
and if this is high call whatever you want to happen on start.
The detection bit in the hardware is set once stop is received, until
any other I2C change occurs. So to poll it, you have to also check the
data received, and start value, and stop has been seen only when this
is true, and none of the other bits are... |
|
|
asmallri
Joined: 12 Aug 2004 Posts: 1635 Location: Perth, Australia
|
|
Posted: Thu Nov 05, 2020 7:28 pm |
|
|
allenhuffman wrote: | Ttelmah wrote: | As you say some of the PIC24/33's have a PCIE bit (I2CxCONH:6) that
enables this. Others don't.
Without this all you can do is poll the status bit. |
I ran into an issue where the Master writes a message, then before the main loop can handle it, the Master goes to Read, clearing the stop bit (since last seen is now start). That is what got me going down this rabbit hole ;-) and wanting to do it inside the ISR somehow. |
So.. do you really need to do this in the ISR? I handle this type of problem by starting a short timer inside the I2C ISR and exit the ISR normally. If another I2C interrupt occurs before the timer expires I restart the short timer. If however there is no more activity, the timer will eventually rollover generating a timer interrupt. This timer interrupt indicates expected end of I2C activity and I can now read the I2C status bit inside the timer iSR to see if this is what I expected. _________________ Regards, Andrew
http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!! |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Fri Nov 13, 2020 11:07 am |
|
|
asmallri wrote: | So.. do you really need to do this in the ISR? I handle this type of problem by starting a short timer inside the I2C ISR and exit the ISR normally. If another I2C interrupt occurs before the timer expires I restart the short timer. If however there is no more activity, the timer will eventually rollover generating a timer interrupt. This timer interrupt indicates expected end of I2C activity and I can now read the I2C status bit inside the timer iSR to see if this is what I expected. |
That sounds promising. Perhaps the rollover could be dealt with by having flags set inside the RECEIVE portion of the ISR. When the timer fires (after a rollover) it wouldn't need to do anything if that flag wasn't set (indicating we were not receiving bytes and thus don't need to check the stop bit).
This would be better than what I am doing in the main while(TRUE) loop, since I have to add extra code to detect situations when the Master does a WRITE then READ before that detection code had time to run. _________________ 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: Fri Nov 13, 2020 11:14 am |
|
|
Ttelmah wrote: | Now detecting stop externally to the I2C routines can be done by polling
the bit reflecting stop. Detecting with interrupt on change, would require the
routine to be set to trigger on low to high on the SDA line, and then poll
the SCL line and check this is high. Stop is a low to high on SDA while
SCL is high. With the PIC24, actually quite easy, since there is nothing to
stop you programming an interrupt onto the existing SDA connection.
Setup a capture on every rising edge on this pin. Set this as a lower
hardware priority than the I2C routine. Then have it's handler poll SCL
and if this is high call whatever you want to happen on start.
|
Would checking the P bit in the I2C status register also do this?
Code: |
#word I2C2STAT = getenv("SFR:I2C2STAT")
#bit P = I2C2STAT.4 // bit 4 - stop
void SDAisr()
{
if (P == 1)
{
mode = RX_COMPLETE;
}
}
|
I'll have to see what the impact is of generating an interrupt on every SDA low/high transition.
I was doing some testing using a delay_us() inside the ISR (yeah, I know) but looking at I2C captures, sometimes the stop bit is 1us later, sometimes it is 6us later... and with bytes coming in 7us apart I don't think this approach is good. I could be polling inside the ISR and miss the next byte, perhaps, if it comes sooner. (Though I expect the one-byte buffer would hold the byte and the ISR would be called as soon as I return from the previous ISR, but I haven't checked.) _________________ 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: 19516
|
|
Posted: Fri Nov 13, 2020 12:15 pm |
|
|
The problem is you specified 'inside the interrupt'.
The bit saying a stop bit has been seen is set, but is cleared when anything
else happens on the I2C bus. When you arrive in the I2C interrupt a
byte has been received or a write requested, and this event clears the
bit saying a stop has been seen.
Because your chip doesn't support interrupt on start/stop, you won't get
to the interrupt with this bit set. |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Wed Nov 25, 2020 2:01 pm |
|
|
Ttelmah wrote: | The problem is you specified 'inside the interrupt'.
The bit saying a stop bit has been seen is set, but is cleared when anything
else happens on the I2C bus. When you arrive in the I2C interrupt a
byte has been received or a write requested, and this event clears the
bit saying a stop has been seen.
Because your chip doesn't support interrupt on start/stop, you won't get
to the interrupt with this bit set. |
The stop bit is cleared when "anything" else happens? The code I have that works on several PIC24 variants we use halts with this:
Code: |
// Wait for either a stop bit, or another incoming data byte.
while ((P == 0) && (I2C_SYSTEM_BUS_IRQ_PENDING_BIT == 0));
|
Today I started testing that inside an ISR (ugh, blocking for a bit) and it seems to work great, but one PIC variant is reporting the Stop bit too soon "sometimes" (maybe 1 out of 10 messages) though my I2C analyzer shows the stop bit is detected after all bytes from the Master. This particular chip had other issues in the errata dealing with missing bit status so I expect this may just be another chip bug. Which means I may not be able to do this on one of our boards. So much for common 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: 19516
|
|
Posted: Thu Nov 26, 2020 1:42 am |
|
|
The point is when interrupts occur for your chip:
Code: |
event interrupt P S D
start No 0 1 0
Address Yes 0 1 0
Data Yes 0 1 1
Last data Yes 0 1 1
Stop No 1 0 0
|
The point is you won't get an interrupt when stop occurs. The last interrupt
will be on the last data byte arriving, which is before the stop occurs.
The next interrupt will be on the address byte being received, at which point
there has been a start event, so the stop bit will have turned off. With
chips that don't support interrupt on start/stop, You should never
arrive in the interrupt, with the stop bit set.... |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Sun Nov 29, 2020 12:36 am |
|
|
Ttelmah wrote: | With
chips that don't support interrupt on start/stop, You should never
arrive in the interrupt, with the stop bit set.... |
Agreed, and reality matches.
The puzzling thing now is this particular chip flagging a stop bit before the last few data bytes are actually received. I’ll have to check, but other PIC24s I work with have only a single byte (TBF/RBF for it) so I don’t think it’s seeing a stop bit but hasn’t processed other characters yet. _________________ 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: 19516
|
|
Posted: Sun Nov 29, 2020 1:44 am |
|
|
Did you look at my reply in the other thread about this?.
I suspect a combination of two things. Possibly this particular chip has a
slightly higher Vih than the other devices you have (tolerance), and/or
the bus rise time is actually out of spec. Either of these could cause
incorrect detection of a stop, and the latter could easily affect only
one device, depending on the topology.
Try with the bus voltages set to SMBUS in the #use I2C, and look at
the rising edges of the bus. Are they <1uSec (if this is a slow I2C bus)
or <300nSec (for a fast bus). If not you need to look at reducing the
pull up resistors used. Remember that for a 3.3v I2C bus the resistors can
be as small as just under 1KR. |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Mon Nov 30, 2020 5:30 pm |
|
|
Ttelmah wrote: | Did you look at my reply in the other thread about this?.
I suspect a combination of two things. Possibly this particular chip has a
slightly higher Vih than the other devices you have (tolerance), and/or
the bus rise time is actually out of spec. Either of these could cause
incorrect detection of a stop, and the latter could easily affect only
one device, depending on the topology.
Try with the bus voltages set to SMBUS in the #use I2C, and look at
the rising edges of the bus. Are they <1uSec (if this is a slow I2C bus)
or <300nSec (for a fast bus). If not you need to look at reducing the
pull up resistors used. Remember that for a 3.3v I2C bus the resistors can
be as small as just under 1KR. |
Yes, I have passed it along to the hardware designers to see what they think. Thanks. The system has been in use the past few years, but running at 400 instead of 1000 speed. Removing the timing delays and making use of clock stretch has revealed various issues I have been working with. _________________ 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: 19516
|
|
Posted: Tue Dec 01, 2020 2:10 am |
|
|
Slightly 'worried' by your speed remarks.
Are you trying to run I2C in fast mode+ (over 400Kbps)?.
If so, you do realise that Fast Mode*+ (over 400K), and high speed mode
(over 1Mbps) _both require_ active (current source) pull-ups?. Not
just simple resistors. The drivers on your PIC are not rated to run in fast
mode+.
You can actually 'do it', by adding an external active bus transceiver, but
not using the standard PIC transceivers.
The data sheet is carefully ambiguous about this, saying that the device
supports 100K and 400K bus specifications, but showing the clock being
setup for rates up to 1MHz. If you can meet the rise time requirements,
you can actually run at the higher rates, but not with a long bus. |
|
|
|
|
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
|