AVR Programming

Jul 29, 2013 @ 10:41pm

To control the servos on the submarine I am using an AVR (ATtiny24a). Besides controlling the servos the AVR is also acting as a secondary thermometer, reading the the battery voltage, and interfacing with the pressure sensor. It then forwards all of this over SPI to the Raspberry Pi.

The AVR communicates with the host (the Raspberry Pi) through SPI. The protocol over SPI is a simple packetized protocol that repeats the same packets over and over. The packets start with a short magic sequence (used mostly for finding packets during initialization) and ends with a CRC checksum. It also includes a packet counter and ACK from the AVR, allowing the raspberry pi to verify it's reading the data (and during a failure reset the AVR).

The AVR does have two PWM outputs, but it's not enough outputs. Because of this I am using the 16-bit and 8-bit timers together to generate all 4 servo outputs. The RC Servo signals are also based on a specific pulse width, not just a duty cycle.

This turns out to work just fine, according to my oscilloscope I'm able to get pulses below 1ms and above 2ms as well as everything in between (which is what the RC servos are designed for). There is a tiny amount of jitter in the signal, but it doesn't look like it's enough to cause any problems. You can see the jitter in the video below.

Battery Voltage Readout
The ATtiny24A has an A/D converter, the Raspberry Pi does not, so I chose to use the AVR as the A/D converter to read out the battery voltage. This turned out to be fairly straightforward, just configure it, wait for the interrupt, and read the data and configure the next measurement, and it's the same code to read the internal temperature sensor. Both of these don't have much of a reference and will require calibration to figure out the actual voltages and temperatures.

Pressure Sensor
The pressure sensor chosen for this is a MS5535C, it's an absolute pressure sensor, rated all the way up to 14 bar (which should be enough to get valid readings past 400ft), and being an absolute pressure sensor should be unaffected by internal air pressure that the sub might experience (from cooling or heating of the internal air and compression of the hull). The protocol is well documented though odd, the data lines switch between synchronous serial and an asynchronous interrupt line, requiring code to stop the clock during measurements. The only major problems I had were the ROM could be read easily but measurements locked the protocol. After testing it just started working and I figured it was a loose wire that was fixed by touching it (I believe the clock wire was loose, I had to solder a pullup resistor to the master clock line as I forgot it in the original design). If anyone needs code to read this I have it implemented in the code below.

With the AVR appearing to be working, I'm ready for the initial source code drop while I figure out how to make my git database public. It should be pretty obvious where things are, but the code is mostly in sub-code-0.01a/code/rpi/rpi-sync/ with the AVR portion is in tiny/ and contains working code for everything mentioned above. I've also included the Raspberry Pi portion of the code, if nothing else works, the SPI module does work, and demonstrates communicating with the AVR as well as fault detection. Known bugs currently are that the SPI module seems to be detecting quite a few packet drops, but the packet IDs are all the same so I don't think they are real packet drops. Also it appears that after flashing the AVR an extra reset is required to make SPI work, I suspect this is caused by a clock pulse generated by the raspberry pi when setting up SPI, but I have not been able to track it down and resetting it after the packets fail to arrive appears to work just fine.

Actual code is in sub-code-0.01a/code/rpi/rpi-sync/tiny/ for the AVR portion and sub-code-0.01a/code/rpi/rpi-sync/controller/ for the Raspberry Pi portion. I've only confirmed the Makefiles in those two directories work.



Email (For new comment notifications, optional):
What is 1 + 8 minus one?