1

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.

"i2c1 event interrupt" and "i2c1 error interrupt" enabled

UART DMA configuration I2C DMA confuguration

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 FIRST I2C Data transfer 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                          */ 

DMA Registers

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?

1
  • Please provide enough code so others can better understand or reproduce the problem. Commented Feb 8, 2023 at 11:59

1 Answer 1

0

Finally found the solution. I will summarise some issues I had:

HAL_I2C_Master_Transmit_DMA(i2cHandler, MPUADDR, i2cData, 2);
  1. The Deliverable data: The deliverable data must be global variable for DMA, otherwise when I am leaving the function/ or calling a destructor of the object the memory is freed and the DMA aborts.

  2. The delivery target in my case the i2cHandler must not be the copy of the original structure/object, because the callback function addresses are checked from parallel interrupts based on the original object and updated in the calling HAL_I2C_Master_Transmit_DMA function. If incorrect ending up in a loop in the HAL_I2C_EV_IRQHandler because the hi2c->XferISR is always NULL.

    What to check: If the I2C handler is exactly the same in the interrupt handler from the function or the name is different, but the new one only uses a pointer to the old one. In my case thy where not the same from the myin called hi2c1 and the function i2cHandler.

    Name from the main

    The solution for me was to use the copy of the pointer only not the content of the handler.

    Copy of the struct

  3. With the STM32 H7 boards there is a memory allocation issue which is explained with the solution in the below article.

    https://community.st.com/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.