Although there are plenty of unit test frameworks that support C, I'm a little stumped on how to write unit tests for micro controller code (PIC in my case, but I think the question is more general than that).
Much of the code written for micro controllers revolves around Writing configuration and data values to registers, reading incoming data from registers and responding to interrupt events. I'm wondering if anyone can provide some pointers on the most effective way to this.
Write mock versions of your register access functions/macros. Note that this assumes that your code uses a common set of register access functions, and not ad-hoc stuff like
*(volatile int*)0xDEADBEEF = 0xBADF00D
everywhere.Call your interrupt handlers directly from your test code (may be problematic on some architectures¹), a "software interrupt" if available, or from a timer interrupt handler if you need them to execute asynchronously. This may require wrapping your interrupt enable/disable code in functions/macros that you can mock up.
¹ 8051 comes to mind: at least with the Keil 8051 compiler, you can't call interrupt functions directly. This could be worked out with the C preprocessor though.
Is there perhaps any kind of loopback mode so that you can use the controller itself to generate events that you can test against?
You write;
"Much of the code written for micro controllers revolves around Writing configuration and data values to registers, reading incoming data from registers and responding to interrupt events".
I agree that this is often the case in practice, but I don't actually think this is a good thing, and I think rethinking things a little will help you with your test goals.
Perhaps because microcontroller programmers can reach out and touch the hardware any time they like, many (most?) of them have got into the habit of doing just that, throughout their code. Often this habit is followed unquestioningly, maybe because so many people doing this sort of work are EEs not computer scientists by training and inclination. I know, I started out that way myself.
The point I am trying to make, is that microcontroller projects can and should be well designed like any other software project. A really important part of good design is to restrict the hardware access to hardware drivers! Partition off all the code that writes registers, responds to interrupts etc. into modules that provide the rest of your software with nice, clean, abstracted access to the hardware. Test those driver modules on the target using logic analyzers, oscilloscopes, custom test rigs or whatever else makes sense.
A really important point is that now the rest of your software, hopefully the great majority of it, is now just C code that you can run and test on a host system. On the host system the hardware modules are stubbed out in a way that provides visibility into what the code under test is doing. You can use mainstream unit testing approaches on this code. This needs some preparations and work, but if you are well organized you can create a reusable system that can apply to all your projects. The potential benefits are enormous. I wrote a little more about these ideas here;
[http://discuss.joelonsoftware.com/default.asp?joel.3.530964.12][1]
One approach to this might be to use an emulator. I've been working on an AVR emulator and one of the ideas for using it is indeed to unit test code. The emulator implements the CPU and registers, interrupts and various peripherals, and (in my case) bytes written to the emulated UART go to the regular
stdout
of the emulator. In this way, unit test code can run in the emulator and write its test results to the console.Of course, one must also ensure that the emulator is correctly implementing the behaviour of the real CPU, otherwise the unit tests on top of that can't be trusted.