On Hubris and Humility
cliffle.com
cliffle.com
Interrupts: they are dispatched, so does the program has to go back to "main" loop to handle an interrupt or are they executed in the peripheral interrupt context? What is the "time-to-serve-an-interrupt" in Hubris (real-time wise)? How is it guaranteed?
Also, how shared interrupt are handled and dispatched (interrupts like EXTI10_15)? Is there something that deals with (or prevents me from) requesting an interrupt for PA10 AND PB10?
Drivers: are isolated, this means that my MCU with 4 UARTs needs 4 instances of the same code (each for every UART)?
Isolation: there are a lot of ways to make an embedded system misbehave other than corrupting memory, for example, what about a situation in which a task leaves (one, some, all) interrupts disabled? Unless the OS won't let me fiddle with interrupts, which is bad (for a driver that goes into a "everybody, shut up! I'm reading a Dallas button" situation, with interrupts disabled).
Is there something in Hubris that protects me from starvation? Like an interrupt being fired constantly, making the system 100% busy? This is not a crash, and other tasks may not even notice about the misbehavior since they might not be even scheduled.
Also: the word "priority" is mentioned once in the article. What is the scheduling policy?
What resources is Hubris using? SysTick? PendSV?
To answer a few of your questions from the stuff I know offhand before I've had my coffee:
> Drivers: are isolated, this means that my MCU with 4 UARTs needs 4 instances of the same code (each for every UART)?
You are free to organize this however you'd like, each approach has pros and cons, up to you. tasks are isolated from each other, the scope of a task is for you to decide.
> what about a situation in which a task leaves (one, some, all) interrupts disabled?
Users can't disable interrupts, they can only mask or unmask receiving notifications for said interrupts. This means one task cannot shut off another task's interrupts either.
> Also: the word "priority" is mentioned once in the article. What is the scheduling policy?
Tasks have priorities. Smaller is higher priority. Currently we have up to 256.
At any time, the highest priority task that is runnable is being run. This means that within priority levels, scheduling feels cooperative, as we don't time-slice, but in between them, it's preemptive; if a higher priority task becomes unblocked, then it will run next.
> What resources is Hubris using? SysTick? PendSV?
SVcall, SysTick, and PendSV are all used, yes. Mind you these are Arm specific things that wouldn't be used on other platforms, of course.
I think the above article missed the "notifications" part. Without notifications, a blocking IPC wouldn't have sense in an RTOS: a task would not be able to process an interrupt because it's blocked while "sending".
I guess the existence of notifications is there to provide methods for an UART driver/task that blocks waiting for interrupts. When the interrupt arrives, the driver deals with it and instead of sending the data directly to a listener, it just "notifies" incoming data to another task (pretty much the "usual" way of doing things).
This makes "UART" to sit on its own task, setting the right priority for it, implement a circular buffer, etc. Complexity quickly escalates for a (for example) "sensor fusion" driver, which has to manage 3 other drivers (accelerometer, gyro and magnetometer drivers), each one on top of another drivers (SPI, I2C, etc.).
But I guess that's a price to pay.
> Users can't disable interrupts, they can only mask or unmask receiving notifications for said interrupts.
Sorry. I interpreted that drivers were also tasks (or they live in tasks?), so being able to interface the hardware I guess setting PRIMASK=1 could be an option too.
Perhaps battery-powered systems is not your application target, but I would be interested to see how __wfi() works within the Hubris context.
I would strongly encourage you to check out the docs that Steve pointed you to, and of course, the source itself! And nothing beats actually throwing it on some hardware and messing around with it, which should help clarify the model -- and why we believe it to be a good fit for real-time applications.
I read all the docs and I understand Humility as an OS, it's extremely simple (for a OS) and it is going to be fun to develop against. Or at least, I'm excited to give it a shot.
My initial ideas are audio controllers that parse sensor streams and convert that to OSC signals but I have no idea what implementing the network stack will look like as I need UDP from Rust on a microcontroller.
If anyone has experience and wants to share drop me a line at @ben:matrix.graythwaite.ca I'd love to chat about it
[0] https://www.st.com/en/evaluation-tools/32f411ediscovery.html
Thanks Brian for the link. Looking forward to watching where Open Firmware community / Oxide / Rust take embedded. Exciting stuff.
What a time to be sourcing for new hardware. We're rooting for you.
P.S. The Oxide design motif reminds me of 96-pin Euro/VME connectors.
Anyone who's done the UWaterloo trains course will recognize these patterns immediately, and (IIRC) interrupt dispatching is was done in a similar manner there as well.
Finally, the supervision patterns here strike me as being very similar to those within the BEAM, and remind me of the infamous quote from Robert Virding (http://erlang.org/pipermail/erlang-questions/2008-January/03...). Obviously a necessary reimplementation here, but humorous nonetheless.
Great project, great talk.
What a throwback!
Interrupt code is at https://gist.github.com/mtrudel/c29fa60e5b2f3b6fdc46a9e3c65d.... I've been meaning for years to clean this stuff up and resurrect it. Maybe this is the kick in the ass I need to finally do so!
However, it mentions that one of the usecases is for the oxide BMC. AFAICT, a "modern" BMC is typically a more or less full featured OS running quite a lot of code, like a TCP/IP (v4 & v6) stack, IPMI and Redfish implementations (which then requires a web server with TLS library etc etc.) and so on. Without the capability to make use of the existing open source user space code in these areas, this seems like a quite tall order to write and maintain? And how does the "static tasks" system without the capability to launch tasks dynamically, handle things like multiple concurrent IPMI/Redfish users?
The idea is to have a minimal BMC that only does very few things and instead puts as many things as possible to the host OS.
A completely unrelated anecdote.
When I clicked the link, I was greeted with a beautiful black and white and blue page, perfectly indented.
I scrolled and looked at the ascii and thought how great it was to just see a web page again.
Then I looked at the source to see if they had designed any extra special formatting and was greeted with <style id="brave_speedreader_style"> and realized I had Brave Speedreader on. I was a little disappointed when I turned it off and the hyperlinks turned pink.