I had messed up one of my circuit boards, and in the debugging process I wanted to eliminate the external crystal as a problem (since there are so few other components in a bare AVR circuit). I looked at the ATmega328 manual, and found that it features an “Internal 128kHz RC Oscillator”, which sounded safe enough. I pulled out my Arduino-based ISP programmer, and set the appropriate fuse to select that clock.
The first thing that I realized after doing this is that 128kHz is 128 times less than 16MHz, so that triple blink that happens when you start up your Arduino, that usually only takes about a second, will take on the order of minutes in this mode. I never had the patience to actually sit and wait this long, but the next option in the Clock Sources list is a “Calibrated Internal RC Oscillator”. I had stayed away from this since I didn’t want to calibrate it, but it seems like you don’t have to calibrate it yourself if you’re willing to tolerate a 10% frequency uncertainty.
So the ATmega went back into the programmer, but then I got a message along the lines of “invalid device signature: 0x000000”. Uh oh. I knew that this was a possibility: for some reason, the ATmega parts use the programmed clock source when in programming mode, instead of defaulting to an internal source, which means that it’s possible to program your ATmega into a mode that it is no longer programmable. I knew of this issue, so made sure to not set it to “external clock” mode, so I was surprised that it was still unprogrammable.
After doing some researching, I learned the problem is there is a maximum programming speed based on the clock speed of the target ATmega, and my Arduino-programmer was exceeding it.
Slowing down the programmer
Ok, time to dive into the ArduinoISP source code. It’s using a lot of registers that I’m not familiar with, but one that looks promising is the “SPCR” register in the spi_init() function. The ArduinoISP sketch uses the hardware SPI support, and SPCR is the SPI Control Register. Looking at the docs, the bottom two bits of this register control the SPI clock speed, which seems promising — but the sketch already has them set to the minimum setting of 1/128 of the cpu clock. I forget the exact minimum ISP clock, but it’s smaller than the target’s cpu clock, and since the two ATmega’s clocks were off by a factor of 128, this wasn’t going to work.
One thing I debated doing was to reduce the clock speed of the programmer ATmega. If I had alternate-frequency crystals, it would have been decently easy to replace that, though I’m not sure what other effects that would have on the system (would probably screw up the baud rate calculation for the serial port). But, alas, I didn’t, so the option would be to reprogram the programmer to use a different clock source, and I wasn’t very confident in my ability to do that.
Instead, I decided to modify the programmer’s firmware. As I mentioned, the ArduinoISO sketch uses the hardware SPI, which was already clocked as slow as it can go, so I’d have to come up with an alternative SPI implementation. Normally, the difficulty in this would be maximizing the potential clockspeed, but in this case that’s not an issue and bit-banging the protocol seemed pretty easy. It probably should have been, but I messed up some of the bit twiddling and I started to run into how much harder it is to debug firmware than it is to debug software running on your primary computer.
Anyway, I was eventually able to get it to work, though the programming was painfully slow (several minutes). If you have the misfortune of getting stuck with a 128kHz ATmega, you can use my modified ArduinoISP code to rescue it.