Replies: 8 comments 8 replies
-
At least in my head something like All those points are totally valid and to be hones I don't have much pure technical reasons for not implementing the async-traits in the base HALs however I have / had some doubts
I'm not totally against adding async support to the HAL(s) but while there are hard technical reasons for doing that, we should be at least be aware of the down-sides. For me the biggest thing is that it currently doesn't seem to be possible to implement async-traits that are completely agnostic over the runtime (but maybe I'm wrong - I wish I am) Most of these things are not pure technical issues but gut feelings to be honest - and even the hard-facts like depending on git-dependencies might vanish in future I also admit that currently there isn't any other serious embedded async runtime on the horizon so being agnostic over the async-runtime is maybe more a philosophical thing currently - but maybe there will be other promising async-runtimes in the future |
Beta Was this translation helpful? Give feedback.
-
One thing that came to my mind after looking into the async GPIO code: There we only depend on Really don't know if that is sane - also makes things way more complicated |
Beta Was this translation helpful? Give feedback.
-
That's not true! :) You can impl the (The reason you might want to use
This way you can use the inherent methods in Rust stable, and you only need Rust nightly if you need the traits (for HAL-independent drivers).
I suggest you impl both in the same HAL, yep. If you do separate crates you'll have to duplicate lots of code (or expose lots of inner guts from one to use in the other). The resulting API is less usable too because duplicate types. Another advantage of single-HAL is you can mix blocking+async on the same peripheral instance. For example, if you're using an SPI ethernet chip, you'll be doing tiny 1-byte register access, and big chonky 1500-byte packet transfers. Async-yielding for the 1-byte transfers is not worth it because it's just a handful of clock cycles (the async context switch will be more than that) but it is for the big packet transfers, so if you mix you can get a faster+smaller driver. |
Beta Was this translation helpful? Give feedback.
-
We could put embassy behind an unstable cfg (different from a feature to avoid semver guarantees, this is what tokio does) and declare specifically embassy support as unstable. I would also say before we merge anything async-related, let's get our first release out the door and build on from there.
To follow on from @Dirbaio's comment, you're right that we do use
This is a use-case I hadn't considered, thanks! |
Beta Was this translation helpful? Give feedback.
-
Agreed!
in |
Beta Was this translation helpful? Give feedback.
-
One thing I hadn't considered is that the async driver compiled in esp-hal proper uses the peripheral interrupt, making it unavailable if a user doesn't want to use async at all, or they want to get an interrupt for a different event. In the GPIO example, the I guess this is where the blocking and async paradigms clash, the only way I can think about handling this would: Forwarding the actual interrupt handler to a user interrupt handler i.e
Inside the vectored interrupt part is where the async bits will be managed. But I really don't like this at all, we have to duplicate handlers, and users are confused as to which handler to declare. It just becomes a nightmare. Any thoughts on how to manage this? |
Beta Was this translation helpful? Give feedback.
-
While I also don't like it, I currently also don't see any alternative. Maybe it's a necessary trade-off when user's want to make use of the async model - especially if they want to mix it with the traditional model. As long as it doesn't affect pure non-async code it might be something that just needs to be properly documented 🤷♂️ |
Beta Was this translation helpful? Give feedback.
-
To summarize my thoughts from the esp-rs community meeting:
|
Beta Was this translation helpful? Give feedback.
-
As of 7c9adcb the
feature/embassy
branch implementsembassy::time::Driver
&embedded_hal_async::digital::Wait
inside a new crate,esp-hal-async
. Although this attempt has been successful I don't know if it's the approach we wish to move forward with.Problem 1, the async traits cannot be implemented directly
Due to rust's orphan rule, we cannot implement traits directly on the esp-hal types, instead, a wrapper type is needed. My GPIO implementation is similar to @bjoernQ's in his experiments repo, but I chose to implement
Deref
to call methods on the original pin, instead of converting the pin into an async pin. The long-term plan would be to re-export all pins asAsyncPin
's so no conversion needs to be done. This brings me to the second problem.Problem 2, embedded_hal_async traits should suppliment embedded_hal traits
So, Gpio's are now wrapped in
AsyncPin
, what happens to esp-hal? None of the peripheral constructors work unless we implement every single trait implemented on the original pin on theAsyncPin
(e.gesp-hal/esp-hal-common/src/spi.rs
Line 55 in 7c9adcb
It's important to mention here that @bjoernQ's extension trait method doesn't fail here, but gets a bit odd with other peripherals. For instance, it's common in the r-e ecosystem to use
into_XXX
methods on gpio pins, but what about spi? You'd create a normal spi instance then callinto_async
on it? It could work I suppose.Problem 3, which hal to use?
I'm living in the future where I may want to use both blocking and async APIs. You may think this is rare, but I imagine it could be quite common if you are running an RTOS you may want to block on a thread for one specific peripheral, then in another thread multiplex a few peripherals handling into one task to save stack space (perhaps these other peripherals are used less frequently). Another example would be RTIC, I know we don't have a port right now, but RTIC can block in the idle thread, and be async in the rest of the tasks.
The question is right now, what's the point of
esp-hal-async
if it exposes both blocking and async APIs? Why not just cut out the middle-man and have esp-hal have blocking and async implementations?Beta Was this translation helpful? Give feedback.
All reactions