Wgranie programu
W tego typu Atmegach z wgranym bootloaderem FLIP, kod wgrywa się na układ za pomocą programu o takiej samej nazwie dodatkowo należy się zaopatrzyć w kabel USB. Jest on dostępny na stronie producenta. Do wgrywania wykorzystuje się plik HEX który powstaje w procesie kompilacji kodu na innym programie.
Sposób obsługi programatora oraz tworzenie nowego pliku projektu opisano na stronie Leon Instruments, Link zamieściłem w sekcji głównej ATmega dla tego bloga.
Opis portów we/wy
W tym poście przedstawię sposób konfiguracji portów wejścia wyjścia.
Każdy z portów składa się z 8 pinów. Pin może być ustawiany z 8 bitów. Wykorzystywany przeze mnie układu posiada porty A, B, C, D, E, F, każdy z nich ma 8 pinów o numerach od 0 do 7. Sposoby odwołania się polegają na podaniu numer czy to w formacie binarnym, szesnastkowym czy dziesiętnym, poprzez podanie maski, która jest kolejną potęgą liczby 2 dla następnych wyprowadzeń, lub z wykorzystaniem zdefiniowanych wcześniej nazw w pliku avr/io.h.
Przykładowe ustawiania pinu przedstawiłem poniżej:
PORTA.DIR = PIN2_bm; //bit mask PORTB.DIR = (1<<PORT4); //po nazwie, operacja przesiniuęcia biowego PORTC.DIR = 0b00000011; //za pomocą wartosci binarnej PORTD.DIR = 0x03 //wartosc szesnastkowa PORTE.DIR = 1 //wartosc dziesietna
Należy pamiętać, że po resecie układu wszystkie piny są ustawione jako wejściowe bez podłączonego podciągania zasilania z VCC lub uziemienia z GND. Jest on wtedy w stanie wysokiej impedancji, którego opór wynosi setki MOhm.
Każdy z pinów jest odpowiednio zabezpieczony przez diody wejściowe. W celu dodatkowej ochrony należałoby wykorzystać diody Schotkiego.
Do pinów XMEGA można bezpiecznie podłączać napięcia, które mieszczą się przedziale wartości bezpiecznej czy takiej z zakresu napięć zasilania (od GND do VCC).
Kolejnym elementem jest wydajność prądowa pinów wyjściowych. Limit prądu jaki może popłynąć przez ten pin wynosi około 20-25 mA. Przy czym maksymalny prąd jaki można pobrać z całego układu wynosi 200 mA. Czyli ta wartość musi być rozłożona na ilość wykorzystywanych pinów.
Kolejnym elementem jest wydajność prądowa pinów wyjściowych. Limit prądu jaki może popłynąć przez ten pin wynosi około 20-25 mA. Przy czym maksymalny prąd jaki można pobrać z całego układu wynosi 200 mA. Czyli ta wartość musi być rozłożona na ilość wykorzystywanych pinów.
Programowanie
Programowanie opiera się na wprowadzeniu odpowiedniej wartości do rejestrów mikrokontrolera. Może to być wykonane tak jak w innych rodzajach AVR-ów, czyli poprzez wprowadzenie następującej komendy:
- nazwa zmienianego rejestru = (1<<BIT1) | (1<<BIT2)
Drugi sposób jest nowszy. Do ich zaprogramowania wykorzystuje się struktury:
- nazwa układu peryferyjnego.nazwa rejestru = ....; np. PORTA.DIR, PORTB.OUT, PORTA.DIRCLR.
Poniżej przedstawiam krótki opis niektórych ważniejszych rejestrów.
Jednym z podstawowych rejestrów który daje możliwość ustawiania pewnych opcji na pinie jest PINxCTRL. Do każdego pinu przyporządkowany jest inny rejestr kontrolny.
Rys. 1. Rejestr PINxCTRL
Pozwala on na ustawienie rezystorów podciągających, szybkość narastania zbocza, przerwania czy np. odwrócenie wartości podawanych na wyprowadzenie.
DIR (Data Direction Register) służy do ustawienia stanu wejścia bądź wyjścia dla konkretnego wyprowadzenia pinu. Wprowadzenie wartości 1 oznacza wyjście a zero to wejście. Składa się on z 8 bitów.
Rys. 2. Rejestr DIR
Kolejnym rejestrem jest DIRSET (Data Direction Set). Pozwala on na ustawienie pinów jako wyjścia. Wpisanie 1 pozwala na ustawienie wartości. Odczytanie zwróci wartość znajdującą się w rejestrze. Jest on również rejestrem 8 bitowym numerowanym od 0 do 7.
Rys. 3. Rejestr DIRSET
Następnym rejestrem jest DIRCLR (Data Direction Clear). Pozwala on na ustawienie poszczególnych pinów jako wejścia. Wpisanie do niego wartości 1, czyści odpowiadający bit w rejestrze DIR.
Rys. 4. Rejestr DIRCLR
Jest jeszcze rejestr DIRCR (Data Direction Toggle). Wpisanie jedynki spowoduje przełączenie stanu na wybranym pinie.
Teraz pora na rejestr OUT (Data Output Value) pozwala on na ustawienie odpowiedniego stanu na pinie. Wprowadzenie jedynki powoduje pojawienie się stanu wysokiego, 0 natomiast stan niski.
Rys. 5. Rejestr OUT
Kolejny rejestr z tego zestawu to OUTCLR (Data Output Value Clear). Pozwala on na ustawienie stanu niskiego na wybranym pinie poprzez wpisanie wartości 1. Przykład użycia dla pinu 5 wygląda następująco:
PORTC.OUTCLR = PIN5_bm;
Następnie OUTSET (Data Putput Value Set). W tym przypadku wpisanie 1 ustawia stan wysoki. Przykład użycia dla pinu 5 wygląda następująco:
PORTC.OUTSET = PIN5_bm;
OUTTGL ( Data Output Value Toggle ) przełącza stan na wybranym wyprowadzeniu.
Kolejna grupa rejestrów IN ( Data Input ). Jest to rejestr wejściowy który służy do odczytania stanu jaki w danym momencie znajduje się na pinie. Dodatkowo wybrane wejście nie jest próbkowane, aby odczytać stan bufor wejściowy musi być włączony.
Rys. 6. Rejestr IN
INTCTRL (Interrupt Control). Jest on podobnie jak poprzednie siedmiobitowy, z tą różnicą, że nie do wszystkich bitów można uzyskać dostęp. Wartości 7 do 4 są zarezerwowane dla wykorzystania w przyszłości. Dla uzyskania odpowiedniej kompatybilności z innymi mikrokontrolerami, te bity, przy wprowadzaniu danych do rejestru, należy ustawić na 0. Pozostałe wartości pozwalają na włączenie odpowiedniego przerwania dla portu.
Rys. 7. Rejestr INTCRTL
INT0MASK (Interrupt 0 Mask). Pozwala na ustawienie maskowania dla pinów wykorzystywanych do przerwania 0. Wprowadzenie 1 ustawia pin na przerwaniu 0.
INT1MASK (Interrupt 1 Mask). Działa tak samo jak poprzedni opisywany, z tą różnicą, że ustawiane jest przerwanie pierwsze.
INTFLAGS (Interrupt Flag). Bity od 7 do 2 są zarezerwowane. Flagi są ustawiane gdy zostanie wykryta odpowiednia zmiana stanu. Ich zerowanie wykonuje się poprzez wprowadzenie wartości 1 w odpowiednie miejsce w rejestrze.
Rys. 8. Rejestr INTFLAGS
I ostatni jaki będzie omawiany w tym poście czyli REMAP. Jego zadaniem jest przemapowienie funkcji pinów jak np. SPI na inne dostępne wyprowadzenia.
Rys. 9. Rejestr REMAP
Bit 7 oraz 6 są zarezerwowane. W przypadku wprowadzania danych do rejestru, aby zachować kompatybilność, należy do nich wprowadzić 0.
Bit 5 SPI. Pozwala na zmianę pinów interfejsu SPI poprzez wpisanie 1.
Bit 4 zmienia piny USART0 z Px[3:0] na Px[7:4].
Bit 3 TC0D Timer 0, Przesuwa lokację z Px3 na Px7.
Bit 2 TC0C z Px2 na Px6.
Bit 1 TC0B z Px1 na Px5.
Bit 0 TC0A z Px0 na Px4.
Przykładowy program
Program będzie dosyć prosty będą ustawione pewne wyprowadzenia, na które po kolei będzie podawany stan wysoki, przerwa czasowa, stan niski. Co pozwoli na cykliczne mruganie podłączonymi diodami. Wykorzystałem trzy diody zostały one podłączone z jednej strony do GND, z drugiej natomiast do wyprowadzeń A1, B3 oraz C6.
Poniżej przedstawiam drugi program, który dodatkowo obsługuje przycisk podłączony do pinu E5.
#define F_CPU 2000000UL #include <avr/io.h> #include <util/delay.h> void Mrugaj(void); int main(void) { //Ustawienie pinu jako wyjściowy //Za pomocą bitu maski PORTA.DIR = PIN1_bm; //Operacja przesunięcia bitowego PORTB.DIR = (1<<PORT3); //Za pomocą bitu maski PORTC.DIR = PIN6_bm; while(1) { Mrugaj(); } } //Zmiana stanu pinu 0 na przeciwny void Mrugaj(void) { _delay_ms(500); //Zapalenie diody PORTA_OUT |= (1<<PIN1_bp); _delay_ms(500); //Zgaszenie diody PORTA_OUT &= ~(1<<PIN1_bp); _delay_ms(500); //Zapalenie diody PORTB.OUTSET = PIN3_bm; _delay_ms(500); //Zgaszenie diody PORTB.OUTCLR = PIN3_bm; _delay_ms(500); PORTC.OUTSET = PIN6_bm; _delay_ms(500); PORTC.OUTCLR = PIN6_bm; }
Poniżej przedstawiam drugi program, który dodatkowo obsługuje przycisk podłączony do pinu E5.
#define F_CPU 2000000UL #include <avr/io.h> #include <util/delay.h> void Mrugaj(void); int main(void) { //Ustawienie pinu jako wyjściowy //Za pomocą bitu maski PORTA.DIR = PIN1_bm; //Operacja przesunięcia bitowego PORTB.DIR = (1<<PORT3); //Za pomocą bitu maski PORTC.DIR = PIN6_bm; //Ustawienie na pinie E3 wejście //z podciągnięciem do zasilania PORTE.DIRCLR = PIN5_bm; PORTE.PIN5CTRL = PORT_OPC_PULLUP_gc; while(1) { Mrugaj(); //Sprawdza czy na pinie jest E5 jest stan wysoki if(!(PORTE.IN & PIN5_bm)) { PORTB.OUTTGL = PIN3_bm; } } }
Jeśli chodzi o samą wygodę to jest ona średnia. Zdecydowanie byłoby łatwiej gdy by były one dostępne w jednym programie jak np. w STM32, gdzie wgrywanie następuje bezpośrednio z programu głównego w którym kod został napisany. Więc wniosek jest prosty jeśli nie ma dużej ilości zmian w kodzie, i zależy nam na jak najtańszym zakupie wtedy płytki z wgranym Flipem są jak najbardziej w porządku.
[1] 8-bit Atmel XMEGA AU Microcontroller
[2] Leon Instruments Kurs ATXMega
[3] Francuz T. AVR Praktyczne projekty
Bibliografia
[1] 8-bit Atmel XMEGA AU Microcontroller
[2] Leon Instruments Kurs ATXMega
[3] Francuz T. AVR Praktyczne projekty