HAL_I2C_MEM_READ_IT fails if a NAK occurs on the memory address
Hi Everyone
I use STM32G474RE with CubeIDE 1.13.1 and MCU Package G4 V1.5.1
I have a problem, when an I2C_MEM_READ_IT encounters a NAK on the memory address.
A typical I2C mem read is:
Start DevAdr(W) (Ack) MemoryAdr (Ack) RepeatedStart DevAdr(R) data(A), data(A)... data(N) Stop
If during this transaction, the first DevAdr(W) is Acknowledged, but the Memoryaddress is NACK, the transaction should stop there and does not need to continue trying repeated start etc.
This is done here:
static HAL_StatusTypeDef I2C_RequestMemoryRead(I2C_HandleTypeDef *hi2c, uint16_t DevAddress,
uint16_t MemAddress, uint16_t MemAddSize, uint32_t Timeout, uint32_t Tickstart)
{
I2C_TransferConfig(hi2c, DevAddress, (uint8_t)MemAddSize, I2C_SOFTEND_MODE, I2C_GENERATE_START_WRITE);
/* Wait until TXIS flag is set */
if (I2C_WaitOnTXISFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK) {
return HAL_ERROR;
}
/* If Memory address size is 8Bit */
if (MemAddSize == I2C_MEMADD_SIZE_8BIT)
{
/* Send Memory Address */
hi2c->Instance->TXDR = I2C_MEM_ADD_LSB(MemAddress);
}
/* If Memory address size is 16Bit */
else
{
/* Send MSB of Memory Address */
hi2c->Instance->TXDR = I2C_MEM_ADD_MSB(MemAddress);
/* Wait until TXIS flag is set */
if (I2C_WaitOnTXISFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK)
{
return HAL_ERROR;
}
/* Send LSB of Memory Address */
hi2c->Instance->TXDR = I2C_MEM_ADD_LSB(MemAddress);
}
/* Wait until TC flag is set */
if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_TC, RESET, Timeout, Tickstart) != HAL_OK){
return HAL_ERROR;
}
return HAL_OK;
}
The memory address is sent out (8bit memory address) and the code is waiting for the TC flag being set (Transmit complete)
If there is a NAK, TC never gets set, instead NAKF is set. But this code does not check for the NAK flag.
There is is a timeout, which triggers, but the I2c_Mem_Read is exited with the hardware in a bad state.
When a next I2C_MEM_read is started, it failes here:
static HAL_StatusTypeDef I2C_RequestMemoryRead(I2C_HandleTypeDef *hi2c, uint16_t DevAddress,
uint16_t MemAddress, uint16_t MemAddSize, uint32_t Timeout,
uint32_t Tickstart)
{
I2C_TransferConfig(hi2c, DevAddress, (uint8_t)MemAddSize, I2C_SOFTEND_MODE, I2C_GENERATE_START_WRITE);
/* Wait until TXIS flag is set */
if (I2C_WaitOnTXISFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK)
{
return HAL_ERROR;
}
The TXIS flag stays zero. The transaction stops immediately after transmitting the device address.
The bus is blocked, clock stays low and the bus is stuck.
Does anyone experience the same thing?
Johannes