Raspberry Pico: Unit Test Framework for Your Projects

The Raspberry Pico is a new microcontroller launched in February 2021. The community was excited about this new board, and several people started amazing projects. I grabbed two boards early on, and while still working on my Arduino based robot, did the usual blinking led and potentiometer tutorials.

The Pico captured me, I wanted more than just run demos. So, I decided to start library development for a shift register and a temperature sensor. When developing a library, I want to have tests for several reasons. First, I like to use TDD and start with writing a test that will cover a n new feature before its implementation. Second, once you have a substantial test suite, it helps you to keep the library in a working shape when you refactor its code base.

In this article, I will show how to install and use the unit testing framework cmocka. We will see the basic boilerplate code and an example for testing a Raspberry Pico program.

This article originally appeared at my blog.

Installation

Grab the CMocka source from the official cmocka mirror. Then, extract the tar, compile and install. The steps in a nutshell:

The make step should show this output:

If all goes well, you can install the compiled libraries in your system.

The files will be installed at /usr/local/lib.

Unit Test Example

Let’s write a very basic unit test example.

The important things here:

  • Always include all four libraries: <stdarg.h>, <stddef.h>, <setjmp.h>, <cmocka.h>
  • Define test cases as functions that receive an argument void** state
  • The test functions include different type of assert statements, shown here is assert_int_equal see the official documentation for the full list of asserts.
  • In the main function, add all defined test functions to the struct CMUnitTest tests[]

Running Tests

To invoke that test on the CLI, you will need to add CMocka installation path to the environment variable export LD_LIBRARY_PATH.

Then, run your compiler and link to the CMocka library. I’m using clang in the following example.

Finally, you can run the test, and see formatted output that shows which tests were successful.

Testing a Pico Program

Now that we have setup the testing framework, let’s use it to write tests for our Pico programs. At the time of writing this article, I was developing a library for working with shift registers. The library exposes a struct object that defines the pin layout, and several functions for setting bits or a bitmask to the shift register. I will not cover the entire library, but just highlight two test cases that show the essential how-to. Go to Github to see the entire rp2040-shift-register-74HC595 library.

ShiftRegister Struct: Definition and Testing

The shift register is controlled by three input pins:

  • Serial (SER): Set a single bit, low or high
  • Serial Clock (SRCLK): Send a clock signal that will write the active SER bit to the shift register
  • Register Clock (RCLK): Send a clock signal to copy the contents of the shift register into the storage register

These pins are defined in the following struct object.

The first test is about initializing a shift register and see that it’s defined pined are correctly defined inside the struct. We will use the familiar assert_int_equal test.

Running the tests gives this output:

Writing a single bit

The most basic function is to write a single bit into the shift register. To keep track of this, the register object holds two state variables: The serial_pin_state and the shift_register_state. If a new bit is written with the write_bit function, the state will be updated accordingly.

To implement this, we first add the state variables to the ShiftRegister.

Then, we implement the write_bit function. This function sets the serial_pin_state to the given bit. If this bit is a 1, shift_register_state will shift right and add a 1, if the bit is a 0, it will just shift right.

For testing, we will write two bits: 1 followed by 0. After each step, we test the pin_state is set correctly. Finally, we test that the resulting bitmask is correct. To receive the bitmask representation of the shift register, the method print_shift_register is called, and its compared to a string object. The test method uses assert_memory_equal, a convenient test method to test that any types are equal.

All tests are passed:

Conclusion

This article introduced the CMocka unit testing framework for C programs. I showed how to compile, install and use it. Then, two examples were shown. The first example showed the necessary boilerplate code that you need to run a CMocka test. The 2nd example showed how to use CMocka for testing Pico code, but with a grain of salt: At the time of writing, I had no experience how to test that the hardware signals were transmitted from the Pico. In a future article about library design, I will cover this issue and detail how to test both the library function “as-is” and the hardware side. In my opinion, unit-testing helps you to write better code: By writing a test before the implementation, you structure the feature upfront, and when you have a substantial test suite, you can better maintain and refactor your code.

IT Project Manager & Developer