Skocz do zawartości
Zaloguj się, aby obserwować  
Elvis

[Test/recenzja] Embedded Linux - test modułu MMnet1001 cz.3 - Porty I/O, dostęp do peryferiów

Pomocna odpowiedź

Jest to trzecia i ostatnia część prezentacji modułu MMnet1001.

W części pierwszej opisywałem dostęp do portów I/O.

Przykłady od producenta

Przykładowy program bazował na przykładach dostarczonych przez producenta (Propox).

Działanie programu jest nieco dziwne - do portów I/O odwołujemy się przez system plików. Nie są to prawdziwe pliki, a jedynie "wirtualne". Jest to ogólna zasada w Linuxie - do peryferiów odwołujemy się przez pliki.

W pliku led_v1.c znajdziemy opisywany program. Jego działanie obrazuje oscylogram poniżej:

Porównywać będziemy impulsy o poziomie 0. Jak widać aktualna wersja potrafi wygenerować impuls o szerokości 25µs, co odpowiada częstotliwości 20kHz. Jest to nieco lepiej niż w poprzednio testowanym programie (ok. 14kHz), ale nadal dużo poniżej możliwości małych mikrokontrolerów.

Warto jeszcze zwrócić uwagę na jeden fragment programu - po wygenerowaniu paczki (1000) impulsów, program czeka przez pewien czas wywołując

usleep(1000);

. Jest to bardzo ważne - bez opóźnienia system ma problemy z działaniem.

Mapowanie rejestrów

Dostęp do portów I/O przez system plików jest nieprawdopodobnie wolny. Pozostaje poszukać innej metody.

W linuxie nie można bezpośrednio odwoływać się do dowolnego adresu w pamięci.

Można jednak wykorzystać funkcję mmap, aby bezpośrednio dostać się do rejestrów. Tą samą metodą można odwołać się do innych układów peryferyjnych mikrokontrolera, np. PWM.

Na początek musimy poznać trochę procesor oraz adresy jego rejestrów.

Dokumentacja dostępna jest na stronie producenta: http://www.atmel.com/dyn/products/datasheets.asp?family_id=605

Najważniejsze to ogólny opis procesora: http://www.atmel.com/dyn/resources/prod_documents/6221s.pdf

Oraz dokładny opis: http://www.atmel.com/dyn/resources/prod_documents/doc6221.pdf

Nie musimy teraz wszystkiego czytać, ale warto wiedzieć, że adres rejestru portu PIOA znajdziemy w pierwszym dokumencie, a wszystkie wykorzystane rejestry oraz działanie portów I/O wyjaśnione jest w drugim.

Program testowy bazuje na przykładzie znalezionym w internecie - po drobnych poprawkach nawet działa.

Na początek otwieramy urządzenie reprezentujące pamięć (potrzebujemy go, aby wywołać mmap):

open("/dev/mem", O_RDWR | O_SYNC)

Następnie wywołujemy funkcję mmap:

mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, AT91C_BASE_PIOA)

Warto zwrócić uwagę na parametr AT91C_BASE_PIOA. Jest to stała zdefiniowana następująco:

#define AT91C_BASE_PIOA           0xFFFFF000

Jej wartość to adres interesujących nas rejestrów. Po wywołaniu mmap dostaniemy wskaźnik, który będzie odpowiadał adresowi 0xFFFFF000 pamięci fizycznej. Za pomocą zwykłej arytmetyki wskaźników możemy się już odwoływać do fizycznych rejestrów procesora.

void write_pio(unsigned int offset, const unsigned int value)
{
  *((int*)(((char*)pin_addr) + offset)) = value;
}

unsigned int read_pio(unsigned int offset)
{
  return *((int*)(((char*)pin_addr) + offset));
}

Mając dostęp do rejestrów możemy już napisać funkcje sterujące liniami I/O:

int pio_set_gpio_output(unsigned pin, int value) - ustawia kierunek portu (wejście lub wyjście)

int pio_set_value(unsigned pin, int value) - ustawia stan linii portu

int pio_get_value(unsigned pin) - odczytuje stan linii

W załączonym programie led_v2.c znajdziemy pełny kod programu.

Poniżej rezultat działania:

Tym razem prędkość działania jest znacznie wyższa. Impuls ma szerokość poniżej 1µs (ok. 880ns), co odpowiada częstotliwości ok. 568kHz.

To już lepiej, 28x szybciej niż poprzednio.

Optymalizacja

Okazuje się, że wywoływanie funkcji pio_set_value zajmuje sporo czasu.

Zoptymalizujemy kod i będziemy bezpośrednio odwoływać się do wskaźników.

Aby wyzerować linię:

*pio_c0dr = 0x0200;

-

Żeby ustawić:

*pio_s0dr = 0x0200;

Teraz kod działa następująco:

Jak widać szerokość impulsu spadła do 80ns, czyli uzyskaliśmy częstotliwość 6,25MHz.

Wreszcie możemy pościgać się z atmegą 🙂

Podsumowując, Linux nie jest przeszkodą w szybkim dostępie do układów peryferyjnych. Można mieć wielozadaniowy system operacyjny, a jednocześnie niskopoziomowy dostęp do sprzętu.

led_v3.c

led_v2.c

led_v1.c

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

Zaloguj się, aby obserwować  

×
×
  • Utwórz nowe...