SAM3X8E (Arduino Due) Rejestry Pin IO

9

Jak działają rejestry IO Arduino Due? Arduino Uno tylko na ustawiony DDRx, a następnie PINxczytać, PORTxpisać, chciałbym zrobić to samo z Arduino Due, ale ma wiele więcej rejestrów, takich jak PIO_OWER, PIO_OSER, PIO_CODR, PIO_SODR, itd. Nie znajduję żadnej korespondencji pomiędzy Arduino Uno i Rejestry Arduino Due.

Istnieje również kilka przydatnych funkcji, takich jak pio_clear, pio_set, pio_geti innych, wszystko wyjaśnione tutaj:

http://asf.atmel.com/docs/3.19.0/sam3x/html/group__sam__drivers__pio__group.html

Myślę, że zrozumiałem, co robią te trzy wymienione funkcje, ale nie inne, na przykład:

pio_configure (Pio *p_pio, const pio_type_t ul_type, const uint32_t ul_mask, const uint32_t ul_attribute)

Nie mogę dowiedzieć się, co ul_attributei ul_typesą.

Alex
źródło
Oto klasa GPIO zaimplementowana dla AVR i SAM. Może dać wskazówkę, jak korzystać z rejestrów: github.com/mikaelpatel/Arduino-GPIO/blob/master/src/Hardware/…
Mikael Patel

Odpowiedzi:

7

Jeśli zapoznałeś się z sekcją 31 arkusza danych, dostępną tutaj , sprawy mogą stać się dla ciebie trochę jaśniejsze.

Oto podsumowanie tego, co wiem:

PIO oznacza Parallel Input / Output i oferuje funkcję odczytu i zapisu wielu portów rejestrów jednocześnie. Gdzie arkusz danych wspomina o rejestrze, na przykład PIO_OWER, biblioteka Arduino ma makra umożliwiające dostęp do nich w tym formacie REG_PIO? _OWER gdzie? ma wartość A, B, C lub D dla różnych dostępnych portów.

Nadal używam powolnej funkcji pinMode () Arduino do ustawiania wejścia / wyjścia na pinach, ponieważ sprawia, że ​​kod jest bardziej czytelny niż wywołania rejestrów oparte na akronimie, takie jak REG_PIOC_OWER = 0xdeadbeef, ale następnie używam rejestrów bezpośrednich, aby ustawić piny dla wydajność / synchronizacja. Jak dotąd nic nie zrobiłem z danymi wejściowymi, więc wszystkie moje przykłady są oparte na danych wyjściowych.

Do podstawowego użycia użyłbyś REG_PIO? _SODR, aby ustawić wysokie linie wyjściowe, a REG_PIO? _CODR, aby ustawić je na niskie. Na przykład REG_PIOC_SODR = 0x00000002 ustawiłby bit 1 (ponumerowany od zera) na PORTC (jest to cyfrowy pin 33) wysoki. Wszystkie pozostałe piny na PORTC pozostają niezmienione. REG_POIC_CODR = 0x00000002 ustawi bit 1 na PORTC na niski. Ponownie wszystkie pozostałe szpilki pozostaną niezmienione.

Ponieważ nadal nie jest to optymalne lub zsynchronizowane, jeśli pracujesz z danymi równoległymi, istnieje rejestr, który pozwala zapisać wszystkie 32 bity portu za pomocą jednego wywołania. Są to REG_PIO? _ODSR, więc REG_PIOC_ODSR = 0x00000002 ustawi teraz bit 1 na PORTC high, a wszystkie inne bity na PORTC zostaną natychmiast ustawione na niski w pojedynczej instrukcji CPU.

Ponieważ jest mało prawdopodobne, abyś kiedykolwiek znalazł się w sytuacji, w której musisz ustawić wszystkie 32 bity portu jednocześnie, musisz zapisać bieżącą wartość pinów, wykonać operację AND, aby zamaskować te, które chcesz zmienić, wykonaj operację LUB, aby ustawić te, które chcesz ustawić wysoko, a następnie wykonaj zapis i jeszcze raz, a to nie jest optymalne. Aby temu zaradzić, sam procesor wykona dla Ciebie maskowanie. Istnieje rejestr o nazwie OWSR (rejestr stanu zapisu wyjściowego), który zamaskuje wszystkie bity, które zapisujesz do ODSR, które nie pasują do bitów ustawionych w OWSR.

Więc teraz, jeśli wywołamy REG_PIOC_OWER = 0x00000002 (ustawia to bit 1 OWSR na wysoki) i REG_PIOC_OWDR = 0xfffffffd (to usuwa wszystkie bity oprócz bitu 1 OWSR), a następnie ponownie wywołamy REG_PIOC_ODSR = 0x00000002, tym razem zmieni tylko bit 1 PORTC i wszystkie inne bity pozostają niezmienione. Zwróć uwagę na fakt, że OWER włącza wszystkie bity, które są ustawione na 1 w zapisywanej wartości, oraz że OWDR wyłącza wszystkie bity, które są ustawione na 1 w zapisywanej wartości. Chociaż zrozumiałem to, kiedy to czytałem, nadal popełniłem błąd w kodzie podczas pisania mojego pierwszego kodu testowego, myśląc, że bity wyłączone OWDR, które nie były ustawione na 1 w wartości, którą napisałem.

Mam nadzieję, że dzięki temu przynajmniej zrozumiałeś PIO właściwego procesora. Przeczytaj i zagraj, a jeśli masz dodatkowe pytania, postaram się na nie odpowiedzieć.

Edycja: Jeszcze jedna rzecz ...

Skąd wiesz, które bity PORTÓW odpowiadają którym cyfrowym liniom należnym? Sprawdź to: Due Pinout

Mick Waites
źródło
3

Występuje dość prosta równoważność podstawowego bezpośredniego dostępu do pinów. Poniżej znajduje się przykładowy kod, który pokazuje, jak ustawić pin wysoki, a następnie niski. Pierwszy dotyczy Arduino Due, drugi dotyczy Arduino Uno / Mega / etc.

const unsigned int imThePin = 10; //e.g. digital Pin 10

#ifdef _LIB_SAM_

    //First lets get the pin and bit mask - this can be done once at the start and then used later in the code (as long as the variables are in scope
    Pio* imThePort = g_APinDescription[imThePin].pPort; 
    unsigned int imTheMask = g_APinDescription[imThePin].ulPin; 

    //Lets set the pin high
    imThePort->PIO_SODR = imTheMask;
    //And then low
    imThePort->PIO_CODR = imTheMask;

#else

    //First lets get the pin and bit mask - this can be done once at the start and then used later in the code (as long as the variables are in scope
    volatile unsigned char* imThePort = portOutputRegister(digitalPinToPort(imThePin)); 
    unsigned char imTheMask = digitalPinToBitMask(imThePin);

    //Lets set the pin high
    *imThePort |= imTheMask;
    //Now low
    *imThePort &= ~imTheMask;

#endif

Wszystko, co jest do tego potrzebne, powinno być domyślnie dołączone - a jeśli nie, #include <Arduino.h>powinno wystarczyć, aby to osiągnąć.

W rzeczywistości dostępne są funkcje, które można wywołać, gdy Piopojawi się wskaźnik do wykonania ustawień / usuwania / rezystorów pullup / itp. używając nieco czystszych wywołań funkcji. Pełna lista znajduje się w plik nagłówka.

Tom Carpenter
źródło
0

To przykład kodu, który miga diodą na pinie 33. Kod pożyczony z góry - wielkie dzięki za bardzo pomocne wyjaśnienia :) To początek projektu rozmowy z ekranem dotykowym TFT z zrzutem 16-bitowych kolorowych pikseli, które potrzebują szybki dostęp do portów. Myślę, że mam odpowiedni kod - szczególnie linię, która ustawia pin na niskim poziomie. Dioda LED szczęśliwie miga.

void setup() 
{
  pinMode(33, OUTPUT); 
  REG_PIOC_OWER = 0x00000002; 
  REG_PIOC_OWDR = 0xfffffffd; 
}

void loop() 
{
  REG_PIOC_ODSR = 0x00000002; 
  delay(1000);             
  REG_PIOC_ODSR = 0x00000000;    
  delay(1000);   
}
James Moxham
źródło