Adventures with an ATmega

As part of some university coursework, I’ve recently been playing around with an Atmel 8-bit microcontroller in a quest to build a data logger for home brewing. The aim is to log various sensor readings over the course of primary fermentation of a batch of beer to see how it’s progressing without having to disturb the brew.

While working with hardware is fun, it has the downside that you’re working with hardware. Things break as much as they do in software, but are harder to debug. A nice solution to this is to use a simulator to test the software, rather than using the hardware itself. I’ve been using the simavr simulator. It’s got all the right features, but more importantly its code is easy to understand and extend. In fact, most of the simulator is written as a library which one can build a simulated circuit board around.

I’ve built simulations of several of the components used in the brewing logger now, including an SD card and a flash memory. The code isn’t brilliant, but they’re working well enough to get my firmware booting. Hopefully they might be useful to other people too — hence the code is on gitorious. The SD card simulator is for a generic SDv2 card. The flash memory is for an ST M25P16 (but should support any of the M25P family, with a little work). The serial LCD is for a custom LCD daughter board provided by my university, so that’s probably not so useful. The RHT03 temperature/humidity sensor is general purpose; as is the DS3231 real-time clock.

Put together, and with a little extra work, these will allow closed loop testing of the microcontroller firmware — without ever having to go near the hardware itself. Bliss. (This is all under the misguided assumption that the simulations are sound and complete, but they’ll get there eventually.)

As an example of how easy simavr makes this, take a look at the code needed to instantiate and hook up the humidity sensor simulation:

/* Create the sensor. */
rht03_t rht03;
rht03_init (avr, &rht03);

/* Connect its bidirectional data pin to pin D3 on the microcontroller. */
avr_connect_irq (avr_io_getirq (avr, AVR_IOCTL_IOPORT_GETIRQ ('D'), 3), rht03.irq + IRQ_RHT03_DATA);
avr_connect_irq (rht03.irq + IRQ_RHT03_DATA, avr_io_getirq (avr, AVR_IOCTL_IOPORT_GETIRQ ('D'), 3));