main: first implementation of a way to handle interrupts from sensors. untested!!
This commit is contained in:
@@ -12,17 +12,17 @@ use embassy_executor::Spawner;
|
|||||||
use embassy_time::{Duration, Instant, Timer, WithTimeout};
|
use embassy_time::{Duration, Instant, Timer, WithTimeout};
|
||||||
|
|
||||||
use enum_map::EnumMap;
|
use enum_map::EnumMap;
|
||||||
use esp_hal::{gpio::{Output, OutputConfig, Pin}, time::Rate};
|
use esp_hal::{gpio::{Event, Input, InputConfig, Output, OutputConfig, Pin}, handler, time::Rate};
|
||||||
use esp_hal::{
|
use esp_hal::{
|
||||||
clock::CpuClock, timer::{systimer::SystemTimer, timg::{TimerGroup, Wdt}}
|
clock::CpuClock, timer::{systimer::SystemTimer, timg::{TimerGroup, Wdt}}
|
||||||
};
|
};
|
||||||
|
|
||||||
use embassy_sync::{
|
use embassy_sync::{
|
||||||
blocking_mutex::raw::NoopRawMutex, channel::DynamicReceiver, pubsub::PubSubChannel
|
blocking_mutex::raw::NoopRawMutex, channel::DynamicReceiver, once_lock::OnceLock, pubsub::PubSubChannel, signal::Signal
|
||||||
};
|
};
|
||||||
use esp_storage::FlashStorage;
|
use esp_storage::FlashStorage;
|
||||||
use log::*;
|
use log::*;
|
||||||
use renderbug_bike::{events::{Prediction, SensorSource, SensorState}, graphics::display::DisplayControls, logging::RenderbugLogger, simdata::IMUReading, storage::{SharedFlash, SimDataRecorder}, tasks::{oled::{OledUI, OledUiSurfacePool, oled_ui}, safetyui::{SafetyUi, safety_ui_main}, ui::UiSurfacePool}, tracing::Tracer};
|
use renderbug_bike::{events::{Prediction, SensorSource, SensorState}, gpio_interrupt::{InterruptDispatch, PinInterrupt}, graphics::display::DisplayControls, logging::RenderbugLogger, simdata::IMUReading, storage::{SharedFlash, SimDataRecorder}, tasks::{oled::{OledUI, OledUiSurfacePool, oled_ui}, safetyui::{SafetyUi, safety_ui_main}, ui::UiSurfacePool}, tracing::Tracer};
|
||||||
use renderbug_bike::events::Measurement;
|
use renderbug_bike::events::Measurement;
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use esp_backtrace as _;
|
use esp_backtrace as _;
|
||||||
@@ -45,6 +45,12 @@ static WIFI_INIT: StaticCell<esp_radio::Controller<'static>> = StaticCell::new()
|
|||||||
|
|
||||||
rtos_trace::global_trace!(Tracer);
|
rtos_trace::global_trace!(Tracer);
|
||||||
|
|
||||||
|
static INTERRUPTS: OnceLock<InterruptDispatch<'static, 4>> = OnceLock::new();
|
||||||
|
#[handler]
|
||||||
|
fn gpio_interrupt_handler() {
|
||||||
|
INTERRUPTS.try_get().unwrap().process_interrupts();
|
||||||
|
}
|
||||||
|
|
||||||
#[esp_rtos::main]
|
#[esp_rtos::main]
|
||||||
async fn main(spawner: Spawner) {
|
async fn main(spawner: Spawner) {
|
||||||
// If we aren't using the second CPU, we can use the bootloader space for the heap instead
|
// If we aren't using the second CPU, we can use the bootloader space for the heap instead
|
||||||
@@ -94,6 +100,20 @@ async fn main(spawner: Spawner) {
|
|||||||
// Spawn the rendering task as soon as possible so it can start pushing pixels
|
// Spawn the rendering task as soon as possible so it can start pushing pixels
|
||||||
spawner.must_spawn(renderbug_bike::tasks::render::render(peripherals.SPI2.degrade(), peripherals.DMA_CH2.degrade(), peripherals.GPIO5.degrade(), surfaces, safety_surfaces, display_controls, wdt));
|
spawner.must_spawn(renderbug_bike::tasks::render::render(peripherals.SPI2.degrade(), peripherals.DMA_CH2.degrade(), peripherals.GPIO5.degrade(), surfaces, safety_surfaces, display_controls, wdt));
|
||||||
|
|
||||||
|
let imu_interrupt = PinInterrupt::new(Input::new(peripherals.GPIO36.degrade(), InputConfig::default()), Event::RisingEdge);
|
||||||
|
let pd_interrupt = PinInterrupt::new(Input::new(peripherals.GPIO16.degrade(), InputConfig::default()), Event::RisingEdge);
|
||||||
|
let sd_detect_interrupt = PinInterrupt::new(Input::new(peripherals.GPIO42.degrade(), InputConfig::default()), Event::RisingEdge);
|
||||||
|
let gps_pulse_interrupt = PinInterrupt::new(Input::new(peripherals.GPIO45.degrade(), InputConfig::default()), Event::RisingEdge);
|
||||||
|
|
||||||
|
INTERRUPTS.init(InterruptDispatch::new([
|
||||||
|
imu_interrupt.clone(),
|
||||||
|
pd_interrupt.clone(),
|
||||||
|
sd_detect_interrupt.clone(),
|
||||||
|
gps_pulse_interrupt.clone()
|
||||||
|
])).ok();
|
||||||
|
let mut io = esp_hal::gpio::Io::new(peripherals.IO_MUX);
|
||||||
|
io.set_interrupt_handler(gpio_interrupt_handler);
|
||||||
|
|
||||||
#[cfg(feature="motion")]
|
#[cfg(feature="motion")]
|
||||||
{
|
{
|
||||||
use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice;
|
use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice;
|
||||||
@@ -108,7 +128,7 @@ async fn main(spawner: Spawner) {
|
|||||||
let i2c = I2c::new(peripherals.I2C1, Config::default()).unwrap().with_scl(scl).with_sda(sda).into_async();
|
let i2c = I2c::new(peripherals.I2C1, Config::default()).unwrap().with_scl(scl).with_sda(sda).into_async();
|
||||||
let i2c_bus = I2C_BUS.init(Mutex::new(i2c));
|
let i2c_bus = I2C_BUS.init(Mutex::new(i2c));
|
||||||
#[cfg(feature="mpu")]
|
#[cfg(feature="mpu")]
|
||||||
spawner.must_spawn(renderbug_bike::tasks::mpu::mpu_task(motion_bus.dyn_sender(), I2cDevice::new(i2c_bus)));
|
spawner.must_spawn(renderbug_bike::tasks::mpu::mpu_task(motion_bus.dyn_sender(), I2cDevice::new(i2c_bus), imu_interrupt));
|
||||||
#[cfg(feature="gps")]
|
#[cfg(feature="gps")]
|
||||||
spawner.must_spawn(renderbug_bike::tasks::gps::gps_task(motion_bus.dyn_sender(), I2cDevice::new(i2c_bus)));
|
spawner.must_spawn(renderbug_bike::tasks::gps::gps_task(motion_bus.dyn_sender(), I2cDevice::new(i2c_bus)));
|
||||||
}
|
}
|
||||||
|
|||||||
62
src/gpio_interrupt.rs
Normal file
62
src/gpio_interrupt.rs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
use core::cell::RefCell;
|
||||||
|
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
use critical_section::Mutex;
|
||||||
|
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal};
|
||||||
|
use esp_hal::gpio::Input;
|
||||||
|
|
||||||
|
pub struct InterruptDispatch<'a, const COUNT: usize> {
|
||||||
|
interrupts: [PinInterrupt<'a>; COUNT]
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, const COUNT: usize> InterruptDispatch<'a, COUNT> {
|
||||||
|
pub fn new(interrupts: [PinInterrupt<'a>; COUNT]) -> Self {
|
||||||
|
Self { interrupts }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_interrupts(&self) {
|
||||||
|
for interrupt in &self.interrupts {
|
||||||
|
interrupt.handle_interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct PinInterrupt<'a> {
|
||||||
|
pin: Arc<Mutex<RefCell<Input<'a>>>>,
|
||||||
|
signal: Arc<Signal<CriticalSectionRawMutex, esp_hal::gpio::Level>>,
|
||||||
|
event: esp_hal::gpio::Event
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PinInterrupt<'a> {
|
||||||
|
pub fn new(pin: Input<'a>, event: esp_hal::gpio::Event) -> Self {
|
||||||
|
Self {
|
||||||
|
pin: Arc::new(Mutex::new(RefCell::new(pin))),
|
||||||
|
signal: Arc::new(Signal::new()),
|
||||||
|
event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_interrupt(&self) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let locked = self.pin.borrow(cs);
|
||||||
|
let mut pin = locked.borrow_mut();
|
||||||
|
if pin.is_interrupt_set() {
|
||||||
|
pin.clear_interrupt();
|
||||||
|
self.signal.signal(pin.level());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn listen(&self) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let locked = self.pin.borrow(cs);
|
||||||
|
let mut pin = locked.borrow_mut();
|
||||||
|
pin.listen(self.event);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn wait_for_interrupt(&self) -> esp_hal::gpio::Level {
|
||||||
|
self.signal.wait().await
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ pub mod graphics;
|
|||||||
pub mod tracing;
|
pub mod tracing;
|
||||||
pub mod storage;
|
pub mod storage;
|
||||||
pub mod simdata;
|
pub mod simdata;
|
||||||
|
pub mod gpio_interrupt;
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use mpu6050_dmp::{address::Address, error_async::Error, sensor_async::Mpu6050};
|
|||||||
use nalgebra::Vector3;
|
use nalgebra::Vector3;
|
||||||
use crate::events::SensorSource;
|
use crate::events::SensorSource;
|
||||||
|
|
||||||
|
use crate::gpio_interrupt::PinInterrupt;
|
||||||
use crate::{backoff::Backoff, events::Measurement};
|
use crate::{backoff::Backoff, events::Measurement};
|
||||||
|
|
||||||
const G: f32 = 9.80665;
|
const G: f32 = 9.80665;
|
||||||
@@ -19,7 +20,7 @@ const GYRO_SCALE: GyroFullScale = GyroFullScale::Deg2000;
|
|||||||
const ACCEL_SCALE: AccelFullScale = AccelFullScale::G2;
|
const ACCEL_SCALE: AccelFullScale = AccelFullScale::G2;
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
pub async fn mpu_task(events: DynamicSender<'static, Measurement>, bus: I2cDevice<'static, NoopRawMutex, I2c<'static, Async>>) {
|
pub async fn mpu_task(events: DynamicSender<'static, Measurement>, bus: I2cDevice<'static, NoopRawMutex, I2c<'static, Async>>, _interrupt: PinInterrupt<'static>) {
|
||||||
let backoff = Backoff::from_millis(5);
|
let backoff = Backoff::from_millis(5);
|
||||||
let busref = RefCell::new(Some(bus));
|
let busref = RefCell::new(Some(bus));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user