Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[Tiny13] reanimacja po wyłączeniu RESET

Tomator.pl 27 Sie 2008 16:22 5985 5
  • #1 27 Sie 2008 16:22
    Tomator.pl
    Poziom 10  

    Witam

    Zbudowałem sobie programator jak STK500, działa programowanie wysokonapięciowe, programuję sobie Tiny13... Po drodze jednak wyłączam RESET, bo jest mi nóżka potrzebna do czegoś innego... No i mogę go tak zaprogramować tylko raz :(

    STK500 zrobiłem wg schematu od hammera, złącze do HV dodałem na podstawie tego schematu. Niestety, nie umożliwia on włączenia sygnału RESET, bo do tego jest specjalna procedura (włączenie zasilania jednocześnie z podaniem 12V na RESET).

    Czy można tu zastosować jakąś przeróbkę programatora i wtedy będzie on w stanie wejść w tryb programowania przy wyłączonym RESET? To znaczy, czy można podłączyć tranzystor do którejś nóżki Mega8535 i on włączy 5V kiedy trzeba?

    A jeśli nie, to jak przywrócić µC do komunikacji z programatorem?

    Próbowałem zrobić sobie własny reseter, ale cosik mi nie wyszło. Nie działa jakby. Możliwe, że elektrycznie: napięcia nie szły jednocześnie może... Bo trochę głupio to podłączyłem. Ale może też chodziło o coś innego.

    Czy ktoś wie, czy podczas programowania w trybie HV ważne jest zachowanie stałej częstotliwości taktowania, czy można po prostu przełączać SCK wtedy kiedy ma się akurat jakiś bit do wysłania?

    0 5
  • #4 28 Sie 2008 11:59
    Tomator.pl
    Poziom 10  

    Dzięki wojnar za link. Widzę, że nie trzeba trzymać stałego taktowania, ani nie musi ono mieć wypełnienia 50%. Można po prostu puścić jeden takt, gdy jest coś do wysłania.

    Czeska strona ma też link do wersji na innym układzie, więc i po angielsku można sobie opis poczytać, nawet obszerniejszy.

    Z listingu odczytałem jednak, że najpierw włączane jest zasilanie 5V, potem 16 taktów zegarem, przerwa i dopiero załączenie 12V na RESET. Tiny13 tego nie łyknie, jeżeli wyłączony jest RESET. Wtedy trzeba zasilanie i 12V na RESET podać jednocześnie, a opisany pod linkiem układ tego nie zrobi. Może więc nie zadziałać. Jak rozumiem, przydałby się głównie w przypadku załączenia zewnętrznego taktowania. Ale na to mam już STK500. Oczywiście wystarczyłoby przerobić program, ale po pierwsze nie mam pod ręką Tiny2313, a po drugie nie lubię grzebać w asm. Spróbuję więc poprawić schemat i program w C dla Tiny13, bo tych mam jeszcze pół laski. A po reanimacji będę miał 3/4 :)

    Nie mniej jednak dzięki za linka, mam dzięki temu kilka nowych informacji. Może uda mi się własny reseter w końcu wygenerować.

    crazy_phisic, też dzięki za odzew. Tamte programatory też nie wyglądają na mogące reanimować układ z wyłączonym RESETem (opis odsyła do dokumentacji, czyli featura chyba niezamplementowana), ale zawsze to trochę dodatkowych danych, też się przyda, dodałem do ulubionych.

    0
  • #5 28 Sie 2008 12:09
    wojnar
    Poziom 16  

    Dzięki :-)
    No, w drugim linku co podał crazy_phisic, jest u Parallel programer to:

    Cytat:
    Changing SPIEN or RSTDISBL fuse bit.

    Czyli chyba rozwiązuje Twój problem.

    0
  • #6 29 Sie 2008 03:30
    Tomator.pl
    Poziom 10  

    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:

    [Tiny13] reanimacja po wyłączeniu RESET

    a program obecnie wygląda tak:


    Code:
    #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?

    1