Skip to content

Commit f58cae4

Browse files
authored
feat: add mpu-6000 example (#15)
* feat: add mpu-6000 example * Update mpu-6000.rs
1 parent ca08e5f commit f58cae4

1 file changed

Lines changed: 140 additions & 0 deletions

File tree

lab05/src/bin/mpu-6000.rs

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
use defmt::{error, info, warn};
5+
use defmt_rtt as _;
6+
use embassy_executor::Spawner;
7+
use embassy_stm32::{
8+
gpio::{Level, Output, Speed},
9+
spi::{Config, Mode, Phase, Polarity, Spi},
10+
time::Hertz,
11+
};
12+
use embassy_time::{Duration, Timer};
13+
use panic_probe as _;
14+
15+
/// MPU6000 Registers & Constants
16+
const MPU_WHO_AM_I: u8 = 0x75;
17+
const MPU_WHO_AM_I_VALUE: u8 = 0x68; // Expected value for MPU-6000
18+
const MPU_USER_CTRL: u8 = 0x6A;
19+
const MPU_PWR_MGMT_1: u8 = 0x6B;
20+
const MPU_ACCEL_XOUT_H: u8 = 0x3B;
21+
const MPU_READ: u8 = 0x80;
22+
23+
#[embassy_executor::main]
24+
async fn main(_spawner: Spawner) {
25+
let peripherals = embassy_stm32::init(Default::default());
26+
info!("Device started");
27+
28+
// Create the SPI bus configuration
29+
let mut config = Config::default();
30+
config.frequency = Hertz(1_000_000);
31+
32+
// MPU6000 requires SPI Mode 3 (CPOL=1, CPHA=1)
33+
config.mode = Mode {
34+
polarity: Polarity::IdleHigh,
35+
phase: Phase::CaptureOnSecondTransition,
36+
};
37+
38+
let mut spi = Spi::new(
39+
peripherals.SPI1,
40+
peripherals.PA5, // SCK
41+
peripherals.PA7, // MOSI
42+
peripherals.PA6, // MISO
43+
peripherals.GPDMA1_CH0,
44+
peripherals.GPDMA1_CH1,
45+
config,
46+
);
47+
48+
// We use the PA8 pin as CS
49+
let mut cs = Output::new(peripherals.PA8, Level::High, Speed::VeryHigh);
50+
51+
// Disable I2C interface
52+
let disable_i2c_buf: [u8; 2] = [MPU_USER_CTRL, 0x10];
53+
cs.set_low();
54+
if let Err(e) = spi.write(&disable_i2c_buf).await {
55+
error!("Failed to disable I2C interface: {:?}", e);
56+
}
57+
cs.set_high();
58+
59+
// Wake up MPU6000
60+
let wake_buf: [u8; 2] = [MPU_PWR_MGMT_1, 0x01];
61+
cs.set_low();
62+
if let Err(e) = spi.write(&wake_buf).await {
63+
error!("Failed to wake up MPU-6000: {:?}", e);
64+
}
65+
cs.set_high();
66+
67+
// Yield execution to the executor for 100ms to allow the sensor to stabilize
68+
Timer::after(Duration::from_millis(100)).await;
69+
70+
// Verify WHO_AM_I
71+
let command = [MPU_WHO_AM_I | MPU_READ, 0x00];
72+
let mut rx = [0u8; 2];
73+
74+
cs.set_low();
75+
let res = spi.transfer(&mut rx, &command).await;
76+
cs.set_high();
77+
78+
match res {
79+
Err(e) => {
80+
error!("SPI transfer failed during WHO_AM_I check: {:?}", e);
81+
}
82+
Ok(_) => {
83+
let who_am_i_value = rx[1];
84+
info!("Sensor's WHO_AM_I register is 0x{:02X}", who_am_i_value);
85+
86+
if who_am_i_value == MPU_WHO_AM_I_VALUE {
87+
info!("Sensor is MPU-6000");
88+
} else {
89+
warn!("This is not an MPU-6000 sensor. Expected 0x68.");
90+
}
91+
}
92+
}
93+
94+
// Scaling factors matching the default configured ranges
95+
// ±2g -> 16384 LSB/g -> multiply by (9.81 / 16384.0) for m/s²
96+
// ±250°/s -> 131 LSB/°/s -> multiply by (250.0 / 32768.0) for °/s
97+
let accel_scale: f32 = 9.81 / 16384.0;
98+
let gyro_scale: f32 = 250.0 / 32768.0;
99+
100+
// Continuous Data Reading Loop
101+
loop {
102+
let mut tx_buf = [0u8; 15];
103+
let mut rx_buf = [0u8; 15];
104+
tx_buf[0] = MPU_ACCEL_XOUT_H | MPU_READ;
105+
106+
cs.set_low();
107+
let transfer_result = spi.transfer(&mut rx_buf, &tx_buf).await;
108+
cs.set_high();
109+
110+
match transfer_result {
111+
Ok(_) => {
112+
// Parse raw 16-bit signed values (big-endian) skipping the first dummy byte
113+
let ax_raw = i16::from_be_bytes([rx_buf[1], rx_buf[2]]) as f32;
114+
let ay_raw = i16::from_be_bytes([rx_buf[3], rx_buf[4]]) as f32;
115+
let az_raw = i16::from_be_bytes([rx_buf[5], rx_buf[6]]) as f32;
116+
117+
let gx_raw = i16::from_be_bytes([rx_buf[9], rx_buf[10]]) as f32;
118+
let gy_raw = i16::from_be_bytes([rx_buf[11], rx_buf[12]]) as f32;
119+
let gz_raw = i16::from_be_bytes([rx_buf[13], rx_buf[14]]) as f32;
120+
121+
// Apply scaling
122+
let ax = ax_raw * accel_scale;
123+
let ay = ay_raw * accel_scale;
124+
let az = az_raw * accel_scale;
125+
let gx = gx_raw * gyro_scale;
126+
let gy = gy_raw * gyro_scale;
127+
let gz = gz_raw * gyro_scale;
128+
129+
info!("Accel (m/s²): X={}, Y={}, Z={}", ax, ay, az);
130+
info!("Gyro (°/s): X={}, Y={}, Z={}", gx, gy, gz);
131+
}
132+
Err(e) => {
133+
// If a read fails, we just log it and the loop will try again after the delay
134+
warn!("Failed to read from sensor: {:?}", e);
135+
}
136+
}
137+
138+
Timer::after(Duration::from_millis(100)).await;
139+
}
140+
}

0 commit comments

Comments
 (0)