Skip to main content

STK8BA58 Embedded Driver

Image

This driver is the most complex thing I’ve written to date.

Why? #

Long story short: Helping someone who reached out to me through this website led things to me getting the same device as them, the Picoboy. I ended up wanting to make a BSP to make working with the Picoboy easier, and in the proccess I found out that there isn’t a crate for the accelerometer it uses. So what other option did I have other than to make one myself?

How #

I started by implementing the traits from the accelerometer crate, just reading the registers where the acceleration is and doing the math needed to get a g value. I would have stopped there, but I saw that other crates that implemented accelerometer’s trait had extra functionaliy. Mostly methods to configure and tweak the registers on the accelerometers. I figured I’d do the same, and what a rabbithole.

I started by manually implementing a method for each function of the accelerometer. For context, the accelerometer has 31 registers, and many of those have various separate functions. I quickly realized this wouldn’t be sustainable. Lots and lots of work to implement every single function for every single register. At the same time, I noticed a pattern in the methods that wrote bit flags to the registers.

So I decided to try generics. Sure, I had written some generic code before - but it wasn’t without hand holding. embedded_hal makes it easy and even gives you examples on how to use it’s generic types. But I was on my own on this one. I also had been reading Rust for Rustaceans (by Jon Gjengset), which at the point I was, generics had been talked about a bit already. And I did it, on my own I made a generic function to read flags from registers.

But it required a lot of impl From<BITFLAGS_STRUCT> for Register, which ends up causing the same problem: Code repetition an lots of work. After seeing what I had done though, I couldn’t help but feel like I could go further. That I could Really get out of my comfort zone with this one. And I did: I wrote a macro. My first macro! Here it is:

macro_rules! reg_from_flags {
    ($f:ident) => {
        impl From<$f> for Register {
            fn from(_value: $f) -> Self {
                Self::$f
            }
        }
    };
}

Honestly, I couldn’t believe it. I know it’s a really simple macro, and that just using ident is not the right way to do it. But I made a macro! This feels like an acheivement for me. I really didn’t think I was capable of doing something I consider so complex.

So if I wrote a macro, what’s stopping me from trying to make everything generic? Nothing. Not only I made the setting of flags generic, but also the reading of “modes”, which consist of several bits and are therefore represented as enums.

I know this crate is not the best, that it has a lot that can be improved, but I’m really proud of it. I feel like I’ve really got out of my comfort zone with it and learnt a lot making it. It’s missing unit tests, which is something I’ve never done yet either. But for now, I’m done working on it. I might add them some time later.

Check out the project on gitlab: https://gitlab.com/slusheea/stk8ba58