Hacker News new | ask | show | jobs
by steve_adams_86 1181 days ago
The thing that tripped me up the most was concurrent tasks. In languages like Go or JavaScript it’s pretty easy to figure out how to decrement a timer or wait until x time to perform a task without having the waiting period be blocking. On an arduino, you have a few options but none of them are likely to be familiar to high level software devs.

It isn’t rocket science, but there are loads of little details like that which will make you pause and then write loads of bugs and awful software before you finally figure it out. Meanwhile, accomplishing the same thing with a high level language might be trivial.

It can be discouraging but I’ve come to love it. You learn a lot, and having a physical board doing a tangible thing with actuators and sensors can be really gratifying.

8 comments

RTOSes are developed to solve this exact problem of concurrency. Try Zephyr, ThreadX (from MS) or FreeRTOS (from Amazon) or whichever OS your microcontroller vendor supports. It will be eye opening, and you get to learn to write safe code in C with synchronization primitives just like our ancestors.
Amazon did not create FreeRTOS; they simply took over maintenance a few years back. I didn’t know that happened until I fact-checked your comment, but it is enough to make me never want to use it ever again. And that makes me very sad.
They improved the licensing to MIT. The pre-acquisition license was "GPL" but it had a noncompliant restriction prohibiting comparative benchmarks. There have also been useful improvements to the codebase. Amazon is a net positive in this case.
FreeRTOS is now MIT licensed, and the primary developer is actually getting paid to work on FreeRTOS.

This can only improve FreeRTOS and the embedded ecosystem in general.

And, if Amazon becomes a problem, people can fork and bail.

ESP32 running with Arduino framework comes with FreeRTOS out of the box.
>just like our ancestors.

why am I laughing at how much this stings? we're not that old, damnit!

I saw a tee shirt the other day that said "It sucks to be the same age as old people". We are that old. :-)
Ha, I'd never seen FreeRTOS – thanks! It looks awesome.
Many microcontrolers have timers and counters or even state machines (PIOs on RP2040 is a nice example of that) for this reason. They allow you to handle those cases out of the main computing unit. The MSP430s are also full of these magic things. They are harder to get introduced to than just writing Python. But you don't realize how powerful those things are until you step out of how you were handling things on a multi-GHz computer with ton of RAM.
And these peripherals can run at hundreds of MHz doing real work in every cycle. I can probably do very low latency audio processing with an interrupt firing at the sample rate. Delay is a few samples instead of at least couple of ms like on a PC with an audio interface.
You probably could, but I’d recommend getting a chip with a dedicated I2S peripheral and use freertos with a high priority dedicated audio task that’s sole task is processing audio. You really don’t want to miss an audio sample. It’s very audible, and depending on what you’re doing makes audio processing essentially a hard real-time constraint.
FreeRTOS has a massive effect on throughput. If your audioprocessing is predictible and your interrupts too there is no reason to need that overhead.
Yes working on a Arm M7 at 480MHz I get 1 to 3 samples latency on most things I'm doing (mostly synthesis). And that's on a single core even.
I recently used Rust (RTIC) for that and it was relatively pleasant experience, it had "tasks" (that cleverly used unused interrupt handlers for context switching so it was nice and efficient) that could be triggered by various stuff, not unlike threads, and they had priorities. As long as you busy waited only in the main, lowest priority one, it "just worked"
Not having high-level languages available is a big part of the fun of programming microcontrollers.
I completely agree. It brings you back to more fundamental aspects of problem solving that sometimes you miss with higher level programming. There are a lot of things I can do on a modern web server with a language like Go that are pretty cool, but not particularly interesting because it's kind of trivial. There are so many resources available to the program, things to fall back on for resilience, plenty of common problems are ironed out into popular libraries, etc.

Trying to automate something truly reliable and consistently with a microcontroller on the other hand can be simultaneously soul crushing and exciting — there are so many edge cases and challenging problems.

Sometimes I'll spend hours trying to figure out how to interface with a single sensor, and while it isn't important or impressive in the scheme of things, I really enjoy it.

> Sometimes I'll spend hours trying to figure out how to interface with a single sensor, and while it isn't important or impressive in the scheme of things, I really enjoy it.

I found a fake sensor like that once.... was wondering why my code done by datasheet didn't worked on cheapo breakout board I bought off aliexpress.

Then I read ID register and they used older chip that had some of the stuff set up differently...

Same, I bought a couple waterproof temperature probes under the name of a reputable manufacturer and wound up getting what turns out to be notorious knock offs. It was way harder to set up and the actual sensors measured within several degrees C of each other, haha. I'm a lot more careful of where I order components from, now.
You can always run Espruino on your ESP32 -- a nodejs like environment for microcontroller. It works well and has lots of drivers for different components.
While we're on the general topic, let me share this Gist: https://gist.github.com/phkahler/1ddddb79fc57072c4269fdd6716...

fade a GPIO LED on/off cyclically in 6 lines of code. It should read "every millisecond or faster" but OK.

Using Rust and esp-idf you can simply call the standard library threading facilities if you want to do concurrency, and it's all handled in the background by FreeRTOS for you.
Realistically you will need to use an RTOS for threads and scheduling on a micro.