I downloaded -0008 from the CVS and after some debugging in the make.sh, I finally got it to Arduino-0008 to compile. Once I had that running, the Programmer2 code compiled without any problems.
So I downloaded it to my Arduino board, breadboarded up another ATMega168 with its own crystal (16MHz) and powered it from my Arduino board. I wired up the LEDs and control lines as documented. Then I gave it a try...
Well the LEDs flashed as expected, but none of the commands would work. The Probe_Device() function was failing to identify the ATMega168. Well, I take that back. On one or two rare occasions (out of dozens), the *p command returned the correct data (which led my thinking towards a signal timing issue - see below). I double checked all of the connections and everything seemed correct. I even put an already programmed chip in my breadboard (with a blink LED program) to confirm that I had the ATMega168 wired up properly and the oscillator was running. It worked fine so I knew my circuit was good.
So next I started digging into the code and put some debugging in the Send_ISP function. I was seeing discrepencies on received data. The echo back of the first byte through MISO when sending the second byte was not matching. The echo back of the second byte when sending the third seemed to be okay. Then I tore into the Atmel datasheet and focused on the serial programming docs. What ended up solving my problem was loosening up the timing of the RESET pin in the SeizeTarget() function. I think the timing was just too quick and the 4 microsecond blip high was not enough to get the chip in program mode. Also the 21ms delay after bringing the RESET line back low is dangerously close to the 20ms minimum recommended by the datasheet. Overall I couldn't see any real reason to no give the RESET transitions lots of time.
Here's the revised SeizeTarget() function that works consistently for me. The timings are probably excessive, but it's only an extra 50ms or so on command start and seems to give consistent results.
static void SeizeTarget()
delay(10); /* Let the RESET line settle low
delay(10); /* "Blip" the RESET line high for 10ms
digitalWrite(RESET,0); /* Bring the RESET line back low
delay(50); /* Wait 50ms before sending command
targetSeized = 1;
So with this change in place, everything is working perfectly. Thanks for developing this code. It allowed me to use some spare parts and a simple circuit to load the bootloader onto blank ATMega168's without having to buy an expensive programmer.