Searching \ for '[PIC]: Problem with S bit in SSPSTAT in I2C slave' in subject line. ()
Make payments with PayPal - it's fast, free and secure! Help us get a faster server
FAQ page: techref.massmind.org/techref/i2cs.htm?key=i2c
Search entire site for: 'Problem with S bit in SSPSTAT in I2C slave'.

Exact match. Not showing close matches.
PICList Thread
'[PIC]: Problem with S bit in SSPSTAT in I2C slave '
2006\01\18@103301 by Ian Chapman

flavicon
picon face
I'm running a PIC16F818 as an I2C bus slave (100 kHz mode) and I have
encountered a problem which appears to be an oddity of the SSP module.
I'd be interested to hear whether anyone else has come across this and
whether the workaround that I'm proposing below is valid.

I'm using an SSP interrupt handler based on AN734 (but with the missing
"bsf SSPCON,CKP" in the State 5 routine) that I have previously used in
another application without any apparent problems.

The problem is that, after a write of a single data byte to the slave
(State 2 in AN734), the S bit in SSPSTAT always reads as zero instead of
one.  The other SSPSTAT bits are as expected (D/A = 1, R/W = 0, BF = 1).

There is no such problem with the prior write of the address byte (State
1 in AN734) which returns S = 1, D/A = 0, R/W = 0, BF = 1 as expected.

I've checked the I2C bus lines with an oscilloscope and a logic analyser
and they appear to behave as expected and in accordance with the timings
in the I2C specification.  The main difference compared to my previous
application is that the bus runs about 50% faster (about 90 kHz instead
of 60 kHz) but still meets the 100 kHz spec by a safe margin.

My original application treats the S=0 condition as an error: it rejects
the incoming data and attempts to reset the SSP module.  I have added a
workaround to ignore the S bit in the comparison for State 2, and the I2C
writes appear to work fine now.  I'm happy about that, but I don't like
to rely on this without a better understanding of what's going on.

I'm also wondering whether to ignore the state of the S bit in other
states (or all states) as an added precaution, but I'm concerned that
this opens up a greater possibility of the slave misinterpreting an
unexpected bus condition as valid data.  Any views on this?

I'll be carrying out some more tests on Friday (including I2C reads from
the slave) so if anyone can suggest any worthwhile experiments then I'll
try to include them.  It occurs to me that my interrupt handler currently
clears the SSPIF flag before reading SSPSTAT, so I'll try reversing this
order to check whether the clearing of SSPIF in this state somehow resets
the S bit (unlikely, surely?).

Many thanks in advance for any suggestions.
--
Ian Chapman
Chapmip Technology, UK

2006\01\18@110748 by olin piclist

face picon face
Ian Chapman wrote:
> I'm running a PIC16F818 as an I2C bus slave (100 kHz mode) and I have
> encountered a problem which appears to be an oddity of the SSP module.
> I'd be interested to hear whether anyone else has come across this and
> whether the workaround that I'm proposing below is valid.
>
> I'm using an SSP interrupt handler based on AN734 (but with the missing
> "bsf SSPCON,CKP" in the State 5 routine)

You will probably get more responses if those helping you don't need to look
up some app note.  Besides, it doesn't matter how you arrived at your code,
only what it is now and what it is doing.  And no, I don't remember off the
top of my head what exactly the S bit is either.

So explain what you are doing, show the relevant code snippets, and describe
the symptoms.  There are some gotchas in the MSSP, but I can't comment
because I don't understand what you are doing from a simple read of your
message.


******************************************************************
Embed Inc, Littleton Massachusetts, (978) 742-9014.  #1 PIC
consultant in 2004 program year.  http://www.embedinc.com/products

2006\01\18@113113 by Michael Rigby-Jones

picon face
>-----Original Message-----
>From: spam_OUTpiclist-bouncesTakeThisOuTspammit.edu [.....piclist-bouncesKILLspamspam@spam@mit.edu]
>Sent: 18 January 2006 15:33
>To: piclistspamKILLspammit.edu
>Subject: [PIC]: Problem with S bit in SSPSTAT in I2C slave
>mode on PIC16F818
>
>
>I'm also wondering whether to ignore the state of the S bit in
>other states (or all states) as an added precaution, but I'm
>concerned that this opens up a greater possibility of the
>slave misinterpreting an unexpected bus condition as valid
>data.  Any views on this?


A start bit is a start bit, whether it was accidently or purposely generated the PIC cannot tell.  For any given I2C bus transaction, the MSSP will only generate an interrupt if it has seen a start bit followed by the correct slave address.  By using a simple state machine to keep track of the transaction from this point, you always know how to respond to the next interrupt.  The state machine is reset to the first state by the D/A bit indicating a valid slave address has just been received. The following is chopped out of an old project, and a lot of fluff removed so please pardon any silly typos (and obviously it's error handling may not be suitable for your application).

Regards

Mike

#define MSSP_DA_DATA 1
#define MSSP_DA_ADDRESS 0
#define MSSP_RW_READ  1
#define MSSP_RW_WRITE 0

enum {
 I2C_ADDRESS_IN,
 I2C_DATA_IN,
 I2C_DATA_OUT,
 I2C_DATA_DISCARD,
 I2C_DUMMY_OUT
};

/* ISR starts here */

if( SSPIE && SSPIF ) {

 /* have we just received a valid slave address? */
 if( DA == MSSP_DA_ADDRESS ) {
   /* reset I2C state */
   I2cState = I2C_ADDRESS_IN;
 }

 switch (I2cState) {
   case I2C_ADDRESS_IN:
     /* first clear the buffer */
     temp = SSPBUF;
       
     /* check what the master wants to do */
     if( RW == MSSP_RW_READ ) {
       /* master wants to read data so get byte from
          circular buffer and write it to SSPBUF */
       if( GetTxData( &SSPBUF ) == 0 ) {
         /* oops, nothing to send */
         I2cState = I2C_DUMMY_OUT;
         /* put 0xFF into SSPBUF to prevent SDA getting stuck low */
         SSPBUF = 0xFF;
       } else {
         I2cState = I2C_DATA_OUT;
       }
       /* release SCL */
       CKP = 1;

     } else {
       /* master wants to write data */
       I2cState = I2C_DATA_IN;
       /* release SCL */
       CKP = 1;
       }
       break;
 
   case I2C_DATA_IN:
     /* check SSPBUFF has valid data */
     if( BF ) {
       /* try to put data into RX circular buffer */
       if( PutRxData( SSPBUFF ) == 0 ) {
         /* oh dear, an overflow. Ignore rest of incomming data */
         I2cState = I2C_DATA_DISCARD;
       }
       /* release SCL */
       CKP = 1;
     }
     break;

   case I2C_DATA_OUT:
     /* Ensure buffer is empty and SCL is disabled */
     if ( !BF && !CKP ) {
       if( GetTxData( &SSPBUF ) == 0 ) {
         /* oops, nothing to send */
         I2cState = I2C_DUMMY_OUT;
         /* put 0xFF into SSPBUF to prevent SDA getting stuck low */
         SSPBUF = 0xFF;
       } else {
         I2cState = I2C_DATA_OUT;
       }
       /* release SCL */
       CKP = 1;
     }
     break;

   case I2C_DATA_DISCARD:
     /* just read SSPBUF to clear the interrupt flag and discard data */
     temp = SSPBUF;
     /* release SCL */
     CKP = 1;
     break;

   case I2C_DUMMY_OUT:
     /* Ensure buffer is empty and SCL is disabled */
     if ( !BF && !CKP ) {
       /* put 0xFF into SSPBUF to prevent SDA getting stuck low */
       SSPBUF = 0xFF;
       /* release SCL */
       CKP = 1;
     }
     break;

 }        /* switch (I2cState) */

} /* if( SSPIE && SSPIF ) */

=======================================================================
This e-mail is intended for the person it is addressed to only. The
information contained in it may be confidential and/or protected by
law. If you are not the intended recipient of this message, you must
not make any use of this information, or copy or show it to any
person. Please contact us immediately to tell us that you have
received this e-mail, and return the original to us. Any use,
forwarding, printing or copying of this message is strictly prohibited.
No part of this message can be considered a request for goods or
services.
=======================================================================

2006\01\18@121121 by Alan B. Pearce

face picon face
>I'm running a PIC16F818 as an I2C bus slave (100 kHz mode) and
>I have encountered a problem which appears to be an oddity of
>the SSP module. I'd be interested to hear whether anyone else
>has come across this and whether the workaround that I'm
>proposing below is valid.
>
>I'm using an SSP interrupt handler based on AN734 (but with the
>missing "bsf SSPCON,CKP" in the State 5 routine) that I have
>previously used in another application without any apparent problems.

I have used the same code on a 16F876, after modifying it to be an interrupt
routine.

>The problem is that, after a write of a single data byte to
>the slave (State 2 in AN734), the S bit in SSPSTAT always
>reads as zero instead of one.  The other SSPSTAT bits are
>as expected (D/A = 1, R/W = 0, BF = 1).

I take it you are looking at the SSPSTAT bits using an ICD?

>There is no such problem with the prior write of the address
>byte (State 1 in AN734) which returns S = 1, D/A = 0, R/W = 0,
>BF = 1 as expected.

Does the 16F818 data sheet give the same definition for the S bit as AN734
(page 3, I'm looking at DS00734A)?

2006\01\18@135638 by Ian Chapman

flavicon
picon face
Thanks, everyone.  I was starting to compose answers to your individual
questions when the answer suddenly dawned on me.  I think it's a timing
issue which isn't covered by the code in AN734, and which may appear in
some applications and not others.  My conclusion is that the workaround
that I suggested is a satisfactory solution.

I'll record my reasoning here in case it helps anyone in the future.  It
does assume some familiarity with the SSP module and AN734.

The PIC16F818 is running on its internal 4MHz clock.  With an interrupt
latency of up to 10 cycles in my foreground routine, it can take 10-20
microseconds to enter the interrupt service routine and save context
before SSPSTAT can be read.  By then, the I2C master may have already
sent its stop condition.  This clears the S bit before SSPSTAT is read,
causing the S bit to be read as a zero rather than a one.

Under these circumstances, I think it is appropriate to ignore the S bit
in SSPSTAT when comparing to states which can occur right at the end of
an I2C transaction.  In terms of AN734, these are State 2 (I2C write --
last byte was data byte), State 4 (I2C read -- last byte was data byte),
and State 5 (slave I2C logic reset by NACK from master).  It may also
apply to State 1 (I2C write -- last byte was address byte) if the master
polls for I2C devices by sending just an address byte followed by a stop
condition.

I assume that AN734 was developed on a PIC running at, say, 20MHz with
no foreground interrupt latency and, perhaps, a slower I2C bus speed, in
which case this timing issue would never occur.

Thanks for your individual responses.  I'll check them again in slower
time to see whether they've raised anything that I've missed.
--
Ian Chapman
Chapmip Technology, UK

2006\01\19@043945 by Alan B. Pearce

face picon face
>I assume that AN734 was developed on a PIC running at,
>say, 20MHz with no foreground interrupt latency and,
>perhaps, a slower I2C bus speed, in which case this
>timing issue would never occur.

I don't believe this. There must be something strange in your code.

I haven't gone digging in the code to check, but IIRC the I2C bus hangs up
until the receiving device releases the clock line to signal the ACK/NAK.
This is done in code on the PIC, so any interrupt latency just appears as a
delay in releasing the clock line. Hence the S bit should still show the
correct state until you release the clock line in the code.

I ran the code on a 16F876 at 3.6864MHz clock with absolutely no glitches
like you describe, so I have no reason to believe it was developed on a
faster chip, with the consequences you suggest.

2006\01\20@054353 by Ian Chapman

flavicon
picon face
Thanks, Alan.  You've made me think hard about this, but I'm still standing
by my earlier analysis.

Alan B. Pearce wrote:
>I haven't gone digging in the code to check, but IIRC the I2C bus hangs up
>until the receiving device releases the clock line to signal the ACK/NAK.

This might be true for devices with the new design of MSSP module that has
the ability to do clock stretching when the slave receives data.  However,
the data sheet for the PIC16F818 (see Figure 10-56 on page 78) indicates
that the SCL clock line is never held by the slave in this mode (indeed,
the state of the CKP bit that enables this to occur when data flows in the
opposite direction is not even shown in the timing diagram).

My understanding from this is that there is no mechanism in the PIC16F818
hardware for the slave to delay the master in sending a stop condition at
the end of a transmission.

>This is done in code on the PIC, so any interrupt latency just appears as a
>delay in releasing the clock line. Hence the S bit should still show the
>correct state until you release the clock line in the code.

I've done some tests with a logic analyser which show the stop condition
occurring before my interrupt service routine takes any actions affecting
the SSP module.  They also appear to confirm that the slave is not carrying
out any clock stretching during the transmission from the master.

My code drives a port pin low on entry to the ISR (immediately after saving
context) and before it carries out any actions on SSPSTAT, SSPIF etc.  The
logic analyser trace shows this bit going low 1-2 instruction cycles after
the stop condition on the I2C bus.  There seems to be no automatic action
taken by the slave to delay this stop condition.  Even taking into account
that the ISR was triggered before the stop condition (allowing for latency
and the cycles taken by my context save code before the port bit is driven
low), there is still no opportunity for my ISR to take any action to delay
this condition.

I guess another possibility is that the SSP module is supposed to latch the
state of the S bit so that it can be read as a one by the ISR even after a
stop condition has reset its real-time state to a zero.  However, I haven't
seen any reference to this in the data sheet and, even if it does occur, I
don't see how my code could cause the state of the latch to be lost.  The
only action that my ISR takes in relation to the SSP module before reading
SSPSTAT is to clear the SSPIF interrupt flag after checking that it is set.
I might try a quick test with the clear of SSPIF after the read of SSPSTAT,
but I don't expect it to make a difference.

>I ran the code on a 16F876 at 3.6864MHz clock with absolutely no glitches
>like you describe, so I have no reason to believe it was developed on a
>faster chip, with the consequences you suggest.

The possibility that occurs to me is that the results are different on the
PIC16F876 because it contains the MSSP module, rather than the SSP module
as in the PIC16F818.

I'm still open to the idea that I'm doing something wrong, but I don't see
from the evidence above how this can be the case.

Many thanks once again.
--
Ian Chapman
Chapmip Technology, UK

2006\01\20@054737 by Ian Chapman

flavicon
picon face
I wrote:
> ... the data sheet for the PIC16F818 (see Figure 10-56 on page 78) ...

Sorry -- that was a typo.  It should have referred to Figure 10-6.
--
Ian Chapman
Chapmip Technology, UK

2006\01\20@072035 by olin piclist

face picon face
Ian Chapman wrote:
> My understanding from this is that there is no mechanism in the
> PIC16F818 hardware for the slave to delay the master in sending a stop
> condition at the end of a transmission.

Right.  The basic MSSP in the PIC 16 only does clock stretching as slave on
a read, not on a write.  This unfortunately means there is no good way to do
flow control in one direction.

> My code drives a port pin low on entry to the ISR (immediately after
> saving context) and before it carries out any actions on SSPSTAT, SSPIF
> etc.  The logic analyser trace shows this bit going low 1-2 instruction
> cycles after the stop condition on the I2C bus.

OK, that means you're rather slow about getting into the interrupt, but why
is this an issue?

> There seems to be no
> automatic action taken by the slave to delay this stop condition.

Right, but why would you want to?

{Quote hidden}

It sounds like everything is working as intended.  What exactly is the
problem?  Can you describe it in plain english without references to an AN
or things that require looking in the manual like finding out what the "S"
bit is?


******************************************************************
Embed Inc, Littleton Massachusetts, (978) 742-9014.  #1 PIC
consultant in 2004 program year.  http://www.embedinc.com/products

2006\01\20@082417 by Ian Chapman

flavicon
picon face
Olin Lathrop wrote:
>OK, that means you're rather slow about getting into the interrupt, but why
>is this an issue?

It shouldn't be a problem, other than the need to cater for the possibility
within the SSP interrupt handler that the S bit in SSPSTAT has changed state
because the I2C transmission ended before SSPSTAT is read.

I've now added code to do this, and it seems to work fine.  My concern was
that the code in AN734 doesn't do this, and I've haven't read anything here
which suggests that other people who have successfully adopted that code
have run into this issue before.

>> There seems to be no
>> automatic action taken by the slave to delay this stop condition.
>
>Right, but why would you want to?

That was in answer to Alan Pearce's suggestion that the slave might stretch
the I2C clock during the ACK phase of a transmission from the master in
order to delay the stop condition until the interrupt has been serviced
(and therefore preserve the states of the S and P bits in SSPSTAT which
indicate, respectively, that a start or stop condition occurred last).

My tests indicate that this doesn't happen, though.  It's possible that the
behaviour of the MSSP module on the PIC16F876 that Alan used the code with
is different from the SSP module on the PIC16F818 that I'm using.

>It sounds like everything is working as intended.  What exactly is the
>problem?  Can you describe it in plain english without references to an AN
>or things that require looking in the manual like finding out what the "S"
>bit is?

OK.  I'm writing an interrupt service routine to enable a PIC16F818 to act
as an I2C bus slave.  The ISR doesn't retain its own state information but
assumes that the bits in SSPSTAT reflect the I2C state machine in the SSP
module.  AN734 from Microchip uses this approach and carries out a series of
comparisons on bits read from SSPSTAT to determine the current state and the
action to take.

In AN734, only five out of sixteen possible states of four bits in SSPSTAT
(S, BF, R/W and D/A) are considered valid -- the rest are shown as error
conditions for which an appropriate action is to reject/not send any data
and perhaps to reset the SSP module.  All of these five states include the
S=1 condition, which from the data sheet means that an I2C start condition
has occurred more recently than a stop condition.

My tests indicate that, if a stop condition occurs on the I2C bus before the
ISR reads SSPSTAT, then the S bit reads as a zero instead of a one.  This is
what I'd expect from reading the data sheet, but I'm surprised that the code
in AN734 doesn't take account of this possibility.  I'd imagine that others
who have tried to adopt the code in AN734 might encounter this problem and
reach the same conclusion -- hence my original question and the reason why I
focussed on AN734 (it was a bit garbled, though -- sorry!).

I've now run a series of tests using a logic analyser to observe the states
of the I2C bus lines, the timing of entry to my ISR, and the value read from
SSPSTAT (written to output pins before any of my other code gets a chance to
mangle it) and I've convinced myself that the way to solve the problem is to
accept the S=0 condition as well as the S=1 condition in three of the states
recognised as valid by my ISR.  This seems to work fine -- at least, for the
I2C bus states that occur while the master is behaving properly.

I hope this explanation is a bit clearer.

Thanks and all the best.
--
Ian Chapman
Chapmip Technology, UK

2006\01\20@102250 by olin piclist

face picon face
Ian Chapman wrote:
> The ISR doesn't retain its own state
> information but assumes that the bits in SSPSTAT reflect the I2C state
> machine in the SSP module.

Hmm, that may not work in all cases.  It certainly wouldn't be my first knee
jerk response to the problem.

> AN734 from Microchip uses this approach ...

This is totally irrelevant.  Remember rule #1: Microchip examples suck.
There is a lot of bad code out there, some of it from Microchip.  There is
no substitute for reading the data sheet and using your own brain to figure
out what to do.

> My tests indicate that, if a stop condition occurs on the I2C bus
> before the ISR reads SSPSTAT, then the S bit reads as a zero instead of
> a one.  This is what I'd expect from reading the data sheet, but I'm
> surprised that the code in AN734 doesn't take account of this
> possibility.

I'm not.  See rule #1.

> I'd imagine that others who have tried to adopt the code
> in AN734 might encounter this problem and reach the same conclusion

Quite possibly not.  Most people know not to do that in the first place.
The remaining few who copy code from Microchip app notes are mostly clueless
and aren't capable of the analisys you went thru.  Their stuff may only
sortof work or they get frustrated and give up.

> hence my original question and the reason why I focussed on AN734

Hopefully you have now learned rule #1.


******************************************************************
Embed Inc, Littleton Massachusetts, (978) 742-9014.  #1 PIC
consultant in 2004 program year.  http://www.embedinc.com/products

More... (looser matching)
- Last day of these posts
- In 2006 , 2007 only
- Today
- New search...