114 comments

[ 5.6 ms ] story [ 183 ms ] thread
Honestly I find assembly language to be easier than Rust and very suitable for embedded systems.
Good for you.

I personally very much applaud the effort to port Rust to Espressif chipsets.

Embedded systems today are pretty complex, especially highly connected IoT devices that run mesh networks, have dfu ota, ML edge computing and more.

There are RTOS that allow you to tap into this stuff, but its basically all written in C. I wish there was more available in Rust, not just for the language benefits, which there are many but for more modern tooling.

Assembly still has its use cases but often its not applicable to today’s general purpose microcontrollers unless your doing some intensive realtime calculations, even then it should be scoped to that specific routine.

Knowing how to read asm is super useful, and once I would have recommended writing asm as the best way to learn to read it. I still think everyone should write some asm, and not just friendly mips or riscv asm, something with a few warts and some redundancy, and some intrinsics. But reading the output of modern optimizers isn't really related to the type of asm that mere mortals write, you only get better at that by doing it. Looking at the outputs of perf reports and using godbolt a lot seem the best route. Maybe you'll never need any more performance than a naive implementation in python can give you, but it is like any other stack of abstractions in that knowing a little bit about the layers you don't work at makes you do your job better.
Nice bait. A professional embedded developer doing serious work would never in their right mind forgo C for embedded development. The fact that these people are working on porting Rust to increase safety over C is laudable and it's sad that you are either too naive or just don't care enough about your users to see why using a language that catches simple mistakes that allow for exploits and crashes is a good thing.
Demonizing engineers isn't a winning adoption strategy.

I'm convinced Rust will fade away like Scala precisely because criticism and bad experiences are met with poorly constructed straw men. It illustrates how immature the language and community are if this is the best argument available.

Virtually every HN thread for years has comments condemning C and C++ developers. Not a single one of those lunatics seems to understand most C and C++ developers have managers and company policies they must navigate. What do you think is going to happen when someone gives this straw man to their boss?

If people are going to be demonized for trying Rust and switching to something else, for whatever reason, the net effect will be people will avoid Rust and find something nicer like Swift, Nim, Pony, and Zig.

> I'm convinced Rust will fade away like Scala precisely because criticism and bad experiences are met with poorly constructed straw men. It illustrates how immature the language and community are if this is the best argument available.

I doubt it. Scala choices were directly dictated by JVM. No JVM language managed to outpace Java. Java usually adds most interesting features from other such langs and assimilates them.

Rust doesn't let underlying compiler dictate everything.

There is a huge risk in regards to complexity, but community has (so far) been vocal against such things. Yes, Rust community isn't a cult of hivemind pod people. Imagine my shock!

Honestly as a dev coming from higher levels langs (Java), being able to write sensible non-GC code and it not dying in segfaults, UB sheitfuckery, or null pointer bullshit is a gift. Plus no data races? Sign me up.

Scala gives you a better horse (Java + Haskell), Rust gives you a car with a seatbelt.

I understand the technical merits of Rust and how it's distinct from the JVM.

The point was non-technical merits matter just as much, if not more.

True, but I already addressed it. So far Rust hasn't entered overly complicated spot for me.

Yes, borrow checker is harsh. Lifetime's are a pain. But only way out by other languages are:

A) Add GC/RC

B) Sweep it under rug, and pray.

It seems borrow checker is irreducible complexity.

Scala otoh made Trait order implementation matter and allowed custom operators. Compared to those blunders, Rust mistakes are minor.

Say that to ?const ?async. If the keyword generics group doesn't accept that they're wrong they've killed Rust.
?const ?async is placeholder syntax. They'll bikeshed something better while stabilizing the language feature, much like the existing .await syntax which was chosen very late in development of async.
Not according to their blog post yesterday. They were absolutely defending it as the only consistent and reasonable choice
What? Where did you get that idea? I talked with them on Zulip, they were perfectly reasonable. Even on Reddit they consider alternative syntax like `print<?async, ?const>`.

Issue is. They want code generation to solve coloring problem of async. I asked about using `#[maybe(async)]` syntax but they pointed that attribute macros have deficiencies. Can't differentiate on async-ness or lack of it, plus attribute macros lack exhaustiveness check that `match expr` afford.

And community reacted unanimously against it. If they proceed blindly with it, then yes you will have a point.
I don't think the non-technical critique has been addressed at all. It's been downplayed and dismissed to bring the discussion back to the technical accomplishments. What I'm saying is Rust's technical achievements aren't very useful if adoption isn't there. Adoption depends on getting the non-technical things right.

Nothing has been said about how to address the pathology seemingly unique to Rust making it suffocatingly toxic. It's the only programming language in recent memory where people scour the Internet condemning people for writing software in any other language. Even when the software is written in Rust, if it's not to some mythical standard, the community will unleash a wave a hate like in the case of Actix. There's memes about the "Rust evangelist strike force" plaguing open-source software authors to "rewrite it in rust". I can't think of any other language that has anything similar. Shrugging this off is an attempt to diminish and minimize the damage, rather than acknowledging the problem.

Presenting a false dichotomy solely on technical merits misses the big picture.

> I don't think the non-technical critique has been addressed at all.

But I talked about syntax already, what do you...?

> Nothing has been said about how to address the pathology seemingly unique to Rust making it suffocatingly toxic. It's the only programming language in recent memory where people scour the Internet condemning people for writing software in any other language

Social aspects aren't immutable facts of language, but exterior ever changing things. It's like finding a game having helpful community. Only for it to become toxic later as player count increases. Same can be possible in other direction if Rust becomes more professional/boring.

And honestly, I don't care about arguing memes and one incident that was widely panned by everyone close to Rust.

RIIR isn't something you get branded with when you write your first Hello World, but something actively discouraged.

That said as someone that's neither here nor there, anti-Rust backlash is palpable and might work exactly to ingrain said "Evanglism Strike Force" mindset into it.

I find myself defending it more, even though I just want to use it. And don't care too much about community.

> Scala choices were directly dictated by JVM

Initially, yes. But Scala has evolved beyond the JVM, with Scala.js [1] being rock-solid, and Scala Native [2] under development. Neither are truly hampered by the initial JVM roots of Scala.

> Scala gives you a better horse

Weird analogy ;)

[1] https://www.scala-js.org/ [2] https://scala-native.org/en/stable/

> Neither are truly hampered by the initial JVM roots of Scala.

I'm reminded of a talk ex-Scala guy had, where he rhetorically asked "Scala, if Java cut their nose... Gods what are you doing?!". Stuff like compareTo being an 32 bit int, rather than just 8 bit, because compatibility, and so forth. I doubt they got rid of those nitpicks.

Although what pushed me of it was order dependent Traits and implicits everywhere. Plus Arcane type signatures.

I haven't kept up with Scala since 2, but if it works for you, it works for you.

> Weird analogy

- Will get you to your destination, intact

- Will shit everywhere (GC)

- Knows few useful tricks (Type system)

- Not made of metal (not low level)

Pay attention to this, fellow Rust enthusiasts. Seeing this makes me ashamed to have chosen this language (edit: and community) for my current open-source project.
Cool, let's see a Bluetooth driver in assembly
As an alternative to C and now Rust, after developing for about a month, every day, a moderately large ESP32 project with MicroPython, I feel like suggesting it for most projects. I even wrote the driver of a chip connected to my devices (the sx1276 LoRa radio), and the experience has been very positive.
Does tinygo support esp32? It looks like an accessible option as well.
Yes, but unfortunately not the wifi of the esp32
I also really like MicroPython! Having said that, I have been working on an alternative to it for a number of years now -- primarily to provide a more robust and performant high-level alternative to C and Rust on the ESP32-family of chips:

https://github.com/toitlang/toit

I'd love to pick your brain and fully understand your experience with MicroPython. I've been doing programming languages for a number of years now, and I find that it is incredibly useful to understand what developers appreciate (and dislike) about the available stacks.

I've looked at Toit (and love MicroPython), but the reason why I don't use either for my hobby projects is that the ecosystem is so large with C++, that it doesn't make sense to use anything else.

Do I write MicroPython, a language I know well, but that has a few libraries, or do I stumble my way around C++ in an ecosystem that has basically everything? The choice has been very easy so far.

That's a fair and valid point. I firmly believe that live reloading of individual apps on your ESP32 during development is a big win for productivity, but clearly so is an established and mature ecosystem.
Is there any way to easily interoperate with C++ libraries? That would basically solve the problem.
One can relatively easily extend MicroPthon, but then you of course have to rebuild and reflash. Hot loading of native libraries I haven't seen.
There are ways and we've seen successful integration of C++ libraries and functionality - but it is not what I would call easy yet.

Toit is evolving rapidly and we find that being fully open source helps our users tweak things where necessary. It's been a fun ride so far and we've got some pretty awesome and sophisticated use cases that involve custom C++ code.

I'll definitely give it a go, it looks very interesting!
What great news! The support for the sx1276 is awful. I was digging around your github, you're referring to Freakwan[1], right?

[1] https://github.com/antirez/freakwan

Yep indeed! FreakWAN. Yesterday we tested a the first networks here in Catania and in the nearby Palazzolo. Everything is starting to work :)
It has some 8 bit BASIC feeling to the whole experience.
I've been working on some rust code for the rp2040 mcu as my entry into rust and embedded programming and I think it has killed my enthusiasm for both rust, and embedded. I want to work on an esp project but I feel so burned right now that I am just thinking of dropping rust all together.

I'm actually really happy to see Espressif progress on this, I just want to throw how I'm feeling the void.

I think you have to be careful not to stretch your learning budget too thin. Coincidentally, I recently started tinkering with embedded as well and decided against using Rust (not new to me) for it because I prefer the well trodden path when first getting started in something. There is plenty of opportunity to venture out later.
Similar to the times when boards with USB support weren't a thing, where you had to program it over serial. Now with USB it's so easy to program these boards, that you can jump right to the thing which interested you from the beginning, without having to deal with things like first flashing an Arduino which then served as a programmer.

I currently don't see any benefit of using Rust on a MCU if you're a hobbyist, but that doesn't mean that it isn't a wonderful language to use on a Raspberry Pi or anything above that.

Care to share the specifics? Embedded programming in of itself is difficult and tedious, and unless you really love it, professionally makes you less money than much easier forms of SWE. But I'm curious to understand if you are mad at embedded or mad at Rust.
In general I'm not mad, the learning curve of both combined was a lot and beat me down, and the rp-hal library is still beta and ironing out its kinks. I experienced a lot of frustration (and still do) around USB HID implementations. Simple things I thought would be given, eg sharing an rp-hal I2C bus was made tedious by rust's ownership rules.

I think the matter of embedded programming being difficult was just exacerbated by this. I'm just a hobbyist in the embedded world, and I really find it fun and interesting, but as a hobbyist I only have limited time to be working on my project and I want something to show for my time, besides rustc messages about my unsafe code.

Depending on your needs, you may be able to get away with using e.g. MicroPython on your ESP. Gets you embedded (light), but obviously not the Rust part.

It's been pretty easy to work with, compared to "normal" embedded work with C that in my experience is a lot of tedious work to learn and set up before you get some momentum and can start focusing on the actual application.

If you want to do some simple (or semi-complicated) stuff, there's no easier way than MicroPython. Just flash and run, done.
I get it. I can't even get my rust to run on armv7, it is built against a glibc way newer than is available for the board and I can't figure out how to fix it. So I'm using the c++ compiler on the board and being annoyed.
Why are you linking against glibc in the first place? An embedded single-purpose device that's always going to run a single piece of code has no use for dynamic linking. Use a statically linked libc only, and compile in freestanding mode for bare metal stuff.
Because my target isn't bare metal? I've done embedded for decades and it has been quite a while since I used something that didn't have an rtos or linux of some flavor on it other than a uc. An armv7 is so much more powerful than the stuff I started out using it almost seems silly to worry about stripping out the os, but even if I wanted to the bsp for the hardware is integrated with the linux install.

All that said... I may not need anything out of glibc for this project so it is probably worth trying without it. I'm calling into c based bsp methods that do depend on glibc but they will be fine. So thanks!

Same situation here - very excited particularly about no_std but it would be a big time investment on a framework/language I probably won't use professionaly. Still wanted to move away from Arduino/C++, found the sweet spot on MicroPython.
Ha-ha, kind of same situation here. I was burned by sheer complexity of RP2040 bootstrap code. Now I switched to some STM32F0 chinese board which seems to be much simpler. I'm not sure if I would end up using Rust because I know little about Rust, but I want to try it along the path. Although I think I would prefer bare assembly.
I've also been working on a hobbyist rust embedded project and happened to pick the esp to do it on! Shoot me an email if you'd be interested in comparing notes - I've had a few frustrations but I feel like I'm getting into the groove of productivity. Email is my username at gmail :)
Maybe give Toit (toitlang.org) a try.

We have been working on it for a few years now, and it gets more and more complete. Recently Espressif started contributing as well (and added Toit to their esp-idf installer).

Some selling points of Toit:

* modern language

* very fast execution for a dynamic language. (more than 10x faster than micropython)

* consistent libraries.

I'll give it a look over and see if I can get a blinky.toit going.
Just want to add I’m very impressed with Toit.

I’ve been using ESP-IDF for 2 years and have 100k lines, but I would love to consider Toit in the future.

I think the issue here is being new to Rust. I moved to embedded Rust after using C and it's a breath of fresh air to have the type system catch so many things for me. But I was already proficient in Rust before I made that move.

The RP2040 in particular is pretty great though, being able to flash firmware with `cargo run--release` is amazing, and I can use tools like probe-rs and defmt to help debug my firmware.

My only "complaint" at the moment is a bit of immaturity in the USB side of things but I get it, USB is a pretty complicated stack and it'll just take time for things to mature.

For reference, here's some keyboard firmware I wrote for the RP2040. To me it feels reasonably high level and concise for something that drives a real world USB device (as simple a keyboards may be)

https://github.com/bschwind/key-ripper/tree/main/firmware

Thanks, for the repo link! The build/release process for the rp2040 and package management is actually what drew me to rust for embedded initially, super quick turn around to writing to fiddling with the hardware.

I think you're right about it being new to rust, and I recognise my folly in learning both embedded and rust in parallel. I wish I could go back and un-burn myself on it.

I really like the arduino way of having a small amount of simple code that does something powerful on embedded hardware.

They do a good job of hiding complexity (their compiler supports all of C++20, yet it's really rare to see anything more than a few basic classes).

For projects where I just want to make a thing that works, this is amazing compared to other toolchains.

I really hope rust can offer the same. Even a mediocre coder should be able to start from a blank file and, within 10 minutes, make something that tweets when the sun comes up.

So far, rust on esp32 is far from that... But hopefully they can get there!

I’m a decent programmer. The Arduino superset makes microcontroller programming so much more straightforward. It’s mostly things like setting up the bit masks, or enabling the right peripherals, but I’m really pleased it’s there.
A lot of people look down on the arduino ecosystem because "it's for beginners", but there is no benefit to complexity for complexities sake.

If your product needs to do X, Y, and Z, and that can be built in arduino in a few days, and built in some other "professional" toolchain in a few months, then you will save money by building your real product on arduino.

And when the thing you're doing is outside the scope of what arduinos library ecosystem can provide (eg. you need to drive some GPIO pin with cycle accurate latencies), you can still write your assembly to do it.... But you still get the benefits of simplicity for the rest of your functionality.

> And when the thing you're doing is outside the scope of what arduinos library ecosystem can provide (eg. you need to drive some GPIO pin with cycle accurate latencies), you can still write your assembly to do it.... But you still get the benefits of simplicity for the rest of your functionality.

In my experience, escaping the Arduino system isn't so simple. The Arduino framework pulls a lot of stuff into the global namespace when you include even just one of their headers, some of which is incompatible with standard C++. For example they `#define` all pin names, some of which can be common terms like `led`, `button`, `mosi` or `clk`. Any of those you then can't use a variable name. It's even worse because the pin names differ between boards, and there's no master list of defined terms.

All the defines for pin names are fully uppercase. Is it really such a hindrance not to be able to call your variable LED_BUILTIN or CLKPS1?
Not all pins have names that are so specific, and it's a common convention to uppercase e.g. enumerators.
> If your product needs to do X, Y, and Z, and that can be built in arduino in a few days, and built in some other "professional" toolchain in a few months, then you will save money by building your real product on arduino.

Not necessarily. This is only true if you only think about software. Your "real product" also consists of hardware, and if you can do X, Y, and Z on a certain chip with the Arduino environment, you can most likely do exactly the same on a smaller and cheaper chip without the Arduino environment. Simply replacing Arduino C++ by plain C code without useless abstractions can already give you a very noticeable performance improvement and code size reduction on small microcontrollers. Development time is essentially a one time investment, while the chip price is a fixed cost for every unit you build. It's purely a question of how many units you want to build in the end. And for the record, if you can build it in an Arduino environment within a few days, you can definitely build it in "some other 'professional' toolchain" in just a few more days at most.

> A lot of people look down on the arduino ecosystem because "it's for beginners", but there is no benefit to complexity for complexities sake.

It's possible to be beginner friendly and not badly designed. Unfortunately Arduino doesn't really achieve that. The Arduino API is pretty terrible, the "IDE" is awful (they did improve it a lot recently in fairness), and the boards are very expensive.

Mbed is better in pretty much every way except that they screwed around with several different rubbish build systems for years, which meant it was very difficult to set up and as a result very beginner unfriendly. But the actual APIs are a lot nicer than Arduino's.

They do finally have a good IDE (Mbed Studio, based on Theano). I would probably use that for new microcontroller projects.

I would recommend to anyone using the arduino framework to switch to PlatformIO. It’s just a plugin for VSCode so you have all the benefits that come with that ecosystem.

Arduino is great if you are happy with one single massive file for all your code (I know you can add additional files, but it’s not intuitive).

For large projects that needs to be split up and architected use platformio.

The whole point of the rust-embed ecosystem is to bring the ease of use found in something like Arduino to embedded development more generally. Upstreaming ESP support in LLVM (what the OP is about) is a key part of this.
Looking at my firmware code, 4 quadrant motor torque control in particular. It is plain C and at the level it is written I really doubt C++ / Rust would add any value. For all the horror safety stories: firmware runs on whole bunch of devices for close to 10 years already without single fault caused by whatever bug there might be.

Obviously not advocating plain C for business middleware servers. Those benefit greatly from C++ type of languages.

More and more firmware is using complex protocols like TCP/IP and TLS, which are risky to implement in a memory-unsafe language. Embedded Rust is very attractive for those applications.
It already exists for those willing to broaden their horizons to Python, Basic, Pascal, Java, TinyGo, Oberon-07 and .NET.

Naturally having Rust as well is a positive, the more the merrier.

This is exactly where I'm at. I'm a professional SDE and I'm pretty damn good at writing code and solving problems at all kinds of different levels of complexity and abstraction, although professionally I mostly write Java code and build web services and that kind of thing.

When I got into electronics and embedded development recently as a hobby, I started with Arduino. And for the vast majority of my projects, which are mostly simple smarthome IOT type things, or little toys for my kiddo, the Arduino framework is just fine and the ecosystem of libraries is great.

But when I recently started a project that was much lower-level (in fact, it was your example exactly -- driving pins with cycle-accurate timing), where I didn't need those libraries, I used ESP-IDF without Arduino.

I'm also just lazy, and just don't want to deal with more complexity than I have to.

How was your experience with ESP-IDF? I've only used Arduino so far (I've basically had exactly the same experience as you), and haven't needed anything more, but I've been thinking of using the IDF for my next project, since I can't use Rust yet.
>there is no benefit to complexity for complexities sake

Arduino is added complexity. In my limited hobbyist experience, going to the datasheets and using official toolchains has been very straightforward. It pays to build the understanding ahead of time rather than debugging some random person's Arduino library when your peripheral stops working.

Yep. You think you can get by without understanding what the Arduino libraries are doing under the hood, until you can't. Then you wasted all that time. I'm just as guilty as anyone spending just as much time avoiding learning something, than just taking the time to learn it.
It used to be that official tools chains were a huge money and time expense - Not to mention requiring substantial understanding before you even got to them. Even AVRs which had an open source tool-chain still required a $50-200 programmer to get started. The PICs were more popular, but proprietary tool-chain. And the communities associated with both were great at gatekeeping and dismissive of beginners who weren't doing things "the right way'.

Arduino's added complexity opened up the space to people who had little-to-no programming experience. People who had a computer with a USB port. People who had no familiarity with binary let alone hexadecimal to set a bitmask so they could turn an LED on. Let alone figure out which bits to flip to set a timer.

Arduino is added complexity to the benefit of accessibility. The complexity of the datasheets and toolschains make most products an unassailable wall. That said, the real gem of Arduino is its community that is welcoming and helpful to beginners.

> If your product needs to do X, Y, and Z, and that can be built in arduino in a few days, and built in some other "professional" toolchain in a few months, then you will save money by building your real product on arduino.

I'd hazard a guess there is no software that would take "months" to build while it takes days on arduino, unless you count "developer learning C++ properly" in that month.

Most uC platforms provide enough SDK and code generation that you can hit the ground running with simple code and complex code won't be any easier in arduino

The real strength of the Arduino tooling is that they have hidden all the complexity in setting up the toolchain needed to produce a binary. You install the Arduino IDE. You edit code, you compile it, upload it to the device, it works. End of story. Well for the most part, but compared to the rest of the embedded software world, it is a pretty smooth ride.

It isn't so much that the programming model is less complicated. Sure that's an advantage if you are just noodling around. The Wiring framework has introduced a lot of developers to embedded development. But once you start to do projects that are a bit more than just a demo of something it actually is a bit easier to write software using, for instance ESP-IDF (FreeRTOS port for ESP32). You don't have to reinvent concurrency, for one. And it makes it easier to make use of more of what the ESP32 chips can offer.

The bane of embedded development is awful tooling and people who aren't very good programmers inventing abstractions that do more harm than good. Setting up the ESP-IDF toolchain correctly is much harder than it needs to be. If you haven't done it before, it is going to cost you a weekend to set up. You can probably make something work half-way in a few hours, but to get all the gremlins out...that can take a while. I recently spent on the order of 3 hours getting things to work properly again after upgrading to a newer version of ESP-IDF and it is slightly infuriating how bad the tooling is.

And as if the tooling wasn't bad in itself, the embedded world is in love with Python - which adds yet another dimension of problems. Python isn't a language that lends itself to producing software that behaves predictably on random computers. Please stop using it for tooling. Write tooling in a portable language that can produce proper binaries. Preferably statically linked binaries so that at least you do not have to waste time wondering why your tooling doesn't work. Write tooling in Rust or Go.

(And if you think ESP-IDF is a handful, good lord, pray that you never have to deal with Zephyr.)

I used to hope that Platformio (https://platformio.org/) would help solve problems, but it seems that none of the MCU vendors really give a shit about figuring out a good solution. Everyone wants to make their own mess. (Yeah, it is Python, but not at the amateur software engineer level as the nonsense you see in vendor toolchains)

Yeah, Arduino (or rather Wiring) is limiting. But the "professional" embedded world can sit down and shut up until they can demonstrate something that is even half way as reliable as the Arduino IDE.

I think the root cause is misaligned incentives for the involved parties.

IC vendors have a lot of incentive to lock you in their ecosystem. Embedded developers are paid to produce firmware for widgets- their priority is shipping a firmware binary to manufacturer.

Besides, I don't find Arduino IDE that reliable- I still have to figure out which board definition to use (is this a micro or nano? Perhaps nano pro? Why doesn't this blink code not work on RP2040 board? Oh right, I selected adafruit rp2040 board when I was using pico, which uses board pin numbers vs rp2040 gpio numbers)

I think it is more about inertia than trying to accomplish vendor lock-in. Software is much more important for embedded applications than it used to be. I regularly see people choose MCUs that are many times more expensive than what they might have chosen -- simply because they can't afford the software development costs on MUCs that have poor SDKs.

The industry is starting to understand this, but it takes time to fix. And the industry still needs to shed a lot of managers that lack a basic understanding of engineering software ecosystems and tooling.

Figuring out what board definition to use is a luxuriously simple problem to have. :-) Try to figure out how to configure a bunch of sensors hooked up to anything running Zephyr. It seems to have been put toghether under the motto "there is no problem so complex that we can't make it even more complex".

If you find Zephyr too complex, maybe give RIOT a try. It also supports all the ESP32 family members (with WiFi and BLE) and generally has a simpler API and build system.

e.g. you can build and flash any application and open a debug shell with

    make BOARD=esp32s3-devkit flash term
The ESP32 toolchain is installed with an easy to use script: https://doc.riot-os.org/group__cpu__esp32.html#esp32_local_t...
Well, for the two smallish projects where I did use zephyr, I didn't find it too bad. But I must have suffered enough fiddling with the real devicetree before :)
(not sure why you got downvoted. gave you an upvote to balance out unnecessary downvote)
> (And if you think ESP-IDF is a handful, good lord, pray that you never have to deal with Zephyr.)

Well, that's stings. Can you elaborate on your trouble with getting Zephyr working on ESP32? My memory is it's actually one of our simpler platforms, though it's true Zephyr isn't itself an IDE. It's an RTOS with a C API; you're expected to build at the command line with a wrapper tool (west), and to have downloaded and unpack an SDK tarball. But really there's not much more to it than that.

Not OP, but from a professional perspective I wouldn't say it's pain free. Your first issue is going to be figuring out whether your needs are even supported by the stack by going to [0]. I appreciate the difficulty of supporting hardware, but that much red would definitely have hurt it during RTOS selection for me. Second, what if the hardware people want to use the S3 because of availability concerns? There's no table I've ever found, you just have to troll through code and GitHub issues to figure it out.

One other frustration is how obtuse the error messages can be. If west encounters a situation it doesn't like, it will often dump stack traces rather than print an error message. If you have something in the wrong directory or a typo etc, the magic in the build system often just fails and prints a generic error message or nothing at all. Maybe you screwed up the DT, maybe you named something incorrectly, maybe it's in the wrong directory, or maybe you typo'd. All of these can produce the same error messages at build time, which gets annoying.

With that said, the zephyr experience is remarkably pain-free and Linux-like compared to some vendor toolchains and generally good enough that I advocate for it internally.

[0] https://www.espressif.com/en/news/Zephyr_updates

Some of that seems a little unfair. The desire in the first paragraph is for a fully-integrated, vendor-supplied SDK for a single board where everything works. The bit in the second is about doing configuration and integration work on new hardware.

I think both criticisms are reasonable but they aren't from the same perspective. In this case, yes, Espressif (who I'm not affiliated with and don't want to speak for, though I have worked on the ESP32 -- it was actually Zephyr's launch hardware for SMP, as it happens) doesn't quite have everything wired up yet. And that's unfortunate, but not so much a ding at Zephyr as with this particular integration (other chip vendors, Nordic especially, tend to be farther along).

And as for doing devicetree work... yeah, I don't like it either and try to stick to the kernel. But it's a ton cleaner than the kind of cut/paste you see with other solutions (and especially with whole-board IDE/SDKs!). In Zephyr, if you have a part that has an instance of some existing hardware integrated on another platform (a Synopsys DMA controller, some third-party I2C accelerometer, whatever), the configuration is usually/hopefully as simple as a three-line block of DTS with the addresses and interrupts filled in. For platform integrators, it's probably our single most attractive feature.

I don't use Zephyr on ESP32. I try to use it on the nRF91. And there is a lot more to it if you actually want to build a device that has a few sensors, does a bit of mobile networking AND you need to develop this over time and upgrade the SDK from time to time.
For a hobby project I’ve used Zephyr via the segger embedded studio for the nrf52. Coming from full stack web development and having dabbled with Arduino IDE, the learning curve was a lot steeper. But I totally understand why, the problem space of supporting all of the different chips and all of the different libraries is huge. It didn’t help that nordics was transitioning from their old stack to the zephyr based one and all the forums and documentation was incredibly confusing because of that. After learning the options menu where you select which parts of the stack to include in your binary things started making a bit of sense, but I still have no idea whether the softdevice is still a thing or not . If you ever want more user feedback feel free to reach out.

There are definitely amazing features in the ecosystem. E.g. the fact that you can run a live debugger on this tiny chip is mind blowing.

Python is the new BASIC, and given the choice I rather that they chose Python over JavaScript.
> The bane of embedded development is awful tooling and people who aren't very good programmers inventing abstractions that do more harm than good.

Use VSCode. It's not great, but it's SOOOO much better than everything else in the embedded space (that doesn't cost $100K+) that it's ridiculous.

As for programmers, any programmer of talent decamped from the embedded world to anything else. As long as semiconductor companies refuse to pay real salaries, this will continue.

> Write tooling in a portable language that can produce proper binaries. Preferably statically linked binaries so that at least you do not have to waste time wondering why your tooling doesn't work. Write tooling in Rust or Go.

No. Just no. Installing random crap in any language on my computer is where things fail.

Use a bloody container. To contain the mess, it's what I have to do anyway. For the love of all that is holy and unholy, distribute a container. This is the kind of scenario that containers were MADE for--lots of random tools that need to be version locked and only upgraded as a single unit.

Agreed, I've also somehow stuck with arduino's setup despite its occasional shortcomings since it's just so simple to configure different devices and whip up something quickly. No messing around with anything but the very core essentials.

The only thing that is sometimes faster from idea to deployment is micropython, since it's possible to just copy paste regular python with minor changes and it just works.

I agree with a sibling comment point that Arduino's main strength is that it simplifies the installation of tooling, not that the code is particularly easy. But, on the code side, I think that embedded-hal is excellent

https://docs.rs/embedded-hal/latest/embedded_hal/

Here are the supported boards

https://github.com/rust-embedded/awesome-embedded-rust#hal-i...

There's a book on rust on esp https://esp-rs.github.io/book/

Here's how to blink a led using esp-idf-hal, targetting espressif

https://github.com/esp-rs/esp-idf-hal/blob/master/examples/b...

    /! Blinks an LED
    //!
    //! This assumes that a LED is connected to GPIO4.
    //! Depending on your target and the board you are using you should change the pin.
    //! If your board doesn't have on-board LEDs don't forget to add an appropriate resistor.
    //!

    use esp_idf_hal::delay::FreeRtos;
    use esp_idf_hal::gpio::*;
    use esp_idf_hal::peripherals::Peripherals;

    fn main() -> anyhow::Result<()> {
        esp_idf_sys::link_patches();

        let peripherals = Peripherals::take().unwrap();
        let mut led = PinDriver::output(peripherals.pins.gpio4)?;

        loop {
            led.set_high()?;
            // we are sleeping here to make sure the watchdog isn't triggered
            FreeRtos::delay_ms(1000);

            led.set_low()?;
            FreeRtos::delay_ms(1000);
        }
    }
For ESPs I recently had quite some fun prototyping using MicroPython. REPL directly on the controller so I can try things out, a mechanism to "mount" a local directory on controller so larger things can be tested easily etc. and then support for many of the features (I2C, SPI, Wifi, BLE, ... all work, one can even send binary for the low energy core on the ESP32, while some things weirdly are missing, like support for the temperature sensor on the ESP32-C2)
It's amazing how quickly you can make something that works with the EPS32 and Arduino, but for me, since this is for learning I feel I'm not really learning too much since so much is abstracted from you. As far as I know you just can't reasonably do bare metal programming on the EPS32.

So for the simple project I am doing right now I'm using a 8051 microcontroller (AT89S51), mostly because it is super cheap to buy locally but also I am forced to deal more with the details of how embedded applications run. But it does feel like learning 8051 is not too relevant today.

Give the RP2040 a look, assuming "locally" is somewhere with access to them. You can start off micropython-level and then go lower as you want.
Great! I took a quick look and saw there it seems to be available locally, and pretty cheaply even.

A few questions, I saw that the chip itself is surface mount, would I need to make my own PCBs to be able to make more "permanent" projects with it? Also, what kinds of external things I would need to get started, like specific programmer hardware, etc.

> I saw that the chip itself is surface mount, would I need to make my own PCBs to be able to make more "permanent" projects with it?

If you want to directly use an RP2040 chip: yes, but you can do that for a few $ at e.g. jlcpcb where they can directly assemble the SMD components on the board for you. If you build your own "more permanent" project, you most likely want to build a PCB anyway, to integrate all the peripherals and connectors you need. Otherwise there is the RPi Pico board which is a small PCB with the RP2040 on it. It's the standard "small PCB where you can install a pin header" type of development / eval board.

> Also, what kinds of external things I would need to get started, like specific programmer hardware, etc.

I helped someone else with an RP2040 project recently and apparently all you need is some crystal for the clock, some flash chip for the program code, potentially a voltage regulator, and either a USB connector or an SWD connector (or ideally both). If you have SWD, you can program and debug the RP2040 from another RP2040 based module (there is "SWD programmer" firmware available, there is also the "Raspi Debug Probe" available now), and if you have USB and add some form of boot switch, you can directly program it via USB.

In addition to the pin header holes, the Pi Pico's edge connectors are designed to be soldered onto things too, if the RP2040 itself is too fiddly.
If you're using the Pi Pico as a starting point, you can get going with just a USB cable. At least as far as micropython is concerned. You can use a second Pico as a programmer board if you're going much further than that.
what do you mean by bare metal in this scenario?
I think of it more like "direct" control over the hardware, like no RTOS and no framework, just your binary code running directly by the processor, and accessing the hardware features via registers.

With the ESP32 it seems that this is not something reasonable to do, as most things require extensive setup that is implemented in the framework.

Like we used to code in the 8 and 16 bit days of home computers.

The language runtime is the "OS", and you talk directly to io ports and memory addresses.

<rant> I tried using Rust for a Nordic microcontroller project recently but ended up giving up. It was just too difficult to figure out how to do things in Rust as a beginner. For example, I couldn't find a (maintained) Bluetooth stack for the nRF52. I finally figured how to link to Nordic's proprietary Bluetooth stack but then I realized I wanted to use the Thread protocol. I couldn't figure out how to do that. Meanwhile there are entire sample apps and guides in C for what I'm trying to achieve[0]. It sucks because I love Rust and would much rather use it than C/C++. I guess this is less of an obstacle for people who have embedded programming experience, but I don't.

[0] https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/...

That's ecosystem maturity problems. Regardless, your first mistake was not immediately reaching for linking to the C libs from Rust, which is something the language is designed to do rather easily.
For matter/thread you'll likely even have to go the other way around - link to your thing written in rust from your matter/thread project.

And yes - this is partially a maturity thing, although more in the sense in that the embedded ecosystem is very vendor specific, and you're traveling outside the path the vendor forged for you, so you'll be an early trailblazer - you get to deal with all the integration shit, rather than finding some other random person on the internet that's dealt with something similar.

(And it's not necessarily that the vendors path is all that great, but at least there's a whole collection of other people that's struggled with it and posted about it online).

Our professor in college was livid when we suggested not using the vendors toolchain (back in the early 2000's), "yes $vendor's toolchain is broken and shit, but it's marginally less broken and shit than $non-vendor toolchain".

Same experience - started and gave up so many times..

I am having luck currently with embassy-rs, on rp2040, including Wi-Fi, not BLE tho.

I think overall the space is improving rapidly year-over-year. It’s hard with suppliers focusing on the C stacks and the Rust stuff being all volunteer.. but IMO things are getting better.

It's been a while, but tbf not using the Nordic proprietary BT stack on their microcontrollers was a pain in C too.
Is it on their list at any priority to make it so developers could do like `rustup toolchain the-esp32-platform` instead of needing a forked rust? https://github.com/espressif/rust-esp32-example/blob/main/do...
That is the first thing he mentions in the post. :-)

The answer is "not yet". But, some of their LLVM PR's were accepted recently, which is a big milestone!

It’s cool espressif is funding this, I’m especially interested to see how networking plays out as that seems like an area where rust would excel, the complexity kind of blows up quickly once there.
> At this point, I'd also like to make it clear that you do not need the forked compiler for our RISC-V-based chips, esp32c2, esp32c3, esp32c6 etc. You only need the forked compiler for our Xtensa-based chips, esp32, esp32s2 & esp32s3.

What a weird choice, have same "family" name of ESP32 yet completely different ISAs

It’s not so weird as you think. They all are supported by ESP-IDF equally and therefore feel very similar to program and work with.
I'm wondering why the change of the architecture in the first place and not wait for next iteration of the platform. I guess maybe they wanted to keep the brand name ?
They've developed the ESP32 platform for 6 years already. "The next platform" could be decades away, not worth waiting for and missing out on the RISC-V tooling (compilers, debuggers, etc).
This seems promising…

I was actually thinking about zig on one of these, but I assume xtensa LLVM must make that easier too.

What is the reason rust maintains llvm fork? I've looked at readme with no clear answer. Is it just convinience and turnaround time?
I think so. I don't know if this is still the case, but I believe there was a policy to not carry any patches that haven't been merged upstream.

In any case, building with an unpatched LLVM is still supported.

It’s faster to fix bugs in a local fork and then send them upstream than it is to wait for upstream to incorporate the fix. Historically they’ve tried to keep the fork as close to upstream as possible, but there’s no reasons to make users wait on fixes in the meantime.
Maybe I'm crazy but I'm much more interested in seeing things like TinyGo making progress.

Go feels ergonomic in an embedded environment, and if its concurrency could be utilized there it could be very powerful.

Rust is still awesome and I love working with it, but it seems much more daunting in the embedded world. I should probably give it a shot.

In any case, I'm so stoked to see the progress being made on projects like this. The freedom to program in more languages, especially safer languages, will make the embedded world so much more accessible.