working everything properly well
This commit is contained in:
132
mqtt_display/src/mpu/task.rs
Normal file
132
mqtt_display/src/mpu/task.rs
Normal file
@@ -0,0 +1,132 @@
|
||||
// src/mpu/task.rs
|
||||
//! MPU6050 sampling task.
|
||||
//!
|
||||
//! This task:
|
||||
//! 1. Initializes the MPU6050 sensor
|
||||
//! 2. Continuously reads sensor data at a fixed rate
|
||||
//! 3. Publishes readings to the IMU channel
|
||||
|
||||
use embassy_time::{Duration, Instant, Timer};
|
||||
use log::{error, info, warn};
|
||||
|
||||
use crate::bus::I2cDevice;
|
||||
use crate::contracts::ImuReading;
|
||||
use crate::mpu::api::sender;
|
||||
use crate::mpu::driver::Mpu6050;
|
||||
|
||||
/// Sampling interval in milliseconds.
|
||||
/// 50ms = 20Hz, reasonable for display updates.
|
||||
const SAMPLE_INTERVAL_MS: u64 = 50;
|
||||
|
||||
/// MPU6050 I2C address (0x68 with AD0 low, 0x69 with AD0 high)
|
||||
const MPU_ADDR: u8 = 0x68;
|
||||
|
||||
/// The MPU6050 sampling task.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `i2c` - An I2C device handle from the shared bus
|
||||
///
|
||||
/// # Panics
|
||||
/// Does not panic; logs errors and retries on failure.
|
||||
#[embassy_executor::task]
|
||||
pub async fn mpu_task(i2c: I2cDevice) {
|
||||
info!("MPU task starting...");
|
||||
|
||||
let mut mpu = Mpu6050::new(i2c, MPU_ADDR);
|
||||
|
||||
// Initialize with retries
|
||||
let mut init_attempts = 0;
|
||||
loop {
|
||||
init_attempts += 1;
|
||||
|
||||
// Verify device is present
|
||||
match mpu.verify() {
|
||||
Ok(true) => {
|
||||
info!("MPU6050 detected at 0x{:02X}", MPU_ADDR);
|
||||
}
|
||||
Ok(false) => {
|
||||
warn!(
|
||||
"Device at 0x{:02X} is not MPU6050 (attempt {})",
|
||||
MPU_ADDR, init_attempts
|
||||
);
|
||||
Timer::after(Duration::from_secs(2)).await;
|
||||
continue;
|
||||
}
|
||||
Err(_e) => {
|
||||
warn!(
|
||||
"I2C error verifying MPU6050 (attempt {})",
|
||||
init_attempts
|
||||
);
|
||||
Timer::after(Duration::from_secs(2)).await;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize sensor
|
||||
match mpu.init() {
|
||||
Ok(()) => {
|
||||
info!("MPU6050 initialized successfully");
|
||||
break;
|
||||
}
|
||||
Err(_e) => {
|
||||
error!("MPU6050 init failed (attempt {})", init_attempts);
|
||||
Timer::after(Duration::from_secs(2)).await;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Allow sensor to stabilize after wake-up
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
|
||||
info!("MPU task entering sampling loop ({}ms interval)", SAMPLE_INTERVAL_MS);
|
||||
|
||||
let tx = sender();
|
||||
let mut consecutive_errors = 0u32;
|
||||
|
||||
loop {
|
||||
let start = Instant::now();
|
||||
|
||||
match mpu.read() {
|
||||
Ok((accel_g, gyro_dps, temp_c)) => {
|
||||
consecutive_errors = 0;
|
||||
|
||||
let reading = ImuReading {
|
||||
accel_g,
|
||||
gyro_dps,
|
||||
temp_c,
|
||||
timestamp_ms: start.as_millis(),
|
||||
};
|
||||
|
||||
// Try to send; if queue is full, drop oldest by using try_send
|
||||
// This ensures we never block the sampling loop
|
||||
if tx.try_send(reading).is_err() {
|
||||
// Queue full - that's okay, main will get the next one
|
||||
}
|
||||
}
|
||||
Err(_e) => {
|
||||
consecutive_errors += 1;
|
||||
if consecutive_errors == 1 || consecutive_errors % 10 == 0 {
|
||||
warn!("MPU read error (consecutive: {})", consecutive_errors);
|
||||
}
|
||||
|
||||
// If too many errors, try to reinitialize
|
||||
if consecutive_errors >= 50 {
|
||||
error!("Too many MPU errors, attempting reinit...");
|
||||
if mpu.init().is_ok() {
|
||||
info!("MPU reinit successful");
|
||||
consecutive_errors = 0;
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sleep for remainder of interval
|
||||
let elapsed = start.elapsed();
|
||||
let target = Duration::from_millis(SAMPLE_INTERVAL_MS);
|
||||
if elapsed < target {
|
||||
Timer::after(target - elapsed).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user