RPicSim is an open source software library written in Ruby that provides an interface to the MPLAB X PIC simulator and allows you to write simulator-based automated tests of PIC firmware. While RPicSim has been available since early this year, we just released version 1.0.0 and are excited to share why we made it and to encourage people to start using it.
Motivation for RPicSim
The Pololu RC Switch family of products.
In 2013, we developed a new and improved family of RC Switches based on the PIC10F322. Many of our other products have a bootloader that allows the firmware to be upgraded over USB or serial by the end user, but the 512-word flash memory of the PIC10F322 was too small to support upgradeable firmware. This meant we really needed to get the firmware right before releasing it.
Our traditional method of developing firmware usually involves writing the firmware, compiling it, and then loading it onto real hardware and testing it manually while looking at its behavior with an oscilloscope. Some problems with this method are that it is hard to test internal details of the firmware, and it is easy to miss bugs that appear over time in features tested previously.
Test-driven development (TDD) is a different style of development. The main idea of TDD is that before changing the behavior of your code, you should first create or change a test for it in an automated test suite and make sure that the test fails. By maintaining and running the test suite frequently during development, you help ensure that the code will keep working and that new changes will not break the old features.
Test-driven development works well with unit testing, which is the practice of testing a small piece of code in isolation from the other code in the application. This allows you to build a large system out of several smaller components and test each component separately, as you are writing it.
These testing techniques are very popular in the Ruby community, and we have been using them for our website and some of our internal systems for many years. This type of testing is not a replacement for careful planning and code reviews, but we think it helps us write and maintain high-quality software. That’s why we decided to start applying it to our embedded firmware development, starting with the new RC switches. By the way, this isn’t a new idea; there is at least one book about it.
We ended up writing about 300 different test cases for the RC switch firmware (itself a ~1000-line assembly language program). As a concrete example, here is a test that ensures that abnormally long pulses on the RC input are rejected:
it 'rejects a 2577 microsecond pulse (just too long)' do pulse 2577 run_us 100 expect(pulseWidth.value).to be_within(4).of(2577*16) expect(goodPulsesNeeded.value).to eq 3 end
Rather than using real hardware, the tests all work by interacting with a simulated microcontroller. In January 2014, after releasing the RC switches, we released the simulator-integration code as a Ruby library named RPicSim. Later on, we used RPicSim to help develop the proprietary bootloader on the P-Star 25K50 Micro.
Capabilities of RPicSim
RPicSim allows you to run simulations of PIC microcontroller firmware and see exactly what is happening inside the simulated device. You can see the stack pointer, the program counter, and the contents of all RAM registers and SFRs. All the real work of simulating the firmware is done by the MPLAB X simulator, which is written by Microchip and used in the MPLAB X IDE. RPicSim simply provides an easy way for you to access the simulator from Ruby code outside of MPLAB X.
RPicSim can simulate input signals to your device deterministically. Do you think a bug will happen when the RA0 pin sees a rising edge if the program counter is at address 0x004? If so, you can add a test for that exact situation.
To support unit testing, RPicSim has features for putting the simulated device into a particular state and then running it until specific conditions are met. For example, you can jump directly to a subroutine, set its input parameters to known values, run the subroutine, and then test the resulting state of the device to make sure that all the desired effects happened. It is impractical to set up a way to run this kind of test on actual hardware, but with a simulator it is usually straightforward.
RPicSim works well with RSpec, a testing framework that helps you write, describe, and organize your tests. That’s what we use for most our automated testing, including the example I showed earlier.
To learn more, see the RPicSim documentation.
Why we chose Ruby
Some people might wonder why we chose the Ruby language for RPicSim, since it is not a language typically associated with embedded development. One reason is that we needed a language that can run on the Java Virtual Machine (JVM), since the MPLAB X simulator is written in Java. Also, Ruby is an interpreted language, so you won’t have to worry about recompiling your RPicSim tests every time they change. In general, we think Ruby is a great, versatile programming language and it is a pleasure to work in. There is a lot of information online about Ruby, and many questions about it are answered within minutes on Stack Overflow. No special IDE is required for Ruby development; you can use your favorite text editor and terminal.
We think that there are many situations where hobbyists and embedded firmware engineers would benefit from using test-driven development tools such as RPicSim. We have been using it for our products and we would encourage anyone doing serious PIC firmware development to try it out.