Hacker News new | ask | show | jobs
by rbtying 2174 days ago
I’ve been playing with Rust on the ESP32 using these tools on and off over the last couple of months or so, relying more in linking to the existing FreeRTOS/C HAL for accessing the peripherals.

One thing I haven’t quite figured out: a substantial number of onboard features are configurable at image build time, which then change the effective C libraries via preprocessor definitions. So, it doesn’t quite work to naively run bindgen on the header file once, and then embed that in a -sys crate and put it on crates.io

I think you can hand craft a -sys crate with all the appropriate config options as cargo features, but that seems both very time-consuming and likely to drift from the newest esp-idf versions. The alternative of running bindgen periodically (e.g. as part of the build process) works fine for one project, but then how do you publish reusable libraries online?

1 comments

The ESP32 API surface is huge, and the libraries have many configuration settings. Rust-ifying this is a huge endeavour. One way could be to just interface with the vendor HAL using Rust wrapper, but doing that in a safe way that respects the lifetime rules can't be easy? Also AFAIK some lower level radio APIs are locked and hidden behind a binary blob, so the ESP32 can't be misused as a jammer.

Its very tempting to try this due to the huge amount of resources the hardware has, but it is a huge amount of work. Just being able to access the registers isn't very valuable, the ESP is about Wifi, BT and I2S. If there are no ergonomic Rust APIs for those, why even bother?

It's true and a bit surprising how much of the ESP32's API's are configurable or change based on config options. Espressif has built an impressive amount of functionality on top of FreeRTOS. It'd be nice to see Rust more widely adopted, but it seems to require an entirely rewritten SDK as so much of the API are C macros and defines.

Given that I decided to go a middle ground and use Nim with its new ARC (GC reference counting and move semantics). In theory it's less efficient than compile time Rust memory management but it works well in practice. Wrapping the C API is trivial and handles all of the C defines as well as writing in C, since it compiles down to it. And you can use any Nim or C libraries. It's surprisingly effective!

Except you still get data races from the C API's which Rust would likely help prevent. So it's cool to see someone toying with an xtensa llvm backend. I wish LLVM still fully supported a C backend so you could compile Rust to C and build that. Hopefully in the long run, more native rust libraries will exist for more full functionality embedded.

Was looking at Zig for the same reason, manual memory management but less error prone due to "defer", and a design ethos that is very reminiscent of C. Can even compile C directly! I really, really like the aesthetics of the language, but there is no xtensa backend yet.

Rust might just be a leap too big and can only work in blank-slate scenarios.

Zig seems promising too! But it’s still LLVM based (?), which seems to be a limitation in the embedded world. Nim’s templates/macros are nice for fiddly stuff. Not sure how Zig handles places where compile time macros can make things nice. Yah I figure in ~5 years Rust might be better positioned in embedded work as a goto solution.
If you like macros, Zig might not be for you. Part of its mission statement:

"There is no hidden control flow, no hidden memory allocations, no preprocessor, and no macros."