cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_I2C_MEM_READ_IT fails if a NAK occurs on the memory address

Johannes
Senior

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

 

 

 

 

4 REPLIES 4
Foued_KH
ST Employee

Hello @Johannes , 

Could you please share you code ?

Foued

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Hello Foued
Thank you for helping me. 
I attached the code. It is a very basic CubeIDE project which uses I2C3. It has a very simple loop in main.c which tries to do a mem read on 0x14 adr 0x12 every 500ms 
The i2c blocks after two attempts. 
First read attempt: Deviceaddress is ACKed, Sub-address is "NAKed" 
I try to talk to a LTC1760 which rejects a subaddress, if it is not available. 

Johannes_0-1695021375604.png

This transaciton ends "normal".
Now, If I try to repeat that, the result is:

Johannes_1-1695021504785.png

Not the bus is stuck. Clock is stuck low (STM32 holds it low) the I2c Hardware shows the "busy flag". 
See attached project (STM32G474RET6)

The Bus can be reset by clearing the PE bit in CR1, waiting a few cycles and setting it again

Johannes

 

Hello @Johannes , 

Please make sure that you are using the correct sub-address 

Foued

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Hi Foued
Sorry, if I am confused? Yes for sure, I should use the correct sub address. But what if an i2c or smbus communication is disturbed and one byte during communication is NAKed ? This is a legit scenario. I just have to accept, that the HAL driver stops working after that? 
Let be be clear here: sending the wrong subaddress is JUST A WAY TO DEMONSTRATE the problem. For sure, I will send the correct subaddress.