> If you want blocking code to run asynchronously, just run it on another task
What kind of embedded work are you doing exactly? Linux "soft" embedded or MMUless embedded? I don't have infinite NVIC priority levels to work with here... I can't just spin up another preemptively scheduled (blocking) task without eating a spare interrupt and priority level.
Otoh, I can have as many cooperatively scheduled (async) tasks as I want.
Also, at least in Rust, it's trivial to convert nonblocking to blocking. You can use a library like pollster or embassy-futures.