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

_SFR_TO_ADDR i _BV. Do czego służą i jak działają makra? W Winavr.

antyBrygadaW 29 Wrz 2007 18:55 2477 6
  • #1 4332382
    antyBrygadaW
    Poziom 15  
    Posty: 190
    Pomógł: 1
    Ocena: 9
    do czego służą i jak działają makra _SFR_TO_ADDR i _BV w winavr?
  • Pomocny post
    #2 4334021
    al777
    Poziom 27  
    Posty: 646
    Pomógł: 105
    Ocena: 83
    Jeśli to pierwsze makro to miało być _SFR_IO_ADDR to wyjaśnienie jest następujące : w plikach nagłówkowych avr-lib wszystkie rejestry specjalne zdefiniowane są adresami w przestrzeni adresowej pamięci. Jak ktoś używa asemblera, to do instrukcji typu in, out, cbi, sbi, ... potrzebne są mu adresy w przestrzeni wejścia-wyjścia i to makro zamienia jedne na drugie (tzn. przestrzeń adresową w przestrzeń IO : SFR->IO, np.
    out _SFR_IO_ADDR(PORTD), r24
    .
    Co do drugiego makra - w plikach nagłówkowych flagi (pojedyncze bity) są zdefiniowane w ten sposób, że podany jest ich numer w bajcie. Ale żeby posłużyć się taką definicją potrzebna jest liczba, w której tylko bit odpowiadający tej pozycji ma wartość 1, a pozostałe są równe 0, czyli np. numer bitu 3 zamieniany jest na (binarnie) 0000 1000. Tak właśnie działa _BV. Przykład - ustawianie bitu 7 w porcie A :
    PORTA |= _BV(PA7);
    .

    Wszystkie te mądrości są oczywiście w dokumentacji kompilatora, ale wykopywanie ich stamtąd jest dość żmudne :D . Polecam jakąś książkę, której autor namęczył się właśnie po to, żeby zebrać w jednym miejscu informacje najbardziej przydatne, np. "Mikrokontrolery AVR - programowanie w języku C" Andrzeja Witkowskiego.
  • #3 4335049
    antyBrygadaW
    Poziom 15  
    Posty: 190
    Pomógł: 1
    Ocena: 9
    kurczę trochę nie łapię... to w niektórych rozkazach (w tekscie programu w C) stosuje się adres w pamięci ram, a w niektórych (w kodzie assemblera) adres w przestrzeni IO? nie przeczytałem jeszcze pdfa do AVR więc może czegoś nie wiem...

    mam jeszcze jedno pytanie (mam tą książkę, ale uważam, że jest marna) chcę napisać program w C który będzie miał procedury przerwań w assemblerze, jak się do tego przybrać? czy wystarczy dyrektywą .global ustalić jakąś nazwę procedury w assemblerze i wywołać ją (jak?) w procedurze przerwania w C?
  • #4 4339103
    al777
    Poziom 27  
    Posty: 646
    Pomógł: 105
    Ocena: 83
    Większość tego co napisałem pochodzi właśnie z tej książki, zapewniam również że widziałem gorsze (i droższe) - więc pozwolę sobie nie zgodzić się z oceną. Ale do rzeczy.
    Jeśli to drugie pytanie było do mnie to szczerze i uczciwie przyznam że nie wiem, bo przy AVR-ach nigdy nie brakowało mi szybkości i nie musiałem klepać w asm, a bajkopisarstwa uprawiał nie będę. Przy '51 robiłem to tak, że funkcję obsługi przerwania deklarowałem jako "extern" w pliku C, a kod pisałem w pliku ASM należącym do tego samego projektu, i kompilator (Raisonance) się na to godził, ale podejrzewam że tu tak nie będzie można.
    Gdybym miał zgadywać, to rozwiązałbym to w taki sposób : w pliku C wogóle nie piszę nic o obsłudze przerwania, a w ASM robię tak :
    
    .org 5 ;to jest wektor dla przepelnienia T0
       rjmp t0_ovf
    (...)
    t0_ovf:
       ; tu napisac kod obslugi
       reti
    

    ale podkreślam jeszcze raz że to hipoteza do sprawdzenia, a sam nie mam teraz czasu nad tym siedzieć i główkować dlaczego nie działa (nowy pomysł zawsze na początku nie działa, a jak działa to nie tak jak trzeba :D ).
    Jak ktoś ma chęć i cierpliwość niech popróbuje i da znać co mu wyszło, ale proszę na mnie piesków nie wieszać jak się nie uda - uprzedzałem że to tylko taki pomysł.

    Dla moderatorów którzy będą chcieli krytykować mnie za pisownię - w kodzie programu unikam polskich znaczków bo większość kompilatorów źle to znosi.
  • #5 4339190
    BoskiDialer
    Poziom 34  
    Posty: 1530
    Pomógł: 353
    Ocena: 42
    co do _sfr_io_addr:
    - głównie chodzi o to, że standardowa przestrzeń IO ma 64 komórki (dostępne przez instrukcje in/out), ale dostępne również w przestrzeni pamięci ram (przesunięcie +0x20).. w nowszych/większych procesorach te 64 komórki może być za mało - wtedy dodatkowe komórki są pod wyższymi adresami w przestrzeni pamięci, ale oznacza to, że są nie osiągalne przez in/out. Tak więc do każdego rejestru można odwoływać się przez dostęp do pamięci (polecenia ld/st - zawsze 2 cykle) lub do przestrzeni io (in/out - zawsze 1 cykl).. można np wpisywać wartość do rejestrów tak:
    >> st PORTA, r24
    ale jeśli zalezy na optymalizacji kodu i rejestr jest dostępny przez in/out, to można go zapisać tak:
    >> out _SFR_IO_ADDR(PORTA), r24
    zastosowanie _SFR_IO_ADDR jest po to, żeby przesunąć wartość podawaną do out o 0x20 w dół.. równoważny zapis (aczkolwiek nie polecam - czytelność):
    >> out PORTA-0x20, r24

    Co do kodu i przerwań - jakkolwiek kod C może być skompilowany do poziomu asemblera, wiązanie wektorów przerwań odbywa się na poziomie linkera (wiązanie z plikiem objektowym układu). Najważniejsze nagłówki i deklaracje są w <avr/io.h> i <avr/interrupt.h> - można je includować tak samo do kodu C jak i do kodu asemblera.
    W C wektory przerwań deklaruje się przeważnie tak:
    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    SIGNAL(SIG_INTERRUPT1/* lub inne przerwanie*/)
    {
        /* tu kod */
    }

    a równie dobrze można z poziomu asemblera:
    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    .global SIG_INTERRUPT1
    SIG_INTERRUPT1: /* lub inne przerwanie*/
        /* tu kod */
        reti
    

    Taka funkcja będzie bezpośrednio wywoływana przez skok z tablicy wektorów przerwań. Nie wolno tutaj zapomnieć o odkładaniu rejestrów i zachowywaniu rejestru stanu.. ale co tu dużo mówić...
  • #6 4340376
    al777
    Poziom 27  
    Posty: 646
    Pomógł: 105
    Ocena: 83
    Właśnie ze względu na konieczność roztrząsania wielu kwestii (np. odkładanie rejestrów roboczych na stos), o których "pamięta za mnie" kompilator C, do asemblera sięgam w ostateczności.
    Jeśli już koniecznie trzeba optymalizować, to chyba lepiej napisać kod w C, pozwolić go skompilować do asemblera (jest taka opcja, w tej chwili nie pamiętam nazwy), przejrzeć i ewentualnie poprawić ten wynik (nie dotykając sekcji których się nie rozumie) i "podać dalej" tzn. na asembler i linker.
    Dlatego podziwiam ludzi którzy potrafią i chcą pisać w asemblerze.
  • #7 4345745
    BoskiDialer
    Poziom 34  
    Posty: 1530
    Pomógł: 353
    Ocena: 42
    Z rejestrami nie ma tak źle - zaledwie SREG + używane rejestry: SREG to 4 instrukcje (push,in / out,pop), na każdy rejestr po 2 (push / pop).
    W moim przypadku kod do przerwań zdecydowanie częściej pisze od razu w asemblerze - na ogół mają być wykonywane błyskawicznie i takie też są. Często są też zależności czasowe etc...
    Właściwie kwestia przyzwyczajenia i można śmiało pisać moduły asemblera wywoływane z poziomu C jak i na odwrót moduły C wywoływane z poziomu asemblera - w przypadku wektorów przerwań trzeba jednak wtedy odłożyć więcej rejestrów (r0-1, r18-r27,r30-r31 dodatkowo r1 musi być wyzerowany) ale i do tego da się przyzwyczaić..

Podsumowanie tematu

✨ Makro _SFR_IO_ADDR w WinAVR służy do konwersji adresów rejestrów specjalnych z przestrzeni pamięci RAM na adresy w przestrzeni wejścia-wyjścia (IO), co jest istotne przy używaniu instrukcji asemblerowych takich jak in, out, cbi, sbi, które operują na przestrzeni IO. Standardowa przestrzeń IO obejmuje 64 komórki dostępne przez instrukcje in/out, natomiast rejestry są również dostępne w przestrzeni pamięci RAM z przesunięciem o 0x20. Makro to umożliwia optymalizację kodu, pozwalając na szybszy dostęp do rejestrów przez instrukcje IO zamiast wolniejszych instrukcji pamięciowych ld/st. Makro _BV (bit value) przekształca numer bitu na wartość binarną z ustawionym tylko tym bitem (np. bit 3 na 0x08), co ułatwia manipulację pojedynczymi bitami w rejestrach, np. ustawianie bitu w porcie. Dyskusja porusza także kwestie integracji kodu asemblerowego z procedurami przerwań w C, wskazując na konieczność odpowiedniego zarządzania rejestrami i wektorami przerwań, a także na różnice w dostępie do rejestrów w przestrzeni IO i pamięci RAM. Zalecane jest ostrożne podejście do pisania asemblera, korzystanie z wygenerowanego kodu asemblerowego przez kompilator C oraz świadome zarządzanie rejestrami w procedurach przerwań dla optymalizacji i poprawności działania.
Wygenerowane przez model językowy.
REKLAMA