Attitude Estimation· Live
Home / Chapter 2 / 2.6

STM32: use the driver in main.c and read the data

Lesson 2.6 · STM32 · free

Video coming soon

We write the three board functions with HAL, put them in one imu_t struct and give it to the driver. Then we start the sensor once and read it fifty times per second, and six raw numbers move live in the serial plotter.

In this lesson · 5 steps
  1. Include the driver
  2. The three board functions
  3. Start the sensor
  4. Read and print every tick
  5. Build, run and plot

1Include the driver

main.c · USER CODE BEGIN Includes

main.c now knows the driver: imu_t, ism330dhcx_init and ism330dhcx_read.

/* USER CODE BEGIN Includes */
#include "ism330dhcx.h"
/* USER CODE END Includes */
Why?
Use the header of your own sensor if it's another IMU.

2The three board functions

main.c · USER CODE BEGIN 0

The only STM32-specific code: on another board, only these three functions change.

/* USER CODE BEGIN 0 */
/* read: start at register reg, read length bytes */
int stm32_read(uint8_t address, uint8_t reg, uint8_t *data, uint16_t length)
{
  if (HAL_I2C_Mem_Read(&hi2c1, address << 1, reg, I2C_MEMADD_SIZE_8BIT, data, length, 100) != HAL_OK)
    return -1;
  return 0;
}

/* write: one value into register reg */
int stm32_write(uint8_t address, uint8_t reg, uint8_t value)
{
  if (HAL_I2C_Mem_Write(&hi2c1, address << 1, reg, I2C_MEMADD_SIZE_8BIT, &value, 1, 100) != HAL_OK)
    return -1;
  return 0;
}

void stm32_delay(uint32_t ms)
{
  HAL_Delay(ms);
}

/* our IMU: its address + the three board functions */
imu_t imu = {
  .address = ISM330DHCX_ADDR,   /* 0x6A */
  .read    = stm32_read,
  .write   = stm32_write,
  .delay   = stm32_delay,
};
/* USER CODE END 0 */
Why?
stm32_write: puts one value into one register (HAL_I2C_Mem_Write, address << 1), returns 0 = OK.
stm32_read: reads length bytes starting at register reg (HAL_I2C_Mem_Read, address << 1), returns 0 = OK.
stm32_delay: waits ms (HAL_Delay).
imu (an imu_t) holds the address and the three functions. Board answers at 0x6B? Change ISM330DHCX_ADDR in the header. See lesson 2.4 for the big picture.

3Start the sensor

main.c · USER CODE BEGIN 2 (replace the WHO_AM_I code from 2.3)

We start the sensor once and print if it worked. ism330dhcx_init checks WHO_AM_I, resets the sensor and sets the range and output rate.

  /* USER CODE BEGIN 2 */
  if (ism330dhcx_init(&imu))
    printf("IMU ready\r\n");
  else
    printf("IMU not found: check the wires, the address and the sensor type\r\n");
  /* USER CODE END 2 */
Why?
It returns true if everything worked.

4Read and print every tick

main.c · inside while (1), USER CODE BEGIN 3 (inside the tick block from 1.3)

Every tick, 50 times per second, we read the sensor and print six values.

    /* USER CODE BEGIN 3 */
    if (tick == 1)
    {
      tick = 0;

      imu_raw_t raw;
      if (ism330dhcx_read(&imu, &raw))
        printf("ax:%d,ay:%d,az:%d,gx:%d,gy:%d,gz:%d\r\n",
               raw.ax, raw.ay, raw.az, raw.gx, raw.gy, raw.gz);
    }
  }
  /* USER CODE END 3 */
Why?
The timer sets tick every 20 ms; we clear it and do our work. One call reads 12 registers: gyro x, y, z, then accel x, y, z. We print them as name:value, so the plotter shows six lines. Raw numbers for now: g and degrees per second come later.

5Build, run and plot

  1. Build Project (0 errors), Debug; open the serial plotter (115200 baud, ST-LINK port) and connect, then press Resume
  2. Six lines move in the plot; tilt and turn the board and they swing
Check & troubleshoot

What you should see

  • The console prints IMU ready once at start
  • Six lines (ax, ay, az, gx, gy, gz) update fifty times per second
  • When you tilt the board, the accelerometer lines move; when you rotate it, the gyroscope lines move

If it doesn't work

  • IMU not found: check the wires (SCL → PB6, SDA → PB7, 3V3, GND) and the address: hex 6A or 6B, depending on the SDO pin of your board
  • Nothing in the plotter: open the plotter before you press Resume, baud 115200, choose the ST-LINK port
  • Code disappears after Generate Code: keep every line inside a USER CODE section, including imu_raw_t raw;

Good to know

  • Two conventions: our board functions return 0 when they worked; the driver functions (ism330dhcx_init, ism330dhcx_read) return true when they worked
  • imu_raw_t is the driver's struct for the six raw values; ISM330DHCX_ADDR is the sensor address from the header
  • tick is the flag from lesson 1.3: the timer sets it every 20 ms
  • Resume is the play button in the debugger. Open the plotter first, then start the program, so you don't miss the first message

Next: Lesson 2.6b: the same driver on the ESP32, with Wire instead of HAL.