SAMD20 I2C Slave Bug

Aug 11th 2020

This bug may also be in the SAMD21 and SAML21 parts as the SERCOM peripheral is very similar between them. 

This problem appears when the SAMD20 was used an I2C slave on a noisy bus.. 

The problem appears when the master starts transmitting data, all is going well until the R/W bit at which point noise on the clock causes the SAMD20 to see a clock pulse.  At this point the address is clocked into the SAMD20 peripheral and it issues the Address Match interrupt.  During this interrupt the SCL line is held low in clock stretching mode.  The master however tries to release the SCL line and generates a bus fault and gives up (blue above).  The SAMD20 in slave mode however then goes through it's interrupt handler determines the address is a good match and drives the SDA line low for an ACK and releases the clock stretching on the SCL and waits for the low pulse on the SCL, and waits, and waits....  

The problem is that the SAMD20 has no time out capabilities on the  I2C peripheral so it will wait forever for the master.  The master mean while might realize that the SDA line is held low and keep spitting out bus faults..  Hopefully at this point the master can reboot the SAMD20 to get it working again.

This problem in the SAMD20 I2C peripheral is bad, that is there is nothing in the peripheral that can be done to detect this problem and recover.  

Note at this point you might look at the SAMD20 datasheet and say "Surely this condition causes the error interrupt to be triggered."

So you go and enable the error interrupt.... and ... what the heck....

That is right the peripheral does not have an error interrupt... thank you microchip for saying it does and then revoking that... 

So how do fix this problem? 

Well the only way we have come up with is that when we get an address match interrupt we have to start a timer. If the timer expires before we get data then we must reset the I2C peripheral and assume the bus is locked up. 

Note if you have used Microchip (Atmel's) parts for sometime you know the frustrations we have with the datasheets and how they provide conflicting information.  As I like to say half of the time it is wrong, the other half of the time it is really bad. 

So how could Microchip fix this, well first off get the datasheet correct. Second is the state machine for the I2C needs a time out counter which when it expires will generate an interrupt. Then you can create a handler to reset the I2C peripheral in that interrupt handler. 

Note as far as the I2C slave locking up, this apparently is common with I2C peripherals, a common fix is for the master to detect this lockup and then send 9 SCL clock pulses, which in theory should reset the slave.  From the I@C spec:

"If the data line (SDA) is stuck LOW, the master should send nine clock pulses. The device
that held the bus LOW should release it sometime within those nine clocks. If not, then
use the HW reset or cycle power to clear the bus."