Following on from yesterday's post about developing code which uses the memory-mapped IO on the Raspberry Pi, but on a separate development system which does not have the same hardware, I began to think about the steps needed for testing such code.
The first stage is unit-level testing. As much of the code as possible should be tested independently of the hardware access. At this level a lot can be tested by just checking that the right primitives are called, but there comes a point where we need to check that the primitives are having the intended effects.
A little bit can be done, still at the "virtual" level, by using the imaginary memory approach on the development system. Test code can be written to ensure that the correct values are written to and read from the correct memory addresses. But that's about as far as we can go with virtual testing. After that we need to test on the real hardware. This serves the vital purpose of validating all the little assumptions which went in to the code. After all, there's no particular reason that writing a value to a memory location should have any particular external effect, except that that is how the hardware has been built.
If a piece of code is supposed to raise or lower a GPIO pin, or send some data over SPA, I2C or a UART, we need to check that it actually does it.
This, however is where testing begins to get tricky. The pins on the Raspberry Pi are just that, pins. They have no way on their own of reporting their status, and we have already gone as far as we can with simulations. So we need something external to test whether the code works. Off the top of my head there are several possibilities for this:
- Simple GPIO outputs can be tested with a multimeter, but it can be clumsy getting the probes on the right pins, and can only deal with very slow tests.
- Testing faster moving data on one pin at a time could perhaps be done with an oscilloscope
- All the GPIO outputs can be observed all at once with a row of LEDs and resistors, but deciding what patterns to send, and verifying that the result is right might be mildly tricky
- I could perhaps make some other custom hardware to check some or all of the pins, but how would I know that I had built that correctly!
- A logic analyser can monitor a few pins at once and keep track of how and when they change. This might make checking both the GPIO and serial pins possible
- Inputs could be tested by attaching push-buttons
- And so on.
The main problem with all these options is that they are "manual" tests. The hardware and equipment may help out (in the case of the logic analyser, help out a lot), but whether things have succeeded or failed is ultimately determined by someone looking at the output.
In the rest of my software development efforts I try as much as possible to automate tests. Automating tests makes them much easier (and usually quicker) to run, which in turn means that they gut run more often, and can be vigilant enough to catch unexpected regressions in old code. It would be great to be able to do this with hardware.
To do that, however, I would need some sort of system to monitor all the pins, comparing against the expected outputs and supplying the expected inputs. I was wondering where I might get or build such a device when I suddenly realized that I have one right here. Perhaps the best way to test the IO of a Raspberry Pi, is with another Raspberry Pi!
There must be a way of connecting the pins of two Pis together, a kind of "cross-over" cable which makes sure that all inputs go to outputs and vice versa. Given that the GPIO pins are switch-able, it might be that this "cable" also need some sort of buffering, to prevent problems if (for example) two outputs are connected together by mistake. I'm sure this is do-able, though.
I wonder if anyone has tried this already? If you have, or you know someone who has, please let me know!