一、外设配置

首先,查阅原理图,如下图:

这款传感器仍旧采用spi与MCU进行通信。

首先,在CUBEMX中进行SPI 的配置。由于需要将采集到的数据显示在PC端,我们采用USART2利用串口的方式与PC端通信。这些的配置和测评4的cubemx配置除过SPI参数部分其他完全相同,大家可以点击链接参考CUBEMX的基础配置,此处我不再赘述。(后面仅讲解SPI参数部分配置)

这里首先想通过这个芯片的数据手册和大家进行一些分享学习,这款ISM330DHCX芯片功能比较强大,可以测试加速度,角速度,芯片内部温度三种数据,支持spi/i2c通信。

此外,这款芯片还支持机器学习

ISM330DHCX内嵌了专门的机器学习处理核心,从而提供了系统灵活性,使得原本在应用处理器中运行的某些算法可以迁移到MEMS传感器上,同时还能实现一致的功耗降低。

在cubemx配置过程中,发现这款芯片上还有其他三个引脚,我们是否需要配置呢?

其中,INT1,INT2我们在CUBEMX中是不需要进行配置的,因为查看数据手册我们可以得知,这两个引脚的功能是一个中断的作用,我们无需在CUBEMX和后面的程序中对此做任何修改。

但是,CS片选引脚,我们需要再后面的程序中将其拉低,才可以让芯片正常工作。

根据时序图配置CPOL和CPHA

CPOL: CS 拉低(选中从机 )后,SPC 在 “等待传输” 的那段空闲期(最开始的水平段 )是高电平 → 所以 CPOL = 1 。

CPHA: 这个相较于CPOL而言较为复杂。

首先看他的定义:决定 “数据采样是在时钟的上升沿还是下降沿” ,本质是 “数据与时钟沿的对齐方式” 。

CPHA = 0 :在 “时钟空闲电平跳变到相反电平的第一个边沿” 采样(比如 CPOL=1 时,空闲是高,第一个边沿是 “下降沿” ,就用下降沿采样 )。

CPHA = 1 :在 “时钟完成一次跳变后的第二个边沿” 采样(比如 CPOL=1 时,先从高→低(下降沿 ),再低→高(上升沿 ),第二个边沿是上升沿,就用上升沿采样 )。

根据我们这个时序图发现,时钟空闲电平跳变到相反电平的第一个边沿,并没有进行数据采样

而是,在时钟完成一次跳变后的第一个边沿采样。

CUBEMX中这部分的配置如下,其他部分完全相同

二、BSP包下载与安装,代码编写

参考测评3下载对应的板级支持包,也同样参考测评3将下载的BSP包安装到相应路径

我将修改好的ism330dhcx_read_data_polling.c文件同样分享给大家,可以直接粘贴替换。

/*
 ******************************************************************************
 * @file    read_data_polling.c
 * @author  Sensors Software Solution Team
 * @brief   This file shows how to get data from ISM330DHCX sensor on STWINKT1B.
 *
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; Copyright (c) 2020 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
 *
 ******************************************************************************
 */

/* 仅启用STWINKT1B开发板定义 */
#define STWINKT1B  /* 主控为STM32L4R9ZIJ6的STWINKT1B开发板 */

#if defined(STWINKT1B)
/* 传感器通信接口:SPI3(STWINKT1B上ISM330DHCX连接SPI3,原理图3/7节) */
#define SENSOR_BUS hspi3
/* 片选引脚定义(根据STWINKT1B原理图3/7,ISM330DHCX的CS引脚为PF13){insert\_element\_0\_} */
#define CS_PORT    GPIOF
#define CS_PIN     GPIO_PIN_13
/* 串口输出接口:USART2(TX=PA2,RX=PA3,用于数据发送到PC) */
#define COM_UART   huart2
#endif

/* Includes ------------------------------------------------------------------*/
#include <string.h>
#include <stdio.h>
#include "ism330dhcx_reg.h"
#include "stm32l4xx_hal.h"  /* STM32L4系列HAL库 */
#include "usart.h"           /* USART2初始化代码(CubeMX生成) */
#include "spi.h"             /* SPI3初始化代码(CubeMX生成) */
#include "gpio.h"            /* GPIO初始化代码(CubeMX生成) */

/* Private macro -------------------------------------------------------------*/
#define BOOT_TIME          10  // 传感器启动时间(ms),符合数据手册4.2节电气特性

/* Private variables ---------------------------------------------------------*/
static int16_t data_raw_acceleration[3];       // 加速度原始数据
static int16_t data_raw_angular_rate[3];       // 角速度原始数据
static int16_t data_raw_temperature;           // 温度原始数据
static float_t acceleration_mg[3];             // 加速度转换后数据(mg)
static float_t angular_rate_mdps[3];           // 角速度转换后数据(mdps)
static float_t temperature_degC;               // 温度转换后数据(℃)
static uint8_t whoamI, rst;                    // 设备ID和复位状态
static uint8_t tx_buffer[256];                 // 串口发送缓冲区

/* Private functions ---------------------------------------------------------*/
static int32_t platform_write(void *handle, uint8_t reg,  uint8_t *bufp, uint16_t len);
static int32_t platform_read(void *handle, uint8_t reg, uint8_t *bufp, uint16_t len);
static void tx_com(uint8_t *tx_buffer, uint16_t len);
static void platform_delay(uint32_t ms);
static void platform_init(void);

/* Main Example --------------------------------------------------------------*/
void ism330dhcx_read_data_polling(void)
{
  stmdev_ctx_t dev_ctx;  // 传感器设备上下文

  /* 初始化设备接口 */
  dev_ctx.write_reg = platform_write;    // 绑定写函数
  dev_ctx.read_reg = platform_read;      // 绑定读函数
  dev_ctx.mdelay = platform_delay;       // 绑定延时函数
  dev_ctx.handle = &SENSOR_BUS;          // 绑定SPI句柄

  /* 初始化硬件平台 */
  platform_init();

  /* 等待传感器启动(数据手册4.2节规定启动时间Typ=35ms,此处留有余量) */
  platform_delay(BOOT_TIME);

  /* 读取设备ID(数据手册9.11节,WHO_AM_I寄存器地址0Fh,默认值6Bh) */
  ism330dhcx_device_id_get(&dev_ctx, &whoamI);
  if (whoamI != ISM330DHCX_ID)  // 校验设备ID
    while (1);  // ID错误则卡死

  /* 软件复位传感器(数据手册9.14节,CTRL3_C寄存器SW_RESET位) */
  ism330dhcx_reset_set(&dev_ctx, PROPERTY_ENABLE);
  do {
    ism330dhcx_reset_get(&dev_ctx, &rst);
  } while (rst);  // 等待复位完成

  /* 配置传感器工作模式 */
  ism330dhcx_device_conf_set(&dev_ctx, PROPERTY_ENABLE);  // 使能设备
  ism330dhcx_block_data_update_set(&dev_ctx, PROPERTY_ENABLE);  // 使能块数据更新(BDU)

  /* 配置输出数据率(ODR):根据数据手册9.12/9.13节 */
  ism330dhcx_xl_data_rate_set(&dev_ctx, ISM330DHCX_XL_ODR_12Hz5);  // 加速度计12.5Hz
  ism330dhcx_gy_data_rate_set(&dev_ctx, ISM330DHCX_GY_ODR_12Hz5);  // 陀螺仪12.5Hz

  /* 配置量程:根据数据手册4.1节机械特性 */
  ism330dhcx_xl_full_scale_set(&dev_ctx, ISM330DHCX_2g);           // 加速度计量程±2g
  ism330dhcx_gy_full_scale_set(&dev_ctx, ISM330DHCX_2000dps);      // 陀螺仪量程±2000dps

  /* 配置滤波器(数据手册6.4节):加速度计LPF2使能 */
  ism330dhcx_xl_filter_lp2_set(&dev_ctx, PROPERTY_ENABLE);

  /* 轮询模式读取数据 */
  while (1) {
    uint8_t reg;

    /* 读取加速度数据(数据就绪标志:STATUS_REG寄存器XLDA位) */
    ism330dhcx_xl_flag_data_ready_get(&dev_ctx, &reg);
    if (reg) {
      ism330dhcx_acceleration_raw_get(&dev_ctx, data_raw_acceleration);
      acceleration_mg[0] = ism330dhcx_from_fs2g_to_mg(data_raw_acceleration[0]);
      acceleration_mg[1] = ism330dhcx_from_fs2g_to_mg(data_raw_acceleration[1]);
      acceleration_mg[2] = ism330dhcx_from_fs2g_to_mg(data_raw_acceleration[2]);
      snprintf((char *)tx_buffer, sizeof(tx_buffer),
              "Acceleration [mg]: X=%.2f, Y=%.2f, Z=%.2f\r\n",
              acceleration_mg[0], acceleration_mg[1], acceleration_mg[2]);
      tx_com(tx_buffer, strlen((char const *)tx_buffer));
    }

    /* 读取角速度数据(数据就绪标志:STATUS_REG寄存器GDA位) */
    ism330dhcx_gy_flag_data_ready_get(&dev_ctx, &reg);
    if (reg) {
      ism330dhcx_angular_rate_raw_get(&dev_ctx, data_raw_angular_rate);
      angular_rate_mdps[0] = ism330dhcx_from_fs2000dps_to_mdps(data_raw_angular_rate[0]);
      angular_rate_mdps[1] = ism330dhcx_from_fs2000dps_to_mdps(data_raw_angular_rate[1]);
      angular_rate_mdps[2] = ism330dhcx_from_fs2000dps_to_mdps(data_raw_angular_rate[2]);
      snprintf((char *)tx_buffer, sizeof(tx_buffer),
              "Angular rate [mdps]: X=%.2f, Y=%.2f, Z=%.2f\r\n",
              angular_rate_mdps[0], angular_rate_mdps[1], angular_rate_mdps[2]);
      tx_com(tx_buffer, strlen((char const *)tx_buffer));
    }

    /* 读取温度数据(数据就绪标志:STATUS_REG寄存器TDA位) */
    ism330dhcx_temp_flag_data_ready_get(&dev_ctx, &reg);
    if (reg) {
      ism330dhcx_temperature_raw_get(&dev_ctx, &data_raw_temperature);
      temperature_degC = ism330dhcx_from_lsb_to_celsius(data_raw_temperature);
      snprintf((char *)tx_buffer, sizeof(tx_buffer),
              "Temperature: %.2f\r\n", temperature_degC);
      tx_com(tx_buffer, strlen((char const *)tx_buffer));
    }

    platform_delay(100);  // 轮询间隔100ms
  }
}

/* SPI写函数(平台相关) */
static int32_t platform_write(void *handle, uint8_t reg, uint8_t *bufp, uint16_t len)
{
  /* 片选拉低(选中传感器) */
  HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_RESET);
  
  /* 发送寄存器地址(SPI写命令:地址最高位为0,数据手册5.1.2节) */
  uint8_t tx_reg = reg & 0x7F;
  HAL_SPI_Transmit(handle, &tx_reg, 1, 100);
  
  /* 发送数据 */
  HAL_SPI_Transmit(handle, (uint8_t*)bufp, len, 100);
  
  /* 片选拉高(释放传感器) */
  HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_SET);
  return 0;
}

/* SPI读函数(平台相关) */
static int32_t platform_read(void *handle, uint8_t reg, uint8_t *bufp, uint16_t len)
{
  /* 片选拉低(选中传感器) */
  HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_RESET);
  
  /* 发送寄存器地址(SPI读命令:地址最高位为1,数据手册5.1.2节) */
  uint8_t tx_reg = reg | 0x80;
  HAL_SPI_Transmit(handle, &tx_reg, 1, 100);
  
  /* 接收数据 */
  HAL_SPI_Receive(handle, bufp, len, 100);
  
  /* 片选拉高(释放传感器) */
  HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_SET);
  return 0;
}

/* 串口发送函数(平台相关) */
static void tx_com(uint8_t *tx_buffer, uint16_t len)
{
  HAL_UART_Transmit(&COM_UART, tx_buffer, len, 1000);  // 通过USART2发送
}

/* 延时函数(平台相关) */
static void platform_delay(uint32_t ms)
{
  HAL_Delay(ms);  // 使用HAL库延时
}

/* 平台初始化函数(硬件初始化) */
static void platform_init(void)
{
  /* 初始化SPI3、USART2、GPIO(由CubeMX自动生成,需确保以下配置):
   * - SPI3配置:模式3(CPOL=1,CPHA=1),速率≤10MHz(数据手册4.4.1节)
   * - CS_PIN(PF13):推挽输出,初始高电平(原理图3/7节){insert\_element\_1\_}
   * - USART2:波特率115200,8N1
   */
  MX_SPI3_Init();
  MX_USART2_UART_Init();
  MX_GPIO_Init();
  
  /* 初始化片选引脚为高电平(未选中传感器) */
  HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_SET);
}

在主函数中添加相应的.h文件和一部分代码

然后,编译烧录即可

三、效果实现

通过串口打印到PC端,可以接收到三种数据,如下图所示:

其中角速度单位为: mdps  ( milli degrees per second) 表示  毫度每秒

同样,我们MATLAB生成对应的折线图,观测数据变化

在两侧的红框里边是处于静止状态,中间的部分是我进行抖动的变化,据图可见数据变化还是比较灵敏,但是在静止状态下我们发现会出现一些抖动的点,这部分还没有理解是怎么回事。

 

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐