├── README.md └── attiny-hvsp-programmer.ino /README.md: -------------------------------------------------------------------------------- 1 | # AVR High-voltage Serial Fuse Reprogrammer with Chip Erase function 2 | 3 | Check out the full story behind this: [Removing a curse from ATtiny85 Fuses](https://blog.wokwi.com/removing-a-curse-from-attiny85-fuses). 4 | 5 | If you want to make your own, take a look at [the wiring tutorial](https://www.hackster.io/sbinder/attiny85-powered-high-voltage-avr-programmer-3324e1). 6 | 7 | ## Compiling 8 | 9 | To compile and flash this code, first install [Arduino ATtiny core](https://github.com/damellis/attiny). 10 | 11 | ## License 12 | 13 | License: GPL 3+ 14 | 15 | -------------------------------------------------------------------------------- /attiny-hvsp-programmer.ino: -------------------------------------------------------------------------------- 1 | // AVR High-voltage Serial Fuse Reprogrammer with Chip Erase function 2 | // 3 | // Modified by Uri Shaked to add the Chip Erase function: 4 | // https://blog.wokwi.com/removing-a-curse-from-attiny85-fuses 5 | // 6 | // Code taken from the following tutorial, under GPL 3+ license: 7 | // https://www.hackster.io/sbinder/attiny85-powered-high-voltage-avr-programmer-3324e1 8 | // Adapted from code and design by Paul Willoughby 03/20/2010 9 | // http://www.rickety.us/2010/03/arduino-avr-high-voltage-serial-programmer/ 10 | // and Wayne Holder 11 | // https://sites.google.com/site/wayneholder/attiny-fuse-reset 12 | // 13 | // Fuse Calc: 14 | // http://www.engbedded.com/fusecalc/ 15 | 16 | #define LED 3 // Status indicator LED 17 | #define RST 4 // (13) Output to level shifter for !RESET from transistor 18 | #define SCI 3 // (12) Target Clock Input 19 | #define SDO 2 // (11) Target Data Output 20 | #define SII 1 // (10) Target Instruction Input 21 | #define SDI 0 // ( 9) Target Data Input 22 | 23 | #define HFUSE 0x747C 24 | #define LFUSE 0x646C 25 | #define EFUSE 0x666E 26 | 27 | // ATTiny series signatures 28 | #define ATTINY13 0x9007 // L: 0x6A, H: 0xFF 8 pin 29 | #define ATTINY24 0x910B // L: 0x62, H: 0xDF, E: 0xFF 14 pin 30 | #define ATTINY25 0x9108 // L: 0x62, H: 0xDF, E: 0xFF 8 pin 31 | #define ATTINY44 0x9207 // L: 0x62, H: 0xDF, E: 0xFFF 14 pin 32 | #define ATTINY45 0x9206 // L: 0x62, H: 0xDF, E: 0xFF 8 pin 33 | #define ATTINY84 0x930C // L: 0x62, H: 0xDF, E: 0xFFF 14 pin 34 | #define ATTINY85 0x930B // L: 0x62, H: 0xDF, E: 0xFF 8 pin 35 | 36 | int error = 0; 37 | byte FuseH = 0; 38 | byte FuseL = 0; 39 | byte FuseX = 0; 40 | 41 | void setup() { 42 | pinMode(RST, OUTPUT); 43 | digitalWrite(RST, HIGH); // Level shifter is inverting, this shuts off 12V 44 | pinMode(SDI, OUTPUT); 45 | pinMode(SII, OUTPUT); 46 | pinMode(SCI, OUTPUT); 47 | pinMode(SDO, OUTPUT); // Configured as input when in programming mode 48 | 49 | digitalWrite(SDI, LOW); 50 | digitalWrite(SII, LOW); 51 | digitalWrite(SDO, LOW); 52 | 53 | delayMicroseconds(30); // wait long enough for target chip to see rising edge 54 | digitalWrite(RST, LOW); // 12v On 55 | delayMicroseconds(10); 56 | pinMode(SDO, INPUT); // Set SDO to input 57 | delayMicroseconds(300); 58 | unsigned int sig = readSignature(); 59 | 60 | if (sig == ATTINY13) { 61 | chipErase(); 62 | writeFuse(LFUSE, 0x6A); 63 | writeFuse(HFUSE, 0xFF); 64 | readFuses(); // check to make sure fuses were set properly 65 | if (FuseL != 0x6A || FuseH != 0xFF) { 66 | error = 5; // fast flash if fuses don't match expected 67 | } 68 | } else if (sig == ATTINY24 || sig == ATTINY44 || sig == ATTINY84 || 69 | sig == ATTINY25 || sig == ATTINY45 || sig == ATTINY85) { 70 | chipErase(); 71 | writeFuse(LFUSE, 0x62); 72 | writeFuse(HFUSE, 0xDF); 73 | writeFuse(EFUSE, 0xFF); 74 | readFuses(); // check to make sure fuses were set properly 75 | if (FuseL != 0x62 || FuseH != 0xDF || FuseX != 0xFF) { 76 | error = 5; // fast flash if fuses don't match expected 77 | } 78 | } else { 79 | error = 1; // slow flash if device signature is invalid 80 | } 81 | 82 | digitalWrite(SCI, LOW); 83 | digitalWrite(RST, HIGH); // 12v Off 84 | digitalWrite(LED, LOW); // LED off for succerss 85 | } 86 | 87 | void loop() { 88 | // Flash LED if there was an error 89 | while (error > 0) { 90 | int d = 500 / error; 91 | digitalWrite(LED, HIGH); 92 | delay(d); 93 | digitalWrite(LED, LOW); 94 | delay(d); 95 | } 96 | } 97 | 98 | byte shiftOut (byte val1, byte val2) { 99 | int inBits = 0; 100 | //Wait until SDO goes high 101 | while (!digitalRead(SDO)) 102 | ; 103 | unsigned int dout = (unsigned int) val1 << 2; 104 | unsigned int iout = (unsigned int) val2 << 2; 105 | for (int ii = 10; ii >= 0; ii--) { 106 | digitalWrite(SDI, !!(dout & (1 << ii))); 107 | digitalWrite(SII, !!(iout & (1 << ii))); 108 | inBits <<= 1; 109 | inBits |= digitalRead(SDO); 110 | digitalWrite(SCI, HIGH); 111 | digitalWrite(SCI, LOW); 112 | } 113 | return inBits >> 2; 114 | } 115 | 116 | void writeFuse (unsigned int fuse, byte val) { 117 | shiftOut(0x40, 0x4C); 118 | shiftOut( val, 0x2C); 119 | 120 | shiftOut(0x00, (byte) (fuse >> 8)); 121 | shiftOut(0x00, (byte) fuse); 122 | } 123 | 124 | void readFuses () { 125 | shiftOut(0x04, 0x4C); // LFuse 126 | shiftOut(0x00, 0x68); 127 | FuseL = shiftOut(0x00, 0x6C); 128 | 129 | shiftOut(0x04, 0x4C); // HFuse 130 | shiftOut(0x00, 0x7A); 131 | FuseH = shiftOut(0x00, 0x7E); 132 | 133 | shiftOut(0x04, 0x4C); // EFuse 134 | shiftOut(0x00, 0x6A); 135 | FuseX = shiftOut(0x00, 0x6E); 136 | } 137 | 138 | unsigned int readSignature () { 139 | unsigned int sig = 0; 140 | byte val; 141 | for (int ii = 1; ii < 3; ii++) { 142 | shiftOut(0x08, 0x4C); 143 | shiftOut( ii, 0x0C); 144 | shiftOut(0x00, 0x68); 145 | val = shiftOut(0x00, 0x6C); 146 | sig = (sig << 8) + val; 147 | } 148 | return sig; 149 | } 150 | 151 | // See table 20-16 in the datasheet 152 | void chipErase () { 153 | shiftOut(0b10000000, 0b01001100); 154 | shiftOut(0b00000000, 0b01100100); 155 | shiftOut(0b00000000, 0b01101100); 156 | } 157 | --------------------------------------------------------------------------------