cancel
Showing results for 
Search instead for 
Did you mean: 

How and when is a I2C slave supposed to tell the master "bad request"?

SKled.1
Senior II

Implementing a I2C in slave mode, I found in the reference manual,

26.7.2 Control register 2 (I2C_CR2):

Bit 15 NACK: NACK generation (slave mode)

The bit is set by software, cleared by hardware when the NACK is sent, or when a STOP

condition or an Address matched is received, or when PE=0.

0: an ACK is sent after current received byte.

1: a NACK is sent after current received byte

.

This sounds to me like you're supposed to set NACK only when you just received a byte and e.g. got the RXNE IRQ.

From reading descriptions about I2C protocol elsewhere, I got the idea that if a master sends a bad request, like accessing a non-existant register or writing to a readonly register, a slave may signal that with a NACK.

Now I wonder where in the sequence of I2C bus activites (or, interrupts that I get) to place this NACK.

After I got the following incomplete I2C transaction sequence: {start, Waddr, Wdata(registerNum), restart, Raddr}, the MCU will be in the interrupt with the ADDR flag set.

As that might not count as "receiving a byte", this would be the wrong place to set the NACK bit?

I can't reject the request yet with NACK when the register number is received (as a data byte), because the bit for whether a register is to be read or written is only known with the Raddr (Address with read-bit=1) event at the end of this broken sequence.

So I would set NACK bit on the first byte sent, but wouldn't this also possibly just mean "there are no more bytes" / end of transmission?

The current state of my implementation:

Receiving existing registers' contents from the slave by the master works.

Handling not-allowed requests does not work:

Currently, I set the NACK bit in the interrupt routine when I get the Raddr, do *not* enable TX IRQ like I would for legal requests, and set my state machine to IDLE again.

But then I never get another interrupt, and I see that BUSY as well as TXIE are set in the ISR register.

BUSY is still on because the master did not generate a stop conditionor anything else after the Raddr of the described event sequence above, I guess.

So I wonder how this is supposed to be done.

I guess I could disable and enable the peripheral to clear the busy bit in that scenario, but I doubt that's "the way" 😉

The master end of things here is a Linux program using the usermode I2C driver that comes with the kernel.

At the point of the end of that sequence above, there is a read error on the master, so I guess form that end, the fact that the command was not allowed has been noted.

1 REPLY 1
claymcclure
Associate

This appears to be an oversight in ST's I2C peripheral implementation. Were you able to find a work-around?