cancel
Showing results for 
Search instead for 
Did you mean: 

STM32CubeMX with STM32F100RCT: I2C Memory with DMA issues

_Anani Popov
Associate II

Hi All,

I am using STM32CubeMX HAL functions (STM32CubeF1 FW package V1.6.1 in STM32F100RCT MCU project) to handle 24LC128 I2C EEPROM comms. Followed the advice in the HAL library help:

DMA mode IO MEM operation:

  • Write an amount of data in no-blocking mode with DMA to a specific memory address using HAL_I2C_Mem_Write_DMA()
  • At MEM end of write transfer HAL_I2C_MemTxCpltCallback is executed and user can add his own code by customization of function pointer HAL_I2C_MemTxCpltCallback
  • Read an amount of data in no-blocking mode with DMA from a specific memory

address using HAL_I2C_Mem_Read_DMA()

  • At MEM end of read transfer HAL_I2C_MemRxCpltCallback is executed and user can add his own code by customization of function pointer HAL_I2C_MemRxCpltCallback
  • In case of transfer Error, HAL_I2C_ErrorCallback() function is executed and user can add his own code by customization of function pointer HAL_I2C_ErrorCallback

So my code looks as follows:

Writing:

if(CheckI2C1DeviceReady() == FALSE)
		{
			return I2C_ERR;
		}
 
		ResultI2C1 = HAL_BUSY;
 
		do
		{
			I2cStatus = HAL_I2C_Mem_Write_DMA(&hi2c1,EE_DEV_ADDR,Addr,sizeof(EEADR),WrBufferEE,WrPreBytes);
 
			if(I2cStatus == HAL_OK)
			{
				break;
			}
			else if(I2cStatus == HAL_ERROR || I2cStatus == HAL_TIMEOUT)
			{
				return I2C_ERR;
			}
		}while(I2cStatus == HAL_BUSY);
 
		if(CheckI2C1EndWrite() == FALSE)
		{
			return I2C_ERR;
		}

where:

static BOOLEAN CheckI2C1DeviceReady(void)
{
//	INT32U TimeOut = WAIT_I2C1_READY;
 
	HAL_StatusTypeDef I2C1Status;
 
	do
	{
		I2C1Status = HAL_I2C_IsDeviceReady(&hi2c1,EE_DEV_ADDR,EE_READY_TRIES,EE_READY_TOUT);
 
		if(/*--TimeOut <= 0 ||*/ I2C1Status == HAL_TIMEOUT || I2C1Status == HAL_ERROR)
		{
			return FALSE;
		}
	}while(I2C1Status != HAL_OK);
 
	return TRUE;
}
static BOOLEAN CheckI2C1EndWrite(void)
{
//	INT32U TimeOut = WAIT_I2C1_TRANSFER;
 
	while(ResultI2C1 != HAL_OK)
	{
		if(/*--TimeOut <= 0 ||*/ ResultI2C1 == HAL_ERROR)
		{
			return FALSE;
		}
	}
 
	HAL_Delay(5U);
 
	return TRUE;
}

The end of transfer and error handling comes from the call-back functions:

void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
	if(hi2c->Instance == I2C1)
	{
		I2C1_TxComplete();
	}
 
	if(hi2c->Instance == I2C2)
	{
		I2C2_TxComplete();
	}
}
 
void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
	if(hi2c->Instance == I2C1)
	{
		I2C1_RxComplete();
	}
 
	if(hi2c->Instance == I2C2)
	{
		I2C2_RxComplete();
	}
}
 
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
{
	if(hi2c->Instance == I2C1)
	{
		I2C1_Error();
	}
 
	if(hi2c->Instance == I2C2)
	{
		I2C2_Error();
	}
}

and goes trough handling functions:

/***************************************************************************************************
*					  				TX COMPLETE WHEN WRITE A BLOCK OF DATA TO EEPROM ON THE I2C1 BUS
*
*	Description	: End of TX when write multiple bytes to EEPROM on the I2C1 via DMA channel
*	Arguments		: None
*	Returns			: None
*	Notes				: None
*
***************************************************************************************************/
 
void I2C1_TxComplete(void)
{
	ResultI2C1 = HAL_OK;
}
 
/***************************************************************************************************
*					  				RX COMPLETE WHEN READ A BLOCK OF DATA TO EEPROM ON THE I2C1 BUS
*
*	Description	: End of RX when read multiple bytes to EEPROM on the I2C1 via DMA channel
*	Arguments		: None
*	Returns			: None
*	Notes				: None
*
***************************************************************************************************/
 
void I2C1_RxComplete(void)
{
	ResultI2C1 = HAL_OK;
}
 
/***************************************************************************************************
*					  		ERROR WHEN WRITE OR READ A BLOCK OF DATA TO/FROM EEPROM ON THE I2C1 BUS
*
*	Description	: Error when write or read multiple bytes to/from EEPROM on the I2C1 via DMA channel
*	Arguments		: None
*	Returns			: None
*	Notes				: None
*
***************************************************************************************************/
 
void I2C1_Error(void)
{
	ResultI2C1 = HAL_ERROR;
}

Reading:

if(CheckI2C1DeviceReady() == FALSE)
		{
			return I2C_ERR;
		}
 
		ResultI2C1 = HAL_BUSY;
 
		do
		{
			I2cStatus = HAL_I2C_Mem_Read_DMA(&hi2c1,EE_DEV_ADDR,Addr,sizeof(EEADR),RdBufferEE,RdPreBytes);
 
			if(I2cStatus == HAL_OK)
			{
				break;
			}
			else if(I2cStatus == HAL_ERROR || I2cStatus == HAL_TIMEOUT)
			{
				return I2C_ERR;
			}
		}while(I2cStatus == HAL_BUSY);
 
		if(CheckI2C1EndRead() == FALSE)
		{
			return I2C_ERR;
		}
static BOOLEAN CheckI2C1EndRead(void)
{
//	INT32U TimeOut = WAIT_I2C1_TRANSFER;
 
	while(ResultI2C1 != HAL_OK)
	{
		if(/*--TimeOut <= 0 ||*/ ResultI2C1 == HAL_ERROR)
		{
			return FALSE;
		}
	}
 
	return TRUE;
}

Sometimes the execution is stacked in static BOOLEAN CheckI2C1DeviceReady(void)...

MY QUESTIONS:

  1. Is the procedure correct?
  2. Is there some examples available?
  3. Any suggestions...

Regards,

Anani

NB: I have found a post related to my issue - https://community.st.com/s/feed/0D50X00009XkVw0SAF

but still confused... In my CubeMX I2C interrupts are enabled (see below):

and my FW is stacked after HAL_I2C_Mem_Read_DMA() call...

RE: The result of my debugging:

The execution of HAL_I2C_IsDeviceReady() ALWAYS returns HAL_BUSY although I2C_WaitOnFlagUntilTimeout() ALWAYS returns HAL_TIMEOUT!!!

(see attached I2C Debug.docx)

Re: New event captured (see attached file).

Re: I have increased the priority of I2C and relevant DMA interrupts to the absolute maximum level of 0 (see attached screenshots).

0690X000006CFGCQA4.png

 0690X000006CFGHQA4.png

FreeRTOS still works fine. BUT…. Same event as described in the doc file yesterday happened…

RE: I am trying to resolve my I2C issue by experimenting with some abort communication code (see attached picture). I assume that the closing of I2C communication by the Master (MCU) is not done correctly in some cases when I2C interrupts are not the only ones with highest priority.

I have caught another event displayed on the pictures below:

0690X000006CFTkQAO.png

0690X000006CFTpQAO.jpg

Surprisingly it looks like the current byte read is interrupted after just 3 bits been read (well, my scope resolution is quite poor)! ITERREN flag is set, but my I2C error interrupt service routine break-point is not hit! I have NO reasonable explanation whatsoever!

What could that be?

0 REPLIES 0