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

[ATxmega64B3] - Czy dostęp do bitów w rejestrach GPIORx jest faktycznie atomowy

Bambzo 28 Lut 2013 18:36 1698 5
  • #1 11999360
    Bambzo
    Poziom 12  
    Witam

    W ostatnim czasie próbuję zapoznać się bliżej z procesorem ATxmega64B3. W ramach testów zająłem się tematem flag (czyli zmiennych bitowych), które mogą być zmieniane zarówno w pętli głównej jak i w przerwaniach. Jak wiadomo temat ten ściśle związany jest z zagadnieniem zapisu/odczytu atomowego. Ponieważ bitowy zapis/odczyt atomowy najłatwiej jest podobno uzyskać poprzez dostęp do rejestrów GPIORx (gdyż umieszczone w przestrzeni IO procesora) postanowiłem przetestować tę ścieżkę i porównać praktykę z teorią opisaną m.in w książce "Język C dla mikrokontrolerów AVR"
    Postanowiłem przetestować dwa rozwiązania:

    Rozwiązanie 1 - dostęp do GPIORx za pomocą makrodefinicji:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Jak widać na przedstawionych rozwinięciach tylko przy włączonej optymalizacji uzyskujemy atomowy zapis bitu do rejestru GPIOR0 (zapis za pomocą jednej instrukcji sbi). Gdy optymalizacja jest wyłączona zapis bitu do GPIOR0 wymaga dwóch operacji na rejestrze r18 (odczyt + modyfikacja). Nie jest więc to operacja atomowa.

    Rozwiązanie 2 - dostęp do GPIORx za pomocą wskaźnika:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    W tym rozwiązaniu otrzymałem jeszcze bardziej zaskakujące rezultaty. Zarówno przy włączonej jak i wyłączonej optymalizacji zapis bitu do rej. GPIOR0 nie jest atomowy.

    Oba przykłady zaczerpnięte są z w/w książki. Mam świadomość, że książka opisuje procesory ATmega a nie ATxmega, ale wydaje mi się, że w tym temacie sa one zgodne.

    Proszę o jakieś sugestie i komentarze, ponieważ jest to temat bardzo istotny. W książce przy opisie rozwiązania 2 wyraźnie pisze w ramce, że dostęp do tak zdefiniowanych flag odbywa się atomowo !!! Coś więc tutaj się nie zgadza. Być może ja robię jakiś błąd? A może w ATxmega należy postępować inaczej przy dostępie do GPIORx? Tylko dlaczego w takim razie w rozwiązaniu 1 przy włączonej optymalizacji jest OK?

    Wszystkie przykłady wykonałem za pomocą najnowszej wersji środowiska ATMEL STUDIO 6.

    Pozdrawiam i dziękuję z góry za opinie
  • #2 12000791
    tmf
    VIP Zasłużony dla elektroda
    Kwestia ustawień kompilatora, u mnie:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    czyli jak widać jest ok, na XMEGA256A3BU.
    Niemniej trzeba sobie zdawać sprawę z tego, że kompilator może ale nie musi wygenerować optymalny kod. Zauważ, że w książce nigdzie nie jest napisane, że w takiej sytuacji jest gwarancja, że użyta zostanie instrukcja sbi/cbi, a jedynie, że może się tak stać. Stąd też jeśli dostęp musi być atomowy, albo trzeba znać kompilator, którego się używa, albo zamknąć to w blok np. ATOMIC_BLOCK, albo użyć asemblera, albo, co jest dostępne na XMEGA użyć instrukcji LAT, LAS itd. które służą właśnie do realizacji semaforów.
  • #3 12001327
    Bambzo
    Poziom 12  
    Dziękuje za odpowiedź.

    Tak to by się zgadzało, że za odpowiedni kod odpowiada w tym przypadku odpowiednia konfiguracja kompilatora. Czy mógłbyś zasugerować jakie ustawienia (oprócz oczywiście stopnia optymalizacji) należałoby wprowadzić w kompilatorze aby wygenerować taki "atomowy" kod jaki uzyskałeś. Samo włączenie optymalizacji (-Os) za bardzo mnie nie urządza ponieważ utrudnione jest wtedy debugowanie a ja nie mam zbyt wiele czasu na eksperymentowanie. Najlepiej by było uzyskać w miarę jednakowy kod "dostępu atomowego" dla wersji DEBUG i RELEASE.

    Na chwilę obecną najlepszym dla mnie chyba rozwiązaniem jest jednak zastosowanie bloku ATOMIC_BLOCK bo wtedy jest absolutna pewność, że przerwanie nic nie namiesza. No ale wtedy nie wykorzystuje się do końca zalet jakie dają nam rejestry GPIOR.
  • #4 12001608
    tmf
    VIP Zasłużony dla elektroda
    Ja po prostu stosuję -Os, ponieważ ta opcja włącza dziesiątki różnych przełączników optymalizacji, nigdy nie miałem dosyć samozaparcia, aby to analizować. Jednak pamiętaj, aby nie debugować przy -O0 (wyłączonej optymalizacji) - wtedy generowany kod jest tak znacząco różny, że debugowanie traci sens. Najniższym akceptowalnym poziomem jest -O1. Z drugiej strony jeśli debugujesz kod krytycznie zależny od przerwań i atomowości dostępu, to lepiej debugować go przy takim poziomie optymalizacji, jaki będzie przy wersji release. To trochę utrudnia debugowanie, ale nie aż tak bardzo, a wątpliwe fragmenty zawsze można analizować na podglądzie asemblera. Można też zwiększyć poziom szczegółowości generowanych dla debugera informacji przez gcc, w Atmel Studio masz odpowiedni przełącznik, w tej chwili nie pamiętam nazwy.
  • #5 12001675
    BlueDraco
    Specjalista - Mikrokontrolery
    Zawsze można użyć mikrokontrolera, który ma jawne rejestry umożliwiające atomowe operacje logiczne na portach realizowane w sprzęcie - do wykonania takiej operacji wystarczy jeden zapis. :)

    Co do problemu ze wskaźnikiem - może się mylę, ale czy to nie jest przypadkiem tak, że w AVR instrukcje RMW mogą dotyczyć tylko "podprzestrzeni" IO, a przy dostępie przez wskaźnik kompilator musi używać operacji mogących działać na dowolnej lokacji? TMF - wyjaśnij łaskawie...
  • #6 12002102
    tmf
    VIP Zasłużony dla elektroda
    Na etapie optymalizacji kompilator zamienia instrukcje RMW na atomowe SBI/CBI, w porcie gcc dla AVR jest specjalna sekcja optymalizacji tego dotycząca.
    Co do rejestrów umożliwiających realizację operacji logicznych na sprzęcie to tak właśnie jest w przypadku GPIOR, problem raczej tkwi w samym języku c, który jak wiesz nie ma tego typu konstrukcji i wszystko jest załatwiane na etapie optymalizatora, lub przez makra ze wstawkami w asemblerze. Jak wcześniej pisałem, XMEGA (nie wszystkie) mają instrukcje wykonywane atomowo, oprócz SBI/CBI wykonywane na 32 bajtach IO, także instrukcje operujące na dowolnej komórce pamięci, także IO, typu LAS, LAC i LAT, ustawiające, kasujące lub zmieniające na przeciwny stan flagi. Także problemem nie jest sprzęt, ale raczej to jak przekazać, co chce się osiągnąć kompilatorowi. IMHO na dzień dzisiejszy jedynym pewnym rozwiązaniem jest wstawka w asemblerze. Prawdę mówiac nawet nie mam pomysłu jakiego konstruktu językowego użyć, żeby wyrazić intencję programisty - jeśli ktoś ma pomysł, to zawsze można powalczyć i spatchować kompilator. Ew. można zastosować w gcc konstrukcję __builtin, ale to właściwie niczym by się nie różniło od makra/funkcji/wstawki w asemblerze.
    Prościej jest z portami IO, gdzie są osobne rejestry CLR/SET/TGL, które wymuszają zmianę atomową niezależnie od widzimisie kompilatora.
REKLAMA