logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[atmega8][c] Reset z programu do bootloadera?

krdln 26 Gru 2010 17:00 2848 21
  • #1 8915345
    krdln
    Poziom 13  
    Witam,
    mam sobie meżkę z bootloaderem usbasploader (polecam btw). W programie chciałbym umieścić funkcję powrotu do bootloadera. Robię to w ten sposób:
    void reset() { cli();wdt_enable(WDTO_15MS);while(1); }

    Słyszałem, że watchdog działa tak, jak fizyczne zwarcie linii RESET do masy. Jednak po wywołaniu reset() program wraca do swojego początku, zamiast w pełni resetować urządzenie. Co innego, jeśli zewrę reset – wtedy odpala się bootloader. Moim pytaniem jest, czy da się z poziomu programu zrobić pełniejszy reset? :D

    Żeby nie trzeba było za dużo szukać, przeklejam maina bootloadera:
    int __attribute__((noreturn)) main(void)
    {
        /* initialize  */
        wdt_disable();      /* main app may have enabled watchdog */
        bootLoaderInit();
        odDebugInit();
        DBG1(0x00, 0, 0);
    #ifndef NO_FLASH_WRITE
        GICR = (1 << IVCE);  /* enable change of interrupt vectors */
        GICR = (1 << IVSEL); /* move interrupts to boot flash section */
    #endif
        if(bootLoaderCondition()){
            uchar i = 0, j = 0;
            initForUsbConnectivity();
            do{
                usbPoll();
    #if BOOTLOADER_CAN_EXIT
                if(requestBootLoaderExit){
                    if(--i == 0){
                        if(--j == 0)
                            break;
                    }
                }
    #endif
            }while(bootLoaderCondition());  /* main event loop */
        }
        leaveBootloader();
    }

    (bootLoaderCondition() to po prostu sprawdzenie zworki)

    Wesołych Świąt :)
  • #2 8915544
    mirekk36
    Poziom 42  
    krdln napisał:
    W programie chciałbym umieścić funkcję powrotu do bootloadera. Robię to w ten sposób:
    void reset() { cli();wdt_enable(WDTO_15MS);while(1); }

    Słyszałem, że watchdog działa tak, jak fizyczne zwarcie linii RESET do masy. Jednak po wywołaniu reset() program wraca do swojego początku, zamiast w pełni resetować urządzenie. Co innego, jeśli zewrę reset – wtedy odpala się bootloader. Moim pytaniem jest, czy da się z poziomu programu zrobić pełniejszy reset? :D


    Dobrze syłyszałeś, tak się własnie programowo w pełni i prawidłowo resetuje procka. Ja tylko i wyłącznie tak zawsze robię w jeśli działam ze swoim bootloaderem.

    Jeśli ci coś działa nie tak to znaczy, że coś jeszcze gdzie indziej źle robisz. Poza tym można ustawiać najkrótszy czas zamiast 15ms. Ale to nie ma akrat wpływu na to czy taki sposób resetu zadziała czy nie.

    No i nie jest to żaden sposób na powrót do bootloadera tylko jest to sposób na programowe pełne zresetowanie procesora, po którym rozpoczyna on program od miejsca określonego za pomocą fusebitów. Jeśli są odpowiednio ustawione (pamiętaj o tym) to rozpocznie się od bootloadera ;)
  • #3 8916011
    krdln
    Poziom 13  
    No tak, błąd był gdzie indziej, przyjrzałem się dokładniej funkcji bootLoaderInit() i oto, co znalazłem:
        if(!(MCUCSR & (1 << EXTRF)))    /* If this was not an external reset, ignore */
            leaveBootloader();

    Nie mam niestety żadnego innego programatora, więc nie mogę zmodyfikować bootloadera, żeby zrobić tam np. jakąś flagę. Wobec tego, da się jakoś oszukać meżkę, że reset z watchdoga był resetem zewnętrznym? Próbowałem dodać
    MCUCSR |= (1<<EXTRF);

    ale nie działa.
  • #4 8916197
    mirekk36
    Poziom 42  
    Wcześniej myślałem że jakąś literówkę walnąłeś, ale widzę, że ty nadal coś o jakiejś

    "meżce"

    mówisz, człowieku co to jest?

    A flagę to możesz sobie ustawiać, i tak po resecie będzie tak jak ma być czyli wyjdzie ci z tego bootloadera. Programator się kłania niestety.
  • #5 8916461
    krdln
    Poziom 13  
    Cytat:
    człowieku co to jest?

    Atmega, w skrócie mega, g wymienia się na ż, więc zdrobnienie od mega brzmi meżka. Mi tam się podoba :P

    Cytat:
    A flagę to możesz sobie ustawiać, i tak po resecie będzie tak jak ma być czyli wyjdzie ci z tego bootloadera. Programator się kłania niestety.

    Wiem. Mówiąc o fladze miałem na myśli modyfikację bootloadera, myślałem, że wynika to z mojej wypowiedzi:
    Cytat:
    Nie mam niestety żadnego innego programatora, więc nie mogę zmodyfikować bootloadera, żeby zrobić tam np. jakąś flagę.

    Zrobiłeś offtopa i nie odpowiedziałeś w końcu na pytanie.

    Wracając do tematu, mam taką funkcję reset
    void reset() {
        cli();
        MCUCSR |= (1<<EXTRF);
        wdt_enable(WDTO_15MS);
        while(1);
    }

    Z tego, co jest w datasheecie wynika, że w tym bicie 0 pojawia się przy załączeniu zasilania, lub gdy się je tam wpisze ręcznie. Więc skoro zapisuję tam jedynkę, to powinna przetrwać. A wygląda, jakby znikała. Ktoś pomoże?
    (Nie wkleję całego kodu bootloadera, ponieważ to wiele plików i nie chcę syfić forum.)
  • #6 8916724
    mirekk36
    Poziom 42  
    Ok, teraz do mnie dotarło co to jest "meżka", przerażający dziwoląg językowy ale niech będzie ;) ważne, że już rozumiem i rzeczywiście nawet śmieszne ;)
    Za to co do takie słowa jak "syfić" to już mógłbyś sobie darować.

    Żadnego oftopa nie zrobiłem tylko przypomniałem, że bez programatora się nie obejdzie.

    A jeśli chodzi o twoje próby ustawiania tego bitu i to co wynika z dokumentacji to:

    Cytat:

    Bit 1 – EXTRF: External Reset Flag
    This bit is set if an External Reset occurs. The bit is reset by a Power-on Reset, or by writing a
    logic zero to the flag.


    ten bit może być ustawiony tylko przez zajście zewnętrznego resetu, a programista ma możliwość co najwyżej zresetowania tej flagi przez wpisanie zera. Jak zatem chciałeś "oszukać" procka? (gdzie tam masz napisane, że można programowo ustawiać ten bit?)
  • #8 8916800
    krdln
    Poziom 13  
    @gdL
    Myślałem o tym. Powala prostotą :) Co prawda zrabialne, ale mam już płytkę gotową, poza tym mam chyba tylko 1 pin wolny, i to gdzieś daleko.
    Swoją drogą, po co tranzystor? Nie zadziałało by, gdyby pin podpiąć do resetu przez jakiś mały opornik?

    @mirekk36
    jakoś, hmm, nie wiem dlaczego, wydawało mi się oczywiste, że skoro da się wpisać zero, to jedynkę też. ale skoro jest tak jak mówisz, to szkoda. dzięki za uświadomienie mnie :)

    Gdybym miał dostęp do programatora i chciał zrobić to jakąś flagą, to myślicie, że ostatni bajt ramu jest na to dobrym miejscem?
  • #9 8916866
    gdL
    Poziom 27  
    Wydaje mi się, że powinno zadziałać bez. Ale można to zrobić dowolnie. Nie wiem jakie są stałe czasowe resetu i jak wygląda Twoja aplikacja. Widziałem już różne. Tranzystor może przyspieszyć resetowanie, jeśli masz kondensator między reset i gnd.
  • #10 8916953
    mirekk36
    Poziom 42  
    krdln napisał:

    Gdybym miał dostęp do programatora i chciał zrobić to jakąś flagą, to myślicie, że ostatni bajt ramu jest na to dobrym miejscem?


    Taka próba przekazywania pewnych "wiadomości" pomiędzy resetami, nie jest dobrą praktyką programowania. Wręcz złą ;)

    Po pierwsze producent nie gwarantuje, że pamięć RAM nie zostanie w postaci nienaruszonej.

    Po drugie ostatnia komórka (jak już się na coś takiego porywać, to najgorszy pomysł bo tam od razu jak coś to zacznie odkładać się coś na stos. Z kolei na początku pamięci będą umieszczane wszystkie zmienne globalne i statyczne. Więc też nie dobrze. Można by było próbować coś w środku, albo skorzystać z którejś z opcji INIT aby tam wstawić własny kod próbujący odczytać taką "sztuczną" flagę.

    Prędzej do tego celu przydać by się mogła jakaś komórka w pamięci EEPROM, no ale przy zbyt wielu resetach wiadomo, że taka komórka prędzej czy później to jednak się zapesuje ;)

    Próbuj już lepiej coś z tym zewnętrznym resetem poprzez jakiś pin.

    No a poza tym to rozumiem, że ten cały problem to chyba tylko przejściowy na krótko, bo zapewne programator gdzieś tam masz - tylko teraz brak do niego dostępu ;)
  • #11 8917038
    Fredy
    Poziom 27  
    A nie można zrobić skoku w asemblerze w miejsce gdzie zaczyna sie bootloader?
  • #12 8917293
    krdln
    Poziom 13  
    @Fredy
    z tego, co mi się wydaje, to skok do pozycji 0 spowoduje przejście do początku programu, nie bootloadera. Chyba, że jakiś „ujemną” tam wstawić [edit: dokładnie to 0x1000 − rozmiar_bootloadera_w_wordach (czyli 0xC00 w tym wypadku)]:D Ale i tak to nie pełny reset.

    @mirekk36
    No tak, coś słyszałem, że tu stos jest od góry :] Ale zawsze można go przesunąć zostawiając jeden bajt wolny i by było idealnie. Co do zachowania stanu ramu, to niby producent nie gwarantuje, ale mi wystarczy skuteczność np. 60%, żeby za którymś razem poszło.

    Możesz przybliżyć co to jest ta "opcja INIT"? Nie mogę za bardzo znaleźć o co chodzi.
  • #13 8917542
    Fredy
    Poziom 27  
    Ja nic nie mówiłem aby skoczyć na pozycję 0 , wręcz przeciwnie , trzeba zrobić jumpa tam gdzie znajduje się początek programu Bootloadera.
  • #14 8917775
    mirekk36
    Poziom 42  
    Fredy napisał:
    Ja nic nie mówiłem aby skoczyć na pozycję 0 , wręcz przeciwnie , trzeba zrobić jumpa tam gdzie znajduje się początek programu Bootloadera.


    Dokładnie jak pisze Fredy, skok do obszaru bootloadera w twoim szczególnym przypadku, chociaż nie jest to pełny reset może być nawet lepszą alternatywą niż kombinacje z zewnętrznym resetem a szczególnie niż kombinacje z zapisem flagi do ram.

    Odnośnie sekcji INIT to musisz zaczytać maunala AVR GCC, takich sekcji jest kilka i są wykorzystywane przez kompilator to wstępnej inicjalizacji procka, do niektórych można samemu napisać własny fragment obsługi. Ale jak mówię to przekazywanie poprzez RAM a jeszcze do tego przesuwanie stosu to niezbyt ciekawe rozwiązanie.

    Zdecydowanie lepsze będzie skok do obszeru bootloadera bezpośrednio.
  • #15 8918482
    krdln
    Poziom 13  
    Oj, wybaczcie. Mój błąd. Nie wiem skąd to zero wziąłem. Chyba coś z innym tematem mi się pomieszało.

    A co do skoku do bootloadera, to po nim stos chyba nie jest czyszczony i po kilku cyklach programowania może mi się pamięć wysypać, dobrze myślę? Więc to też nie jest super rozwiązanie...

    A jeśli chodzi o zmienne globalne i statyczne to mam takie poboczne pytanie, czy one są wrzucane do pamięci w takiej kolejności, w jakiej są w kodzie źródłowym? Pamiętam, że jak robiłem testy w c na kompie to właśnie tak było.
  • #16 8918496
    mirekk36
    Poziom 42  
    krdln napisał:

    A co do skoku do bootloadera, to po nim stos chyba nie jest czyszczony i po kilku cyklach programowania może mi się pamięć wysypać, dobrze myślę? Więc to też nie jest super rozwiązanie...


    Źle myślisz, skok do bootloadera spowoduje ponowne ustawienie stosu we właściwe miejsce, więc akurat o to nie musisz się w ogóle martwić ;)

    krdln napisał:

    A jeśli chodzi o zmienne globalne i statyczne to mam takie poboczne pytanie, czy one są wrzucane do pamięci w takiej kolejności, w jakiej są w kodzie źródłowym?


    Mogą ale nie muszą i tego należy się trzymać ;)
  • #17 8918595
    krdln
    Poziom 13  
    A, czyli bootloader ma na samym początku jakiś kod „przygotowujący”, czyli ta sekcja INIT pewnie, tak?

    To jeszcze mam pytanie, co się dzieje z rejestrami IO po takim skoku domyślnie, bez kombinowania z initem? Są zerowane, jak przy resecie, czy trzeba ręcznie poczyścić przed tym skokiem?
  • #18 8918913
    mirekk36
    Poziom 42  
    Pisząc o sekcjach INIT miałem na myśli to co standardowo robi kompilator języka C a nie bootloader. A skoro bootloader pisany był w C to musi zawierać takie sekcje ;)

    No właśnie rejestry nie będą wyzerowane, ale ponieważ w twoim konkretnym przypadku chodzi TYLKO o bootloader to nie ma to takiego znaczenia i nic samemu nie musisz czyścić ;) ... bootloader gdy skończy swoje działanie to później już dokona prawidłowego RESET'u procka.
  • #19 8918951
    Freddie Chopin
    Specjalista - Mikrokontrolery
    mirekk36 napisał:
    Pisząc o sekcjach INIT miałem na myśli to co standardowo robi kompilator języka C a nie bootloader. A skoro bootloader pisany był w C to musi zawierać takie sekcje ;)

    To nie jest żaden standard C, tylko sposób działania avr-libc i avr-gcc.

    Cytat:
    No właśnie rejestry nie będą wyzerowane, ale ponieważ w twoim konkretnym przypadku chodzi TYLKO o bootloader to nie ma to takiego znaczenia i nic samemu nie musisz czyścić ;) ... bootloader gdy skończy swoje działanie to później już dokona prawidłowego RESET'u procka.

    Wyzerowanie rejestrów MA znaczenie, choćby dlatego, że mogą być włączone przerwania, może trwać zapis do EEPROMu, mogą się dziać różne inne dziwne rzeczy. Zaś po skończeniu swojego działania bootloader nie wykona przecież żadnego resetu tylko zwyczajnie skoczy do programu...

    4\/3!!
  • #20 8919042
    mirekk36
    Poziom 42  
    Freddie Chopin napisał:
    mirekk36 napisał:
    Pisząc o sekcjach INIT miałem na myśli to co standardowo robi kompilator języka C a nie bootloader. A skoro bootloader pisany był w C to musi zawierać takie sekcje ;)

    To nie jest żaden standard C, tylko sposób działania avr-libc i avr-gcc.


    No to już tylko takie czepianie się słowek, i nie ma to akurat tutaj wielkiego znaczenia, ale oczywiście tak, zgadza się to jest sposób działania avr-gcc ;)



    Freddie Chopin napisał:
    Cytat:
    No właśnie rejestry nie będą wyzerowane, ale ponieważ w twoim konkretnym przypadku chodzi TYLKO o bootloader to nie ma to takiego znaczenia i nic samemu nie musisz czyścić ;) ... bootloader gdy skończy swoje działanie to później już dokona prawidłowego RESET'u procka.

    Wyzerowanie rejestrów MA znaczenie, choćby dlatego, że mogą być włączone przerwania, może trwać zapis do EEPROMu, mogą się dziać różne inne dziwne rzeczy. Zaś po skończeniu swojego działania bootloader nie wykona przecież żadnego resetu tylko zwyczajnie skoczy do programu...


    A co do tego to jednak racja, zapomniałem, że ten bootloader wykorzystuje przerwania, zatem zostaną odblokowane jego własne ale także przypadkowo inne to może być niedobrze ;)

    Ale nie ma sytuacji bez wyjścia bo można poza zatrzymaniem globalnych przerwań wyłączyć też zezwolenia na wszystkie, które się samemu wcześniej uruchamiało i już.

    Wiadomo przecież, że to nie jest elegancki sposób i w zasadzie sam go odradzam od początku, ale przeczytaj sobie Freddie ten temat właśnie od początku - to zrozumiesz dlaczego o takim rozwiązaniu w ogóle mówię ;)
  • #21 8919550
    krdln
    Poziom 13  
    mirekk36 napisał:
    Pisząc o sekcjach INIT miałem na myśli to co standardowo robi kompilator języka C a nie bootloader

    Jak to nie bootloader? :D Skoro kompilator wrzuca to do kodu maszynowego bootloadera, to potem wykonuje to booloader. No ale racja, nie czepiajmy się :P

    mirekk36 napisał:
    bootloader gdy skończy swoje działanie to później już dokona prawidłowego RESET'u procka.

    Ja bym tego nie nazwał prawidłowym resetem. To wygląda bardziej na ręczne sprzątanie po sobie i bootloader sprząta tylko to, czego używał, czyli jeden port i przerwania. Więc jeśli program nie posprząta, to bootloader za niego tego nie zrobi :]

    Istnieje może jakaś wygodna instrukcja/makro/funkcja, do czyszczenia wszystkich rejestrów IO? Może da się to zrobić forką? :D

    Poza tym, apostrof po RESET jest niepotrzebny, chyba nawet błędny. Jeśli da radę przeczytać i wygląda normalnie – bez niego jest ok. Apostrofu używamy, gdy odmieniane słowo się kończy na samogłoskę, której nie wymawiamy. Dygresja taka :P
  • #22 8919693
    Fredy
    Poziom 27  
    Zatem najbezpieczniej byłoby przywrócić wszystkie tknięte rejestry do wartości defaultowych a potem można będzie już jumpa wykonać bezpiecznie.
    Chociaż stosu nie trzeba ruszać bo zostanie skorygowany, porty też będą ustawione od nowa.
REKLAMA