Czeńdżnąć RSTDISBL w jedną stronę jest łatwo i moja podróbka STK500 robi to (wyłącza RESET) bez problemu w trybie serial HV. Problem jest, gdy się chce to potem przeprogramować, bo trzeba wprowadzić µC w tryb programowania, gdy linia RESET jest wyłączona.
Zwykły tryb HV nie daje rady. Tak stoi w docu:
Cytat:
The following algorithm puts the device in High-voltage Serial Programming mode:
1. Apply 4.5 - 5.5V between VCC and GND.
2. Set RESET pin to “0” and toggle SCI at least six times.
3. Set the Prog_enable pins listed in Table 53 to “000” and wait at least 100 ns.
4. Apply VHVRST - 12.5V to RESET. Keep the Prog_enable pins unchanged for at least tHVRST after the High-voltage has been applied to ensure the Prog_enable signature has been latched.
5. Shortly after latching the Prog_enable signature, the device will actively output data on the Prog_enable[2]/SDO pin, and the resulting drive contention may increase the power consumption. To minimize this drive contention, release the Prog_enable[2] pin after tHVRST has elapsed.
6. Wait at least 50 μs before giving any serial instructions on SDI/SII.
Note: If the RESET pin is disabled by programming the RSTDISBL Fuse, it may not be possible to follow the proposed algorithm above. The same may apply when External Crystal or External RC configuration is selected because it is not possible to apply qualified CLKI pulses. In such cases, the following algorithm should be followed:
1. Set Prog_enable pins listed in Table 53 to “000”.
2. Apply 4.5 - 5.5V between VCC and GND simultanously as 11.5 - 12.5V is applied to RESET.
3. Wait 100 ns.
4. Re-program the fuses to ensure that External Clock is selected as clock source (CKSEL1:0 = 0b00) and RESET pin is activated (RSTDISBL unprogrammed). If Lock bits are programmed, a Chip Erase command must be executed before changing the fuses.
5. Exit Programming mode by power the device down or by bringing RESET pin to 0b0.
6. Enter Programming mode with the original algorithm, as described above.
Ale poradziłem sobie jakoś. Zmontowałem układ, któy podaje 5V i 12V jednocześnie i wysyła odpowiednie komendy do µC. Służy do reanimacji ATTiny13 i pracuje na ATTiny13 - więc jeśli został ostatni chip, to można za jego pomocą uratować pozostałe

Reanimowałem swoje wszystkie ATTiny13, a już się bałem, że jedyny z nich pożytek będzie polegać na sprawdzaniu co jest w środku
Tak więc reanimator działa, ale jest z nim trochę kłopotu, nie działa zbyt pewnie. Jeśli zauważy się, że w trakcie działania dioda zaczyna świeecić trochę mocniej, to znaczy, że jest OK - i dobrze, że widać, bo czasem trzeba kliknąć RESET reanimatora kilka razy zanim układ się zreanimuje.
Układ wygląda mniej więcej tak:
a program obecnie wygląda tak:
#include <avr/io.h>
#include <stdint.h>
#include <avr/sleep.h>
#define F_CPU 4800000UL
#include <util/delay.h>
#define SDI (1 << PB0)
#define SII (1 << PB1)
#define SDO (1 << PB2)
#define SCI (1 << PB3)
#define POWER (1 << PB4)
#define RSTDISBL 0
#define LOCK_1 1
#define LOCK_2 2
#define LOCK_BITS ((1 << LOCK_1) | (1 << LOCK_2))
#define FUSES 0x1F
#define CHIP_ERASE_SDI_0 0b10000000
#define CHIP_ERASE_SDI_1 0b00000000
#define CHIP_ERASE_SDI_2 0b00000000
#define CHIP_ERASE_SII_0 0b01001100
#define CHIP_ERASE_SII_1 0b01100100
#define CHIP_ERASE_SII_2 0b01101100
#define NOP_SDI 0b00000000
#define NOP_SII 0b01001100
#define READ_LOCK_SDI_0 0b00000100
#define READ_LOCK_SDI_1 0b00000000
#define READ_LOCK_SDI_2 0b00000000
#define READ_LOCK_SII_0 0b01001100
#define READ_LOCK_SII_1 0b01111000
#define READ_LOCK_SII_2 0b01111100
#define READ_FUSE_H_SDI_0 0b00000100
#define READ_FUSE_H_SDI_1 0b00000000
#define READ_FUSE_H_SDI_2 0b00000000
#define READ_FUSE_H_SII_0 0b01001100
#define READ_FUSE_H_SII_1 0b01111010
#define READ_FUSE_H_SII_2 0b01111110
#define WRITE_FUSE_L_SDI_0 0b01000000
#define WRITE_FUSE_L_INCLK 0b01101010
#define WRITE_FUSE_L_SDI_2 0b00000000
#define WRITE_FUSE_L_SDI_3 0b00000000
#define WRITE_FUSE_L_SII_0 0b01001100
#define WRITE_FUSE_L_SII_1 0b00101100
#define WRITE_FUSE_L_SII_2 0b01100100
#define WRITE_FUSE_L_SII_3 0b01101100
#define WRITE_FUSE_H_SDI_0 0b01000000
#define WRITE_FUSE_H_RESET 0b11111111
#define WRITE_FUSE_H_SDI_2 0b00000000
#define WRITE_FUSE_H_SDI_3 0b00000000
#define WRITE_FUSE_H_SII_0 0b01001100
#define WRITE_FUSE_H_SII_1 0b00101100
#define WRITE_FUSE_H_SII_2 0b01110100
#define WRITE_FUSE_H_SII_3 0b01111100
void inline waitForSDO()
{
while (0 == (PINB & SDO))
{
;
}
}
void tick(uint8_t v)
{
PORTB = ((v & (SDI | SII)) | POWER);
PORTB |= SCI;
_delay_us(0.1);
PORTB &= ~SCI;
_delay_us(0.1);
}
uint8_t sendCommand(uint8_t sdi, uint8_t sii)
{
uint8_t answer = 0;
tick (0); // one start bit
for (uint8_t i = 0; i < 8; i++)
{
uint8_t bits = ((sdi & 0x80) ? SDI : 0) | ((sii & 0x80) ? SII : 0);
tick (bits);
answer <<= 1;
answer |= (PORTB & SDO) ? 1 : 0;
sdi <<= 1;
sii <<= 1;
}
tick(0); // two stop bits
tick(0);
return answer;
}
uint8_t readLock()
{
sendCommand(READ_LOCK_SDI_0, READ_LOCK_SII_0);
sendCommand(READ_LOCK_SDI_1, READ_LOCK_SII_1);
return sendCommand(READ_LOCK_SDI_2, READ_LOCK_SII_2);
}
uint8_t readHighFuses()
{
sendCommand(READ_FUSE_H_SDI_0, READ_FUSE_H_SII_0);
sendCommand(READ_FUSE_H_SDI_1, READ_FUSE_H_SII_1);
return sendCommand(READ_FUSE_H_SDI_2, READ_FUSE_H_SII_2);
}
void longDelay()
{
for (uint8_t i = 0; i < 10; i++)
{
_delay_ms (50);
}
}
void eraseChip()
{
sendCommand(CHIP_ERASE_SDI_0, CHIP_ERASE_SII_0);
sendCommand(CHIP_ERASE_SDI_1, CHIP_ERASE_SII_1);
sendCommand(CHIP_ERASE_SDI_2, CHIP_ERASE_SII_2);
longDelay();
waitForSDO();
sendCommand(NOP_SDI, NOP_SII);
}
void enableInternalCLK()
{
sendCommand(WRITE_FUSE_L_SDI_0, WRITE_FUSE_L_SII_0);
sendCommand(WRITE_FUSE_L_INCLK, WRITE_FUSE_L_SII_1);
sendCommand(WRITE_FUSE_L_SDI_2, WRITE_FUSE_L_SII_2);
sendCommand(WRITE_FUSE_L_SDI_3, WRITE_FUSE_L_SII_3);
longDelay();
waitForSDO();
}
void enableRESET()
{
sendCommand(WRITE_FUSE_H_SDI_0, WRITE_FUSE_H_SII_0);
sendCommand(WRITE_FUSE_H_RESET, WRITE_FUSE_H_SII_1);
sendCommand(WRITE_FUSE_H_SDI_2, WRITE_FUSE_H_SII_2);
sendCommand(WRITE_FUSE_H_SDI_3, WRITE_FUSE_H_SII_3);
longDelay();
waitForSDO();
}
void powerON()
{
// set lines as output, lower programming lines, raise power
DDRB = POWER | SDI | SDO | SII | SCI;
PORTB = POWER;
//_delay_us (0.1);
longDelay();
DDRB &= ~SDO;
PORTB |= SDO; // pull-up enable
}
void powerOFF()
{
// everything off
PORTB = 0;
_delay_ms (10);
DDRB = 0;
}
void recoverChip()
{
powerON ();
eraseChip();
enableRESET();
enableInternalCLK();
powerOFF();
}
void inline shutDown()
{
MCUCR = (1 << SE) | (1 << SM1);
while (1) sleep_mode(); // power down until RESET
}
int main ()
{
while (1)
{
recoverChip();
shutDown();
}
return 0;
}
Jeżeli nie wymyślę niczego mądrego, to spróbuję odczytać po próbie reanimacji np. sygnaturę albo fusy i jeśli efekt będzie niezadowalający, to program spróbuje jeszcze raz... i tak ze sto razy.
Jest tu kilka dużych opóźnień, za dużych, ale pozwalają zobaczyć, co się dzieje, bopóki co trzeba patrzeć, jak idzie reanimacja.
Może ktoś widzi błąd i da się reanimator uczynić bardziej niezawodnym w działaniu?