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

AVR Boot Loader - który ładnie i szybko działa / USB

mirekk36 16 Cze 2009 18:59 108312 252
  • AVR Boot Loader - który ładnie i szybko działa / USB

    Witam,

    Nie wiem wprawdzie czy taka "konstrukcja" nadaje się na DYI, ale najwyżej moderator gdzieś to przeniesie. Myślę, że przyda się to wielu ludziom ;)

    Bootloader w procku - po korektach zajmuje tylko 512b !!!

    działa poprzez USB , RS232

    ... i BlueTooth! ......

    właśnie ukończyłem wszystkie testy z BlueTooth - działa wyśmienicie - widać specjalne opcje dla BT oraz możliwości resetowania procka przez program MkBoot - sprzętowe DTR, RTS i programowe - poleceniem np AT+RST? ;)

    Niby bootloader dla procków to oklepany temat, ale o ile czasem ktoś napisze sobie własny bootloaderek to później bywają problemy z jakimś programem na PC żeby ładować coś do procka, albo problemy tak jak ja miałem z prędkością ładowania danych do procka w pierwszych wersjach.

    Tak więc prezentuję przykładowy kod BootLoadera dla procków AVR, w tym przypadku konkretnym dla ATmega8 (dodam, że testowałem na ATmega32 i też tak samo działa bez najmniejszego zarzutu). Program dla procka jest w języku C i powstał w dużej mierze dzięki koledze BoskiDialer - tzn na bazie fragmentów jego kodu - posklecałem sobie całą maszynkę, którą teraz mogę na w zasadzie dowolnym AVRku puszczać przy minimalnej ilości zmian kodu C oraz pliku makefile

    fragmencik kodu poniżej ale w załącznikach przekazuję wszysciutko w źródłach jeśli chodzi o C dla procka oraz sam plik wynikowy (bez źródeł) programu na PC - powstał on w Delphi;

    AVR Boot Loader - który ładnie i szybko działa / USB

    w kodzie powyżej widać linijkę:
    Code:
    char PROGMEM procek[] = {"ATmega8"};

    oczywiście jeśli przerabiamy dla innego procka to trzeba wstawić jego nazwę,

    O wiele istotniejsza jednak jest zmiana jaką trzeba zrobić w makefile - otóż trzeba w liniach:

    Code:
    MMCU = atmega8
    
    MF = bootloader
    F_CPU = 11059200
    BOOTSTART = 0x1E00


    wstawić odpowiedni procesor dla którego kompilujemy kod. prędkość kwarca lub oscylatora wewn. napędzającego procka, oraz bardzo ważne parametr: BOOTSTART - dla ATmega8 = 1E00 a np dla Atmega32 = 7E00

    poniżej schemat uproszczony do takiego bootloadera - oczywiście nie jest to jakieś oddzielne urządzenie - ale prawie każdy procek u mnie ma jakąś komunikację z PCtem przez RS232 . Wystarczy tylko jak widać podpiąć linie TxD, RxD a na dodatek sygnał DTR, który program na PC używa do zresetowania na chwilkę procka żeby wystartował bootloader w środku.

    AVR Boot Loader - który ładnie i szybko działa / USB

    także wersja dla zwykłego RS232 na MAX232 - bo ktoś pytał ;)
    AVR Boot Loader - który ładnie i szybko działa / USB

    a tu wersja przez BlueTooth:
    AVR Boot Loader - który ładnie i szybko działa / USB

    oczywiście trzeba pamiętać o przestawieniu stosownych fusebitów odnośnie rozmiaru dla BootLoader'a - w tym przypadku trzeba ustawić rozmiar 512 bajtów oraz przestawić wketory przerwań na obszar BLS.

    Program komunikuje się z PC z prędkością 9600 bps dzięki czemu prawie w każdej sytuacji można z niego skorzystać, a pomimo niby tak małej prędkości - programowanie odbywa się (udało się) BŁYSKAWICZNIE !

    spójrzcie na czas poniżej oraz wielkość wsadu 5182 bajty - czasy programowania porównywalne są z prędkością AVRDude !!!
    AVR Boot Loader - który ładnie i szybko działa / USB

    powodzenia

    Fajne! Ranking DIY
    Potrafisz napisać podobny artykuł? Wyślij do mnie a otrzymasz kartę SD 64GB.
    O autorze
    mirekk36
    Poziom 42  
    Offline 
    Ciekawy kurs VIDEO - EAGLE - zajrzyj na mój blog
    mirekk36.blogspot.com - VOLATILE ? to łatwe

    Specjalizuje się w: programowanie: avr c, delphi pc, android
    mirekk36 napisał 9195 postów o ocenie 2231, pomógł 964 razy. Mieszka w mieście Szczecin. Jest z nami od 2006 roku.
  • BotlandBotland
  • #2
    MasterMatan
    Poziom 21  
    Bardzo się przydał ten artykuł, bardzo.
    Widziałem botloadera na stronie http://www.usb.org/developers/hidpage (nawet 2) ale nie rozumiałem na jakiej zasadzie to wszystko działa. Projekt 12 przyciskowego pada bardzo mi się spodobał i jestem w trakcie jego wykonywania. Botloader nawet jest fajnym projektem wykorzystującym bibliotekę V-USB ale czy przypadkiem niezbyt praktycznym...?
  • #3
    mirekk36
    Poziom 42  
    Ale ten projekt w ogóle nie wykorzystuje żadnej biblioteki V-USB - w załączniku masz cały, króciutki około 600-800 bajtów (w zależności od procka) program czystego żywego bootloadera w C ..... i jest bardzo praktyczny, już zaczynam go sobie wszędzie gdzie się da używać, przerabiam kod po kolei dla różnych procków Mega8, 16, 32, 64 itp ;)

    Dodano po 1 [minuty]:

    Krzysiek_1993 -> jak wspominałem już przetestowałem na Atmega32 i pełnym wsadzie - szybkość???? po prostu BŁYSK ;)
  • #4
    BoskiDialer
    Poziom 34  
    Kod bez wątpienia nie będzie działać na atmega128, gdyż funkcje erase_flash i write_page nie uwzględniają istnienia rejestru RAMPZ - kod pisałem ze względu na atmega8 kompletnie ignorując wszystkie inne. Nie zmienia to jednak faktu, że na większości będzie działać.

    Co do prędkości transmisji - 9600bps jest wyjątkowo niską wartością. Ponieważ zapis odbywa się w tle, zapisanie jednej strony (m8) można założyć, że trwa pesymistycznie 9ms (dokumentacja mówi o 4,5ms). W takim przypadku pełną prędkość programowania uzyskało by się przy prędkości powyżej 71111 bps (najbliższa: 115200). Może warto dodać prostą opcję na początku - jeśli bootloader odbierze znak np "%" to wpisuje do UBRR wartość odpowiednią dla 115200 i teraz tylko zależy, czy program wyśle ten znak czy nie. Po wysłaniu ponowne otwarcie portu COM lub zmiana prędkości w dcb i tyle.

    Nadal nie jestem pewien, czy w kodzie na którym się wzorowałeś nie popełniłem błędu - czy test przed wyłączeniem uartu na pewno gwarantuje wysłanie wszystkich znaków. Pusty bufor nadawczy nie oznacza, że nie jest nadawany już żaden bajt. U mnie ten kod chodził poprawnie, gdyż wbrew kodu loadera, aplikacja ignorowała ostatni znak.
  • #5
    mirekk36
    Poziom 42  
    BoskiDialer -> przy tym jak to teraz połączyłem wszystko zarówno w bootloaderze jak i programie na PC - to na prawdę w testach przy prędkości 115200 i 9600 nie wyszły jakieś różnice w prędkości programowania.
    Jak widzisz start bootloadera jest zmieniony - gdyż nie trzeba wciskać żadnego klawisza, tylko Bootloader przez 1,5 sekundy wysyła znak zachęty przez RS232 żeby w tym czasie program na PC mógł go wybadać i zacząć ładować. Z sygnałem DTR który resetuje procka - daje to na prawdę niesamowite rezultaty i efekty. Nawet jeśli ktoś nie użyje DTR - to wystarczy - ręcznie zresetować procka i odpalić UPLOAD - też ładnie pójdzie.

    Jak widać też, Bootloader - po połączeniu się z PC - podaje mu swój rozmiar strony programowania oraz pełną dostępną pamięć do zaprogramowania. Dzięki czemu PC nie wrzuci większego kodu a wysyła go też bardzo optymalnie dostosowując paczki danych do wielkości stron konkretnego procka.

    Odnośnie Mega128 - pewnie, że nie testowałem ale jak mówiłem dla Mega8, 16, 32 i 64 działa bez zająknięcia ;)

    dla 128 najwyżej coś będzie trzeba poprzerabiać odrobinkę ;) - jeszcze się tym nie zajmowałem więc dlatego nie wiem co i jak.
  • #6
    BoskiDialer
    Poziom 34  
    Zacząłem się teraz zastanawiać jak można by zmniejszyć rozmiar owego bootloadera, na pewno kosztowną funkcją jest wywołanie itoa. Stałe można od razu zamienić na ciąg znaków, nie trzeba do tego itoa. Ciągi znaków można zresztą ze sobą połączyć. Zamień to:
    Code:
    crlf;
    
    uart_putchar('&');
    uart_putint(SPM_PAGESIZE);
    uart_putchar(',');
    uart_putint(APP_END);
    uart_putchar(',');
    uart_putstr_P(procek);
    uart_putchar(',');
    uart_putstr_P(BLS_VER);
    uart_putchar('*');
    crlf;

    na:
    Code:

    #define LDR_UC "ATmega8"
    #define LDR_VER "ver.1.00"

    #define STRINGIFY(x) #x
    #define TOSTRING(x) STRINGIFY(x)

    // ...
    uart_putstr_P("\x0d\x0a" "&" TOSTRING(SPM_PAGESIZE) "," TOSTRING(APP_END) "," LDR_UC "," LDR_VER "*" "\x0d\x0a");
    // ...

    Co stanie się zbędne to wywalić, albo oznaczyć funkcje jako statyczne, kompilator sam wywali.

    Swoją drogą dopiero przed chwilą znalazłem konstrukcję dla preprocesora, aby zamieniać stałe liczbowe na ciągi znaków - muszą to być dwa osobne makra.
  • #7
    mirekk36
    Poziom 42  
    BoskiDialer ---> ooo kurka wodna po kompilacji tym twoim sposobem wyszło tylko 414 bajtów dla Mega8 - ale niestety - jakaś sieczka leci przy tym uart_putstr_P zamiast danych które mają przylecieć. Wytestowałem to w zwykłym terminalu i leci chyba milion spacji i pokazuje się na końcu ATmega8 tylko :(

    nie za bardzo kumam tego co nakombinowałeś ale może jeśli jeszcze coś uda ci się pomyśleć to bootloaderek rzeczywiście zmieściłby się w 512 zamiast 1024 bajtów
  • #8
    BoskiDialer
    Poziom 34  
    Racja - popełniłem błąd. Podany ciąg znaków wyląduje w pamięci ram zamiast progmem.
  • BotlandBotland
  • #9
    mirekk36
    Poziom 42  
    BoskiDialer ---> huuuraaa - to i dobrze - tak więc wystarczyło użyć tylko funkcji uart_putstr zamiast uart_putstr_P - i już wszystko leci jak trzeba !!!! tylko rozmiar wolnej pamięci jest w HEXie ale to żaden problem , zaraz w programie na PC przerobię aby odczytywał HEXa ;) super

    no i bootloaderek upcha się w 512 bajtów - dzięki twoim cennym uwagom jak zwykle ;)

    Dodano po 1 [godziny] 2 [minuty]:

    BoskiDialer ---> szkoda, że kolega nie jest ze Szczecina - bo postawiłbym DUŻE PIWKO ;)

    już bootloader działa w wersji 512b !!!!! extra

    poniżej screen z nowszej w pełni chulającej wersji 512kb
    AVR Boot Loader - który ładnie i szybko działa / USB
  • #10
    JmL(TM)
    Poziom 24  
    Gratulacje! Widze, ze w koncu ktos chwali sie czyms innym a nie tylko ta sama wersja zegarka tylko z innym kolorem podswietlania LCD lub programatorem AVR z inna obudowa [np. tym razem po szamponie tak dla odmiany] :D

    Sam robilem cos podobnego:
    AVR Boot Loader - który ładnie i szybko działa / USB

    ...ale z braku czasu stanelo na scisle ograniczonych funkcjach skierowanych tylko pod jeden konkterny uklad.

    Nie za bardzo podoba mi sie wysylanie "string'a" np. jako typ procka

    Code:
    #define LDR_UC "ATmega8"
    
    #define LDR_VER "ver.1.00"


    gdybys zrobil to np. tak:

    Code:
    #define ATMEGA_8  0x01
    
    #define ATMEGA_16 0x02
    ...

    #define LDR_UC ATMEGA_8


    To masz tylko jeden bajt a w sumie mozesz w nim umiescic 255 typow procka a rozpoznawanie po numerze wystarczy dodac w aplikacji na Win32/64...

    Jesli nie jest to sekretem to w jaki sposob obliczasz czas programowania procka? Moglbys wkleic ten fragment kodu?

    Pozdrawiam!
    Michal
  • #11
    mirekk36
    Poziom 42  
    JmL(TM) --> z tą nazwą procka to już sobie poradziłem tak, że wysyłam ją jako string wprawdzie ale nie deklaruję jej już w programie (tak jak było widać to wyżej) - tylko leci nazwa procka podana w makefile, a to dzięki takiej konstukcji:

    Code:
    #define STRINGIFY(x) #x 
    
    #define TOSTRING(x) STRINGIFY(x)

    uart_putstr("\r\n" "&" TOSTRING(SPM_PAGESIZE) "," TOSTRING(APP_END) "," TOSTRING(UC) "," LDR_VER "*" "\r\n");


    a do tego oczywiście w makefile dodałem coś takiego:

    Code:
    -D UC=$(MMCU)


    dzięki czemu ładnie przekazuje mi się taka nazwa procka dla jakiego leci kompilacja - to nawet lepiej bo człowiek przypadkowo nie zapomni podmieniać tej zmiennej "ręcznie" niezależnie czy będzie to string czy cyfrowa sygnaturka.

    Odnośnie obliczania czasu ile trwa pętla programująca procek to robię to w Delphi tak:

    Code:
    var 
    
      _h, _m, _s, _ms: Word;
      _h1, _m1, _s1, _ms1: String;
      czas, tt: TDateTime;
    begin

      ......

      czas := now;
      Tu pętla programująca
      begin

        // a gdzieś  w ciele tej pętli zapętlonej ;)
              tt := now - czas;
              DecodeTime(now-czas, _h, _m, _s, _ms);
              _h1 := IntToStr(_h);
              if Length(_h1) = 1 then _h1 := '0'+_h1;
              _m1 := IntToStr(_m);
              if Length(_m1) = 1 then _m1 := '0'+_m1;
              _s1 := IntToStr(_s);
              if Length(_s1) = 1 then _s1 := '0'+_s1;
              _ms1 := IntToStr(_ms);
              if Length(_ms1) = 1 then _ms1 := '00'+_ms1;
              if Length(_ms1) = 2 then _ms1 := '0'+_ms1;
              Label1.Caption := _h1+'h '+_m1+'m '+_s1+'s '+_ms1+'ms';
              Application.ProcessMessages;
       
      end;
      ......

    end;


    to tak na szybciora coś sklecone - ale ładnie liczy nawet w milisekundach ;) a to potrzebne - bo wsad o długości 200-300 bajtów zapisuje się w procku krócej niż 1 sekunda

    ... aaaa i jeszcze raz dodam, że nawet w całym tym moim sposobie algorytmie zapisu do procka paczkami danych - na prawdę nie ma ŻADNEJ różnicy czy prędkość RS'a jest 9600 czy 115200 - dzięki czemu user na ma dylematu jaką prędkość ustawiać - zawsze taka sama ;)
  • #12
    mosfet
    Poziom 25  
    toż to normalny bootloader RS-232. Czemu w tytule jest USB? Bo jest konwerter? Wolne żarty proszę kolegi.
  • #13
    mirekk36
    Poziom 42  
    mosfet ---> ooo matko z córką - jaka ogromna różnica i jakie oszustwo wielkie ???? RS232 a nie USB ;)

    a czym to się różni???? z punktu widzenia zasady działania, toż to jednoznaczne - tu i tu tak samo przez protokół RS232 lecą dane - tylko w obecnych czasach przez USB jest nieco wygodniej bo już nawet niektóre płyty glówne czy laptopy zwykłego wyjścia RS232 nie mają. To co? specjalnie dla kolegi miałem dorysować jeszcze schemat połączeń przez MAX232 do zwykłego portu RS232 w kompie? ;) i to by tak mocno zmieniło całe zagadnienie bootloadera? A może kolega sam to sobie dorysuje, usiądzie wygodnie, popatrzy wtedy na to przez 5 min i spróbuje ocenić czy jest jakaś różnica ?

    poza tym co ja powyżej napisałem w jednym z postów?
    mirekk36 napisał:
    Ale ten projekt w ogóle nie wykorzystuje żadnej biblioteki V-USB - w załączniku masz cały, króciutki około 600-800 bajtów (w zależności od procka) program czystego żywego bootloadera w C .....
  • #14
    Użytkownik usunął konto
    Użytkownik usunął konto  
  • #15
    mirekk36
    Poziom 42  
    szefuńcio -> najspokojniej w świecie zadziała na innych prockach ale takich, które mają przewidzianą w fusebitach sekcję na boot-loader i można w nich przestawić wektor przerwań. Ale z tego co mi na razie wiadomo to chyba tylko procki z serri AVR ATmega mają taką możliwość. Chociaż może się mylę - może jakieś najnowsze ATtiny też to mają - trzeba by było w notach PDF sprawdzić.
  • #16
    el-electriko
    Poziom 2  
    Czy masz porównanie swojego bootloadera z tym stosowanym w projekcie Arduino? Tu są źródła: Arduino bootloaders.
    Można znaleźć tam kilka wersji dla różnych kontrolerów z rodziny ATmega. Kod też napisany w C.
  • #17
    mirekk36
    Poziom 42  
    el-electriko --> tak porównałem sobie te kody źródłowe.

    różnice:

    Arduino - wielkość bootloadera = 1024 bajty (sporo) ;)
    Mirekk36 - wielkość bootloadera = 512 bajtów

    mój bootloader nie wykorzystuje żadnych zewnętrznych pinów procka, które mógłby używać jakikolwiek program w nim napisany - poza pinem RESET, którego i tak zwykle się nie przeprogramowuje - a można też go nie podłączać do DTR - tak więc mój bootloader jest na prawdę przeźroczysty dla aplikacji

    teraz już tak przerobiłem kod w C, że w zasadzie bez żadnych w nim zmian można go wgrać (skompilować) na żywca do dowolnego procka AVR (no może nie do ATmega128 jak już było napisane)

    a to jaki procek chcemy i jak ma być taktowany to ustawiamy tylko w pliku makefile

    program na PC będzie działał z każdym bootloaderem w każdym procku - więc to dosyć uniwersalne i wygodne
  • #18
    tiggerek1982
    Poziom 15  
    witam mirek36 ,ja z malutką prośbą. mógłbyś zamieścić jeszcze raz załączniki z pozbieranym (po całym dniu walki z przeróbkami) kodem? :| .
    A może i takie laikowate pytanie, ale po wgraniu tego bootloadera w C nie będzie problemu bym wrzucał wsad do procka w bascomie? (nie linczujcie jeśli pytam o coś oczywistego )

    pozdrawiam
    Krystian:|
  • #19
    mirekk36
    Poziom 42  
    tiggerek1982 --> po co zaraz lincz ? ;) -- oczywiście, że będziesz mógł ładować swoje programy do procka napisane obojętnie w czym: Bascom, C czy asembler - wsio rawno

    ok zaraz poprawię załączniki w głównym poście na górze

    Dodano po 7 [minuty]:

    ok - już poprawione załączniki

    przypominam tylko, że kod w C jest teraz dla ATmega8 taktowanej wewn oscylatorem 8MHz

    jeśli ktoś chce to zmienić - to wystarczy tylko pozmieniać parametry w makefile (samego kodu C już nie trzeba "ruszać) , przkompilować make all , ustawić odpowiednie fuski w procku (dla Mega8 są dwa pliki BAT, które poprzez USBASP ustawiają stosowne wszystkie fusebity dla wewn oscylatorka 8MHz a także jeśli ktoś chce dla kwarca większego niż 8MHz - ja akurat używałem kwarca 11052900)

    pozdrówka

    Dodano po 24 [minuty]:

    dodałem w głównym pierwszym poście na wszelki wypadek jeszcze schemacik z udziałem MAX232 dla podłączenia BootLoaderka przez zwykły RS232 - z taką samą w pełni funkcjonalnością
  • #20
    rsikon
    Poziom 26  
    Witam, tak trochę od projektu odbiegnę:

    a co Koledzy myślą - mając wiekszą wiedze niż ja o bootloaderach - o ładowaniu softu z karty np SD. Bootloader czy inna czesc softu wykrywa, że włożono do gniazda kartę i ładuje z niej nowe oprogramowanie.

    Na ile to wykonywalne jest dla "małych" Atmeg typu 16 / 32??

    Radzio
  • #21
    mirekk36
    Poziom 42  
    rsikon -> a dlaczego miałoby być nie wykonywalne?. Bootloader można napisać tak aby ładował sobie wsad z dowolnego łącza RS232, I2C, SPI czy z kart SD. To tylko kwestia napisania softu no i ew chyba nieco większego rozmiaru samego obszaru bootloadera dla kart SD - no ale coś za coś ..... i można to zrobić na dowolnej ATmedze - o ile ma się taką palącą potrzebę
  • #22
    rsikon
    Poziom 26  
    Zbyt dosłownie potraktowałeś "nie wykonalne" :)

    Wiem wszystko da sie zrobic :) tylko na ile jest to "problrmowy" temat.

    Bardziej obawiam sie wielkosci bootloadera.

    Hmm a pomysl z I2C tez mi sie podoba, albo lepiej 1wire.

    Masz moze juz jakies doswiadczenie w podobnym projekcie?
  • #23
    mirekk36
    Poziom 42  
    rsikon --> nie, nie - na kartach SD jeszcze w ogóle nic nie robiłem. Ale nawet tu na elektrodzie jak sam zaczynałem się interesować bootloaderem to zaczytałem trochę o tym jak to ludziska próbują robić coś takiego na SD .... poszperaj to może znajdziesz dla siebie cenne wskazówki.

    Ja zwykle wszystko co robię to w taki czy inny sposób mam podpięte do PC-ta bądź to przez USB bądź przez zwykły RS232. Czasem do innego procka itp itd ....

    a nawet jak nie używam akurat RS'a to zwykle wyprowadzam sobie te dwa piny TxD i RxD bo zawsze później do czegś się przydają

    w związku z powyższym u mnie naturlne jest, że Bootloader RS-owy to najlepsze rozwiązanie i "zawsze pod ręką"
  • #24
    Paweł Es.
    Pomocny dla użytkowników
    Mój Boże TYLKO 512 kilobitów (kb) i to po korektach ? Czy ty pracowałeś może w teamie piszącym (skorygowany oczywiście ) kod Windows Vista wymagający tylko 2GB RAM by otworzyć okienko ??????????? ;)))

    Cytat:
    Bootloader w procku - po korektach zajmuje tylko 512kb !!!


    ;))

    PS. Czy ktoś czyta uważnie ? ;)
  • #25
    mirekk36
    Poziom 42  
    Paweł Es. ---> ok poddaję się surowej krytyce - ale chyba nikt tego nie zauważył ;) bo to aż kłuje w oczy ;)

    oczywiście, że 512 bajtów a w zasadzie 512 słów dwubajtowych - a nie żadnych KILO ;)

    najważniejsze, że każdy wie o co chodzi - bo gdzież by się w takich prockach zmieściło 512KB (jakiś hohlik albo krasnoludek sam mi to wpisał w winietce programu ) hahahaha no dobre
  • #26
    BoskiDialer
    Poziom 34  
    Poprawiłem kilka błędów jak: zerowanie r1 w złej sekcji; brak wpisania wskaźnika stosu do rejestrów SPL,SPH; inicjalizacja uartu przez ustawianie bitów zamiast przypisania. Zrobiłem też trochę porządku. Może któreś ze zmian się przydadzą.
    Załączniki:
  • #27
    mirekk36
    Poziom 42  
    BoskiDialer -> wielkie dzięki, fajnie się czyta twój kod, można się dużo nauczyć - widać, że od dawna pisujesz sofcik w C.

    ale miałbym pytanka do twoich uaktualnień:

    1. Dlaczego uważasz, że to zerowanie rejestru r1 było w złej sekcji (.init9) ?

    2. dlaczego wstawiłeś w sekcji (.init9) skok do main ? - kompilator sam tego nie robi domyślnie przy kompilacji ?

    3. dlaczego funkcję main opatrzyłeś tym atrybutem __naked ? czy dlatego, żeby kompilator nie kończył jej sekwencją jakiejś nieskończonej pętli bo i tak nie potrzebna?

    i jeszcze raz dzięki za te poskracania - na prawdę dużo się z tego nauczyłem ;) .... kurka wodna jak będziesz kiedyś w Szczecinie, daj znać, a duże PIWO cię nie ominie ;) ... masz je u mnie jak w banku!
  • #28
    greatlukas
    Poziom 13  
    Witam, niech ktoś łaskawy mnie oświeci :) bo dawno nic nie "klepałem" na AVR'ki - co to robi, dlaczego i poco :P

    Code:

    void __init0(void) __attribute__((naked, section(".init0")));
    void __init0(void)
    {
       asm volatile(
          "out %0, %A2" "\n\t"
          "out %1, %B2" "\n\t"
          "clr __zero_reg__" "\n\t"
          "out %3, __zero_reg__" "\n\t"
       :: "I"(_SFR_IO_ADDR(SPL)), "I"(_SFR_IO_ADDR(SPH)), "r"((uint16_t)(RAMEND)), "I"(_SFR_IO_ADDR(SREG)) );
    }
    void __init9(void) __attribute((naked, section(".init9")));
    void __init9(void)
    {
       asm volatile(
          "rjmp main"
       ::);
    }
  • #29
    mirekk36
    Poziom 42  
    greatlukas -> ponieważ w makefile jest parametr za pomocą którego świadomie rezygnujemy z całego początku i inicjalizacji - to trzeba samemu "ręcznie" ustawić stos, i wyzerować SREG i rejestr r1 - to właśnie robi sekcja (.init0)

    kolega dodał jeszcze sekcję (.init9) ze skokiem do main - chociaż gdy jej by nie było to też by może jakoś szło - ale może BoskiDialer nas oświeci - bo tu też nie mam pewności
  • #30
    BoskiDialer
    Poziom 34  
    mirekk36:
    ad 1/ Kod zerujący sekcję bss oraz ładujący sekcję data znajduje się gdzieś w okolicach .init3. Niestety kod zerujący sekcję bss już zakłada, że r1 jest równy zero, a więc z formalnego punktu widzenia zerowanie musi znaleźć się w .init0. Ze względu na obecność kodu zerującego bss oraz ładującego data stałymi z pamięci flash, skok do main znajduje się za init3, a zerowanie r1 przed init3.
    ad 2/ Pozbycie się biblioteki startowej czy jak jej tam powoduje usunięcie skoku do funkcji main z sekcji .init9.
    ad 3/ Wybacz, nie widzę "naked", widzę "noreturn", gdyż funkcja nie wraca, a więc kompilator nie odkłada rejestrów na stos, kod maleje.

    greatlukas:
    Czy jest tam co opisywać? __init0 jest funkcją wstawianą w sekcji init0 (wykonywanej zaraz po resecie), pierwsze dwa "out" ustawiają wskaźnik stosu, "clr" zeruje rejestr r1, który zgodnie z konwencją musi być równy 0, następny "out" zeruje SREG, aby zapewnić, że flaga I jest skasowana.

    __init9 natomiast to skok do funkcji main. Jest to obowiązkowe, ponieważ przy kompilacji została wybrana opcja nostartfiles, przez co kompilator sam tego skoku nie dołącza (tak jak nie dołącza tablicy wektorów przerwań o co głównie się rozchodzi). Sekcje .init mają ustalone miejsce w pliku wynikowym co wynika z domyślnego skryptu linkera, ponieważ funkcja main może znajdować się w dowolnym miejscu musi nastąpić skok z ostatniej sekcji init, a więc z init9. Teoretycznie można by się pozbyć funkcji main i wrzucić ją do __init9, jednak tego nie polecam, gdyż funkcja main teoretycznie może tworzyć ramkę stosu, co nie idzie jednak w parze z atrybutem "naked" (wymaganym dla __init9) - kod tworzący ramkę stosu znajduje się w prologu, "naked" jednak usuwa wszystkie prologi i epilogi funkcji, a więc ramka stosu nie została by poprawnie zbudowana.