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 support@ccsinfo.com

PIC24FJ64GA004 - detecting I2C stop bit (P) inside an ISR
Goto page Previous  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: 537
Location: Des Moines, Iowa, USA

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

PostPosted: Tue Dec 01, 2020 2:46 pm     Reply with quote

Ttelmah wrote:
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?.


I am having the hardware designer take a look at this. Since we designed it for this speed and it’s been in use for years before it was slowed down last year for problems that don’t seem to be related to the speed, I hope they hardware folks got it implemented correct. Out system uses five custom designed PIC24 boards and it’s the primary chipset they use here.
_________________
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

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

PostPosted: Tue Dec 01, 2020 6:45 pm     Reply with quote

Should I be able to read the P (stop bit) from inside an ISR?

Doing some testing (polling on P) never sees the P set to 1. Something like this "should" work (and works in my bootloader code) unless something about the ISR is an issue:

Code:

#word I2C2STAT = getenv("SFR:I2C2STAT")
#bit P = I2C2STAT.4                 // bit 4 - stop

#word IFS3 = getenv("SFR:IFS3")
#bit I2C_SYSTEM_BUS_IRQ_PENDING_BIT = IFS3.1    // bit 1 - slave I2C2 IRQ status

...

        // Wait for either a stop bit, or another incoming data byte.
        while ((P == 0) && (I2C_SYSTEM_BUS_IRQ_PENDING_BIT == 0));

        if (P != 0)
        {
            messageReceivedFlag = TRUE;
        }


I do see the I2C interrupt bit set (after I manually clear it before polling it) but I never see the P.

This PIC24 has issues where the first S start bit and interrupt are not seen, always losing the first message on the wire (workaround described in the errata document) so I do wonder if I am running in to another issue. Someone told me this was a 10+ year old part (?).
_________________
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: 19215

View user's profile Send private message

PostPosted: Wed Dec 02, 2020 2:42 am     Reply with quote

As I have already said multiple time, no.
The point is you only arrive in the interrupt after a byte is received. Your
last byte received in the packet, is _before_ the stop bit is received, so the
P bit is not set. The first byte of the next packet is received after the
start bit is sent, so the P bit is turned off, and instead you have the flag
saying a start bit has been received. Since in I2C, you can never send
STOP, DATA, DATA,,,,, You should never arrive in the 'data'
interrupt (which the I2C interrupt is on this chip), with the stop flag set.
Ttelmah



Joined: 11 Mar 2010
Posts: 19215

View user's profile Send private message

PostPosted: Wed Dec 02, 2020 8:32 am     Reply with quote

Actually almost 13 years old. However still deemed 'current'.
The more modern replacement, is the PIC33EP64GS804.
That does have the PCIE bit.
allenhuffman



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

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

PostPosted: Wed Dec 02, 2020 10:01 am     Reply with quote

Ttelmah wrote:
As I have already said multiple time, no.
The point is you only arrive in the interrupt after a byte is received. Your
last byte received in the packet, is _before_ the stop bit is received, so the
P bit is not set. The first byte of the next packet is received after the
start bit is sent, so the P bit is turned off, and instead you have the flag
saying a start bit has been received. Since in I2C, you can never send
STOP, DATA, DATA,,,,, You should never arrive in the 'data'
interrupt (which the I2C interrupt is on this chip), with the stop flag set.


Understood.

But I am in the ISR from a data byte, then polling looking for the P bit. I never see it on this PIC. Basically, something like this:

Code:

...inside the I2C ISR...

    else if (state > TRANSMIT_I2C)
    {
        // Send the data in the TX buffer to the master.

        int byteToSend;
        if (slaveIndexTX < txMsgDataSlave.numBytes)
        {
            byteToSend = txSlaveBuffer[slaveIndexTX++];
        }
        else
        {
            // Pad extra bytes if the master reads more than we are writing.
            // This can happen if we are NAKing something and the master
            // expects a longer message back.
            byteToSend = 0xff;
        }
        i2c_write (SYSTEM_BUS, byteToSend);

        // HACK ==============================================================
        // Wait for either a stop bit, or another incoming data byte.
        while ((P == 0) && (I2C_SYSTEM_BUS_IRQ_PENDING_BIT == 0));

        if (P != 0)
        {
            runTimeVariables.msgStatus = TX_MESSAGE_SENT;
        }
    }


Above, I can block at the while() and when the next byte comes in, it releases, then the ISR gets called again to process the pending byte. But I never see the P at the end of the message.

This morning I am doing the same test on a different PIC variant. I have my bootloader I2C polled code working on this chip, so the P works that way.
_________________
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: 19215

View user's profile Send private message

PostPosted: Wed Dec 02, 2020 10:49 am     Reply with quote

OK. So does the master NACK the last byte it wants, and then send
stop?.
Point is that there won't be another data transmission request after
the NACKED byte.
You can just test the ACK status to detect this for the end of packet.
allenhuffman



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

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

PostPosted: Wed Dec 02, 2020 11:00 am     Reply with quote

Yes, an I2C capture shows the last bye NACK'd then the stop bit shortly after. But the P bit never flips from 0 inside the ISR, apparently.

I am now testing on a 24EP256GP202 but having unrelated issues with the debugger not showing console output reliable. Fun day.
_________________
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

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

PostPosted: Wed Dec 02, 2020 1:04 pm     Reply with quote

I tried this on a different PIC24 variant and it isn't working there, either, so I guess I can't stick around in an ISR looking for the P bit to be set (at least not the way I am trying to do it).

I can disable the interrupt and do a brute force bit of code in my main loop and that works.

I didn't see anything in the datasheet to say there was anything special about looking for the P bit in regards to interrupts, but perhaps there is some masking that goes on that impacts that bit being set.
_________________
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: 19215

View user's profile Send private message

PostPosted: Wed Dec 02, 2020 1:21 pm     Reply with quote

One suggestion.
Set your ISR to NOCLEAR, and clear the interrupt bit yourself immediately
after you have read I2C_ISR_STATE.
It may be that the presence of the non cleared interrupt bit masks off the
stop bit detection.
Would actually make sense, since the assumption is that this will only
be used outside the ISR.

Hionestly if polling for the bit like this, add a counter and exit when this
reaches some value. Otherwise you are asking for the bus to get hung
is a bit is missed....
allenhuffman



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

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

PostPosted: Wed Dec 02, 2020 2:43 pm     Reply with quote

Ttelmah wrote:
One suggestion.
Set your ISR to NOCLEAR, and clear the interrupt bit yourself immediately
after you have read I2C_ISR_STATE.
It may be that the presence of the non cleared interrupt bit masks off the
stop bit detection.
Would actually make sense, since the assumption is that this will only
be used outside the ISR.


Perfect timing. I was reading the Help file last night and saw NOCLEAR and had that on my list. I have to manually clear the bit before I can detect the next one inside the ISR anyway, so I will give that a shot.

Ttelmah wrote:
One suggestion.
Hionestly if polling for the bit like this, add a counter and exit when this
reaches some value. Otherwise you are asking for the bus to get hung
is a bit is missed....


Yeah, I have some "i2c is stuck" code but that's only useful if it's a case where comm gets out-of-sync and the Master is reading more than what the firmware has to reply.

I went down the "I2C bus reset" rabbit hole a year ago, seeing it mentioned and documented with ways to un-stick the lines. But, sadly, FTDI provides no way to do this from their Windows driver/API so we could never implement it :(
_________________
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

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

PostPosted: Wed Dec 02, 2020 2:58 pm     Reply with quote

Ttelmah wrote:
One suggestion.
Set your ISR to NOCLEAR, and clear the interrupt bit yourself immediately
after you have read I2C_ISR_STATE.
It may be that the presence of the non cleared interrupt bit masks off the
stop bit detection.
Would actually make sense, since the assumption is that this will only
be used outside the ISR.


This does appear to work! Thanks for the nudge! I'll do some testing, but I am finally seeing my "P" code running.
_________________
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: 19215

View user's profile Send private message

PostPosted: Thu Dec 03, 2020 2:02 am     Reply with quote

Good. Smile

I2C has two possible 'stuck' states. The first is when the SDA line stops
responding. The clear for this is for the master to send 9 or more clock pulses
until SDA goes high. The second is when a slave holds SCL low. The reset
for this is to reset the slave device(s). However you can also implement a
default bus timeout as SMBUS does. With the slave devices starting a timer
when the 'start' is seen, resetting it for every received byte, and if it times
out, resetting the I2C peripheral. The minimum for this should be 10mSec
and a value like 50mSec s a very nice safe figure. This ensures the slaves
can't remain stuck holding SCL low.

As a comment, if you are making INT_I2C 'hang' waiting for the P bit
in the interrupt, I'd probably suggest you enable nested interrupts, and
set this to a priority below the other interrupt handlers, otherwise you
risk this interfering with these.....
allenhuffman



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

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

PostPosted: Thu Dec 03, 2020 9:26 am     Reply with quote

Ttelmah wrote:

As a comment, if you are making INT_I2C 'hang' waiting for the P bit
in the interrupt, I'd probably suggest you enable nested interrupts, and
set this to a priority below the other interrupt handlers, otherwise you
risk this interfering with these.....


Always a good idea to me. "Program as if someone's life depended on it" is my motto. (https://subethasoftware.com/2020/01/16/code-as-if-someones-life-depended-on-it/).

But we always inherit code that was written assuming success, instead of failure. I've been coding since 1982, and I'm still not confident anything I write is going to work 100% of the time ;-)

The PIC firmware I work on doesn't make use of the watchdog timer, either, which I want to add. That, along with a bootloader (so you can always recover in case of a bricked update process) will go a long way to taking care of unexpected issues.
_________________
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

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

PostPosted: Fri Dec 04, 2020 11:32 am     Reply with quote

Ttelmah wrote:
Set your ISR to NOCLEAR, and clear the interrupt bit yourself immediately after you have read I2C_ISR_STATE.


The alpha software for the Salea logic analyzer is awesome. It scrolls the data realtime.

I have a situation where the Master (PC using FTDI chipset and drivers) tries to write to a PIC24FJ64GA002 device. This PIC operates as a Slave, but also runs as Master for a sub-bus to talk to other PIC24 devices (multiplexer).

I see the Master does a write to 0x6e (the MUX address) and it is ACK's. The PIC must have seen it.

Then, all following bytes are NAK'd.

After the message, the Master tries to Read a response (it should not, but apparently there is either a bug in the Master code or no error is being returned from the FTDI drivers) and the bus locks (slave side).

In my PIC ISR, I turn on an LED before any read or write, and then turn it off at the stop bit. That LED is never on, which makes it look like my ISR was never called:

(Note: this code includes an infinite while loop with the emergency escape code removes so I can use a satus LED to see if it ever hangs while debugging.)

Code:

#word I2C2STAT = getenv("SFR:I2C2STAT")
#bit P = I2C2STAT.4                 // bit 4 - stop

#word IFS3 = getenv("SFR:IFS3")
#bit I2C_SYSTEM_BUS_IRQ_PENDING_BIT = IFS3.1    // bit 1 - slave I2C2 IRQ status


#INT_SI2C2 NOCLEAR LEVEL=7

void  si2c2_isr (void)
{
    int state = i2c_isr_state (SYSTEM_BUS);

    I2C_SYSTEM_BUS_IRQ_PENDING_BIT = 0; // NOCLEAR, so we manually clear.

    if (state == RECEIVE_I2C)
    {
        slaveIndexRX = ZERO;

        LED_SystemOn ();

        // Get a byte of data which is the address of the board.
        boardAddress = i2c_read (SYSTEM_BUS);
    }
...etc...


For some reason, my code never ran this to read the address byte. I am investigating places where interrupts are masked.

Since the LED is off at this point, that means the previous message went through fine, since I clear at the end of a message when the stop bit is seen:

Code:

...snip...
    // Receives a message from the master.
    else if (state > RECEIVE_I2C)
    {
        // Store the message in the RX buffer.
        rxSlaveBuffer[slaveIndexRX++] = i2c_read (SYSTEM_BUS);

        // Wait for either a stop bit, or another incoming data byte.
        while ((I2C_SYSTEM_BUS_IRQ_PENDING_BIT == 0) && (P == 0));

        if (P != 0) // I2C Stop bit seen.
        {
            LED_SystemOff ();

            rxMsgDataSlave.numBytes = slaveIndexRX; // Update numBytes.

            // Message is only received when expected bytes have come in.
            runTimeVariables.msgStatus = RX_MESSAGE_VERIFY;
        }
    }
    else
    {
        //Do nothing.
    }


That tells me it got past while and shut the LED off, but something happens before the next message and the ISR seemingly is not called.

Can i2c_isr_state() ever block?
_________________
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: 19215

View user's profile Send private message

PostPosted: Fri Dec 04, 2020 11:44 am     Reply with quote

Er. Level=7, is the highest priority. Not what is wanted.....
Level=1.
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 Previous  1, 2, 3  Next
Page 2 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