This has been not without its challenges, mainly related to a lack of support for the ATmega4809 chip the Nano Every is based on. I’ve already worked with two very respectable options - Ruduino and avr-hal which between them got me a long way.
Neither entirely satisfied me, though. In both cases, get anything working was a little bit of a struggle and involved a certain amount of hacking things around. Also, “idiomatic Rust” can sometimes be incredibly hard to read (one of my few concerns with Rust is that it can be a write-only language when used entirely correctly), which made working out what changes I needed to make to get things working painfully difficult at times. This is a reflection on me far more than either of these projects, but it meant I found myself spending more time searching in frustration to find out how something ought to be achieved than in actually writing the application code I wanted to write.
What I really wanted was something much simpler, a crate I could link into my project which would provide me with a simple abstraction of the device hardware (maybe not idiomatically entirely perfect Rust, but easy to understand,) so I could then write code that twiddles I/O lines, waits for interrupts, and uses basic timer facilities without too much work.
Also, critically, it needs to actually work on the ATmega4809. Right now, the one in the Arduino Nano, but in future also some hypothetical variant that isn’t actually Arduino based (I have in mind incorporating the chip directly into some of my own board designs.)
Such a thing doesn’t seem to exist right now. So, rather than complain, I decided to write it myself.
Why AVR-Oxide? Because it’s a Rusty AVR of course!
What is it?⌗
It’s a simple hardware abstraction library and basic runtime for Rust on AVR devices. The aim is to provide:
- A low-level abstraction of the core devices that are provided by the AVR microcontroller itself - ports and pins, timer control blocks, serial UARTs, that sort of thing.
- A slightly higher level abstraction for common hardware that might be attached to those devices. LEDs, buttons, a system clock, a serial port.
- An easy way to access those devices in your own code in a relatively device-independent way (through generics/compile-time options rather than runtime dynamic dispatch - the chip you are running on is unlikely to change from one type to another at runtime, after all ;-))
- A basic runtime/supervisor that has a default implementation of
interrupt handlers for all the relevant devices and provides the application
developer with a simple event-based application programming model. I.e.
the application developer should be able to write simple “when button X is
pressed do Y” code without worrying about developing Interrupt Service
Routines or the like.
- One day we may even grow pre-emptive multithreading, or that may just be a grandiose plan. We shall see!
Sounds good; does it exist?⌗
Well yes, yes it does. At the time of writing, we have a basic implementation that can reliably give an application programmer access to the pins of an Arduino Nano Every board, with access to timer interrupts for scheduled or polling tasks.
A little packing up into a crate, and a little documentation, and we should be ready to go. I hope within a couple of days I’ll be able to release it to the world; in the meantime, stay tuned and feel free to write in the comments below if this’ll be useful to you! (I know at least one reader has been attempting the same journey as me…)