Monday 9 March 2020

ATtiny85 Powered High Voltage AVR Programmer



ATtiny85 Powered High Voltage AVR Programmer
This very simple and inexpensive circuit will reset the fuses on a bricked ATtiny chip. Once programmed, no Arduino is required!



Story

This simple and inexpensive high voltage AVR programmer for ATtiny chips requires only an ATtiny85 and a few components to build. Using Wayne Holder’s excellent ATtiny Fuse Reset posts as a starting point, this little device is able to reset the fuses on many ATtiny devices. With the correct (8-pin or 14-pin) wiring, it should be able to reset ATtiny13, 24, 25, 44, 45, 84, and 85 chips.
The fuse reset process requires a 12v reset signal and 5v to power the chip being reset. Wayne’s projects use a 5v power source, and either a separate 12v battery or an Arduino powered charge pump as the 12v source. To keep things simple, this project starts with a 12v power source and uses a 5v voltage regulator to provide 5v to power the ATtiny chips.

Using the Programmer

Hold the momentary switch down for a second or so. In most cases, the LED will light up very briefly (programming mode) and then turn off to indicate the reset has completed successfully.
Error Indications
If the LED stays on or begins flashing slowly, this indicates that the programmer could not read the signature of the target chip. Check the connections, and make sure both chips are plugged in completely and in the correct orientation.
If the LED flashes quickly, this indicates that the fuse reset failed – the programmer recognized the device signature and attempted to reset the fuses, but the fuse values read from the device after the reset were not as expected. In my experience, this is pretty rare.

How to Make

The circuit is so simple that it can be breadboarded in a matter of minutes. You’ll need to use an Arduino (Arduino as AVR) to load the sketch into the master ATtiny85. This must be done only once; the master chip can then be used to reset the fuses on an unlimited number of target devices.

Connections

8-pin
Master   Target (8-pin)
2        2
4 GND    4 GND
5        5
6        6
7        7
8 5v     8 5v
14-pin
Master   Target (14-pin)
2        2
4 GND    11, 12, 13, 14 GND
5        7
6        8
7        9
8 5v     1 5v
In both cases, Master pin 3 goes to the base of the NPN transistor. The emitter goes to ground, and the collector goes to pin 1 of the target chip. The collector is also connected to 12v through the 1KΩ resistor.
Master pin 2 is also connected (through a 330Ω resistor) to the status LED.
Note: To keep the circuit simple, the capacitors normally surrounding the voltage regulator have been omitted. In most cases, the circuit will work fine (especially with the 7805 regulator). If you experience stability problems, a 10µF and 0.1µF capacitor connecting the input and output (respectively) to ground might be necessary.








 CODE:

// AVR High-voltage Serial Fuse Reprogrammer
// Adapted from code and design by Paul Willoughby 03/20/2010
//   http://www.rickety.us/2010/03/arduino-avr-high-voltage-serial-programmer/
// and Wayne Holder
//   https://sites.google.com/site/wayneholder/attiny-fuse-reset
//
// Fuse Calc:
//   http://www.engbedded.com/fusecalc/

#define  LED      3    // Status indicator LED
#define  RST      4    // (13) Output to level shifter for !RESET from transistor
#define  SCI      3    // (12) Target Clock Input
#define  SDO      2    // (11) Target Data Output
#define  SII      1    // (10) Target Instruction Input
#define  SDI      0    // ( 9) Target Data Input

#define  HFUSE  0x747C
#define  LFUSE  0x646C
#define  EFUSE  0x666E

// ATTiny series signatures
#define  ATTINY13   0x9007  // L: 0x6A, H: 0xFF             8 pin
#define  ATTINY24   0x910B  // L: 0x62, H: 0xDF, E: 0xFF   14 pin
#define  ATTINY25   0x9108  // L: 0x62, H: 0xDF, E: 0xFF    8 pin
#define  ATTINY44   0x9207  // L: 0x62, H: 0xDF, E: 0xFFF  14 pin
#define  ATTINY45   0x9206  // L: 0x62, H: 0xDF, E: 0xFF    8 pin
#define  ATTINY84   0x930C  // L: 0x62, H: 0xDF, E: 0xFFF  14 pin
#define  ATTINY85   0x930B  // L: 0x62, H: 0xDF, E: 0xFF    8 pin

int error = 0;
byte FuseH = 0;
byte FuseL = 0;
byte FuseX = 0;

void setup() {
  pinMode(RST, OUTPUT);
  digitalWrite(RST, HIGH);  // Level shifter is inverting, this shuts off 12V
  pinMode(SDI, OUTPUT);
  pinMode(SII, OUTPUT);
  pinMode(SCI, OUTPUT);
  pinMode(SDO, OUTPUT);     // Configured as input when in programming mode

  digitalWrite(SDI, LOW);
  digitalWrite(SII, LOW);
  digitalWrite(SDO, LOW);

  delayMicroseconds(30);  // wait long enough for target chip to see rising edge
  digitalWrite(RST, LOW);  // 12v On
  delayMicroseconds(10);
  pinMode(SDO, INPUT);      // Set SDO to input
  delayMicroseconds(300);
  unsigned int sig = readSignature();

  if (sig == ATTINY13) {
    writeFuse(LFUSE, 0x6A);
    writeFuse(HFUSE, 0xFF);
    readFuses();    // check to make sure fuses were set properly
    if (FuseL != 0x6A || FuseH != 0xFF) {
      error = 5;    // fast flash if fuses don't match expected
    }
  } else if (sig == ATTINY24 || sig == ATTINY44 || sig == ATTINY84 ||
             sig == ATTINY25 || sig == ATTINY45 || sig == ATTINY85) {
    writeFuse(LFUSE, 0x62);
    writeFuse(HFUSE, 0xDF);
    writeFuse(EFUSE, 0xFF);
    readFuses();    // check to make sure fuses were set properly   
    if (FuseL != 0x62 || FuseH != 0xDF || FuseX != 0xFF) {
      error = 5;    // fast flash if fuses don't match expected
    }
  } else {   
    error = 1;      // slow flash if device signature is invalid
  }

  digitalWrite(SCI, LOW);
  digitalWrite(RST, HIGH);   // 12v Off
  digitalWrite(LED, LOW);    // LED off for succerss
}

void loop() {
  // Flash LED if there was an error
  while (error > 0) {
    int d = 500 / error;
    digitalWrite(LED, HIGH);
    delay(d);
    digitalWrite(LED, LOW);
    delay(d);
  }
}

byte shiftOut (byte val1, byte val2) {
  int inBits = 0;
  //Wait until SDO goes high
  while (!digitalRead(SDO))
    ;
  unsigned int dout = (unsigned int) val1 << 2;
  unsigned int iout = (unsigned int) val2 << 2;
  for (int ii = 10; ii >= 0; ii--)  {
    digitalWrite(SDI, !!(dout & (1 << ii)));
    digitalWrite(SII, !!(iout & (1 << ii)));
    inBits <<= 1;
    inBits |= digitalRead(SDO);
    digitalWrite(SCI, HIGH);
    digitalWrite(SCI, LOW);
  }
  return inBits >> 2;
}

void writeFuse (unsigned int fuse, byte val) {
  shiftOut(0x40, 0x4C);
  shiftOut( val, 0x2C);
  shiftOut(0x00, (byte) (fuse >> 8));
  shiftOut(0x00, (byte) fuse);
}

void readFuses () {
  shiftOut(0x04, 0x4C);  // LFuse
  shiftOut(0x00, 0x68);
  FuseL = shiftOut(0x00, 0x6C);

  shiftOut(0x04, 0x4C);  // HFuse
  shiftOut(0x00, 0x7A);
  FuseH = shiftOut(0x00, 0x7E);

  shiftOut(0x04, 0x4C);  // EFuse
  shiftOut(0x00, 0x6A);
  FuseX = shiftOut(0x00, 0x6E);
}

unsigned int readSignature () {
  unsigned int sig = 0;
  byte val;
  for (int ii = 1; ii < 3; ii++) {
    shiftOut(0x08, 0x4C);
    shiftOut(  ii, 0x0C);
    shiftOut(0x00, 0x68);
    val = shiftOut(0x00, 0x6C);
    sig = (sig << 8) + val;
  }
  return sig;
}

 

 

Credits

sbinder