2016-04-11

Re-Adding libsam

If you've followed this blog from the beginning, you'll know that I started out with a pretty standard Arduino sketch, and reduced it piece by piece, until I arrived at a Rust program. This was an awesome approach. It allowed me to verify every small step before moving on to the next one. Writing a working Rust program from scratch would have been infinitely harder.

However, since I've finished the minimal Rust program and started adding features to it, I could no longer take advantage of working code when building those new features. Sometimes the feature was simple and this didn't really matter. Other times it caused me problems, especially given the very limited debugging capabilities I have right now (all I can do to transmit information from the program to myself is blink the LED in various patterns)[1].

When I finally ran into a wall at some point, I decided I needed a better solution. After some thinking, I came up with this idea: There are various C libraries floating around that are written for the express purpose of allowing easy access to the hardware. Why not use one of those when first building a new feature? I still want to write everything myself in Rust (my goal is to understand everything from the bottom up, after all), but I can prototype a new feature using 3rd party code, and then replace it bit by bit with my own.

After looking around for a while, I decided to use a library by Atmel called libsam that I found in the Arduino repository[2]. It seems straight-forward, and it's used by the Arduino code, so at least I know it works.

I decided to build libsam by hand and add the compiled library to the repository, as this is the easiest solution for now.[3] Doing that turned out to be straight-forward. Integrating it was just as straight-forward, as I just had to tell the linker to link the library by passing -l:libsam_sam3x8e_gcc_rel.a in target.json. Here's how that looks:

{
    "llvm-target"         : "thumbv7m-unknown-none-eabi",
    "linker"              : "arm-none-eabi-gcc",
    "pre-link-args"       : [ "-nostartfiles", "-Tlinker-script.ld" ],
    "post-link-args"      : [ "-l:libsam_sam3x8e_gcc_rel.a" ],
    "no-compiler-rt"      : true,
    "target-endian"       : "little",
    "target-pointer-width": "32",
    "arch"                : "arm",
    "os"                  : "none",
    "executables"         : true
}

            

Now that the library is available, we can use its functions by declaring them as extern functions in Rust:

extern {
    fn WDT_Restart(wdt: *mut u32);
}
            

This function restarts the watchdog timer. I'm not going to explain what this means right now, as I plan to make the watchdog timer the topic of the next article.

Please note that the function is not defined exactly as it is in the C code. There, it takes a pointer to a struct that defines the user interface to the watchdog timer. This does not matter though. A pointer is just an address, and as long as we pass it the right address, the function won't know the difference.

Here's how we use that function in the code:

// Initialization code omitted for brevity

loop {
    unsafe { WDT_Restart(0x400E1A50 as *mut u32) };

    // LED blinking code omitted
}
            

Here we just call the function, and pass it the memory address of the watchdog's user interface. Since this is a C function that could do all kinds of things to break our program, this requires an unsafe block.

As I said above, I'm planning to make the watchdog the topic of my next article, so I won't go into it any further right now[4].

And that's it for today. As always, the full code is available on GitHub. See you next time!