Software Development Tips and Tricks


macOS Big Sur Battery Percentage In the Menu Bar

After upgrading to macOS Big Sur beta I noticed that the battery percentage disappeared from my menu bar. One would think getting it back would be as simple as clicking on the battery icon in the menu and selecting Show Percentage, and how could you fault someone for assuming that?

Yet that is a path that leads to both ruin and no menu option to show the battery percentage. Now, to do that you need to go to System Preferences, and find the new preference pane named Dock & Menu Bar:

Click on it and scroll down the left-hand side of the pane until you find the Battery item. Click to discover Show Percentage.

Select Show Percentage and Big Sur will happily once again provide you with what I consider a useful bit of information for determining how much battery you have left.


I2C with the SiFive HiFive1 Rev B

Hey kids! Today we’re going to take a look at the SiFive HiFive1 Rev B and Freedom Metal I2C API.

I am going to be using a classic EEPROM from National Semiconductor, the NM24C17. The NM24C17 is a 16 kilobit (2K) EEPROM that can be written to and read from using I2C.

If you have one of these EEPROMs lying around (and who doesn’t?) and want to use it with your HiFive1 board, you’ll also need:

  • the datasheet
  • a breadboard
  • breadboard wires
  • 2 4.7k pull-up resistors

What you might also want to have handy a digital logic analyzer such as the Logic 8 from Saleae.

The I2C circuit is a simple one, but it is important to note that the NM24C17 EEPROM does not come with I2C pull-up resistors, so we need to add them in our circuit.

Assembling everything with the HiFive1 I2C pins and providing power.

Reading the Datasheet

When working with I2C devices it is so important to read through the datasheet once or twice. Or ten times. Datasheets can be dense and intimidating, but I have rarely come across an issue I was troubleshooting that didn’t end up being caused by not reading the datasheet closely.


Okay, let’s start coding some I2C with Freedom Metal. We’ll start with a basic shell.

Working with I2C in Freedom Metal starts with including the <metal/i2c.h> header file and obtaining a pointer to the I2C device with metal_i2c_get_device. For the HiFive1 Rev B board there is only one device to get, and it’s at index 0. Once you have a pointer to the I2C device, initialize it with metal_i2c_init. We’ll configure our device for 100 kbits/sec (I2C “full speed”) and as the master.

Now, let’s look at our first write function, which will be to write a sequence of bytes to the EEPROM at a given address. This code is very specific to the way the NM24C17 EEPROM functions. We will be using the metal_i2c_write function which takes as its arguments:

  • a pointer to the I2C controller device on the RISC-V chip
  • the address of the I2C bus device to talk to
  • the length of the message to send to the bus device
  • the message to send
  • a flag indicating whether or not to send the I2C stop bit

The first argument will be our struct metal_i2c* i2c_device variable, but the address of the EEPROM on the bus is interesting.

At first blush it appears the address would be 0xa0 to account for the first four bits to transmit are 1 0 1 0, and for the NM24C17 device the 3 page address bits appear to be all 0 (appear is the operative word). That leaves us with the R/W bit, which for a write would be 0. 1010 0000b, or 0xa0, right? Wrong. The R/W bit is not a part of the device address here, which leaves us with 1010000b, which is 0x50.

The message to send to the EEPROM consists of two bytes: the memory address in the EEPROM to write to and the value to write. For simplicity we’ll just write the value 0xab at the address 0x00.

The final argument to metal_i2c_write is to indicate whether or not to signal an I2C stop bit upon completion. Since the stop bit is required for us to write this data to the EEPROM we will use METAL_I2C_STOP_ENABLE.

One thing I’ve found to be true about I2C is that if it works, it works. If it doesn’t, you better have a digital logic analyzer on hand to look at things.


Now let’s read the data that we wrote back in. This requires two function calls: metal_i2c_write and metal_i2c_read.

Notice above that the first step to reading a byte from the EEPROM is to write out the address to be read from, followed by a read. There is only one stop bit in this sequence:

Notice the use of METAL_I2C_STOP_DISABLE; this instructs the I2C controller not to signal a stop bit at the conclusion of the write.

We make double use of the readbuf array by initializing it to the address in the EEPROM we want to read from, and then to hold the data read in.

Writing and Reading Multiple Bytes

Writing and reading one byte at a time to our EEPROM is a bit tedious, so let’s make use of the multiple-byte write.

In this example we send the device address (again, 0x50 for the EEPROM), followed by an address to write to in the EEPROM, and then up to 16 bytes of data.

Before we get to writing again, I’ve made mention that 0x50 is the I2C device address of the EEPROM. While it is, that isn’t the whole story. That is the address for page block 0 of the device, but it supports 8 page blocks. Selecting the page block is done with the lower nibble of the device address. For example, page block 1 can be addressed at 0x51, page block 2 at 0x52, and so on. Each page block is 2 kilobits, or 256 bytes.

At any rate, let’s stick with page block 0 for now and write 16 bytes:

Of course, we are actually writing 17 bytes out to the EEPROM, the first of which is the address we want to write to.

Reading the data back in can look like this:

A Smarter API

After understanding the basics of reading and writing to the NM24C17 it’s time to write an API to encapsulate the nuts and bolts. Our header file looks like this:

Our structure is arranged such that the addr byte is positioned immediately prior to the buf. This organization allows us to take advantage of the C memory layout of the data and writing to the EEPROM. For example:

Our device address is the base address of the EEPROM (0x50) ORed with the page block number. The length of the message to write is the length of the data buffer the user wants to write plus the address byte. Writing starts at the address byte and continues into the buffer.

Remember the exhortation to read the datasheet, and read it several more times? Here is what happens if you start a write on an address not evenly divisible by 16. Notice that our write address starts at 0x22 in page block 1. Sixteen bytes are presumably written, but when trying to read them back in, the last two bytes read are 0xff. Hmm.

From the National Semiconductor datasheet definitions:

  • PAGE – 16 sequential addresses (one byte each) that may be programmed during a “Page Write” programming cycle.
  • PAGE BLOCK – 2,048 (2K) bits organized into 16 pages of addressable memory. (8 bits) x (16 bytes) x (16 pages) = 2,048 bits”

But wait! The Fairchild-printed version of this EEPROM’s datasheet says a bit more:

To minimize write cycle time, NM24C16/17 offer Page Write feature, by which, up to a maximum of 16 contiguous bytes locations can be programmed all at once (instead of 16 individual byte writes). To facilitate this feature, the memory array is organized in terms of “Pages.” A Page consists of 16 contiguous byte locations starting at every 16-Byte address boundary (for example, starting at array address 0x00, 0x10, 0x20 etc.)

Like I said, always read the datasheet and sometimes you have to read two of them to get the whole story.


There are four basic functions needed to use I2C with Freedom Metal:

  • metal_i2c_get_device – obtain a pointer to the underlying I2C device on the microcontroller
  • metal_i2c_init – initialize the I2C device speed and mode
  • metal_i2c_write – address and send data on the bus
  • metal_i2c_read – address and read data from the bus

It really is that simple!

Get the Code

I’ve recently start using PlatformIO to develop on my HiFive1. If you haven’t checked it out I recommend you doing so; it’s very easy to install and start making use of your board right away without having to manually download toolchains and JTAG interfaces. I’ve posted a PlatformIO-based project on GitHub for working with the NM24C17.


Exploring HiFive1 Rev B GPIOs with PlatformIO

In our last post we looked at the GPIO pins of the SiFive HiFive1 Rev B board, and in this one we will continue doing so, but let’s take a look at PlatformIO on that journey. PlatformIO bills itself as “A new generation ecosystem for embedded development” and aims to really simplify pulling together all of the tools needed for embedded development. In our introduction to the HiFive1 Rev B we outlined all of the packages you needed to install and configure to get started with the board. Cross-compilers, JTAG daemons, remote debug tools, SDKs, and so on. What if we could skip all that, not just for one microcontroller platform, but for hundreds of them? Enter PlatformIO.

Installing PlatformIO

PlatformIO, while compatible with a number of popular editors (Sublime Text, Atom, etc.), really shines with Visual Studio Code. While VSCode has features I don’t find appealing (horizontal bars on my code), it is very configurable and I can turn them off and enable Emacs keybindings. After some time with VSCode and PlatformIO, I really began enjoying how straightforward it was to work with the HiFive1 Rev B.

Installing PlatformIO is simple with Visual Studio Code. Open the Extensions panel and search:

Click on Install. You’ll see a “landing page” of sorts for PlatformIO and a window open up on the bottom indicating it is being installed and configured.

Once PlatformIO is installed we’ll create a project for use with our HiFive1 Rev B board. Click on the PlatformIO Projects button and then Create New Project.

This is where PlatformIO really shines. There are over 800 boards to choose from, and depending on the board, multiple frameworks to work with. For example, with the HiFive1 Rev B you can use either the Freedom E SDK (which we use), or the Zephyr RTOS.

Creating a New File

Obviously we’ll need to write some code, so in your project right-click on src and select New File.

Visual Studio Code will prompt you to name the file in the project explorer; ours is named simply main.c. We’ll do the GPIO equivalent of a Hello World by blinking the onboard green LED:

Building and Uploading

PlatformIO automates and streamlines installation of the correct toolchain, debugger, SDK and so on. To build your project there is a checkmark on the bottom of the editor window; if you hover over it you’ll see the label PlatformIO: Build. Click on it and scroll through the output to see what PlatformIO is doing; I’ve found it very helpful to read everything that is going on.

Uploading your project to the HiFive1 Rev B is as simple as clicking the right arrow that is labeled PlatformIO: Upload. Again, if this is your first time using PlatformIO on a given environment you can see it’s installing what’s necessary to upload to your board.

Here is a great example of what PlatformIO is doing in the background:

While it’s possible to do this by hand (and we have!), how nice it is to have it done automatically for you.

Serial Output

PlatformIO does have the ability to open a serial monitor to your HiFive1 Rev B board, though you may have to do a bit of configuration here. Open the project’s platformio.ini and ensure that your environment configuration has monitor_speed=115200 set. This will tell PlatformIO to use 115200 baud to communicate on the serial port. Then open the serial monitor with the “electric plug” icon and choose the first usbmodem port you see.

I typically prefer to use screen on macOS for this – the console output in Visual Studio Code is nice, but I’m used to screen and like having it in a separate terminal window altogether. For example, typing screen /dev/cu.usbmodemIDENTIFIER 115200 (where IDENTIFIER will be specific to your machine) will bring up the serial console to the board.

Testing the GPIO Pins

Okay, PlatformIO is ready to go and we’re going to take a look at the GPIO pins on the HiFive1 Rev B again. I’ve learned a bit since writing about them in this post. For starters, digital pin 14 on the header is not connected and there is no mapping of a pin from the GPIO device.

In addition, pins 11, 12, and 13 on the header correspond to the MOSI, MISO, and SCK signals for the SPI device; since they are tied to SPI writing a digital one to them has no effect. On the other hand, you can write a 1 to pin 10 (SPI SS) and get an output.

That said, you can use the I2C pins (digital pins 18 and 19) and write a digital one or zero to them as long as we’re willing to give them up as I2C pins.

Pins 15 and 16 are interesting. If you look at the HiFive1 Rev B schematic for J4 (the Arduino 6 pin block on the bottom left of the ESP32) you see GPIO 9 and GPIO10 map to DIG15 and DIG16. But then going over here we see that:

  • GPIO9 is tied to a line labeled SPI_CS2 which comes from the ESP-SOLO-1
  • GPIO10 is tied to a line labeled WF_INT which comes from the ESP-SOLO-1

The schematic notes “Solder across SJ1 to connect GPIO_9 to SPI_CA2” (I think that is a typo). On the physical board I cannot find SJ1 or SJ2, so I’m assuming these connections are present.

So, what does that gives us in the end?

  • DIG2 – easy to use to drive a digital output
  • DIG3 – easy to use to drive a digital output, but doing so interferes with the onboard LED
  • DIG4 – easy to use to drive a digital output
  • DIG5 – easy to use to drive a digital output, but doing so interferes with the onboard LED
  • DIG6 – easy to use to drive a digital output, but doing so interferes with the onboard LED
  • DIG7 – easy to use to drive a digital output
  • DIG9 – easy to use to drive a digital output
  • DIG10 – easy to use to drive a digital output, but doing so interferes with using SPI
  • DIG17 – easy to use to drive a digital output
  • DIG18 – easy to use to drive a digital output, but interferes with I2C
  • DIG19 – easy to use to drive a digital output, but interferes with I2C

In the next post I’m going to be building an I2C circuit that contains 4 EEPROMs, each of which will have the same address. To do so I want to use two digital output pins to specify which I2C chip to work with, so to make life easy I want to choose pins that won’t interfere with anything else. DIG2, DIG4, DIG7, DIG9, and DIG17 are my best bests, and since DIG2 and DIG4 are on the same side of the board I’ll start there.


PlatformIO is pretty damn slick if you ask me and worth checking out if you are just starting with the HiFive1 Rev B. While I still recommend that you understand cross-compilers and the underlying tools that go into supporting such a platform, it really does take the hassle out of downloading and configuring everything!

If you have a HiFive1 Rev B board, try checking out our GPIO project. I have no doubt that you’ll be able to build and upload it with minimal fuss using PlatformIO.


HiFive1 Rev B GPIO Pins

Let’s make use of the HiFive1 Rev B schematics to map out the GPIO controller device pins. Of particular interest is sheet 3, and the following components of the schematic in section D1:

We’re going to use this as our starting point. Three GPIO lines labeled 19, 21, and 22 with LEDs on the lines.

Editor’s Note: This write-up on the SiFive HiFive1 Rev B assumes you have one and are familiar with powering it up, connecting to the serial port, and uploading applications. See our last post if you need to orient yourself with the environment.

Using Metal GPIO

If you haven’t done so already, familiarize yourself with Freedom Metal and the API documentation because we’re going to make use of the GPIO functions.

Recall in the schematic above that the onboard LEDs are tied to GPIO 19 (green LED), GPIO 21 (blue LED), and GPIO 22 (red LED). While the Metal LED API could be used here, we’re going to work directly with the GPIO functions to prove to ourselves that the above GPIO pins are correct, and also check out the 8 color combinations the LED can produce.

Our basic loop is going to cycle from 0 to 7 and turning on the red LED if bit 1 is set, the green LED if bit 2 is set, and the blue LED if bit 3 is set. This should cause our HiFive1 on-board LED to cycle through the following color chart:

Okay, let’s get the basics down. The GPIO can be accessed by obtaining a struct metal_gpio* using the metal_gpio_get_device function, like this:

Now that we have the GPIO device itself, let’s enable GPIO 19 as an output pin. In our schematic take note that the other side of the LED is tied to 3.3V. In other words, there is no setting GPIO 19 high or low required here, if it is enabled you’re going to get the LED on.

To set GPIO 19 as an output:

To disable the output of the pin:

Now I thinkthis works for the onboard LED because of the way it is wired to the 3.3V supply. In fact, for Metal GPIO pin 19, if you try to write a 1 to it you actually turn off the onboard LED and turn on the header pin 3. Speaking of the header pins…

Arduino Header and Pins

Going back to the board schematic, this time on sheet 3 in sections A5, A6, B5, B6, and C5, C6.

Now this is interesting! Our Arduino headers as well have notes on which GPIOs are digital-only (high or low), those that are PWM-capable, and which pins are shared by SPI, I2C, and UART. All we need to do is put this into a nice table, and the following is (I think) a complete GPIO mapping for the SiFive HiFive1 Rev B board.

For example, if you wanted to start your project with blinking an LED on a breadboard, you might start with one of the “standard” digital input/output pins on the header, say pin 7. The chart above (which is derived from the schematic) shows that pin 7 on the header is tied to pin 23 of the GPIO controller. So to use header pin 7 we might write:

Or, we could set at the top of our file something along the lines of #define PIN7 23. Just a thought.

Notice once again that this mapping table shows that there are:

  • 20 digital pins
  • 6 PWM-capable pins
  • 1 SPI
  • 1 I2C
  • 1 UART

Unfortunately SiFive’s HiFive1 Rev B page indicates there are only 19 digital pins and there are 9 PWM-capable ones, so there’s something I’m missing. I think at least for PWM, header pins 17, 18, and 19 on the 6-pin header (to the left of the ESP32) are PWM-capable, though that isn’t clear from the schematic. I’ve asked about that here on the SiFive Forums and will reconcile this post once I learn more.

Getting Some Code

This code is a work in progress and is modeled around the Arduino digital IO library. In digitalio.c you’ll see my take on the functions pinMode and digitalWrite. There is also a delay function to write the ever-popular blinking lights demo. All of this code is MIT licensed with portions copied from the SiFive Freedom E SDK.

Let’s look at how we might use these functions to put the onboard LED through all of the possible colors.


Recall the GPIO pins that map to the on-board LEDs are:

  • Red – GPIO_22
  • Green – GPIO_19
  • Blue – GPIO_21

We iterate from 0 to 7 in a loop, test the bits, and set the pins as outputs (since we’re using the onboard LEDs) or disable them. The result is a nice rainbow light show from the HiFive1. If you connect to the serial port you’ll also see the colors being printed out as they are cycled through:


The code that’s actually uploaded to GitHub includes stepping through the binary representation of our LED rainbow and displaying that if you hook up a few LEDs to your breadboard. Check out the code and look closely here at header pins 2, 4, and 7.

Closing Thoughts and What’s Next

Nothing is more fun than working with microcontrollers and embedded systems, and the HiFive1 is no exception. If you take a look at gpios.h in GitHub you can see that I’m looking as to how to best add additional #defines for the various pins. We will see.


An Introduction to the HiFive1 Rev B and RISC-V

Today I’d like to introduce you to a new development board, the HiFive1 Rev B. Equipped with a RISC-V Freedom E310 microcontroller and designed with an Arduino Uno “form factor”, the HiFive1 Rev B is a neat little board that I hope to learn and develop for.

My HiFive1

There is a lot of material out there about RISC-V and how it is going to change the future of CPUs, but what attracted me to it was the notion of a completely open standard Instruction Set Architecture (ISA). That and I think working with new hardware and development environments is cool.

Getting Started

The Getting Started Guide is crucial to read. If you’re anything like me you want to dig in as quickly as possible with as little reading as possible, but trust me, reading the guide first is very useful.

You don’t get anything but the HiFive1 Rev B board if you’ve ordered it from Crowd Supply and will need a trusty USB-A male to USB-micro-B male cable. This connection can be used for both serial communication and power. Of course, if you have only a system with USB-C you’ll need some set of adapters to get to USB micro-B.

For the host platform we will be using a MacBook Pro (Retina, 13-inch, Early 2015) running macOS 10.15 (Catalina). Hopefully if you’re reading this with the intention of working on the HiFive1 with your Macbook Pro you’ll already have the best terminal program ever installed, but if you don’t regular Terminal.app works.

Let’s see our boot screen first:

To see this boot screen you’ll need to use a serial terminal program. macOS is going to present the HiFive as the two USB modem devices in the /dev directory.

The first cu.usbmodem device presented will be the HiFive1, and my suggestion is to open an iTerm and use screen to connect to it. 115200 bps is your speed and the default 8N1 settings should work, so in our case screen /dev/cu.usbmodem0009790151821 115200 is all we had to type in the terminal.

Time to Develop

There are several key pieces of software you’ll need to install on your Mac to begin developing on the HiFive1.

  • a toolchain (i.e., the compiler, assembler, linker, and associated libraries)
  • OpenOCD On-Chip Debugger
  • the Freedom E SDK
  • Segger J-Link OB debugger

We’ll take each in turn.

Installing the Toolchain and OpenOCD

The reference toolchain is a GNU Embedded Toolchain — v2019.08.0 and can be downloaded directly from SiFive. Go to the Boards page, scroll down until you see the section labeled Prebuilt RISC-V GCC Toolchain and Emulator.

Download both the GNU toolchain and OpenOCD packages and untar both into a suitable installation location. I prefer to keep things like this in the /opt directory, so we’ll do the same here in /opt/riscv.

Before going any further ensure that the compiler can run:

You may have received the error message "riscv64-unknown-elf-gcc" cannot be opened because the developer cannot be verified.. Now, this may be controversial, but I don’t hold to my OS telling me what software I can and can’t run, so let’s get rid of that silliness with spctl:

Let’s try again:

Much better.

Get the SDK

We have a HiFive1 board which uses the Freedom E310 chip, thus will want to get the Freedom E SDK. For this I like to keep the SDK in my projects directory.

Note: You must use --recursive here to check out all of the required packages.

Now, let’s compile that first program!

In the top-level directory freedom-e-sdk is a set of Makefiles that make it easy to compile and generate an image suitable for uploading to the HiFive1 board. In this case, PROGRAM is the name of a subdirectory in freedom-e-sdk/software and TARGET is the board you have.

If this is the first time through you’re going to see a bunch of gibbersh about Python, pip3, virtualenv, etc:

And, if you receive an error regarding the C compiler cannot create executables, you need to set your RISCV_PATH environment variable to point to the correct toolchain like export RISCV_PATH=/opt/riscv/riscv64-unknown-elf-gcc-8.3.0-2019.08.0-x86_64-apple-darwin'.

It’s often a good idea to put the various environment variables in a file such as sifive.env and this source the script into your environment.


If everything worked properly you’ll see at the end something like after compiling.

Installing J-Link

Now, we’re going to upload this to our board, but we will need the Segger J-Link OB debugger. If it isn’t installed you’ll see something like this when trying to use the upload target.

To get J-Link head over to the download page and grab the J-Link Software and Documentation pack for macOS.

Install per the instructions, and once that is done you can go back to your SDK directory and type:

If everything is installed correctly and the board is attached you’ll see something like:

And that’s it! If you have a terminal window with a connection to the serial output of the board you’ll see Hello, World!.

Your Own C Program

In the directory freedom-e-sdk there is a software folder that has an example template. We’ll use that to create our own ASCII art banner.

Copy the template with something like cp -R software/empty software/leo-welcome and then edit the software/leo-welcome/Makefile to change the PROGRAM name to leo-welcome. Open main.c in the same directory and replace the contents with:

Compile and upload with make PROGRAM=leo-welcome TARGET=sifive-hifive1-revb upload and behold.

Some Assembly

I’ll be honest, I struggled with this part, but that’s primarily due to the school of hard knocks with piecing together the calling convention for RISC-V. Let’s review a few examples.

Hello World in RISC-V Assembly

Again, start off with the example folder inside freedom-e-sdk with something like

In this case we’re going to write Hello World in assembly so delete software/helloasm/main.c and instead create a file called main.S with the following content.


In RISC-V the a-registers will contain our procedure arguments, the procedure here being C printf. We use la (load address) to bring the address of the hellomsg label into a0 and then call the printf function. All of these, in reality, are pseudoinstructions.

The Makefile in the template will pick up files with a .S extension, so make PROGRAM=helloasm upload will assemble, link, and upload our file to the HiFive1.

Counting Down

Finally, let’s look at a countdown routine with a max and min. Here things are a bit more complicated as we are going to make use of a prologue and epilogue in our routine. The prologue saves the return address on the stack, and the epilogue loads the address back into the ra register such that the instruction ret will branch back to our caller.


We can call this function with C like this:


Compile and upload!

Good References

There are a lot of great references on RISC-V, its instruction set architecture, and so on. I’ve compiled a few of my favorites here.

Closing Thoughts and What’s Next

That wraps it up for this first look at the SiFive HiFive1 Rev B board. Of course, we haven’t even talked about the ESP32-based wireless capabilities of the board, haven’t talked about the Freedom Metal library or any of the stuff that will accelerate our development. Perhaps that’s next!

And, if you’ve made it this far, you might want to check out our next post on exploring the HiFive1 GPIO pins.


Working with ARM Assembly

Don’t ask me why I started looking at writing basic ARM assembly routines. Perhaps it’s for the thrill of it, or taking a walk down memory lane. My first assembly language program was for an IBM System/360 using WYLBUR in college.

This post is not a tutorial on assembly language itself, or the ARM processor for that matter. If the phrases mnemonic, register, or branch on not equal are foreign to you, have a look here. I just wanted to write some easy routines and pick up some basics.

Editor’s note: All of the code below is available on GitHub.

We’ll be using a Raspberry Pi 4. You will (obviously) need the GCC toolchain installed, which can be accomplished with sudo apt-get install build-essential.

Let’s save the following in a file named helloworld.s:


Assemble and link the application together with gcc helloworld.s -o helloworld and run it.

It doesn’t get much more straightforward than this, and you’ve learned three new ARM assembly instructions: ldr, mov, and bl. The remaining text are directives to the GNU assembler which we’ll cover in a minute.

The ldr instruction loads some value from memory into a register. This is key with ARM: load instructions load from memory. In the example above we’re loading the address of the beginning of the string into register r0. A technical note: ldr is actually a psuedoinstruction, but let’s gloss over that.

bl branches to the label indicated (and updates the link register), and in our case, there is this magical printf we’re branching to. More on that later.

Finally, mov r0,#0 is positioning our program’s return code (zero) into r0. Check it:

What if we change the mov r0,#0 to mov r0,#0xff? Try it:

Okay, now for something interesting. Let’s count down from 10 to 1 and then print Hello, world!.


Okay, that escalated quickly! One of the reasons assembly language is so much fun. Let’s take a look at what is going on here and add some comments to our code.

There’s a few things to note here. First, let’s talk about the use of r5 and why that register was deliberately chosen. It turns out that when calling routines in assembly you better not use registers that will get trashed by whatever subroutine your calling (r0-r3). printf can use these registers, so we’ll use r5 in our routine.

Now, I will confess, I am not an assembly language expert much less an ARM assembly language expert. Someone may look at the above code and ask why I didn’t use the subtract-and-compare-to-zero instruction (if there is one) or some other technique. If there is a better way to write the above, please let me know!

Counting Up

In the above example we counted down, now let’s count up, and instead of counting from zero to some max, let’s count up from some minimum value to some maximum value. In other words, we’ll step through a sequence of values using an increment of one.


There’s some new syntax here, in particular the ldr rx,[rx]. This syntax is “load the value that is pointed to by the address in the register.” It makes sense in that there is an instruction immediately before it ldr,=min which is load the address identified by the label min. To be clear, the actual value of that label is going to be dependent on the assembler, your application size, and where it gets loaded into memory. Let’s look at an example of that:


Compile and execute this code to see something like Address of x is 0x21028. Then move x to after fmtstr and you will see the address change. What it will change to, again, is highly dependent on a number of factors. Suffice it to say, using ldr with memory addresses loads the address into a register, not the value at the address. That is what we use ldr rx,[rx] for.

Running our countup code indeed counts up from 14 to 28 and if we look at the return code (echo $?) we get 29, the last value that was in r5.

Writing a Procedure

Here is a basic ARM assembly procedure that computes and returns fib(n), the nth element of the Fibonacci sequence. We chose this specifically to demonstrate the use of the stack with push and pop.


What should be noticed here is the use of push and the list of register values we’re going to save onto the stack. In ARM assembly the Procedure Call Standard convention is to save registers r4-r8 if you’re going to work with them in your subroutine. In the above example we use r4 and r5 to compute fib(n) so we first push r4 and r5 along with the link register. Before returning we pop the previous values off the stack back into the registers.

To use this routine in C we can write:


Then, compile, assemble, and link with gcc fibmain.c fib.s -o fibmain. Recall the procedure call standard convention that the arguments to the procedure will be in r0-r3, hence why our first instruction mov r4,r0 to capture what n we’re calculating the Fibonacci number of.

Taking the Average

Okay, one last routine. We want to take the average of an array of integers. In C that would look something like this:

Here’s a go at it in ARM assembly.


There are some new instructions, an interesting form of the ldr instruction, and a new type of register.

First, the vmov instruction and register s1. vmov moves values into registers of the Vector Floating-Point Coprocessor, assuming your processor has one (if it is a Pi it will). s1 is one of the single-precision floating-point registers. Note that this is a 32-bit wide register that can store a C float.

Next up is the ldr r5,[r0],#4 instruction. Recall that ldr ra, loads the value stored at the address in rb into ra. The #4 at the end instructs the processor to then increment the value in rb by 4. In effect we are walking the array of integers whose starting address is in r0.

Finally, once we add all of the values in the array we have the sum in the register r4. To divide that sum by the length of the array (which was saved off in the floating-point register s1) we load r4 into s0 and perform one last thing: vcvt. vcvt converts between integers and floating-point numbers (which are, after all, an encoding). So s0 gets converted to a floating-point value, as does s1, and then we perform our division with vdiv.

As with r0 being the standard for returning an int from a procedure call, s0 will hold our float value.

We can use this function in our main routine.


Compile with gcc averagemain.c average.s -o averagemain and run.

Closing Thoughts

This post has been a lot of fun to write because assembly is actually fun to write and serves as a reminder that even the highest-level languages get compiled down to instructions that the underlying CPU can execute. One instruction set we didn’t touch on is the store instructions. These are used to save the contents (store) of registers to memory. Perhaps next time.

Once again, all of the code in this post can be found in the armassembly repository on GitHub.


Seriously Good Coffee Doing Serious Good

In the fall of 2018 my CEO and friend David Michel sat down next to me at our corporate Thanksgiving lunch. “Joe, let me show you something,” he said as he pulled out his iPhone. Swiping left and headed for the Photos app he leaned in and exclaimed, “I’m thinking about starting a coffee company.”

I admit that I was confused. “What?” I said, “are you bored here?” “No, no!” he said, and then started to tell me about the story of Hogar Metodista in Costa Rica. Founded by Ray and Lidia Zirkel, the mission of the home is to provide a refuge for Costa Rican children who have been abandoned and need a safe, loving, Christian environment to call their own. The idea behind starting the coffee company was to begin building a sustainable source of income to support that mission.

A week later I e-mailed David writing, “If you need some help, and will have me, I’d love to be a part of this mission.” An hour later he replies, “Just yesterday, I was thinking that I’d love to have you involved.” So involved I became and together with David and others we built Seriously Good Coffee.

Every cent of the net proceeds from every bag (at least $3 per bag) goes to support a Children’s Home in Costa Rica called Hogar Metodista.

There is no one on the Seriously Good Coffee payroll and we work tirelessly to maximize the amount of money that goes to the children’s home. So, if you are interested in not only enjoying a cup of seriously good coffee, but doing some serious good while you’re at it, come visit our Shop page!


Classic Christmas Cheeseball

A holiday classic in these here parts, I give you a Christmas Cheeseball. Yes, you can make this any time of the year, but if you’re counting calories, you may want to make it only during the Christmas season. As I’ve said before, this blog is not going to teach you how to cook, so if you can’t figure out how to turn these ingredients into a cheeseball, well, you need help.

You’re going to need:

  • 2 cups shredded extra sharp cheddar cheese
  • 1/2 pound Velveeta, “shredded”
  • 2 cloves fresh garlic, minced
  • 1 teaspoon Tabasco sauce
  • 1 teaspoon Cajun seasoning
  • 1 teaspoon coarse ground black pepper

The above makes up your cheeseball, and you’re going to roll it in:

  • Chili powder
  • Chopped roasted pecans

In a bowl combine your shredded cheddar cheese and Velveeta. If you’re ever tried to shred Velveeta, well, you know as well as I do that it’s more of a smear, so just treat it like cream cheese. The idea is to combine Velveeta and cheddar cheese together. I prefer extra sharp cheddar, but if you are a wimp (or your guests are) use sharp or mild.

Editor’s note: If you are from foreign lands that have not yet been blessed with Velveeta, look for any locally available processed cheese. For my Uruguayan friends, seek out Claldy Gambú.

Now, add your minced garlic, and don’t be afraid to use minced garlic from a jar or from a tube – the idea is to give this a garlicky kick and the cheeseball doesn’t care if it came from a tube, trust me. Add your Tabasco or whatever insanity sauce you want, along with a “Cajun seasoning”. All of the following are respectable:

Round things out with some black pepper and mold into a ball.

Then, grab your favorite chili powder and dust the ball with it making sure its nicely covered. Chop some roasted pecans and roll your cheeseball in them, taking liberty to “press” the pecans in a bit.

You should end up with something that looks a bit like this:

This is best served a day later (stored in the refrigerator of course), but can be eaten right away.

To serve, lay out a plate of crackers (not saltines, idiot). My favorites are:

  • the venerable Nabisco Sociables
  • the ever popular Club Cracker
  • a plain Triscuit (don’t bother with the flavored Triscuits, they are crap and will just interfere with the cheeseball flavors)
  • Chickin in a Biskit

or just a plain Ritz.



TLS 1.3 with NGINX and Ubuntu 18.04 LTS

OpenSSL 1.1.1 is now available to Ubuntu 18.04 LTS with the release of 18.04.3. This porting of OpenSSL 1.1.1 has opened up the ability to run with TLS 1.3 on your Ubuntu 18.04 LTS NGINX-powered webserver. To add TLS 1.3 support to your existing NGINX installation, first upgrade your Ubuntu 18.04 LTS server to 18.04.3, and then find the ssl_protocols directive for NGINX and add TLSv1.3 at the end:

Restart NGINX with systemctl restart nginx.

It really is as simple as that! If your browser supports TLS 1.3 (and all major browsers do as of November 2019 with the notable exception of Microsoft Edge) it will negotiate to it. As of this writing (November 2019), you would not want to disable TLSv1.2. Odds are you will break tools such as cURL and other HTTPS agents accessing your site. Here’s an example of what that looks like for curl on macOS 10.14.6 (Mojave):

In other words, the stock macOS 10.14.6 curl cannot establish a connection with a webserver running only TLS 1.3.

Enabling 0-RTT

There are a lot of compelling features to TLS 1.3, one of them being 0-RTT for performance gains in establishing a connection to the webserver. NGINX enables TLS 1.3 0-RTT if the configuration parameter ssl_early_data is set to on. If you are using the stock NGINX provided by Ubuntu 18.04 LTS 0-RTT is not supported. Let’s upgrade to the version provided by the NGINX PPA and enable it.

Go back to your NGINX configuration and place the ssl_early_data directive near all of the other ssl_ directives, like this:

Now, all that being said, 0-RTT is not something you will want to enable without careful consideration. The “early” in SSL early data comes from the idea that if the client already has a pre-shared key, it can reuse the key. This is a great post outlining the benefits, and risks, of enabling 0-RTT.


OpenWrt SNMP Interface Descriptions

If you’re familiar with configuring network gear, you know that a very useful best practice is providing “plain English” descriptions of your device’s ports. For example, on my Cisco SF500-48MP switch port 24 is the “uplink port” to the gateway router. I make this clear in the port’s description:

sw01#show interfaces description fa1/2/24
Port      Description
-------   -----------
fa1/2/24  Uplink to Internet Gateway

By doing so, the ifAlias OID for this interface is set:

snmpget -c public -v2c sw01.iachieved.it IF-MIB::ifAlias.24 
IF-MIB::ifAlias.24 = STRING: Uplink to Internet Gateway

What is particularly nice about this is that a network monitoring tool such as Observium will display the ifAlias string as a part of the description of the port. Like I said, this becomes very useful, particularly when trying to track down where ports lead to.

In the previous post we installed SNMP on an OpenWrt router and surfaced it in Observium. By default the snmpd package doesn’t present any information for ifAlias, but we can fix that with snmpset.

Permitting snmpset Access

snmpset will make use of the SNMP private community on our OpenWrt (note: if you were working in a production environment you might consider using SNMP v3 with authentication or at the very least changing your community strings). By default the OpenWrt SNMP configuration only permits use of the private community from localhost (i.e., the router itself). We’ll change that to permit access from our private subnet:

Find this section in your /etc/config/snmpd file

config com2sec private
    option secname rw
    option source localhost
    option community private

and change the option source like this:

option source

Obviously you’ll use the appropriate subnet in your configuration.

Restart snmpd on the router with /etc/init.d/snmpd restart.

Updating ifAlias

To update the appropriate ifAlias entries we need to see the ifDescr list. This can be obtained by walking ifDescr with snmpwalk:

snmpwalk  -c public -v2c gw.gw01.chcgil01.iachieved.it ifDescr
IF-MIB::ifDescr.1 = STRING: lo
IF-MIB::ifDescr.2 = STRING: eth1
IF-MIB::ifDescr.3 = STRING: eth0
IF-MIB::ifDescr.5 = STRING: wlan0
IF-MIB::ifDescr.6 = STRING: wlan1
IF-MIB::ifDescr.7 = STRING: br-lan
IF-MIB::ifDescr.8 = STRING: eth0.1
IF-MIB::ifDescr.9 = STRING: eth1.2
IF-MIB::ifDescr.10 = STRING: eth0.100
IF-MIB::ifDescr.11 = STRING: eth1.3
IF-MIB::ifDescr.12 = STRING: eth1.4

In our Chicago router example let’s label the three interfaces that are OSPF links to other routers:

  • eth1.2 is a link to gw01.dnvrco01
  • eth1.3 is a link to gw01.atlaga01
  • eth1.4 is a link to gw01.dllstx01

From the output of ifDescr we can see that

  • eth1.2 will map to ifAlias.9
  • eth1.3 will map to ifAlias.11
  • eth1.4 will map to ifAlias.12

So let’s set those ifAlias strings!

# snmpset -c private -v2c gw.gw01.chcgil01.iachieved.it ifAlias.9 string "OSPF Link to gw01.dnvrco01"
IF-MIB::ifAlias.9 = STRING: OSPF Link to gw01.dnvrco01
# snmpset -c private -v2c gw.gw01.chcgil01.iachieved.it ifAlias.11 string "OSPF Link to gw01.atlaga01"
IF-MIB::ifAlias.11 = STRING: OSPF Link to gw01.atlaga01
# snmpset -c private -v2c gw.gw01.chcgil01.iachieved.it ifAlias.12 string "OSPF Link to gw01.dllstx01"
IF-MIB::ifAlias.12 = STRING: OSPF Link to gw01.dllstx01

The Catch

The problem with this approach is its persistence – reboot your router and watch those interface descriptions bite the dust. But no worries, the fix is simple.

Go back to /etc/config/snmpd and change your private community to accept interaction from localhost (in other words, what it was originally!):

config com2sec private
    option secname rw
    option source localhost
    option community private

Restart snmpd with /etc/init.d/snmpd restart.

On the router we’re going to edit /etc/rc.local and before exit 0 put:

# Wait for snmpd to accept connections
/bin/sleep 5

/usr/bin/snmpset -c private -v2c localhost ifAlias.9 string "OSPF Link to gw01.dnvrco01" > /tmp/snmpset.log
/usr/bin/snmpset -c private -v2c localhost ifAlias.11 string "OSPF Link to gw01.atlaga01" >> /tmp/snmpset.log
/usr/bin/snmpset -c private -v2c localhost ifAlias.12 string "OSPF Link to gw01.dllstx01" >> /tmp/snmpset.log

I have not optimized the /bin/sleep at this point, but without it snmpset will be talking to an snmpd daemon that isn’t ready. Trust me.

You can now reboot the router and the custom interface descriptions will survive.

Wrapping Up

Why did we go to all the trouble of creating descriptions (aliases) for our OpenWrt interfaces? Again, monitoring tools such as Observium will take those descriptions and apply them to your UI.

At a glance I can quickly see, for example, that eth1.2 is the interface being used for OSPF with gw01.dnvrco01. That information is incredibly useful when working with dozens (or more) links.