cancel
Showing results for 
Search instead for 
Did you mean: 

STEVAL-MKI109V3 and STEVAL-MKI197V1 IMU data rate to 6667Hz

vv.tl
Associate

Motherboard: STEVAL-MKI109V3 (STM32F401VETX)

IMU board: STEVAL-MKI197V (LSM6DSOX)

Hello, I have ran into trouble setting the LSM6DSOX data rates of the XL and GY to 6667Hz in a custom STM32 project. The data is still fetched at a lower rate of around 1667Hz.

Project:

I used STMems_Standard_C_drivers/_prj_MKI109V3/_prj_MKI109V3.ioc and STMems_Standard_C_drivers/tree/master/lsm6dsox_STdC as the basis for the project (github.com/STMicroelectronics/STMems_Standard_C_drivers). I have created my project based on the example lsm6dsox_read_data_drdy.c

It is pretty straightforward. There are two functions:

1)

void lsm6dsox_read_data_drdy(void) {}

2)

void lsm6dsox_read_data_drdy_handler(void) {}

The first function is used to setup the IMU and to call the lsm6dsox_read_data_drdy_handler() function in a while loop. The second function is where the XL and GY data is read from the registers.

I have set the data rates the following:

lsm6dsox_xl_data_rate_set(&dev_ctx, LSM6DSOX_XL_ODR_6667Hz);
  lsm6dsox_gy_data_rate_set(&dev_ctx, LSM6DSOX_GY_ODR_6667Hz);

For some reason, the data is still fetched from the registers with lower rates, around 1667Hz.

The IMU sends data to USB serial in following format:

ax[mg], ay[mg], az[mg], gx[dps], gy[dps], gz[dps], timestamp[],

The userspace program reads the data from USB serial, converts the values and calculates Mahony yaw, pitch, roll, and outputs the following format:

readout[#], timestamp[], ax[m/s^2], ay[m/s^2], az[m/s^2], gx[rad/s], gy[rad/s], gz[rad/s], yaw[Euler deg]. pitch[Euler deg]. roll[Euler deg]

There's some confusion around the timestamp unit. Timestamp is fetched using lsm6dsox_timestamp_raw_get() function. It's called at the same time XL and GY data is fetched from the registers.

Here are 2 samples:

34, 158680, 0.271585, -0.399003, 9.97987, 0.018326, -0.0293215, -0.00122173, 0.00672745, -0.0258199, -0.0297815
35, 158705, 0.241077, -0.482752, 9.95414, 0.0256563, -0.0146608, -0.00122173, 0.00668611, -0.0257625, -0.0306921

First sample timestamp is 158680, and second is 158705, and the difference is 25. What is the unit? What conversion is needed to ms or us?

What I've tried:

1) Set various modes for the IMU. No change.

lsm6dsox_xl_power_mode_set(&dev_ctx, LSM6DSOX_HIGH_PERFORMANCE_MD);
  lsm6dsox_gy_power_mode_set(&dev_ctx, LSM6DSOX_GY_HIGH_PERFORMANCE);
  lsm6dsox_aux_mode_set(&dev_ctx, LSM6DSOX_MODE_4_GY_XL);
  lsm6dsox_spi_mode_set(&dev_ctx, LSM6DSOX_SPI_4_WIRE);
  lsm6dsox_aux_spi_mode_set(&dev_ctx, LSM6DSOX_AUX_SPI_4_WIRE);
  lsm6dsox_ois_mode_set(&dev_ctx, LSM6DSOX_OIS_CTRL_UI_AUX_DATA_UI_AUX);

​2) used polling method instead of interrupt. Does not matter, can't get a faster data rate.

3) suspected that something is off with the project generated from _prj_MKI109V3.ioc using STM32CubeMX. I left default settings for everything, and STM32F401VETX drivers were automatically downloaded and included. Should it be manually configured?

4) Tried to max out USB speed, as I suspected that USB serial can't buffer the data, but that didn't matter, as USB serial should always be at max speed anyway. Sample time is measured in the IMU, so all the data is received from USB serial.

TL;DR: trying to read XL ang GY data from registers at rate of 6667Hz, but can't achieve it. There is some confusion how to accurately read the sample time unit. The data rate error is really apparent at the output, where i run the data through Mahony algorithm using 6667Hz, where I get a wrong calculation results, but get right calculation results when I set the algorithm speed to 1667Hz.

Any insight is welcome.

2 REPLIES 2
Federica Bossi
ST Employee

Hi @vv.tl​ ,

Welcome to ST Community!

First sample timestamp is 158680, and second is 158705, and the difference is 25. What is the unit? What conversion is needed to ms or us? Timestamp output registers: 1LSB = 25 µs as reported in datasheet.

About your issue, it's probably your limitation is due to SPI, you could try to use SPI in DMA.

If my reply answered your question, please click on Select as Best at the bottom of this post. This will help other users with the same issue to find the answer faster 🙂

In order 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.

Thank you so much.

I got the timestamp correctly calculated. So I can confirm the sample frequency varies between 1250 ... 1667 Hz.

The low sample frequency issue might be from the SPI, I agree, as I used the regular SPI from the LSM6DSOX examples. I tried SPI in DMA, but I have encountered another issue - some timestamps are now delayed, and the sample frequencies are negative for those samples (let's say 1 in 10 samples). Also the Ax and Gy values are incorrect. I'm pretty sure it's got something to do with DMA configuration. I have not found an example code for LSM6DSOX and DMA, I'm not sure how to configure the project and what are the LSM6DSOX settings to enable the highest sample frequency.

Are there any DMA examples for STEVAL-MKI109V3 and STEVAL-MKI197V, or something similar for reference?

I'm also using an interrupt. Is that needed with DMA?

interrupt:

lsm6dsox_pin_int2_route_t int2_route;  
 
lsm6dsox_pin_int2_route_get(&dev_ctx, NULL, &int2_route);
int2_route.drdy_xl = PROPERTY_ENABLE;
lsm6dsox_pin_int2_route_set(&dev_ctx, NULL, int2_route);

Example of IMU output with DMA:

readout[#], timestamp[raw], sample frequency[Hz], ax[m/s^2], ay[m/s^2], az[m/s^2], gx[rad/s], gy[rad/s], gz[rad/s], yaw[deg]. pitch[deg]. roll[deg]
 
4511, 5512239, 1250, 1.47817, 4.9005, -0.125025, -0.0158825, -0.00488692, -0.0415388, -7.8192, -37.7639, 8.36797
4512, 5512263, 1666.67, 1.40638, 4.9005, -0.110668, -0.309098, -0.00488692, -0.0415388, -7.81835, -37.7617, 8.36379
4513, 5577831, 1250, 1.52602, 4.9005, -0.0915255, -0.0256563, -0.00488692, -0.0415388, -7.81723, -37.7459, 8.3577
4514, 5446783, 1666.67, 1.44945, 4.9005, -0.0771685, -0.0158825, -0.00488692, -0.0415388, -7.81637, -37.7336, 8.35337
4515, 5446815, 1250, 1.42074, 4.9005, -0.0580259, -0.309098, -0.00488692, -0.0415388, -7.81522, -37.7305, 8.3477
4516, 5512375, 1666.67, 1.49731, 4.9005, -0.043669, -0.270002, -0.00488692, -0.0415388, -7.81437, -37.7269, 8.3432
4517, 5512407, 1250, 1.50209, 4.9005, -0.0245264, -0.28955, -0.00488692, -0.0415388, -7.81322, -37.7229, 8.33717
4518, 5512439, 1250, 1.45902, 4.9005, -0.00538385, -0.309098, -0.00488692, -0.0415388, -7.81206, -37.7197, 8.33131
4519, 5512207, -172.414, 1.45424, 4.9005, -0.144168, -0.00610865, -0.00488692, -0.0415388, -7.8201, -37.8406, 8.37313

Platform Read:

Should I use DMA everywhere, and also in platform_write(/../)? or only for HAL_SPI_Receive_DMA(/../) in platform_read(/../)?

#define STEVAL_MKI109V3
 
static int32_t platform_read(void *handle, uint8_t reg, uint8_t *bufp, uint16_t len) {
#if defined(NUCLEO_F411RE)
  HAL_I2C_Mem_Read(handle, LSM6DSOX_I2C_ADD_L, reg, I2C_MEMADD_SIZE_8BIT, bufp, len, 1000);
#elif defined(STEVAL_MKI109V3)
  reg |= 0x80;
  HAL_GPIO_WritePin(CS_up_GPIO_Port, CS_up_Pin, GPIO_PIN_RESET);
  HAL_SPI_Transmit(handle, &reg, 1, 1000);
  HAL_SPI_Receive_DMA(handle, bufp, len);
  HAL_GPIO_WritePin(CS_up_GPIO_Port, CS_up_Pin, GPIO_PIN_SET);
#elif defined(SPC584B_DIS)
  i2c_lld_read(handle, LSM6DSOX_I2C_ADD_L & 0xFE, reg, bufp, len);
#endif
  return 0;
}

spi.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    spi.c
  * @brief   This file provides code for the configuration
  *          of the SPI instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "spi.h"
 
/* USER CODE BEGIN 0 */
 
/* USER CODE END 0 */
 
SPI_HandleTypeDef hspi2;
DMA_HandleTypeDef hdma_spi2_rx;
DMA_HandleTypeDef hdma_spi2_tx;
 
/* SPI2 init function */
void MX_SPI2_Init(void)
{
 
  /* USER CODE BEGIN SPI2_Init 0 */
 
  /* USER CODE END SPI2_Init 0 */
 
  /* USER CODE BEGIN SPI2_Init 1 */
 
  /* USER CODE END SPI2_Init 1 */
  hspi2.Instance = SPI2;
  hspi2.Init.Mode = SPI_MODE_MASTER;
  hspi2.Init.Direction = SPI_DIRECTION_2LINES;
  hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi2.Init.CLKPolarity = SPI_POLARITY_HIGH;
  hspi2.Init.CLKPhase = SPI_PHASE_2EDGE;
  hspi2.Init.NSS = SPI_NSS_SOFT;
  hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI2_Init 2 */
 
  /* USER CODE END SPI2_Init 2 */
 
}
 
void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{
 
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(spiHandle->Instance==SPI2)
  {
  /* USER CODE BEGIN SPI2_MspInit 0 */
 
  /* USER CODE END SPI2_MspInit 0 */
    /* SPI2 clock enable */
    __HAL_RCC_SPI2_CLK_ENABLE();
 
    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**SPI2 GPIO Configuration
    PB13     ------> SPI2_SCK
    PB14     ------> SPI2_MISO
    PB15     ------> SPI2_MOSI
    */
    GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
    /* SPI2 DMA Init */
    /* SPI2_RX Init */
    hdma_spi2_rx.Instance = DMA1_Stream3;
    hdma_spi2_rx.Init.Channel = DMA_CHANNEL_0;
    hdma_spi2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_spi2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi2_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi2_rx.Init.Mode = DMA_NORMAL;
    hdma_spi2_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
    hdma_spi2_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_spi2_rx) != HAL_OK)
    {
      Error_Handler();
    }
 
    __HAL_LINKDMA(spiHandle,hdmarx,hdma_spi2_rx);
 
    /* SPI2_TX Init */
    hdma_spi2_tx.Instance = DMA1_Stream4;
    hdma_spi2_tx.Init.Channel = DMA_CHANNEL_0;
    hdma_spi2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_spi2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi2_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi2_tx.Init.Mode = DMA_NORMAL;
    hdma_spi2_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
    hdma_spi2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_spi2_tx) != HAL_OK)
    {
      Error_Handler();
    }
 
    __HAL_LINKDMA(spiHandle,hdmatx,hdma_spi2_tx);
 
  /* USER CODE BEGIN SPI2_MspInit 1 */
 
  /* USER CODE END SPI2_MspInit 1 */
  }
}
 
void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
{
 
  if(spiHandle->Instance==SPI2)
  {
  /* USER CODE BEGIN SPI2_MspDeInit 0 */
 
  /* USER CODE END SPI2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_SPI2_CLK_DISABLE();
 
    /**SPI2 GPIO Configuration
    PB13     ------> SPI2_SCK
    PB14     ------> SPI2_MISO
    PB15     ------> SPI2_MOSI
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15);
 
    /* SPI2 DMA DeInit */
    HAL_DMA_DeInit(spiHandle->hdmarx);
    HAL_DMA_DeInit(spiHandle->hdmatx);
  /* USER CODE BEGIN SPI2_MspDeInit 1 */
 
  /* USER CODE END SPI2_MspDeInit 1 */
  }
}
 
/* USER CODE BEGIN 1 */
 
/* USER CODE END 1 */

dma.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    dma.c
  * @brief   This file provides code for the configuration
  *          of all the requested memory to memory DMA transfers.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
 
/* Includes ------------------------------------------------------------------*/
#include "dma.h"
 
/* 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_Stream3_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
  /* DMA1_Stream4_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
 
}
 
/* USER CODE BEGIN 2 */
 
/* USER CODE END 2 */
 

Thank you for the help so far.