Bug Report
The low-level polled transmit path in the Xilinx IIC driver appears to miss a slave NACK when it occurs on the final transmitted data byte.
This affects both:
XIic_Send() via SendData()
XIic_DynSend() via DynSendData()
Observed behavior
XIic_Send() can return the full requested byte count even though the slave NACKed the last transmitted byte.
In our case this shows up with an EEPROM write into a write-protected region:
- the target device does not actually update the memory cell
- the write should be rejected by the slave on the bus
- but
XIic_Send() still reports success, so higher layers interpret the transfer as successful
Why this looks like a driver bug
In SendData() the code checks XIIC_INTR_TX_ERROR_MASK only while waiting for the next TX_EMPTY condition before writing the next byte.
Relevant flow:
- wait for
TX_EMPTY or error
- write one byte to
XIIC_DTR_REG_OFFSET
- decrement
ByteCount
- if
ByteCount == 0, exit loop
- if
XIIC_STOP, wait only for XIIC_INTR_BNB_MASK
- return success (
ByteCount == 0)
Because of this, if the slave NACK happens on the final transmitted byte, there is no final check for XIIC_INTR_TX_ERROR_MASK after the last byte has been written. The code only waits for bus-not-busy and then returns success.
The same pattern exists in DynSendData().
Affected code paths
SendData():
- error is checked here before the next byte:
if (IntrStatus & (XIIC_INTR_TX_ERROR_MASK |
XIIC_INTR_ARB_LOST_MASK |
XIIC_INTR_BNB_MASK)) {
return ByteCount;
}
- but after the final byte is written:
XIic_WriteReg(BaseAddress, XIIC_DTR_REG_OFFSET, *BufferPtr++);
ByteCount--;
- there is no final
TX_ERROR check, only:
if (Option == XIIC_STOP) {
while (1) {
if (XIic_ReadIisr(BaseAddress) & XIIC_INTR_BNB_MASK) {
break;
}
}
}
DynSendData() has the same issue.
Expected behavior
If the slave NACKs the final transmitted byte, XIic_Send() / XIic_DynSend() should not report the full requested byte count as sent.
A final-byte NACK should be reflected as an incomplete transfer, just like NACK on earlier bytes.
Impact
Higher-level drivers that use:
bytes_sent == requested_length as success, or
- wrappers such as register writes built on top of
XIic_Send()
can falsely report success even though the slave rejected the final byte.
This is especially visible with devices that:
- ACK address and earlier bytes
- NACK only the final data byte in specific protocol situations
One real example is EEPROM write protection, where the device may ACK device address and internal address bytes, but NACK the protected data byte.
Suggested fix
After transmitting the final byte, and before returning success, explicitly check XIIC_INTR_TX_ERROR_MASK once more.
This should be done in:
A fix would likely involve checking for TX_ERROR after the final byte has left the FIFO and before treating the transfer as successful, instead of only polling for BNB.
Version
The issue is present in the current xiic_l.c implementation containing:
XIic_Send()
SendData()
XIic_DynSend()
DynSendData()
Bug Report
The low-level polled transmit path in the Xilinx IIC driver appears to miss a slave NACK when it occurs on the final transmitted data byte.
This affects both:
XIic_Send()viaSendData()XIic_DynSend()viaDynSendData()Observed behavior
XIic_Send()can return the full requested byte count even though the slave NACKed the last transmitted byte.In our case this shows up with an EEPROM write into a write-protected region:
XIic_Send()still reports success, so higher layers interpret the transfer as successfulWhy this looks like a driver bug
In
SendData()the code checksXIIC_INTR_TX_ERROR_MASKonly while waiting for the nextTX_EMPTYcondition before writing the next byte.Relevant flow:
TX_EMPTYor errorXIIC_DTR_REG_OFFSETByteCountByteCount == 0, exit loopXIIC_STOP, wait only forXIIC_INTR_BNB_MASKByteCount == 0)Because of this, if the slave NACK happens on the final transmitted byte, there is no final check for
XIIC_INTR_TX_ERROR_MASKafter the last byte has been written. The code only waits for bus-not-busy and then returns success.The same pattern exists in
DynSendData().Affected code paths
SendData():TX_ERRORcheck, only:DynSendData()has the same issue.Expected behavior
If the slave NACKs the final transmitted byte,
XIic_Send()/XIic_DynSend()should not report the full requested byte count as sent.A final-byte NACK should be reflected as an incomplete transfer, just like NACK on earlier bytes.
Impact
Higher-level drivers that use:
bytes_sent == requested_lengthas success, orXIic_Send()can falsely report success even though the slave rejected the final byte.
This is especially visible with devices that:
One real example is EEPROM write protection, where the device may ACK device address and internal address bytes, but NACK the protected data byte.
Suggested fix
After transmitting the final byte, and before returning success, explicitly check
XIIC_INTR_TX_ERROR_MASKonce more.This should be done in:
SendData()DynSendData()A fix would likely involve checking for
TX_ERRORafter the final byte has left the FIFO and before treating the transfer as successful, instead of only polling forBNB.Version
The issue is present in the current
xiic_l.cimplementation containing:XIic_Send()SendData()XIic_DynSend()DynSendData()