wg
wg copied to clipboard
Request for Feedback: embedded-platform
I recently started down a rabbit hole of creating my own abstraction over embedded-hal that makes it easy to mix and match various dev boards. My initial use-case has been to do experiments with Adafruit Feather boards, where I want to plug two devices together and expect the code to "just work" without having to figure out the specific pin/peripheral mappings between them. On the other hand, I didn't want to go all in and rewrite all crates in existence; instead, I wanted to rely on existing -hal and driver crates as much as possible.
As a result, I created https://github.com/dflemstr/embedded-platform (see docs at https://docs.rs/embedded-platform, in particular the example Feather spec). I realize that the scope of that library is huge and hence I would like to get feedback on the approach. I'm happy to share control of the repository in case others think this is a good idea, or yank the crate if not :)
Since I'm not super familiar with this WG, I don't know which exact process to follow here. Please give me input on what to do!
A teaser example:
async fn run() -> Result<(), nrf52840_platform::error::Error> {
use embedded_platform::platform::PlatformExt;
let platform = nrf52840_platform::ParticleArgon::initialize().await?;
feather_blink(platform).await?;
Ok(())
}
async fn feather_blink<P>(mut feather: P) -> Result<(), P::Error>
where
P: embedded_platform::specs::feather::Feather,
{
use embedded_platform::gpio::IntoPushPullOutputPin;
use embedded_platform::gpio::OutputPinExt;
let mut main_led = feather.take_main_led().into_push_pull_output_pin(false)?;
let mut on = false;
let timer = todo!(); // TODO: didn't have time to implement timer API yet
while let _ = timer.next().await? {
on = !on;
main_led.set(on).await?;
}
}
Quoting the README:
This is defines the
embedded-platformset of crates. The idea is to add device and peripheral support to complementembedded-hal-based crates. This makes it possible to plug-and-play and mix-and-match different crates that adhere to common specs. For example, if you have anrf52840-based MCU as well as aili9341-based device, and both adhere to the Adafruit Feather spec (pin layout, voltage levels, ...), you can connect them up and all the wiring will be done for you.The ambition is that
embedded-platformshould be toembedded-halwhattokiois tomio.Some design trade-offs that have been made:
#![forbid(unsafe_code)]; that belongs in-pacor-halcrates.- Don't require
alloc.- Do some compatibility checks at runtime during startup instead of at compile time, for example to check that a pin is used only once. It turns out to be super tricky to do granular ownership mapping of device registers at compile time (this has been done in
drone-os), and instead we opt to do some checks at runtime (e.g.Option::take). This wastes a dozen or so instructions at startup, which is a one-time cost.- All APIs are async-first, so that code won't have to block and we can be power efficient. This does require an executor, and one can be made that doesn't require
alloc, yet to be written.- The crate uses its own HAL-like traits for e.g.
OutputPinorI2cReadto enable async APIs as well as smooth over any incompatibilities betweenembedded_hal::gpio::v1andembedded_hal::gpio::v2etc.- All platform crates should be maintained in this repository so that changes like the last bullet point can be made in lock-step.
- Don't expose interrupts to the user.
mypin.changes()should return an asyncfutures::Streamwhen the pin changes. In the background, we stash away aWakerthat gets called from the interrupt handler.You can think about the intended stack like this:
┌─────────────────────────────────────────┐ │ Peripheral Access Crate │ │ e.g. nrf52840-pac │ ├─────────────────────────────────────────┤ │ Hardware Abstraction Layer │ │ e.g. nrf52840-hal │ ├─────────────────────────────────────────┤ │ Platform Implementation │ │ e.g. nrf52840-platform │ │ ┌─────────────────────────────────────┐ │ │ │ Specific Product │ │ │ │ e.g. Particle Argon │ │ │ ├─────────────────────────────────────┤ │ │ │ Common Spec │ │ │ │ e.g. Adafruit Feather │ │ │ │ or Arduino Shield │ │ │ ├─────────────────────────────────────┤ │ │ │ Adapter │ │ │ │ e.g. "Main SPI bus" on │ │ │ │ specific Feather pins │ │ │ └─────────────────────────────────────┘ │ ├─────────────────────────────────────────┤ │ Device Driver │ │ e.g. ili9341 │ └─────────────────────────────────────────┘
I like the idea. It is to a BSP, what embedded-hal is to an SPI peripheral driver.
@thejpster okay, I will continue working on it for a while longer then and see where it ends up! (possibly adding support for more boards etc)
Closing this as part of 2024 triage. Haven't seen any subsequent activity. Happy to reopen if there's news or new feedback to give.
To close the loop here, I ended up finding the embassy ecosystem to solve the same problem and felt it didn't make sense to try to create something that competes with it.
Thanks much for letting us know!