Skip to main content
Visitor II
November 3, 2020
Solved

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

  • November 3, 2020
  • 5 replies
  • 1933 views

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?

    This topic has been closed for replies.
    Best answer by Amira

    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

    5 replies

    Super User
    November 3, 2020

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

    Technical Moderator
    November 11, 2020

    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

    STomm.1Author
    Visitor II
    November 13, 2020

    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

    Technical Moderator
    November 17, 2020

    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

    STomm.1Author
    Visitor II
    November 19, 2020

    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

    AmiraAnswer
    Visitor II
    July 6, 2021

    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