-
Notifications
You must be signed in to change notification settings - Fork 210
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SPI devices on shared bus (embedded-hal-bus) #925
Comments
Well, just my luck (maybe?) Looks like embedded-hal-bus came out with another implementation of SpiDevice, this one using an UnsafeCell and AtomicBool for a semaphore. https://docs.rs/embedded-hal-bus/latest/embedded_hal_bus/spi/struct.AtomicDevice.html Will try it out and report back here to see if it solves the issues here (seems like maybe it won't since this issue is about ownership, but they do call out rtic specifically so maybe I can get a read on how they intend it to be used) |
I was able to implement a workaround, like so: #![no_main]
#![no_std]
#![feature(type_alias_impl_trait)]
use bmi088::Bmi088;
use core::ptr::addr_of;
use defmt_rtt as _;
use embedded_hal_bus::spi::{AtomicDevice, NoDelay};
use embedded_hal_bus::util::AtomicCell;
use panic_probe as _;
use rtic_monotonics::systick::Systick;
use rtic_monotonics::Monotonic;
use stm32f4xx_hal::{
gpio, pac,
prelude::*,
spi::{Mode, Phase, Polarity, Spi, Spi3},
};
type Accel = AtomicDevice<'static, Spi<pac::SPI3>, gpio::Pin<'B', 5, gpio::Output>, NoDelay>;
type Gyro = AtomicDevice<'static, Spi<pac::SPI3>, gpio::Pin<'D', 2, gpio::Output>, NoDelay>;
type Spi3Bus = AtomicCell<Spi<pac::SPI3>>;
static mut SPI3BUS: Option<Spi3Bus> = None;
#[rtic::app(device = stm32f4xx_hal::pac, peripherals = true)]
mod app {
use super::*;
#[shared]
struct Shared {}
#[local]
struct Local {
accel: Accel,
gyro: Gyro,
spi3bus: &'static Option<Spi3Bus>,
}
#[init]
fn init(cx: init::Context) -> (Shared, Local) {
// Setup clocks
let dp = cx.device;
let rcc = dp.RCC.constrain();
let systick_mono_token = rtic_monotonics::create_systick_token!();
Systick::start(cx.core.SYST, 48_000_000, systick_mono_token);
let clocks = rcc.cfgr.sysclk(48.MHz()).freeze();
let gpiob = dp.GPIOB.split();
let gpioc = dp.GPIOC.split();
let gpiod = dp.GPIOD.split();
let spi: Spi3 = Spi3::new(
dp.SPI3,
(
gpioc.pc10.into_alternate(),
gpioc.pc11.into_alternate(),
gpioc.pc12.into_alternate(),
),
Mode {
polarity: Polarity::IdleLow,
phase: Phase::CaptureOnFirstTransition,
},
1.MHz(),
&clocks,
);
let (accel_dev, gyro_dev) = unsafe {
SPI3BUS = Some(AtomicCell::new(spi));
let bus = SPI3BUS.as_ref().unwrap();
(
AtomicDevice::new_no_delay(&bus, gpiob.pb5.into_push_pull_output()).unwrap(),
AtomicDevice::new_no_delay(&bus, gpiod.pd2.into_push_pull_output()).unwrap(),
)
};
imu_task::spawn().unwrap();
(
Shared {},
Local {
spi3bus: unsafe { addr_of!(SPI3BUS).as_ref().unwrap() },
accel: accel_dev,
gyro: gyro_dev,
},
)
}
#[task(local=[accel, gyro])]
async fn imu_task(cx: imu_task::Context) {
let mut accel = Bmi088::new_with_spi(cx.local.accel);
let mut gyro = Bmi088::new_with_spi(cx.local.gyro);
loop {
let now = Systick::now();
let c1 = accel.acc_chipid().unwrap();
let c2 = gyro.gyro_chipid().unwrap();
defmt::debug!("acc: {}, gyro: {}", c1, c2);
Systick::delay_until(now + 200u32.millis()).await;
}
}
} The sensor is a BMI088 which has an accelerometer and gyro which each have their own CS pins. Got around it by keeping a static ref SPI3BUS and passing that to the AtomicDevice constructor. I this should be safe, even if we have concurrent accesses, due to the AtomicDevice. |
Hi, this is now solved in |
@rland93 did you get this to work with |
Is there a canonical way to share SPI devices that are on the same bus using
embedded-hal-bus
?All variants of shared SPI devices seem to follow a pattern like this:
I have tried
RefCellDevice
andCriticalSectionDevice
(embedded-hal-bus
), as well asArbiterDevice
from rtic-sync in this pattern. It looks like this:They all run into the same issue: the compiler complains that the borrowed
bus
does not live long enough. Makes sense: the bus goes out of scope wheninit()
ends. But, that's not what we want! We want the bus to live forever so that the references to it stays valid through the life of the program. I cannot for the life of me figure out how to mark the bus as having a static lifetime or appeasing the borrow checker in some other way. Is there a standard way to do it?The text was updated successfully, but these errors were encountered: