cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with I2C in DMA mode in the latest versions of the F4 STM32Cube FW

STomm.1
Associate II

Hello everyone.

I think that the stm32f4xx_hal_i2c.c driver present in the STM32Cube_FW_F4_V1.25.1 and STM32Cube_FW_F4_V1.25.2 versions has a bug on I2C transfer in DMA mode.

In the function:

"I2C_MemoryTransmit_TXE_BTF" the value of "hi2c->MemaddSize" remains 0 even when the I2C internal memory address size is 8 bit (I2C_MEMADD_SIZE_8BIT).

This causes the malfunction of the function "HAL_I2C_Mem_Write_DMA"

As a workaround I added the following setting in the MX_I2C1_Init function

hi2c1.MemaddSize = I2C_MEMADD_SIZE_8BIT;

Has anyone else experienced this problem before and how did they solve it?

1 ACCEPTED SOLUTION

Accepted Solutions
Amira
Associate III

Hello,

Apologies for the delayed response. The reported issue is confirmed.

 hi2c->MemaddSize = MemAddSize; initialization is added now in HAL_I2C_Mem_Read_DMA() and HAL_I2C_Mem_Write_DMA() APIs for  /* Prepare transfer parameters *.

The fix will be available in next STM32F4 patch release V1.26.2.

Regards,

Amira

View solution in original post

6 REPLIES 6
TDK
Guru

Agreed. Seems like this value should be set within HAL_I2C_Mem_Write_DMA since the IRQHandler needs to know it.

If you feel a post has answered your question, please click "Accept as Solution".
Amel NASRI
ST Employee

Hi @STomm.1​ ,

Thanks for bringing this issue to our attention. With my quick analysis, I assume that it was introduced since the revision 1.25.0 of STM32CubeF4 package as the function I2C_MemoryTransmit_TXE_BTF was added with it.

I reported it to our development team who should do a deeper analysis and provide a solution.

Meanwhile, could you please explain more the "malfunction of HAL_I2C_Mem_Write_DMA"? Does it mean that there is no data transferred?

-Amel

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.

STomm.1
Associate II

Hi Amel.

I haven't done a thorough analysis; I use DMA mode to program, read/write 3 IO_Expander. What I noticed is this:

1) the first time the HAL_I2C_Mem_Write_DMA function is called (to program the IO_expander), the I2C_MemoryTransmit_TXE_BTF function is called 2 times consecutively; the first time it sees hi2c-> MemaddSize = 0 and then sets hi2c-> Instance->DR = I2C_MEM_ADD_MSB. I believe this causes error in the programming of the IO_Expander.

2) Putting hi2c1.MemaddSize = I2C_MEMADD_SIZE_8BIT in the MX_I2C1_Init, the function I2C_MemoryTransmit_TXE_BTF is always called 2 times consecutively, but this time it sets (I think correctly) hi2c->hi2c->Instance->DR = I2C_MEM_ADD_LSB.

3) In the subsequent calls of the HAL_I2C_Mem_Write_DMA function the I2C_MemoryTransmit_TXE_BTF function it is instead called (I think correctly) once.

So I'm wondering if the initial double call of the I2C_MemoryTransmit_TXE_BTF function may be the problem.

Tommaso

Hi @STomm.1​ ,

Thanks for your answer.

Is it possible for you to share with us a minimum code that can help to reproduce the issue?

-Amel

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.

STomm.1
Associate II

Hi Amel, it's quite simple: the problem occurs on the first call of the HAL_I2C_Mem_Write_DMA function, in mcp23017_init.

main.c:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under Ultimate Liberty license
  * SLA0044, the "License"; You may not use this file except in compliance with
  * the License. You may obtain a copy of the License at:
  *                             www.st.com/SLA0044
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "can.h"
#include "dma.h"
#include "i2c.h"
#include "rtc.h"
#include "tim.h"
#include "usart.h"
#include "usb_device.h"
#include "gpio.h"
 
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "platform/port.h"
#if (IO_EXP_PRESENT==1)					//Defined in main.h
	#include "platform/mcp23017.h"
#endif
/* USER CODE END Includes */
 
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
 
/* USER CODE END PTD */
 
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
 
/* USER CODE END PD */
 
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
 
/* USER CODE END PM */
 
/* Private variables ---------------------------------------------------------*/
 
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
uint8_t mystring[]="Test String !!!\r";
uint8_t send_data_uart=32, receive_data_uart=0, echo_receive_data_uart=0;
 
FLASH_DATA_ORG FlashDataOrg = {.b_date_offset = 0x00, .b_time_offset = 0x04,
.b_mdata.DeviceName_offset = 0x08, .b_mdata.HW_Version_offset = 0x0C, .b_mdata.SW_Version_offset = 0x10,
.b_mdata.Vendor_ID_offset = 0x14, .b_mdata.Prdct_Code_offset = 0x18, .b_mdata.Rev_Number_offset = 0x1C, .b_mdata.Ser_Number_offset = 0x20,
.b_status.s0_offset = 0x24, .b_status.s1_offset = 0x28, .b_status.s2_offset = 0x2C, .b_status.s3_offset = 0x30,
.b_status.s4_offset = 0x34, .b_status.s5_offset = 0x38, .b_status.s6_offset = 0x3C, .b_status.s7_offset = 0x40,
.b_status.s8_offset = 0x44, .b_status.s9_offset = 0x48, .b_status.sa_offset = 0x4C, .b_status.sb_offset = 0x50,
.b_status.sc_offset = 0x54, .b_status.sd_offset = 0x58, .b_status.se_offset = 0x5C, .b_status.sf_offset = 0x60};
/* USER CODE END PV */
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
extern void my_app(void);
app_t 	app;
can_t 	can1app, can2app;
//extern void initialise_monitor_handles(void);	//Only for semi-hosting openOCD debug
/* USER CODE END PFP */
 
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
 
/* USER CODE END 0 */
 
/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
//  initialise_monitor_handles();		//Only for semi-hosting openOCD debug
  /* USER CODE END 1 */
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
 
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_I2C1_Init();
  MX_RTC_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  MX_USB_DEVICE_Init();
  MX_CAN1_Init();
  MX_CAN2_Init();
  MX_TIM1_Init();
  MX_TIM12_Init();
  MX_USART3_UART_Init();
  MX_TIM6_Init();
  MX_TIM7_Init();
  /* USER CODE BEGIN 2 */
//  HAL_NVIC_DisableIRQ(ADC1_2_IRQn);
  HAL_NVIC_ClearPendingIRQ(ADC_IRQn);
  HAL_NVIC_ClearPendingIRQ(EXTI0_IRQn);
  HAL_NVIC_ClearPendingIRQ(EXTI1_IRQn);
  HAL_NVIC_ClearPendingIRQ(EXTI2_IRQn);
  HAL_NVIC_ClearPendingIRQ(EXTI3_IRQn);
  HAL_NVIC_ClearPendingIRQ(EXTI4_IRQn);
  HAL_NVIC_ClearPendingIRQ(TIM6_DAC_IRQn);
  HAL_NVIC_ClearPendingIRQ(I2C1_EV_IRQn);
  HAL_NVIC_DisableIRQ(TIM6_DAC_IRQn);
 
  HAL_TIM_Base_Stop_IT(&htim6);				// Stop Timer 6
  HAL_TIM_Base_Start(&htim1);
  HAL_TIM_Base_Start(&htim2);
  HAL_TIM_Base_Start_IT(&htim3);			// Start Timer 3
  HAL_TIM_Base_Start_IT(&htim7);			// Start Timer 7
  ServiceTimersInit();						// Initialize all Service Timers
 
#if (CAN_SUPPORT==1)						// Defined in port.h
  CAN_Config(&hcan1);						// Configure the CAN peripherals
  CAN_Config(&hcan2);
#endif
#if (USART_SUPPORT==1)						//Defined in port.h
//  USART_Config(&huart2);
//  __HAL_UART_ENABLE_IT(&huart2,UART_IT_RXNE);
  USART_Config(&huart3);;
  __HAL_UART_ENABLE_IT(&huart3,UART_IT_RXNE);
#endif
  ADC_Config(&hadc1);						// Configure the ADC peripheral
  Sleep(1);
#if (IO_EXP_PRESENT==1)						// Defined in main.h
  MCP23017_status = MX_MCP23017_Init();
#endif
  leds_test = true;							// Blink LEDs if init Ok
  /* Start main application */
  my_app();
  /* USER CODE END 2 */
......

MX_MCP23017_Init:

/*! ------------------------------------------------------------------------------------------------------------------
 *  \fn			MX_MCP23017_Init()			
 *  \brief      Initialize the MCP23017 IO Expanders
 *  
 */
MCP23017_Error_et MX_MCP23017_Init()
{
	if (mcp23017_init(master_1, MCP23017_MASTER1_BADDR))
		return MCP23017_ERROR;
	HAL_Delay(i2c_delay);
	if (mcp23017_init(master_2, MCP23017_MASTER2_BADDR))
		return MCP23017_ERROR;
	HAL_Delay(i2c_delay);
#if (USE_PWRGEN==1)
	if (mcp23017_init(master_3, MCP23017_MASTER3_BADDR))
		return MCP23017_ERROR;
	HAL_Delay(i2c_delay);
#endif
 
	return MCP23017_OK;
}
uint8_t master_1[22] = {
							MASTER1_IODIRA,	 
							MASTER1_IODIRB, 	
							MASTER1_IPOLA, 	
							MASTER1_IPOLB, 	
							MASTER1_GPINTENA,
							MASTER1_GPINTENB,
							MASTER1_DEFVALA, 
							MASTER1_DEFVALB, 
							MASTER1_INTCONA, 
							MASTER1_INTCONB, 
							MASTER1_IOCONA,
							MASTER1_IOCONB,
							MASTER1_GPPUA, 	
							MASTER1_GPPUB, 	
							MASTER1_INTFA, 	
							MASTER1_INTFB, 	
							MASTER1_INTCAPA, 
							MASTER1_INTCAPB, 
							MASTER1_GPIOA, 	
							MASTER1_GPIOB, 	
							MASTER1_OLATA, 	
							MASTER1_OLATB 	
						};
uint8_t master_2[22] = {
							MASTER2_IODIRA,	 
							MASTER2_IODIRB, 	
							MASTER2_IPOLA, 	
							MASTER2_IPOLB, 	
							MASTER2_GPINTENA,
							MASTER2_GPINTENB,
							MASTER2_DEFVALA, 
							MASTER2_DEFVALB, 
							MASTER2_INTCONA, 
							MASTER2_INTCONB, 
							MASTER2_IOCONA,
							MASTER2_IOCONB,
							MASTER2_GPPUA, 	
							MASTER2_GPPUB, 	
							MASTER2_INTFA, 	
							MASTER2_INTFB, 	
							MASTER2_INTCAPA, 
							MASTER2_INTCAPB, 
							MASTER2_GPIOA, 	
							MASTER2_GPIOB, 	
							MASTER2_OLATA, 	
							MASTER2_OLATB 	
						};
#if (USE_PWRGEN==1)
uint8_t master_3[22] = {
							MASTER3_IODIRA,
							MASTER3_IODIRB,
							MASTER3_IPOLA,
							MASTER3_IPOLB,
							MASTER3_GPINTENA,
							MASTER3_GPINTENB,
							MASTER3_DEFVALA,
							MASTER3_DEFVALB,
							MASTER3_INTCONA,
							MASTER3_INTCONB,
							MASTER3_IOCONA,
							MASTER3_IOCONB,
							MASTER3_GPPUA,
							MASTER3_GPPUB,
							MASTER3_INTFA,
							MASTER3_INTFB,
							MASTER3_INTCAPA,
							MASTER3_INTCAPB,
							MASTER3_GPIOA,
							MASTER3_GPIOB,
							MASTER3_OLATA,
							MASTER3_OLATB
						};
#endif
 
/*! ------------------------------------------------------------------------------------------------------------------
 *  \fn         MCP23017_Error_et mcp23017_init(uint8_t *RegValues, uint8_t address)
 *  \brief      Initialize the MCP23017 device.
 */
MCP23017_Error_et mcp23017_init(uint8_t *RegValues, uint8_t base_address)
{
	if (HAL_I2C_Mem_Write_DMA(&hi2c1,(uint16_t)base_address,0,I2C_MEMADD_SIZE_8BIT,(uint8_t*)RegValues,22))
		return MCP23017_ERROR;
	return MCP23017_OK;
}

Tommaso

Amira
Associate III

Hello,

Apologies for the delayed response. The reported issue is confirmed.

 hi2c->MemaddSize = MemAddSize; initialization is added now in HAL_I2C_Mem_Read_DMA() and HAL_I2C_Mem_Write_DMA() APIs for  /* Prepare transfer parameters *.

The fix will be available in next STM32F4 patch release V1.26.2.

Regards,

Amira