czwartek, 22 marca 2018

PIC32MM - I/O podstawy.

W artykule opiszę podstawy sterowania pinami w mikrokontrolerach 32-bitowych firmy Microchip . W szczególności skupię się na PC32MM0256GPM048 czyli moim ulubionym obecnie mikrokontrolerem 32-bitowym. Opisywałem już te zagadnienia przy okazji zabaw z PIC24 , wiele rzeczy będzie wspólnych. Migracja z 8 czy 16 bitów na 32-bity w produktach Microchipa jest bardzo płynna i to jest ogromna zaleta ekosystemu PIC. Stanowi to bardzo duże ułatwienie w szczególności dla hobbystów. Mikrokontrolery PIC32 są znacznie prostsze w poznaniu niż np. ARM-y.



Najważniejsze rejestry służące do konfiguracji portów wejścia/wyjścia w mikrokontrolerach PIC32 to:
  • TRISx - ustawia port jako wejście lub wyjście
  • PORTx - odczyt/zapis faktycznej wartości portu
  • LATx - rejestr zatrzaskowy portu (zapis ostatniej wartości portu lub odczyt zapisanej wartości)
  • ODCx - ustawia piny wyjściowe jako zwykłe piny lub z otwartym drenem
  • ANSELx - umożliwia odłączenie niektórych pinów od sekcji analogowej, tam gdzie jest to wymagane. A to czy jest to wymagane na konkretnym pinie czy nie dowiemy się z tego rejestru :)
(gdzie x - oznaczenie literowe portu A,B,C,D..)

Konfiguracja portów jako wejścia lub wyjścia
Każdy port (port to zbiór pojedynczych pinów), posiada swój rejestr TRISx, który odpowiada za ustawienie czy określone piny są wejściem czy wyjściem. Jeżeli do bitu powiązanego z określonym pinem jest zapisane "1" pin jest wejściem, natomiast jeżeli zapiszemy "0", wybrany pin staje się wyjściem.
To jest dokładnie odwrotnie niż w AVR-ach.
Port TRISx może być również oczywiście odczytany, dostaniemy wtedy ostatnio zapisaną tam wartość.
Po włączeniu zasilania, wszystkie piny są skonfigurowane jako wejścia.!!

Zapis/odczyt wartości portu
Jeśli chodzi o zapis i odczyt portów wejścia/wyjścia mamy do dyspozycji dwa rejestry PORTx oraz LATx. Odczytując rejestr PORTx, odczytujemy bezpośrednio wartość logiczną panującą na pinach portów danej chwili, zapisując do tego rejestru zmieniamy bezpośrednio wartości pinów portu.
Zapis do rejestru PORTx powoduje również zapis do odpowiadającego mu rejestru LATx.

Rejestr LATx, można odczytywać jakby był to zwykły rejestr, w którym jest duplikat ostatnio zapisanej wartości do portu, zapis do LATx powoduje zmianę stanów na pinach portu, tak samo jak zapis do rejestru PORTx, ale odczyt z tego rejestru jest odporny na zakłócenia na liniach portu, bo nie jest fizycznie podczas tej operacji czytany port, tylko jego rejestr, to znaczy, że nie możemy odczytać napięcia panującego faktycznie na pinie, jedynie wartość jaką ostatnio zapisaliśmy.

Podsumowując:
  • Zapis do portu możemy dokonywać przez zapis do PORTx lub LATx
  • Odczyt wartości z końcówek portu dokonujemy przez odczyt PORTx
  • Odczyt ostatnio zapisanej wartości do portu, dokonujemy przez odczyt rejestru LATx
  • jeśli chcemy uzyskać podwyższoną odporność na zakłócenia zapis i odczyt realizujmy za pomocą rejestru LATx .

Konfiguracja portów jako cyfrowe lub analogowe
Wszystkie porty które mogą być wejściami analogowymi domyślnie nimi są, ponieważ rejestr ANSELx, który odpowiada za to ustawienie, domyślnie ma zapisaną wartość 0xFFFF. Jeżeli chcemy używać portów analogowych np. z cyfrowymi peryferiami, takimi jak Timery czy UART, musimy ustawić je jako cyfrowe przez wyzerowanie określonych bitów rejestru ANSELx, dodatkowo kiedy porty są ustawione jako analogowe wejścia, próba odczytania ich wartości przez rejestr PORTx skończy się pobraniem samych zer, tak jakby na pinach panował logiczny stan 0.

W przypadku mikrokontrolera PIC32MM0256GPM048 piny analogowe , które wymagają odłączenia od sekcji analogowej jeśli chcemy je używać jako np wyjścia cyfrowe są oznaczone w datasheet jako ANx :

Z pliku nagłówkowego dla PIC32MM0256GPM048, p32mm0256gpm048.h wynika, że piny podpięte do sekcji analogowej to :

Na porcie A : RA0,RA1,RA2,RA3
Na porcie B :RB0,RB1,RB2,RB3,RB4
Na porcie C :RC0,RC1,RC5,RC8

i tu UWAGA !!! jest jak sądze błąd/niedopatrzenie Microchipa ponieważ w pliku nagłówkowym nie uwzględniono np pinów RA6,RB13,RB14 i RB15

A poniżej podaję adekwatne nazwy bitów w rejestrze ANSELx uwzględnione w pliku nagłówkowym (bez RA6,RB13,RB14 i RB15) , potem w przykładzie pokażę jak tego używać.

RA0 --> ANSA0
RA1 --> ANSA1
RA2 --> ANSA2
RA3 --> ANSA3


RB0 --> ANSB0
RB1 --> ANSB1
RB2 --> ANSB2
RB3 --> ANSB3
RB4 --> ANSB4


RC0 --> ANSC0
RC1 --> ANSC1
RC5 --> ANSC5
RC8 --> ANSC8


Do rejestrów możemy zapisywać całe wartości portów, lub odwoływać się do indywidualnych pinów. Do dyspozycji mamy wygodne makra i struktury zdefiniowane w pliku nagłówkowym naszego mikrokontrolera . Plik znajduje się w katalogu kompilatora XC32. W przypadku Linuxa jest dostępny pod ścieżką : 
 /opt/microchip/xc32/v2.05/pic32mx/include/proc/p32mm0256gpm048.h
W programie nie musimy jednak pamietać nazwy pliku nagłówkowego , includujemy magiczny skrót xc.h i już mamy dostęp do naszego pliku.

Przykłady :

Ustawiamy kierunek czyli wejście lub wyjście za pomocą rejestru TRISx :

TRISA = 0x001F ;// ustawiamy 5 pierwszych bitów rejestru na 1 czyli pięć pierwszych pinów portu A będzie wejściami
TRISA = 0x0000;// ustawiamy wszystkie bity rejestru na 0 czyli wszystkie piny portu A są wyjściami

za pomocą zdefiniowanych struktur :

TRISAbits.TRISA1 = 1 ; // ustaw drugi bit rejestru na 1 czyli na pinie RA1 mamy wejście
TRISAbits.TRISA1 = 0 ; // ustaw drugi bit rejestru na 0 czyli na pinie RA1 mamy wyjście.


Ustawiamy stan na wyjściach za pomocą rejestru PORTx : 

PORTA = 0x001F ; // ustawiamy 5 pierwszych bitów rejestru na 1 czyli na pięciu pierwszych  pinach portu A mamy stan wysoki
PORTA = 0x0000 ; // ustawiamy bity rejestru na 0 czyli na wszystkich pinach portu A mamy stan niski

za pomocą zdefiniowanych struktur :

PORTAbits.RA1 = 1 ; // ustaw drugi bit rejestru na 1 czyli na pinie RA1 mamy stan wysoki
PORTAbits.RA1 = 0 ; // ustaw drugi bit rejestru na 0 czyli na pinie RA1 mamy stan niski.

Możemy również zastosować zapis analogicznie jak w AVR-ach :

PORTA | = (1<<_PORTA_RA1_POSITION) ; // ustaw drugi bit rejestru na 1 czyli na pinie RA1 mamy stan wysoki
PORTA & = ~ (1<<_PORTA_RA1_POSITION) ; // ustaw drugi bit rejestru na 0 czyli na pinie RA1 mamy stan niski.

Ustawiamy stan na wyjściach za pomocą rejestru LATx : 

Wartość jaką wpiszemy w rejestr zatrzaskowy LATx jest przepisywana automatycznie do rejestru PORTx.

LATA = 0x001F ; // ustawiamy 5 pierwszych bitów rejestru na 1 czyli na pięciu pierwszych  pinach portu A mamy stan wysoki
LATA = 0x0000 ; // ustawiamy bity rejestru na 0 czyli na wszystkich pinach portu A mamy stan niski

za pomocą zdefiniowanych struktur :

LATAbits.LATA1 = 1 ; // ustaw drugi bit rejestru na 1 czyli na pinie RA1 mamy stan wysoki
LATAbits.LATA1 = 0 ; // ustaw drugi bit rejestru na 0 czyli na pinie RA1 mamy stan niski. 

Odczyt wartości za pomocą rejestru PORTx :
int val ;
val = PORTA ; // zapisz wszystkie wartości pinów portu A do zmiennej val
val = PORTAbits.RA1 ; // zapisz tylko wartość pinu RA1 do zmiennej val

Odczyt wartości za pomocą rejestru LATx :
int val ;
val = LATA ; // zapisz wszystkie wartości rejestru do zmiennej val
val = LATAbits.LATA1 ; // zapisz tylko wartość wybranego bitu z rejestru do zmiennej val


Rejestr ANSELx - odłączenie sekcji analogowej od pinu który chcemy używać jako np.wyjście cyfrowe :

W przypadku niektórych pinów wymienionych wyżej dla PIC32MM0256GPM048 (dla 64 nóżek będzie ciut inaczej ale to doczytamy sobie jednym spojrzeniem na rejestr ANSELx w datasheet), wymagane jest odłączenie sekcji analogowej !! . Jeśli tego nie zrobimy a ustawimy np. za pomocą rejestru TRISx pin jako wyjście i chcemy je mieć jako cyfrowe to wyjście nam nie zadziała. Poniżej przykład sterowania bitami w rejestrze ANSELx :

ANSELAbits.ANSA1 = 1 ; // pin RA1 podłączony do sekcji analogowej (nie możemy działać cyfrowo)
ANSELBbits.ANSB2 = 0 ; // pin RB2 odłączony od sekcji analogowej (możemy działać cyfrowo)

Na koniec ważna uwaga dotycząca pinu RA3, jest to pin wewnętrznie podłączony do oscylatora RC. Jeśli chcemy ten pin wykorzystywać jako normalny pin I/O musimy odłączyć go od oscylatora.
A zrobimy to tak : 

najbardziej prosta  i bezstresowa metoda za pomocą MCC
w panelu MCC opcja Clock Output Pin Configuration powinna być na OSCO pin operates as a normal I/O i już po bólu.


Reasumując dostęp do rejestrów I/O i operowanie na nich w PIC32 jest bardzo proste i sympatyczne. Szybko można się z tym zapoznać i polubić. Przyczynia się do tego ładne opisanie rejestrów definicjami i strukturami zawarte tylko w jednym pliku nagłówkowym do którego dostęp z poziomu programu jest automatyczny za pomocą includowania xc.h
Prezentowana w artykule specyfika rejestrów jest typowa dla wszystkich PIC32.

Na koniec artykułu zapodam przykładowy program w postaci migania diodą LED w którym pokażę dokładnie jakie należy podjąć kroki aby zasterować wybranym pinem. W programie rozważymy "najtrudniejszy" przypadek czyli pin RA3. Działania swoje oprę na mojej ulubionej obecnie płytce developerskiej PIC32MM.




Pozdrawiam
picmajster.blog@gmail.com


Linki:
PIC32MM - Family
PIC32 - I/O ports

GitHub:
Projekt do MPLABX IDE

10 komentarzy:

  1. Nie jest groźne a nawet całkiem sympatyczne. Ja sam nie wiem kiedy się obejrzałem i znalazłem się z 8 na 32-bitach :)

    OdpowiedzUsuń
  2. czekam na omówienie modułów SCCP i MCCP

    OdpowiedzUsuń
  3. Ciekawy procek to i ciekawe moduły :)

    Pozdrawiam
    PICmajster

    OdpowiedzUsuń
  4. Witam mam pytanie a jak jest tak naprawdę z tym darmowym środowiskiem MPLABX IDE ? Mam ochotę poznać mikrokontrolery Pic32 . Wcześniej trochę bawiłem się pic16 jednak cały czas myślę w jakim stopniu MPLABX w wersji free spowalnia mój program i czy ma to tez takie znaczenie przy picach32

    OdpowiedzUsuń
  5. A małe sprostowanie nie tyle z środowiskiem co z kompilatorem np XC8 czy XC32

    OdpowiedzUsuń
  6. MPLABX -IDE to środowisko i ono Tobie nic nie spowolni jest całkowicie free bez żadnych ograniczeń. Do środowiska instalujesz kompilator XC32 w wersji free (domyślnej). Wynikowy kod będzie zajmował Tobie ciut więcej pamięci Flasha, niż wersja płatna PRO. Z punktu widzenia zasobów MCU nie ma to większego znaczenia bo PIC32 mają dużą pamięć flash i nie odczujesz tego w żaden sposób. Jeśli chcesz podoktoryzować się w porównaniach szybkości wykonywania kodu między wersją kompilatora XC32 free a PRO to masz możliwość bezpłatnej 60 dniowej hulanki na wersji PRO ale w/g mnie jest to niepotrzebna strata czasu. Nie jest mi potrzebna do szczęścia wersja PRO, wersja free robi swoje. Przestań myśleć nad takimi aspektami bo cię głowa rozboli :) zacznij działać. MCU PIC32 są cool :) ale żeby wyrobić sobie zdanie trzeba je poznać :) Proponuję Tobie zainteresować się na początek serią PIC32MM w wydaniu GPM (Part Number: DM320107 - PIC32MM USB Curiosity Development Board),potem odpytaj mocniejszą serię MX (Part Number: DM320103 - Curiosity PIC32MX470 Development Board). Na płytkach developerskich masz PICkit3, nie musisz więc oddzielnie kupować programatora.Płytki kosztują ok 100 zł są dostępne również u nas. Płytki które Tobie podałem są bardzo fajne mają złącza do modułów Mikroelektroniki a to już daje nieograniczone możliwości :) Jeśli masz jakieś problemy pomogę, przetarłem trochę szlak :)

    OdpowiedzUsuń
  7. Ok dzięki za odpowiedź. A więc zaczynam przygodę z PIC32 i czekam na kolejne artykuły na ich temat .

    OdpowiedzUsuń
  8. Obecnie czekam na dostawę moich poprawionych płytek developerskich do PIC32MM,polutuję sobie kilka i będziemy jechać z koksem dalej, rozpoznamy interfejsy etc.
    Z tego co widzę Microchip obecnie zmienia oprawę i technologię w zakresie swojej strony www, ciekawe czy za tymi zmianami pójdą inne ciekawsze rzeczy :)

    Pozdrawiam
    PICmajster

    OdpowiedzUsuń
  9. Super wpis. Bardzo pomocne informacje

    OdpowiedzUsuń