I am trying to read and write data to a sensor via i2c with DMA1 in an STM32 Nucleo F401 board where a FreeRTOS is running.
My project is written in C++ and using the stm32 HAL libraries as extern "C".
I can read the sensor data with polling method, and next to the I2C an UART is running with the DMA2 correctly. I have checked and the MX_DMA_Init is running before the MX_I2C1_Init.
When I try to write to the sensor as a master with DMA(HAL_I2C_Master_Transmit_DMA) with the "i2c1 event interrupt" and "i2c1 error interrupt" disabled in FreeRTOS, the parallel tasks are running fine, just the callback HAL_I2C_MasterTxCpltCallback is not triggered.
And when I enable the "i2c1 event interrupt" and "i2c1 error interrupt" from CubeMX, two parallel task in FreeRTOS are running at once, then no more parallel scheduling is happening, and the HAL_I2C_EV_IRQHandler function is called periodically and leaving the function in the last else branch where /* Do nothing */ is commented.


Could you please suggest what could I try to use the i2c with DMA?
I tried to enable and disable the i2c1 event interrupt from CubeMX and expected to trigger the HAL_I2C_MasterTxCpltCallback callback. But only the HAL_I2C_EV_IRQHandler was triggered periodically.
- I tried to use the I2C with polling method and it was working correctly.
- I tried to use the UART with DMA and it was working correctly too.
- I tried checking the order of MX_DMA_Init and MX_I2C1_Init and it was correct.
- I tried to see if any other I2C callback is triggered, but no other I2C callback is triggered.
- I tried to update the CubeMX version from F4 V1.26.2 to F4 V27.1, but I have not seen any improvement.
- I tried to have all the HAL implementation and callback functions embedded in extern "C", but there was no change.
I switched to a STM32 H723ZG board where at least the first transfer of the I2C data happened with DMA
But it happens only for 1 cycle and the DMA fails with error code 1. What is the Transfer error
#define HAL_DMA_ERROR_TE (0x00000001U) /*!< Transfer error */

I have seen that in the h= series, I need to align the data given to the DMA to be able to send and I tried to apply the fix for this. My code now looks like this:
#define TX_LENGTH (16)
uint8_t i2cData[TX_LENGTH];
void I2C_Write8(uint8_t ADDR, uint8_t data)
{
i2cData[0] = ADDR;
i2cData[1] = data;
uint8_t MPUADDR = (MPU_ADDR<<1);
/* Clean D-cache */
/* Make sure the address is 32-byte aligned and add 32-bytes to length, in case it overlaps cacheline */
SCB_CleanDCache_by_Addr((uint32_t*)(((uint32_t)i2cData) & ~(uint32_t)0x1F), TX_LENGTH+32);
HAL_I2C_Master_Transmit_DMA(&i2cHandler, MPUADDR, i2cData, TX_LENGTH);
//HAL_Delay(100);
}
The I2C Init:
static void MX_I2C2_Init(void)
{
/* USER CODE BEGIN I2C2_Init 0 */
/* USER CODE END I2C2_Init 0 */
/* USER CODE BEGIN I2C2_Init 1 */
/* USER CODE END I2C2_Init 1 */
hi2c2.Instance = I2C2;
hi2c2.Init.Timing = 0x60404E72;
hi2c2.Init.OwnAddress1 = 0;
hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c2.Init.OwnAddress2 = 0;
hi2c2.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c2) != HAL_OK)
{
Error_Handler();
}
/** Configure Analogue filter
*/
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c2, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
{
Error_Handler();
}
/** Configure Digital filter
*/
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c2, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2C2_Init 2 */
/* USER CODE END I2C2_Init 2 */
}
The DMA Init:
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Stream0_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
/* DMA1_Stream1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
}
The initialization from the main:
/* USER CODE BEGIN 1 */
/* 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_USART3_UART_Init();
MX_USB_OTG_HS_USB_Init();
MX_SPI1_Init();
MX_ETH_Init();
MX_I2C2_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Init scheduler */
osKernelInitialize();
Could you please suggest what I am doing wrong?

