cancel
Showing results for 
Search instead for 
Did you mean: 

HAL I2C DMA BUGS Why does this simple DMA code Not Work ???

JHERI
Senior

Hello

Having real issues with the I2C DMA HAL code ???

Is it buggy.... very likely from what i'm reading on the web or is there something I am not understanding ??

I'm simply trying to read data back from a i2c flow sensor with minimal interruption to the processor thus why trying to use HAL I2C DMA

when I use use NON DMA I2C code everything is great and works well

HAL_I2C_Master_Receive( &hi2c1, Sensor_Adr << 1 | 0x01, I2C1_DATA , 9, HAL_MAX_DELAY );

0693W00000JMF9cQAH.jpg 

Yet when I use the HAL I2C DMA code its broken ????

HAL_I2C_Master_Receive_DMA( &hi2c1, Sensor_Adr << 1 | 0x01 , I2C1_DATA, 9);

this should work the same way the non DMA code work, but using the DMA hardware, but we can see it does not....

0693W00000JMFBnQAP.jpg 

we can see it starts to initiate a DMA I2C session, but stops after dropping SDA & SCL line why ??????

It should continue to read back the data from the sensor the same way the Non DMA I2C code does. ??

Can someone please help and advise as I am totally lost, what am I missing or is there a bug, thank you in advance for any help

I found this on the internet, not sure if its relevant

I had been struggling with the same problem on STM32F407 and I2C1.

After searching for potential bugs in the program flow, i found out that the function HAL_I2C_Master_Transmit_DMA leads to following line:

dmaxferstatus = HAL_DMA_Start_IT(hi2c->hdmatx, (uint32_t)hi2c->pBuffPtr, (uint32_t)&hi2c->Instance->DR, hi2c->XferSize);

After the first transfer, this won't return HAL_OK, which is necessary for the transmission to continue.

So my solution was simply abort the previous DMA interrupt in the callback function which is called after the transmission has completed. The same can be implied with HAL_I2C_Master_Receive_DMA. To resolve the problem, i added the following callback functions in main.c:

void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c)
 
{if (hi2c->Instance==hi2c1.Instance)
 
   {HAL_DMA_Abort_IT(hi2c->hdmatx);
 
   }
 
}
 
 
 
void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c)
 
{if (hi2c->Instance==hi2c1.Instance)
 
   { HAL_DMA_Abort_IT(hi2c->hdmarx);
 
   }
 
}

I have tried adding these interrupt call backs but still does not work ??

can someone please advise a workaround for this bug or let me know what I am doing wrong

thank you for any help

regards

15 REPLIES 15
JHERI
Senior
/**
  ******************************************************************************
  * @file    i2c.c
  * @brief   This file provides code for the configuration
  *          of the I2C instances.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
 
/* Includes ------------------------------------------------------------------*/
#include "i2c.h"
 
/* USER CODE BEGIN 0 */
extern void _Error_Handler(char *file, int line);
/* USER CODE END 0 */
 
I2C_HandleTypeDef hi2c1;
I2C_HandleTypeDef hi2c2;
I2C_HandleTypeDef hi2c3;
DMA_HandleTypeDef hdma_i2c1_tx;
DMA_HandleTypeDef hdma_i2c1_rx;
 
/* I2C1 init function */
void MX_I2C1_Init(void)
{
 
  /* USER CODE BEGIN I2C1_Init 0 */
 
  /* USER CODE END I2C1_Init 0 */
 
  /* USER CODE BEGIN I2C1_Init 1 */
 
  /* USER CODE END I2C1_Init 1 */
  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 100000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN I2C1_Init 2 */
 
  /* USER CODE END I2C1_Init 2 */
 
}
/* I2C2 init function */
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.ClockSpeed = 100000;
  hi2c2.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c2.Init.OwnAddress1 = 0;
  hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c2.Init.OwnAddress2 = 0;
  hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN I2C2_Init 2 */
 
  /* USER CODE END I2C2_Init 2 */
 
}
/* I2C3 init function */
void MX_I2C3_Init(void)
{
 
  /* USER CODE BEGIN I2C3_Init 0 */
 
  /* USER CODE END I2C3_Init 0 */
 
  /* USER CODE BEGIN I2C3_Init 1 */
 
  /* USER CODE END I2C3_Init 1 */
  hi2c3.Instance = I2C3;
  hi2c3.Init.ClockSpeed = 100000;
  hi2c3.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c3.Init.OwnAddress1 = 0;
  hi2c3.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c3.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c3.Init.OwnAddress2 = 0;
  hi2c3.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c3.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c3) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN I2C3_Init 2 */
 
  /* USER CODE END I2C3_Init 2 */
 
}
 
void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{
 
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(i2cHandle->Instance==I2C1)
  {
  /* USER CODE BEGIN I2C1_MspInit 0 */
 
  /* USER CODE END I2C1_MspInit 0 */
 
    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**I2C1 GPIO Configuration
    PB6     ------> I2C1_SCL
    PB7     ------> I2C1_SDA
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
    /* I2C1 clock enable */
    __HAL_RCC_I2C1_CLK_ENABLE();
 
    /* I2C1 DMA Init */
    /* I2C1_TX Init */
    hdma_i2c1_tx.Instance = DMA1_Stream7;
    hdma_i2c1_tx.Init.Channel = DMA_CHANNEL_1;
    hdma_i2c1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_i2c1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_i2c1_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_i2c1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_i2c1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_i2c1_tx.Init.Mode = DMA_NORMAL;
    hdma_i2c1_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
    hdma_i2c1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_i2c1_tx) != HAL_OK)
    {
      Error_Handler();
    }
 
    __HAL_LINKDMA(i2cHandle,hdmatx,hdma_i2c1_tx);
 
    /* I2C1_RX Init */
    hdma_i2c1_rx.Instance = DMA1_Stream0;
    hdma_i2c1_rx.Init.Channel = DMA_CHANNEL_1;
    hdma_i2c1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_i2c1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_i2c1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_i2c1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_i2c1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_i2c1_rx.Init.Mode = DMA_NORMAL;
    hdma_i2c1_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
    hdma_i2c1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_i2c1_rx) != HAL_OK)
    {
      Error_Handler();
    }
 
    __HAL_LINKDMA(i2cHandle,hdmarx,hdma_i2c1_rx);
 
  /* USER CODE BEGIN I2C1_MspInit 1 */
 
  /* USER CODE END I2C1_MspInit 1 */
  }
  else if(i2cHandle->Instance==I2C2)
  {
  /* USER CODE BEGIN I2C2_MspInit 0 */
 
  /* USER CODE END I2C2_MspInit 0 */
 
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();
    /**I2C2 GPIO Configuration
    PB10     ------> I2C2_SCL
    PC12     ------> I2C2_SDA
    */
    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
    GPIO_InitStruct.Pin = GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C2;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
    /* I2C2 clock enable */
    __HAL_RCC_I2C2_CLK_ENABLE();
  /* USER CODE BEGIN I2C2_MspInit 1 */
 
  /* USER CODE END I2C2_MspInit 1 */
  }
  else if(i2cHandle->Instance==I2C3)
  {
  /* USER CODE BEGIN I2C3_MspInit 0 */
 
  /* USER CODE END I2C3_MspInit 0 */
 
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**I2C3 GPIO Configuration
    PC9     ------> I2C3_SDA
    PA8     ------> I2C3_SCL
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C3;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
    GPIO_InitStruct.Pin = GPIO_PIN_8;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C3;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
    /* I2C3 clock enable */
    __HAL_RCC_I2C3_CLK_ENABLE();
  /* USER CODE BEGIN I2C3_MspInit 1 */
 
  /* USER CODE END I2C3_MspInit 1 */
  }
}
 
void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle)
{
 
  if(i2cHandle->Instance==I2C1)
  {
  /* USER CODE BEGIN I2C1_MspDeInit 0 */
 
  /* USER CODE END I2C1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_I2C1_CLK_DISABLE();
 
    /**I2C1 GPIO Configuration
    PB6     ------> I2C1_SCL
    PB7     ------> I2C1_SDA
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_6);
 
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_7);
 
    /* I2C1 DMA DeInit */
    HAL_DMA_DeInit(i2cHandle->hdmatx);
    HAL_DMA_DeInit(i2cHandle->hdmarx);
  /* USER CODE BEGIN I2C1_MspDeInit 1 */
 
  /* USER CODE END I2C1_MspDeInit 1 */
  }
  else if(i2cHandle->Instance==I2C2)
  {
  /* USER CODE BEGIN I2C2_MspDeInit 0 */
 
  /* USER CODE END I2C2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_I2C2_CLK_DISABLE();
 
    /**I2C2 GPIO Configuration
    PB10     ------> I2C2_SCL
    PC12     ------> I2C2_SDA
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10);
 
    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_12);
 
  /* USER CODE BEGIN I2C2_MspDeInit 1 */
 
  /* USER CODE END I2C2_MspDeInit 1 */
  }
  else if(i2cHandle->Instance==I2C3)
  {
  /* USER CODE BEGIN I2C3_MspDeInit 0 */
 
  /* USER CODE END I2C3_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_I2C3_CLK_DISABLE();
 
    /**I2C3 GPIO Configuration
    PC9     ------> I2C3_SDA
    PA8     ------> I2C3_SCL
    */
    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_9);
 
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_8);
 
  /* USER CODE BEGIN I2C3_MspDeInit 1 */
 
  /* USER CODE END I2C3_MspDeInit 1 */
  }
}
 
/* USER CODE BEGIN 1 */
 
 
 
 
/* USER CODE END 1 */
 
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

here is my init code for dma and I2C

TDK
Guru

Is DMA initialized before I2C?

If you feel a post has answered your question, please click "Accept as Solution".
JHERI
Senior

thank you for your reply

i think not from my code ? does it need to be ?

    LSE_Configuration();                             // SETUP LOW SPEED EXTERNAL OSC 32.768Khz
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_CAN1_Init();
  MX_CAN2_Init();
  MX_I2C1_Init();
  MX_I2C2_Init();
  MX_I2C3_Init();
  MX_SPI2_Init();
  MX_SPI3_Init();
  MX_USART1_UART_Init();
  MX_DMA_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
 
  ms_tick1 = 100;
 
 

Yes it does.
This is a CubeMX bug, should be many threads on it. Not at my computer or I would find it for you, but manually changing code will fix it for the moment.
If you feel a post has answered your question, please click "Accept as Solution".
JHERI
Senior

thanks for your reply, but sadly still no joy ?? SDA & SCL Lines still being held low and obviously messing up the communications to the sensor

here is my code now

/* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_DMA_Init();
  
  MX_GPIO_Init();
  MX_CAN1_Init();
  MX_CAN2_Init();
  MX_I2C1_Init();
  MX_I2C2_Init();
  MX_I2C3_Init();
  MX_SPI2_Init();
  MX_SPI3_Init();
  MX_USART1_UART_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
 
  ms_tick1 = 100;

still SDA and SCL lines stay low ????

here is the dma init code

* Enable DMA controller clock
  */
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, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
  /* DMA1_Stream6_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn);
  /* DMA1_Stream7_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream7_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream7_IRQn);
 
}
 
/* USER CODE BEGIN 2 */
 
/* USER CODE END 2 */
 
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

MM..1
Chief III

Maybe good is show your code for com not only line

HAL_I2C_Master_Receive_DMA( &hi2c1, Sensor_Adr << 1 | 0x01 , I2C1_DATA, 9);

because for example without DMA buffer I2C1_DATA can be local variable , but with DMA cant...

JHERI
Senior

still having all major issues

1) I really don't understand any of this I2C HAL DMA ???

2) when trying to read the data back, the sda and scl lines drop low and that it..... WHY ??

3) it then messes up further i2C reads as the SCL & SDA lines are low

i notice when I set a break point it calls this interrupt

/**
  * @brief This function handles I2C1 event interrupt.
  */
void I2C1_EV_IRQHandler(void)
{
  /* USER CODE BEGIN I2C1_EV_IRQn 0 */
 
  /* USER CODE END I2C1_EV_IRQn 0 */
  HAL_I2C_EV_IRQHandler(&hi2c1);
  /* USER CODE BEGIN I2C1_EV_IRQn 1 */
 
  /* USER CODE END I2C1_EV_IRQn 1 */
}

but i don't have any call back code for this interrupt in main.c should I

I really having issues with NO simple tutorial explaining in simple term how these peripheral work ??

Is The DMA Flawed ?

thanks in advance for any help

JHERI
Senior

Is there anywhere where engineers can get answers to ST Hardware problems other than waiting days for help ?

Is there a direct support contact sensor to speak with ST engineers anywhere?

Thanks for any info,

I can't see how one is supposed to work with ST peripherals and be left high and dry when running in to issues

There has to be a better way to develop and get support

Regards

MM..1
Chief III

When you open folder in your profile C:\Users\profilename\STM32Cube\Repository\STM32Cube_FW_F4_V1.26.2\Projects\STM32446E-Nucleo\Examples\I2C\

you can choice other FW and other board , but in subdir I2C you will see

09. 09. 2021  07:11    <DIR>          I2C_TwoBoards_AdvComIT
09. 09. 2021  07:11    <DIR>          I2C_TwoBoards_ComDMA
09. 09. 2021  07:11    <DIR>          I2C_TwoBoards_ComIT
09. 09. 2021  07:11    <DIR>          I2C_TwoBoards_ComPolling

and in folder DMA you have code for learn...