I am using the SSP in I2C mode on the 16C76(A). I have two PICs and
an EEPROM on the bus. I have it working for the normal cases, but
I'm trying to head off Murphy by checking for and handling I2C bus
The Master, since its in firmware, is easy to control. If I abort a
transfer, I NAK the current byte, then send a STOP (subject to clock
stretching by the slaves).
The PIC that is a slave is implemented using the SSP. If the slave
gets out out of synch, here's what happens:
When the master gets the last byte it wants, it doesn't ACK the last
byte. SSP signals byte complete by dropping BF, but there is no way
to tell that the Master NAKed. SSP is "done", sees STOP and goes
to START-hunt mode. If Murphy told me there was one more byte, I
then load it to the SSPBUF and it never goes out (since the SSP is
not in slave transmit mode anymore). So my transmit routine is hung.
If I time out, I want to re-set the SSP to start-hunt mode. But if I
reset SSPCON to 0, then back to its correct setup, the SSP is NOT
reset. Is there any way to tell what mode the SSP is IN? Is there a
way to re-set it?
Second (more likely?) scenario: I send what I thought was the last
byte to the master. He ACKs it, asking for more. I can't tell
ACK from NACK in slave transmit mode, but the SSP can. Silly
me, I thought I was done and never write anything to the SSPBUF. So
the SSP is holding SCL low (clock stretching) forever! Since I have
SCL low, the Master can't send a STOP. Again, If I could tell the
SSP was in Slave transmit mode, I might be able to detect this
condition. When I cause this fault on the emulator, I can clear the
bus by resetting the SSPCON to 0x00. But as soon as I program the
SSP active again, it goes right back to the same state! Am I missing
NRG Systems "Measuring the Wind's Energy" spam_OUTbarryTakeThisOuTnrgsystems.com
"The witty saying has been deleted due to limited EPROM space"
> When the master gets the last byte it wants,
> it doesn't ACK the last byte.
Very naughty of course.
I had the PIC lock up when naughty masters failed to do this.
My PIC I2C slave software is interrupt driven.
Anyway, the SSP hardware thinks - completely reasonably -
that the master will be wanting another byte, and expects
the PIC to give it one. The PIC may not know what to do
after the last byte of the agreed I2C message format.
Can't continue unless the SSP gets given a byte so
give it a dummy.
In the meantime, the master has done a STOP and effectively
The system locks because the SSP has a byte that the master
has not read. The CPU can detect this condition by various
flags (overflow I think), but can't get out of it.
After eventually getting passed to microchip's wafer fab,
I queried them about this. Eventually I said "lets get this straight,
you've provided hardware flags that tell you when the chip gets
into a stuck condition but never bothered to think of a way
to get out of it??!!". To which I got an embarrased "yes".
I managed to get round the problem of masters not NACKing the final
by loading a dummy byte in the SSP. The first (MS) bit gets put on the
straight away. If this is zero, this locks SDA low and thus screws the
The dummy byte has to be >= 128. So I send 0xFF. SDA := 1,
but this doesn't stop the bus STOP condition.
I expect bus lock will still happen if you did an early illegal
termination in the middle of a valid message. i.e. the SSP
had started transmitting a valid byte with D7 == 0.
> Second (more likely?) scenario:
> I send what I thought was the last byte to the master.
> He ACKs it, asking for more.
> I can't tell ACK from NACK in slave transmit mode,
Ah but you can. The R/W flag is maldocumented.
It is equal to the R/W bit BUT ONLY FOR THE ADDRESS BYTE.
Which is why you have to copy it somewhere safe to read
when you deal with the DATA bytes.
When dealing with DATA bytes, the "R/W" flag is actually
the ACK/NACK from the transfer. I'd wondered how to read
that, so I knew whether to send more data or not.
That was also the cause of a long and justly annoyed
phone call with Microchip.
> When I cause this fault on the emulator,
> I can clear the bus by resetting the SSPCON to 0x00.
> But as soon as I program the SSP active again,
> it goes right back to the same state!
> Am I missing something?
Been there, done that. I suspect it is the emulators
way of telling you that it tried to do it but the
hardware isn't co-operating.
Microchip are quite good at choosing useful peripherals
(I2C, PSP) but unfortunately not very good at
designing them properly or documenting them.
The SSP is not Murphy proof.
Make sure your watchdog is enabled,
and that you don't design PIC I2C into life-support!
Thanks very much for the detailed help. I did not know about the R/W
flag, that will help.
By the way, it is NOT naughty of the master to NACK the last byte of a
device read, its the normal termination sequence. The NACKed byte is
how the slave knows the transfer is done.
If I can see the Master's ACK bit, I can detect the case where the
Master wants more bytes than the slave "thought". If the Master ACKs
when the slave thought it sent the last byte, I can send dummy 0xFF
bytes to him until he NACKs one. Then I know I'm done, and at least
the Bus is not locked.
Conversely, if he NAKs a byte in the middle of a message, I'm also
done. (He IS the master, after all...)
But I guess I will have to fall back on the Watchdog timers to clear
a really buggered I2C transfer where the bus is locked up.
NRG Systems "Measuring the Wind's Energy" .....barryKILLspam@email@example.com
"The witty saying has been deleted due to limited EPROM space"
> I did not know about the R/W flag, that will help.
Only for remembering the message direction between interrupts.
Knowing that it indicates ACK/NACK is not so useful,
because by the time you read it the SSP hardware has
already used that bit to decide whether it needs to
interrupt the CPU to ask for another outgoing byte.
> it is NOT naughty of the master to NACK the last byte
> of a device read, its the normal termination sequence.
True. I didn't read your post carefully enough.
I thought you said " it doesn't NACK the last byte"
which is the condition that caused problems here.
> If I can see the Master's ACK bit, I can detect
> when the Master wants more bytes than the slave "thought".
You don't have to check that bit.
Being interrupt driven, my PIC keeps a count of the data bytes
it sends so it can return the appropriate one from an array.
If the SSP asks for a byte, and all expected ones have been sent,
it sends a dummy byte to SSPBUF.
> Watchdog timers
Yep, if Microchip had designed the SSP properly it would have
a way of getting it out of lockup from software.
Haiku of the day:
Like panning for gold,
I seek grains of perfection,
in river of dung.