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.
9 responses to “Rescuing a mis-programmed ATmega328”
You’re a genius. I just saved an atmega328P chip.
Thanks from Italy 🙂
I tried to run your code to reprogram my ATmega328P that is 128Khz but I can not reprogram. Is there something particular to address in addition to your program?
Hmm not that I know of; one thing to verify is that you can get the unmodified ArduinoISP sketch to program a normal-speed ATmega, and if that works you can try using the modified sketch, again on the normal-speed ATmega (I think it should work fine despite being slow).
If those both work but it doesn’t work when you put in the 128KHz ATmega, then there might be something else wrong with that chip; if the first one works but not the second I’d be interested to hear about it because it would be an issue with my sketch!
Thank you for your quick response. I have tried to program a ATmega328P that works with the sketch “ArduinoISP” home to check if everything was working properly. Then I loaded your sketch and always tried to program the correct circuit and it does not work, I get the following message:
avrdude: stk500_getsync (): not in sync: resp = 0x00
Is what I need to change a speed somewhere?
Thank you in advance for your help.
I have done tests:
I took a functional Atmega328 external oscillator mode and I tried to program it with your sketch ArduinoISP (slow) at different frequencies with a signal generator TTL: 16MHz – 8Mhz – 4MHz – 2MHz – 1Mhz – 500kHz – 250kHz – 128khz – 64kHz – 32kHz – 16khz – 8khz – 4khz – 2kHz and 1kHz, no possible programming all these frequencies … Whereas with the Arduino sketch unmodified I can program 16MHz to 500Khz (then off-hook).
Is this not the Arduino IDE that sending bits too quickly ?
Is there a file to edit at the Arduino directory ?
Thank you in advance.
Ah sorry, just noticed — I had set the baud rate in the sketch to 57600, which is higher than the Arduino IDE will set it to (I think it uses 19200). I think there’s some way to convince the IDE to use a different baud rate, though maybe the easiest way to test this hypothesis is to just change the “Serial.begin” line in the sketch back to 19200 and see if that works. Sorry about that!
You do not have to be sorry, you’re awesome (;-)
I just take the test at 9600 and it works. Finally just enough to get my fuses good value because at the end the program ended badly and I get an error:
avrdude: verification error, first mismatch at byte 0x0000
0x0c != 0xff
avrdude: verification error; content mismatch
but it does not matter, the main thing is to be able to get my Atmega328.
thank you again.
Sorry, not 9600 but 19200
Here is the magic:
Run this line at windows (ms-dos) command prompt.
avrdude -c usbasp -p m328p -U lfuse:w:0xFF:m -B250
This line will set back the fuses to use crystal oscilator again.
That´s it ! 😉
Of course, you must have a USBASP programmer.