cancel
Showing results for 
Search instead for 
Did you mean: 

Need help to read Accelerometer with I2C DMA

polgu.1
Associate II

I'm try to read acceleration from KX132 accelerometer with a STM32F446ZE through I2C with DMA. I create a project with STMCubeMX and enable DMA and interruptions.

The accelerometer has six register each one of 1 byte where save acceleration in this format: XOUT_L,XOUT_H, YOUT_L, YOUT_H, ZOUT_L, ZOUT_H.

I want to read this registers continously with I2C DMA but I have a problem, only can read once time and never jump the complete transfer interruption again. I'll leave parts of my code so you can understand what i'm doing.

This configuration it was create by STMCubeMX. I choose DMA_CIRCULAR mode to repeat reading by DMA but doesn't work.

i2c.c

/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "i2c.h"
 
/* USER CODE BEGIN 0 */
 
/* USER CODE END 0 */
 
I2C_HandleTypeDef hi2c2;
DMA_HandleTypeDef hdma_i2c2_rx;
DMA_HandleTypeDef hdma_i2c2_tx;
 
/* 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 */
 
}
 
void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{
 
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(i2cHandle->Instance==I2C2)
  {
  /* USER CODE BEGIN I2C2_MspInit 0 */
 
  /* USER CODE END I2C2_MspInit 0 */
 
    __HAL_RCC_GPIOF_CLK_ENABLE();
    /**I2C2 GPIO Configuration
    PF0     ------> I2C2_SDA
    PF1     ------> I2C2_SCL
    */
    GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
    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(GPIOF, &GPIO_InitStruct);
 
    /* I2C2 clock enable */
    __HAL_RCC_I2C2_CLK_ENABLE();
 
    /* I2C2 DMA Init */
    /* I2C2_RX Init */
    hdma_i2c2_rx.Instance = DMA1_Stream2;
    hdma_i2c2_rx.Init.Channel = DMA_CHANNEL_7;
    hdma_i2c2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_i2c2_rx.Init.MemBurst = DMA_MBURST_SINGLE;
    hdma_i2c2_rx.Init.PeriphInc = DMA_PINC_ENABLE;
    hdma_i2c2_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_i2c2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_i2c2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_i2c2_rx.Init.Mode = DMA_CIRCULAR;
    hdma_i2c2_rx.Init.PeriphBurst = DMA_PBURST_SINGLE;
    hdma_i2c2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_i2c2_rx.Init.Priority = DMA_PRIORITY_HIGH;
    hdma_i2c2_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_i2c2_rx) != HAL_OK)
    {
      Error_Handler();
    }
 
    __HAL_LINKDMA(i2cHandle,hdmarx,hdma_i2c2_rx);
 
    /* I2C2_TX Init */
    hdma_i2c2_tx.Instance = DMA1_Stream7;
    hdma_i2c2_tx.Init.Channel = DMA_CHANNEL_7;
    hdma_i2c2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_i2c2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_i2c2_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_i2c2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_i2c2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_i2c2_tx.Init.Mode = DMA_CIRCULAR;
    hdma_i2c2_tx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_i2c2_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
    if (HAL_DMA_Init(&hdma_i2c2_tx) != HAL_OK)
    {
      Error_Handler();
    }
 
    __HAL_LINKDMA(i2cHandle,hdmatx,hdma_i2c2_tx);
 
    /* I2C2 interrupt Init */
    HAL_NVIC_SetPriority(I2C2_EV_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(I2C2_EV_IRQn);
    HAL_NVIC_SetPriority(I2C2_ER_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(I2C2_ER_IRQn);
  /* USER CODE BEGIN I2C2_MspInit 1 */
 
  /* USER CODE END I2C2_MspInit 1 */
  }
}
 
void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle)
{
 
  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
    PF0     ------> I2C2_SDA
    PF1     ------> I2C2_SCL
    */
    HAL_GPIO_DeInit(GPIOF, GPIO_PIN_0);
 
    HAL_GPIO_DeInit(GPIOF, GPIO_PIN_1);
 
    /* I2C2 DMA DeInit */
    HAL_DMA_DeInit(i2cHandle->hdmarx);
    HAL_DMA_DeInit(i2cHandle->hdmatx);
 
    /* I2C2 interrupt Deinit */
    HAL_NVIC_DisableIRQ(I2C2_EV_IRQn);
    HAL_NVIC_DisableIRQ(I2C2_ER_IRQn);
  /* USER CODE BEGIN I2C2_MspDeInit 1 */
 
  /* USER CODE END I2C2_MspDeInit 1 */
  }
}
 
/* USER CODE BEGIN 1 */
 
/* USER CODE END 1 */

Set DMA interruptions.

dma.c

/* USER CODE BEGIN 0 */
 
/* USER CODE END 0 */
 
/*----------------------------------------------------------------------------*/
/* Configure DMA                                                              */
/*----------------------------------------------------------------------------*/
 
/* USER CODE BEGIN 1 */
 
/* USER CODE END 1 */
 
/**
  * Enable DMA controller clock
  */
void MX_DMA_Init(void)
{
 
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();
 
  /* DMA interrupt init */
  /* DMA1_Stream2_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream2_IRQn, 6, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream2_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 */

I use HAL_I2C_Mem_Read_DMA() because i can select the register from accelerometer it save the accelerations. When I run this code in debug mode, HAL_I2C_Mem_Read_DMA() works fine and I can read 6 bytes of acceleration on rxData1

​enter to while(1) and stop in HAL_Delay(50). After that, jump to DMA Interruption on stm32f4xx_it.c specifically on DMA1_Stream2_IRQHandler() function (describes below). Here excecute HAL_DMA_IRQHandler(&hdma_i2c2_rx) and go to HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c2) describe in main.c. After all that the code come back to HAL_Delay(50) from while(1) and never go jump to interrupt for refresh data from accelerometer.

I hope you can help me. I'm not sure if I'm doing it right, if you have a tips it will be hopeful for me or if you need more information feel free to ask me.

1 REPLY 1
polgu.1
Associate II

More code...

main.c 

#include "stdio.h"
#include "main.h"
#include "dma.h"
#include "i2c.h"
#include "gpio.h"
 
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#define KX132_ADDRESS 0x1E
#define READ 0x01
#define WRITE 0x00
#define RX_BUFF_LEN 12
uint8_t BUFF_ADDRESS = 0x63;
uint8_t XOUT_L = 0x08;
static uint8_t rxData1[RX_BUFF_LEN];
 
/* 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 */
 
/* USER CODE END PV */
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
 
/* USER CODE BEGIN PFP */
 
/* USER CODE END PFP */
 
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
 
/* USER CODE END 0 */
 
#define RX_BUFF_LEN 12
static uint8_t rxData1[RX_BUFF_LEN];
 
extern DMA_HandleTypeDef hdma_i2c2_rx;
 
int main(void)
{
  /* 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_I2C2_Init();
 
  /* USER CODE BEGIN 2 */
 
  /* USER CODE END 2 */
  
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
 
  HAL_I2C_Mem_Read_DMA(&hi2c2, (uint16_t)(KX132_ADDRESS << 1) | READ, XOUT_L, 1, (uint8_t *)rxData1, 6);
 
  while (1)
  {
 
    HAL_Delay(50);
 
  }
 
  /* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
 
void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c2)
{
  /* Toggle LED: Transfer in transmission process is correct */
  HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_8);
}
 
void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c2)
{
  /* Toggle LED: Transfer in transmission process is correct */
  HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_8);
}
 
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *I2cHandle)
{
  /* Turn LED3 on: Transfer error in reception/transmission process */
  HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_8);
}
 
/**
 * @brief System Clock Configuration
 * @retval None
 */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
 
  /** Configure the main internal regulator output voltage
   */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
 
  /** Initializes the RCC Oscillators according to the specified parameters
   * in the RCC_OscInitTypeDef structure.
   */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 180;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Activate the Over-Drive mode
   */
  if (HAL_PWREx_EnableOverDrive() != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Initializes the CPU, AHB and APB buses clocks
   */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}
 
/* USER CODE BEGIN 4 */
 
/* USER CODE END 4 */
 
/**
 * @brief  This function is executed in case of error occurrence.
 * @retval None
 */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}
 
#ifdef USE_FULL_ASSERT
/**
 * @brief  Reports the name of the source file and the source line number
 *         where the assert_param error has occurred.
 * @param  file: pointer to the source file name
 * @param  line: assert_param error line source number
 * @retval None
 */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
 

DMA Interruption

stm32f4xx_it.c

/* USER CODE END Header */
 
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f4xx_it.h"
 
/* External variables --------------------------------------------------------*/
extern DMA_HandleTypeDef hdma_i2c2_rx;
extern DMA_HandleTypeDef hdma_i2c2_tx;
extern I2C_HandleTypeDef hi2c2;
 
/******************************************************************************/
/*           Cortex-M4 Processor Interruption and Exception Handlers          */
/******************************************************************************/
/**
 
/******************************************************************************/
/* STM32F4xx Peripheral Interrupt Handlers                                    */
/* Add here the Interrupt Handlers for the used peripherals.                  */
/* For the available peripheral interrupt handler names,                      */
/* please refer to the startup file (startup_stm32f4xx.s).                    */
/******************************************************************************/
 
/**
  * @brief This function handles DMA1 stream2 global interrupt.
  */
void DMA1_Stream2_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Stream2_IRQn 0 */
 
  /* USER CODE END DMA1_Stream2_IRQn 0 */
 
  HAL_DMA_IRQHandler(&hdma_i2c2_rx);
  
  /* USER CODE BEGIN DMA1_Stream2_IRQn 1 */
 
  /* USER CODE END DMA1_Stream2_IRQn 1 */
}
 
/**
  * @brief This function handles DMA1 stream7 global interrupt.
  */
void DMA1_Stream7_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Stream7_IRQn 0 */
 
  /* USER CODE END DMA1_Stream7_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_i2c2_tx);
  /* USER CODE BEGIN DMA1_Stream7_IRQn 1 */
 
  /* USER CODE END DMA1_Stream7_IRQn 1 */
}
 
/* USER CODE BEGIN 1 */
 
/* USER CODE END 1 */