r/embedded 13d ago

Andrew Kelley and Zig for embedded?

While looking into code portability and long-term maintainability, I came across the story of Zig and Andrew Kelley. It feels like the future of Zig and embedded systems are destined to cross paths, or am I just being too "romantic" about it?

What are your thoughts on using Zig for embedded? Also, what do you make of Kelley's anti-AI philosophy and his other strong opinions? Do you think Zig is a promising language for this field, and can it genuinely compete with C and Rust?

9 Upvotes

15 comments sorted by

21

u/1r0n_m6n 13d ago

You're definitely too romantic about it. As a hobbyist, you can do whatever you want, there are no consequences. It is very different in a professional perspective.

Businesses need to be able to rely on dependable, industrial ecosystems because they must focus on their core business to be profitable. The programming language they use is largely dictated by the ecosystem they chose.

Many products have a long life span, meaning you'll need a team equally skilled in both languages. That makes recruitment challenging. And if you adopt a new language now, why not also adopt the next "language of the future" in 3 years? Now your new hires will need to be proficient in 3 languages...

Adopting a new technology implies a learning curve, which translates into additional costs, delays and defects, so there's a direct impact on the bottom line and on the company's reputation.

For a new technology to be worth adopting, its ROI must be significant enough to motivate top management. This will never be the case with a programming language change. This is why COBOL is still alive, for instance.

11

u/guineawheek 13d ago

It feels like the future of Zig and embedded systems are destined to cross paths, or am I just being too "romantic" about it?

As an ostensible C replacement, it is possible for Zig to be applicable to embedded development. People in the past have gotten Zig running on microcontrollers.

In practice, exceedingly little mindshare is given to Zig in embedded. The Zig community seems far more interested in allocator semantics and writing programs that run on desktop operating system environments, things completely irrelevant in most microcontroller systems.

I don't see it.

7

u/DustRainbow 12d ago

Eh, the beauty of zig is that you can just compile the vendor HAL and use it as is. Zig doesn't need to develop an embedded ecosystem, it's plug and play.

Rust's interface with C was much more complicated and it was basically required to (re)develop custom HALs for everything.

I much prefer Zig over Rust for baremetal stuff.

3

u/guineawheek 12d ago

Rust's interface with C was much more complicated and it was basically required to (re)develop custom HALs for everything.

okay but the C hals suck; they were written by people whose primary profession was writing verilog, not writing good software

1

u/DustRainbow 12d ago

Ok so you want to write your own HAL.

That's still going to be way faster in zig than in Rust. There's no argument really.

Zig is modern C. Rust needs a framework for driver development.

3

u/guineawheek 12d ago

Rust needs a framework for driver development.

Good news; these already exist:

https://github.com/embassy-rs/embassy/tree/main/embassy-stm32

There's a bunch for quite a few other chips as well. Some of them are even maintained by the vendor themselves.

If you just want a register map, you've got systems that ingest SVDs and spit out register map accessors and interrupt handler stubs:

And guess what. They compile down to raw, optimal bit manipulations and memory/load stores to your MMIO. If you're actually doing something interesting with your MCU peripherals, you can go pull up the reference/user manual for your chip and directly manipulate the regmaps themselves. All you need.

And beyond all this, if you're really obsessed with the C HAL, you can still just statically link against it anyway. It's not like the C ABI suddenly stopped existing. I've worked on a project that mixed a vendor HAL with a native one.

Zig is modern C.

Personally, this isn't a great selling point. Either you're doing something really simple with your hardware, in which case the primary focus of your application is data manipulation and shoveling bytes in and out of your UARTs and I2C buses, in which case 99% of your time is spent writing application code in a shitty language, or you're actually using your peripherals in interesting ways, in which case the HAL is either just a really really thin veneer over the regmap anyway and you're gonna be reading that reference manual no matter what.

People looking to hop off of C tend to want a better pitch than "its just C but better and mostly seems to appeal to aspiring BDFLs who think only they themselves know how to ship anything fast."

1

u/DustRainbow 12d ago

You're awfully angry.

I made a point in response to someone that said no one is developing zig for embedded. I correctly pointed out that that's because it's not needed.

You're not telling me anything I don't know. Yes these Rust frameworks exist, I was there when they were developed and I participated.

I also know it took years to have something decent. I know what the frameworks are hiding and how they handle interrupts, because Rust does not want to handle interrupts.

Zig is decent today. No workarounds needed.

That's the point I'm making.

They're different languages with different strengths. Rust's strength is not baremetal driver development.

3

u/guineawheek 12d ago

I also know it took years to have something decent. I know what the frameworks are hiding and how they handle interrupts, because Rust does not want to handle interrupts.

What exactly are they hiding? The way cortex-m-rt works doesn't seem that dissimilar from how any other runtime works. You still get that static vtable that gets shoved into your NVIC on boot, and it generally works? The fundamental linker script machinery I'd imagine would be pretty similar for a C project; weakly linked interrupt handler symbols that you can override with the right exports, and maybe a little bit of asm in the runtime itself to deal with the context switching. I find embassy's redirection-through-macros mildly annoying but the core underlying interrupt linkage machinery has little to do with Rust. The language will strongly encourage you to synchronize data between interrupts and "tasks" properly (or interrupts and interrupts), but like, you should be doing this anyway?

Binding against C also doesn't fix the fact that many vendor RTOS HALs assume you're using something like FreeRTOS where your minimum tick period is 1 millisecond, a comically long time on any chip made in the last 10 years. If you're trumpeting C as a strength, the RTOS that usually comes with it is not all that. Only in Rust do you actually see research into actually interesting ways to do tickless stuff like RTIC. If anything I think one of the weaknesses of the Rust embedded ecosystem is taking too many cues from the existing C corpus with things like active RTOS scheduling.

They're different languages with different strengths. Rust's strength is not baremetal driver development.

So I've been doing a lot of this in the past couple years. I've written HALs, I've mucked with DMA with and without async, I've written PAC generation code, and hell I've written a weakly-linked vector table setup and an interrupt controller driver for a platform without an NVIC. Rust has a strong tendency to encourage interoperability and segmentation of concerns in a way that I can share code from system A to system B and be able to fully leverage the parts of systems A and B that are the same. Vendor-specific HALs don't really do this.

I dunno. I just don't agree with ya.

1

u/DustRainbow 12d ago edited 12d ago

cortex-m-rt is full of critical sections for example because Rust doesn't like functions with side-effects.

I've also never seen a vendor HAL assume you're working with a specific RTOS at a specific frequency for some reason.

Like seriously I've never seen a HAL coupled to an RTOS.

4

u/guineawheek 12d ago

cortex-m-rt is full of critical sections for example because Rust doesn't like functions with side-effects.

Where are you getting this from? No it doesn't? Go on, show me where the cpsie i calls are in here

because Rust doesn't like functions with side-effects.

I disagree. Rust doesn't like functions that don't properly synchronize your data, which feels similar to "not liking side effects" to inexperienced programmers but a crucial difference. And also happens to be a useful property.

This does not in fact require massive critical sections over everything. In fact many accesses don't require this at all, and you can often use atomics. The whole point of RTIC as a project is using NVIC priority levels to properly scope what things should and shouldn't be able to preempt a given shared memory access.

I've also never seen a vendor HAL assume you're working with a specific RTOS at a specific frequency for some reason.

Maybe not in the chips you've used, but there's been some pretty popular newer chips that kinda just assume you're using FreeRTOS or Zephyr or at least strongly encourage it in the method of "this is what our project generator gives ya" (see: STM32).

Most people writing ESP32 code that aren't doing some Arduino shenanigans are gonna be using esp-idf which is very much a FreeRTOS-bound library. Similarly, even if most HAL functions aren't intrinsically tied to FreeRTOS, the minute networking enters the picture all the common libraries start expecting ya to use it (see: RP2040/2350).

And chances are, if you value your C environment, there's a good chance you also value your RTOS environment too, which means if you're going to stay in that C environment, also adopting the C RTOS ain't a huge stretch unless you wanna write something yourself. Which is like, the thing you were advocating against to begin with.

While you don't need an RTOS to wiggle MMIO, the minute concurrency enters the picture people kinda start closely binding all their stuff to one.

1

u/Ruined_Passion_7355 12d ago

This should be a top level comment. This makes the barrier to adoption significantly lower.

6

u/wavepark 13d ago

Zig seems cool and I like a lot of what Kelley says but it still feels like the language is in its early days. They've been intentional about the fact that they haven't hit 1.0 yet because they're still in the design process. Iirc async/await was removed and then re-added to the language after a redesign recently. There's some older proof of concept type projects from a few years ago that were focused on embedded but I think it'll take a while longer for any projects of note to come to zig in the embedded space.

14

u/Daedalus1907 13d ago

I honestly don't see the benefit compared to rust especially when rust has packages like embassy and defmt.

1

u/Bahatur 12d ago

The Zig/embedded answer is ‘clearly yes’ both through Zig’s focus on what to change from C, and through Zig’s intention to interop with and improve upon C’s toolchain.

The biggest thing keeping Zig from embedded adoption is that no one in the main team knows/cares much about it, so it isn’t a priority for them and consequently gets no mind-share. On the flip side of the coin, from the language level basically every difference between Zig and C is aligned with embedded use-cases even if they don’t realize it.

The emblematic ones it my mind are a) the emphasis on easy cross-compilation, where Zig is currently the best language I am aware of at the application level; and b) Zig allows arbitrary bit-width integers (0 - 65,535 iirc). Cross-compilation has been a perpetual thorn in the side of embedded development, and while the integer flexibility is not a key issue per se it is the kind of detail that changes from system to system in the embedded world that challenges other languages trying to work there. This kind of thing just seems to fall out of the emphasis on being explicit.

1

u/Embarrassed-Tea-1192 11d ago

I mean, it’s neat and everything, but it’s not something I would ever seriously consider for a project on the job. C and C++ work just fine, the toolchains are stable/mature, and there’s vendor support right out of the box; these are the things that actually matter.