CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

PIC24FJ64GA004 - detecting I2C stop bit (P) inside an ISR
Goto page 1, 2, 3  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
allenhuffman



Joined: 17 Jun 2019
Posts: 540
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PIC24FJ64GA004 - detecting I2C stop bit (P) inside an ISR
PostPosted: Fri Oct 30, 2020 1:24 pm     Reply with quote

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: 19480

View user's profile Send private message

PostPosted: Fri Oct 30, 2020 1:51 pm     Reply with quote

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: 540
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Fri Oct 30, 2020 2:11 pm     Reply with quote

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: 1611
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Fri Oct 30, 2020 2:59 pm     Reply with quote

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: 19480

View user's profile Send private message

PostPosted: Sat Oct 31, 2020 1:07 am     Reply with quote

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: 1634
Location: Perth, Australia

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Thu Nov 05, 2020 7:28 pm     Reply with quote

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: 540
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Fri Nov 13, 2020 11:07 am     Reply with quote

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: 540
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Fri Nov 13, 2020 11:14 am     Reply with quote

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: 19480

View user's profile Send private message

PostPosted: Fri Nov 13, 2020 12:15 pm     Reply with quote

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: 540
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Wed Nov 25, 2020 2:01 pm     Reply with quote

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 Smile
_________________
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: 19480

View user's profile Send private message

PostPosted: Thu Nov 26, 2020 1:42 am     Reply with quote

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: 540
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Sun Nov 29, 2020 12:36 am     Reply with quote

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: 19480

View user's profile Send private message

PostPosted: Sun Nov 29, 2020 1:44 am     Reply with quote

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: 540
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Mon Nov 30, 2020 5:30 pm     Reply with quote

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: 19480

View user's profile Send private message

PostPosted: Tue Dec 01, 2020 2:10 am     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2, 3  Next
Page 1 of 3

 
Jump to:  
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