2020-09-03 08:28 AM
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.
2023-06-23 10:22 AM
This appears to be an oversight in ST's I2C peripheral implementation. Were you able to find a work-around?
2024-08-02 05:14 AM
Bit late, but maybe it helps somebody one day. Came across this very same issue and solved this by disabling/enabling the I2C peripheral. Seems to work just fine.
// LL_I2C_AcknowledgeNextData(I2C1, LL_I2C_NACK); does not work because
// there is no next data, also, we want to issue the NACK NOW...
LL_I2C_Disable(I2C1);
LL_I2C_Enable(I2C1);