Programujeme jednočipy/VnParProg c code
- include <avr/io.h>
/* * Atmega8 reset * Resets the fuses of a blocked atmega8 MCU using high-voltage parallel programming. * This operation enables standard serial programming, which uses the internal oscillator. * * Needs two MCUs: the doctor (with default fuses) using this firmware * the patient, which has wrong fuses * (for example RSTDSBL set and/or wrong clock source) * * This program is published under GFDL, being a part of the * http://cs.wikibooks.org/w/index.php?title=Programujeme_jednočipy * textbook. See this textbook for electrical schematic and usage. * Written by Filip Dominec, 2009 */ // Pins definition to comply with dsheet // following pins shall be connected 1:1 from doctor to patient #define DATA0 _BV(PB0) #define DATA1 _BV(PB1) #define DATA2 _BV(PB2) #define DATA3 _BV(PB3) #define DATA4 _BV(PB4) #define DATA5 _BV(PB5) #define XTAL1 _BV(PB6) #define DATA6 _BV(PC0) #define DATA7 _BV(PC1) #define BS2 _BV(PC2) #define RDY _BV(PD1) #define OE _BV(PD2) #define WR _BV(PD3) #define BS1 _BV(PD4) #define XA0 _BV(PD5) #define XA1 _BV(PD6) #define PAGEL _BV(PD7) // following pin turns the patient on and connects +12 V to its RESET pin // use a simple circuit with two transistors (PNP/NPN) to switch this high voltage #define RESET _BV(PC3) void delay(unsigned int num) { unsigned int i,j; for (j = 0; j < 1000; j++) for (i = 0; i < num; i++) ; } void blinkall() { PORTB |= (XTAL1 | DATA0 | DATA1 | DATA2 | DATA3 | DATA4 | DATA5); PORTC |= (DATA6 | DATA7 | BS2 | RESET); PORTD |= (RDY | OE | WR | BS1 | XA0 | XA1 | PAGEL); delay(100); PORTB &= 255^(XTAL1 | DATA0 | DATA1 | DATA2 | DATA3 | DATA4 | DATA5); PORTC &= 255^(DATA6 | DATA7 | BS2 | RESET); PORTD &= 255^(RDY | OE | WR | BS1 | XA0 | XA1 | PAGEL); delay(100); // FIXME: PC0 = 0, //while (1) { blinkall(); } } void initialize_pins() { // DDR = "Data Direction Register" (note that RDY is input) DDRB = (XTAL1 | DATA0 | DATA1 | DATA2 | DATA3 | DATA4 | DATA5); DDRC = (DATA6 | DATA7 | BS2 | RESET); DDRD = ( OE | WR | BS1 | XA0 | XA1 | PAGEL); // initialize the outputs PORTB = (0); PORTC = (0); PORTD = (OE | WR); // PAGEL, XA1, XA0, BS1 must be down, but OE, WR are inverted delay(200); // reset the patient PORTC |= (RESET); delay(20); //PORTD = (PAGEL | XA1 | XA0 | BS1); WTF? } void chip_erase() { // set command mode PORTD &= ~(XA0); PORTD |= (XA1); PORTD &= ~(BS1); // set data to "1000 0000" PORTB &= ~(DATA0 | DATA1 | DATA2 | DATA3 | DATA4 | DATA5); PORTC &= ~(DATA6); PORTC |= (DATA7); // XTAL1 strobe delay(20); PORTB |= (XTAL1); delay(10); PORTB &= ~(XTAL1); delay(20); // WR strobe delay(20); PORTD &= ~(WR); delay(10); PORTD |= (WR); // wait until ready while ((PIND & RDY) == 0) {}; delay(20); } void lfuse_erase() { // set command mode PORTD &= ~(XA0); PORTD |= (XA1); // set BS1,2 = 0 (?) PORTC &= ~(BS2); PORTD &= ~(BS1); // "fuse erase" command = set DATA7-0 to "01000000b" PORTB &= ~(DATA0 | DATA1 | DATA2 | DATA3 | DATA4 | DATA5); PORTC &= ~(DATA6 | DATA7); PORTC |= (DATA6); // XTAL1 strobe delay(20); PORTB |= (XTAL1); delay(10); PORTB &= ~(XTAL1); delay(20); // set data mode PORTD &= ~(XA1); PORTD |= (XA0); // Load Data Low byte. Bit n = “0” programs and bit n = “1” erases the Fuse bit. // Default value: lfuse = 0xE1 PORTB &= ~(DATA1 | DATA2 | DATA3 | DATA4); PORTC &= ~(0); PORTB |= (DATA0 | DATA5); PORTC |= (DATA6 | DATA7); // XTAL1 strobe delay(20); PORTB |= (XTAL1); delay(10); PORTB &= ~(XTAL1); delay(20); // set BS1 and BS2 to “0” for lfuse PORTC &= ~(BS2); PORTD &= ~(BS1); // WR strobe delay(20); PORTD &= ~(WR); delay(10); PORTD |= (WR); delay(20); } void hfuse_erase() { // set command mode PORTD &= ~(XA0); PORTD |= (XA1); // set BS1,2 = 0 (?) PORTC &= ~(BS2); PORTD &= ~(BS1); // "fuse erase" command = set DATA7-0 to "01000000b" PORTB &= ~(DATA0 | DATA1 | DATA2 | DATA3 | DATA4 | DATA5); PORTC &= ~(DATA6 | DATA7); PORTC |= (DATA6); // XTAL1 strobe delay(20); PORTB |= (XTAL1); delay(10); PORTB &= ~(XTAL1); delay(20); // set data mode PORTD &= ~(XA1); PORTD |= (XA0); // Load Data high byte. Bit n = “0” programs and bit n = “1” erases the Fuse bit. // Default value: hfuse = 0xd9 PORTB |= (DATA0 | DATA3 | DATA4); PORTC |= (DATA7); PORTB &= ~(DATA1 | DATA2 | DATA5); PORTC &= ~(DATA6); // XTAL1 strobe delay(20); PORTB |= (XTAL1); delay(10); PORTB &= ~(XTAL1); delay(20); // set BS1 to “1” and BS2 to “0” for hfuse PORTC &= ~(BS2); PORTD |= (BS1); // WR strobe delay(20); PORTD &= ~(WR); delay(10); PORTD |= (WR); delay(20); } int main (void) { initialize_pins(); // note: now it would be time to perform "chip erase" command, if it was locked // chip_erase(); hfuse_erase(); lfuse_erase(); // wait until ready, then turn off RESET while ((PIND & RDY) == 0) {}; delay(500); PORTC &= ~(RESET); return 0; }
Tento program (atmega8-fuse-repair.c) zkompilujeme klasickým postupem a nahrajeme jej do zdravé Atmegy8, aniž bychom měnili výchozí nastavení pojistek: