XMega – ADC ogólnie — część 2

XMega – ADC ogólnie — część 2
Razem głosów: 15 co stanowi: 89.33% całości.

 

obr986_1

 

Co nieco już bliżej wiemy o ADC w mikrokontrolerach XMega, szczątkowo znamy ciekawsze aspekty użytkowe czas więc zająć się pozbieraniem wszystkiego razem i dokonania wreszcie  jakiś kodów :)

By do końca zrozumieć w miarę fenomen ADC musimy przyswoić sobie jeszcze kilka spraw i sposobów ujarzmiania naszego stworka pomiarowego, a wszystko w sumie po to by z niego móc korzystać w naszych projektach.

 

Opcje zegara systemowego


 

W Xmegach  źródło zegara systemowego wybieramy za pomocą rejestru CLK.CTRL.  taktowanie rdzenia może pochodzić z kilku źródeł (podobnie jak w atMegach). Tak więc mamy do dyspozycji opcje:

  • Wewnętrzny oscylator RC 2MHz
  • Wewnętrzny oscylator RC 32 MHz
  • Wewnętrzny oscylator 32.768 KHz
  • Zewnętrzne źródło taktowania
  • Pętla PLL (tego babcie Atmegi nie mają)

Oczywiście nie są to wszystkie opcje a jedynie kilka podstawowych (szczegóły w nocie). Jeśli wybierzemy jako źródło taktowania PLL, musimy podać źródło PLL wraz mnożnikiem. Odbywa się to za pomocą rejestru OSC.PLLCTRL.  Pętla PLL może korzystać z wewnętrznego oscylatora RC 2 MHz, 32 MHz lub zewnętrznego źródła. Włączamy ją rejestrem OSC.CTRL.

Oczywiście musimy pamiętać by ustawić właściwe źródło taktowania dla konkretnego zastosowania, biorąc pod uwagę wymaganą szybkość, dokładność, dopuszczalny pobór mocy , wpływ temperatur czy miejsce na płytce. W zasadzie każdy to wie, ale warto przypomnieć bo potem wielu zapomina, a  dioda led  będzie migać tak samo na 2 Mhz  jak i na 32 Mhz  :)

Zatem ustawmy konfigurację zegara.  Ja jak wiecie lubuje się w kwarcach 16 MHz  więc naszą Xmegę ustawimy na 16 MHz, ale użyjemy nie kwarca i fusów jak w Medze , tu zastosujemy :

  • wewnętrzny oscylator RC 2 MHz i PLL – w komentarzach są podane wartości HEX rejestrów wraz z opisem

Jak widać jest to proste , ale jest parę kruczków , oto one:

  • Źródło zegara i mnożnik  musi być wybrane w PLLCTRL i koniecznie przed włączeniem pętli PLL
  • Przy wyborze źródła PLL musimy określić niezerowy współczynnik  mnożenia. Domyślnie wynosi on „0” (zero) oznacza to, że jeśli nie określimy mnożnika to wyjście PLL będzie „martwe” , a mikrokontroler przestanie reagować.

Zapamiętajcie to dobrze, drobiazg , ale stracicie mniej włosów z głowy podczas zabaw z XMegami :)

Zegar systemowy w XMegach dodatkowo jest podzielony na 4 jakby osobne zegary peryferyjne:

  • Clk_per4
  • Clk_per2
  • Clk_per
  • Clk_cpu

są one wykorzystywane do taktowania różnych urządzeń peryferyjnych naszej Xmegi. Szybkość tych zegarów ustawiamy przy użyciu preskalera w rejestrze CLK_PSCTRL. Moduł ADC  jest taktowany z Clk_per, który ustawimy sobie na 8MHz :

a linijka ustawia Clk_per2, Clk_per na  równą Clk_per4 czyli Clk_sys z preskalerem 2 czyli na 8MHz.

Teraz wypada ustawić rejestr  ADC Prescaler  (ADCx.PRESCALER) który jest używany do dzielenia Clk_per w celu uzyskania rzeczywistego zegara ADC.  Według dokumentu AVR1300 zegar ADC powinien mieścić się w zakresie  100KHz – 1,4Mhz.  Ustawimy wiec ADC na 125KHz dla ADCB.  By osiągnąć 125KHz musimy preskaler  ustawić na 64:

Takim oto sposobem uzyskujemy Clk_per/64  czyli  8Mhz/64 = 125Khz co uzyskamy wpisując do rejestru wartość 0x04.

Konfiguracja przerwań


XMega ma dosyć rozbudowany wielopoziomowy kontroler przerwań, który pozwala programiście przypisać indywidualny priorytet przerwań. Obsługiwane są 2 rodzaje przerwań z ADC  :

  • Threshold Compare Interrupt mode (próg porównania)
  • Conversion Complete Interrupt mode (zakończenie konwersji)

W przypadku trybu progu porównania możemy określić wartość progową dla ADC.  Korzystamy wówczas z rejestrów ADCx.CMPH i ADCx.CMPL. Możemy określić czy przerwanie występuje na podstawie wyniku czy powyżej lub poniżej wartości progowej. Natomiast drugim wypadku przerwanie jest wywoływane gdy zakończy się konwersja pomiaru ADC .  Tu rodzaj trybu przerwania wybieramy przy pomocy kanału ADC w rejestrze ADCx.CHn.INTCTRL.

tak zatem ustawiamy przerwanie po zakończeniu konwersji ADC wpisując do rejestru wartość 0x03.  Gdy już określimy tryb przerwania, mamy do dyspozycji 2 rejestry, które mogą być użyte do wskazania wystąpienia przerwania.

  • ADCx.INTFLAGS – (ADC Interrupt Flag Register) ten rejestr odpowiada za śledzenie poszczególnych wirtualnych kanałów ADC i jeśli wystąpi zdarzenie przerwania to zostanie ustawiony ten rejestr.
  • ADCx.Chn.INTFLAGS – (ADC Channel Interrupt Flags Register)  może być stosowany alternatywnie , ale  ten rejestr jest nieco inny , śledzi on tylko jeden kanał ADC , w odróżnieniu do poprzedniego który śledzi wszystkie kanały.

Dobra praktyka jest kasowanie FLAG przed włączeniem ADC , co realizujemy poprzez wpisanie wartości „1” do odpowiednich bitów rejestru:

Co ciekawe jeśli realizujemy polling , musimy ręcznie kasować flagi przerwań , ale w trybie przerwania bity flag są kasowane automatycznie podczas wykonywania wektora przerwań.

Ogólnie zaleca się stosowanie obsługi przerwań nie tylko przy ADC gdyż stosowanie przerwań pozwala mikrokontrolerowi wykonywać inne zadania bez potrzeby czekania aż np próbkowanie na ADC się zakończy.

 

Wybór trybu pomiaru


Jako że nie odnoszę się do żadnego konkretnego mikrokontrolera , a ogólnie do całej rodziny XMega, warto zaznaczyć że domyślnie ADC jest w Xmegach  włączone w trybie zmniejszonego poboru mocy, ale jeśli zostało wyłączone (ASF wyłącza wszystkie peryferia podczas startu i ponownie je włącza w razie potrzeby –  celu oszczędzania energii)  dla nas oznacza to że musimy ADC włączyć przed zapisem wartości do poszczególnych rejestrów co wykonujemy przez wpisanie  wartości 0x01 do rejestru:

tu taka mała zmyłka  zobaczcie sami  włączamy ADCB.CTRLA  zamiast ADCB.CTRLB, który jest używany do określenia czy ADC pracuje w trybie signed czy unsigned :) Jednocześnie możemy w tym miejscu  określić czy dokonujemy pojedynczego pomiaru czy ciągłego. Ponadto możemy tez wybrać rozdzielczość 12 lub 8 bit.  Co ciekawe ADC rejestruje 16bitów , dlatego też jeśli wybierzemy 12Bit  możemy wybrać czy nasz wynik pomiaru 12bit  jest przesunięty w lewo lub prawo 16 bitowego rejestru. Trochę to zawiłe, ale szczegóły znajdziecie w nocie tymczasem  uruchomimy ADC w trybie signed-single conversion, a wynik 12bitowy będzie przesunięty w prawo co uzyskujemy zapisując do rejestru wartość 0x10 :

Tu mała uwaga – wspominałem już o tym że gdy używamy trybu signed rozdzielczość ADC zostaje zmniejszona o 1 bit i ma fizycznie 11bitów  gdyż  MSB służy tylko do określenia  znaku i ma wartość = 1 gdy wynik ADC jest ujemny.

 

Konfiguracja PORTU I/O 


To stosunkowo istotne zagadnienie gdyż by wykonać pomiar ADC musimy jakoś go podłączyć do świata zewnętrznego i w tym celu musimy odpowiednio skonfigurować odpowiednio PORT do którego pinów ADC jest podłączone.  Przykładowo możemy użyć potencjometru do przyłączenia analogowego sygnału do przetwornika ADC. Niech to np będzie PORTB Pin 1  czyli musimy ustawić PB1 jako wejście co czynimy tak:

Skoro więc używamy trybu signed możemy dokonać pomiaru single-ended jak i różnicowego, co określamy w rejestrze ADCx.CHn.CTRL (ADC Control Chanel Register).Jeśli  wybierzemy tryb różnicowy  możemy ustalić wzmocnienie (Gain) również w  tym rejestrze. Natomiast w trybie single.ended wartość wzmocnienia (GAIN)  = 1. Co przykładowo włączamy wpisując wartość )x01 do rejestru:

„Wirtualne Kanały” ADC są przełączane multiplekserem który określa rejestr ADCx.CHn.MUXCTRL, którym decydujemy co jest dołączone do biegunów dodatniego i ujemnego ADC.  Dla bieguna dodatniego możemy wybrać czy podłączamy źródło zewnętrzne czy wewnętrzne do wejścia przetwornika, a dla ujemnego czy jest podłączony do Pinu zewnętrznego , wewnętrznie do GND czy do PADu GND . Biegun ujemny ma zastosowanie tylko podczas pomiarów w trybie różnicowym, a tymczasem skoro już bawimy się w single-ende ze znakiem to biegun ujemny zostaje automatycznie podłączony wewnętrznie do GND.  Poniższy kod obrazuje wykonanie połączenia PB1 do bieguna dodatniego co czynimy wpisując do  rejestru wartość 0x08:

 

 

 Kalibracja


Tu mamy dosyć lajtowo gdyż moduł ADC w XMegach jest skalibrowany podczas produkcji, a dane kalibracyjne są przechowywane w wewnętrznej pamięci EEPROM. W dokumencie AVR1300 :

http://www.atmel.com/Images/Atmel-8032-Using-the-Atmel-AVR-XMEGA-ADC_Application-Note_AVR1300.pdf

napisano, że dane kalibracyjne kompensują niedopasowanie oraz poprawiają liniowość przetwornika ADC. Również w tym dokumencie znajdziemy informację o konieczności ładowania danych kalibracyjnych do odpowiednich rejestrów ADC przed jego włączeniem.

By uzyskać dostęp do danych kalibracyjnych  z wewnętrznej pamięci EEPROM musimy skorzystać z pamięci nieulotnej kontrolera (NVM). Informacje o kontrolerze NVM i dostępnych poleceniach znajdziemy w rozdziale 30 podręcznika XMEGA-B, w którym jest omówiona przykładowa funkcja :ReadCalibrationByte( )

 

By móc odczytywać dane kalibracyjne musimy oczywiście „zainkludować” dwa pliki nagłówkowe:

Należy jednak pamiętać, że dane kalibracyjne są przeznaczone do kompensacji nieliniowości ADC i nie likwidują one wszystkich niedoskonałości. Błędy przesunięć fazowych i wzmocnienia GAINA możemy jednak kompensować za pomocą dodatkowej kalibracji ręcznej z poziomu kodu naszej aplikacji co jest szczegółowo opisane w dokumencie AVR120 wraz z przykładowym kodem ręcznej kalibracji dla mikrokontrolerów AVR :

http://www.atmel.com/images/doc2559.pdf

Przykładowo możemy załadować dane kalibracyjne w następujący sposób:

 

 

Dodatkowe opcje konfiguracyjne ADC


XMega posiada całkiem sporo rejestrów konfigurujących pracę ADC  np:

 

  • ADC Reference Control Register (ADCx.REFCTRL)  – służy do określania napięcia odniesienia co pozwala określić maksymalną dopuszczalną wartość analogową, którą możemy przekształcić na cyfrową.  W celu uzyskania np  AREF = VCC/1.6 wpisujemy do rejestru wartość 0x10 : 

Jako, że napięcie zasilania VCC dla naszej XMegi = 3,3V  to napięcie odniesienia dla ADC w  tym przykładzie będzie równe około 2,06V  co wynika z powyższego działania  czyli 3,3/1,6. Dodatkowo cały czas używamy trybu signed  więc rzeczywista rozdzielczość pomiaru to 11bitów  (wiemy dlaczego)  daje nam  2 ^ 11 czyli możliwe uzyskanie 2048 różnych wartości. Tak więc by obliczyć wartość LSB bierzemy Vref (2,06 – GND = 2,06) i dzielimy przez liczbę próbek , czyli  2,06 / 2048  co nam daje wynik na poziomie ok 0,001. Dla nas oznacza to, że każdy bit wyniku to około 1mV.  Przykładowo jeśli ADC poda nam wynik 0xA3 wiemy, że na wejściu analogowym mamy około 163mV.  Wyjątkowo ADC może przyjąć wartość cyfrową 0xFE co stanowi 2046mV. Jest to spowodowane błędem pomiarowym przez co wynik jest podawany w przybliżeniu i może się zbliżać do górnej granicy wejścia analogowego, niemniej dla większości zastosowań wynik jest wystarczająco dokładny choć obarczony błędem, którego należy być świadomym. Oczywiście w celu zwiększenia dokładności można manipulować wynikiem w kodzie aplikacji wszystko zależy od programisty.

  • ADC Event Control Register (ADCx.EVCTRL) – system zdarzeń bo możemy tak nazwać Event CONTROL, może być użyty do np  uruchomienia konwersji ADC, co pozwala kontrolować bardzo dokładnie czas rozpoczęcia wykonania pomiaru. Np dokładnie kiedy wystąpi jakieś zewnętrzne zdarzenie wynikające z naszego kodu.

My nie będziemy teraz tego potrzebować więc poprzez wpisanie do rejestru wartości 0x00 wyłączamy kontrolę.

 

Tym oto sposobem nasze ADC zostało skonfigurowane i jest gotowe do dokonania pomiaru.  Mamy jak widzicie wiele możliwości , wielu nie omówimy tez tutaj , ale zalecam zapoznanie się z wymienioną dokumentacją , niemniej jednak wspomnieć należy jeszcze o …

 

Zmniejszenie zużycia energii


Zmniejszenie zużycia energii jest ważnym zagadnieniem, a w dobie grożącego nam kryzysu energetycznego, czy też po prostu podczas używania naszego układu na zasilaniu bateryjnym ma duże znaczenie.

  • ADC Control Register B (ADCx.CTRLB)  możemy użyć do redukowania zużycia prądu przez moduł ADC co odbywa się poprzez zmniejszenie częstotliwości próbkowania. Tak więc możemy ograniczyć się do np maksymalnej częstotliwości próbkowania na poziomie  225kSPS , 150kSPS lub 75kSPS. Domyślnie moduł ADC nie ma włączonych trybów oszczędzania energii.

Wpisanie do rejestru wartości 0x60 spowoduje znaczącą redukcję zapotrzebowania energetycznego modułu ADC poprzez zmniejszenie częstotliwości próbkowania do 75kSPS.  Oczywiście jeśli chcemy zastosować ten tryb  musimy zrobić to na początku konfiguracji ADC  przy wyborze trybu pomiaru.

 

I to by było na tyle … jeśli chodzi o ogólny opis ADC w mikrokontrolerach rodziny XMega, raz jeszcze zachęcam do lektury dokumentacji w celu poznania szczegółów.  Następnym razem opiszę już fizyczny przykład w oparciu o płytkę XMEGA-A3BU Xplained.

 

Podziel się na:
  • Print
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Blogplay