2020-11-03 03:03 AM
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?
Solved! Go to Solution.
2021-07-06 08:44 AM
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
2020-11-03 05:10 AM
Agreed. Seems like this value should be set within HAL_I2C_Mem_Write_DMA since the IRQHandler needs to know it.
2020-11-11 03:18 AM
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.
2020-11-13 03:10 AM
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
2020-11-16 11:49 PM
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.
2020-11-19 07:03 AM
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>© 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
2021-07-06 08:44 AM
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