Elektroda.pl
Elektroda.pl
X
Arrow Multisolution Day
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

DDS z wykorzystaniem ATMega88 i drabinki R-2R

Kubald 08 Gru 2012 22:41 24111 5
  • DDS z wykorzystaniem ATMega88 i drabinki R-2R

    Autor niniejszego opisu planował testować swego czasu tagi RFID na częstotliwość 150 kHz, jednak nie posiadał własnego generatora sygnałowego – dlatego postanowił wykorzystać w tym celu mikroprocesor ATMega88 i bezpośrednią syntezę cyfrową sygnału. Zamiast jednak sięgnąć po gotowe rozwiązanie z Internetu, postanowił się dowiedzieć czegoś więcej o programowaniu procesorów AVR w assemblerze i konwersji cyfrowo/analogowej z wykorzystaniem drabinki R-2R.

    DDS z wykorzystaniem ATMega88 i drabinki R-2R

    Od strony elektronicznej – schemat urządzenia testowego został pominięty. Jest to podstawowa aplikacja procesora ATMega88, z interfejsem ISP, zasilaniem i 16-megahercowym oscylatorem kwarcowym. Drabinka R-2R przyłączona jest do wyprowadzeń PB0-PB5, gdzie PB0 jest najmniej znaczącym, a PB5 – najbardziej znaczącym bitem.

    Używana w testach konwersji cyfrowo/analogowej drabinka R-2R zbudowana jest z rezystorów 10 kΩ (R) oraz 20 kΩ (2R). Podając napięcie zasilania do punktu $$a_{n-1}$$ oraz przyłączając masę do punktu $$a_{0}$$, na wyjściu drabinki uzyskuje się napięcia z zakresu 0 ... $$VCC \cdot (1-\frac{1}{2}^{n})$$ (w opisywanym przykładzie n = 6, więc maksymalne napięcie na wyjściu wyniesie $$VCC \cdot \frac{63}{64}$$). Dla udowodnienia działania, można wykorzystać 1-bitową wersję drabinki i łatwo wykazać, że jeśli na wejściu napięcie wynosi 0 bądź 5 V, na wyjściu wyniesie odpowiednio 0 lub 2,5 V. Po zastosowaniu twierdzenia Thevenina dla takiego przypadku, uzyska się obwód składający się z rezystorów 2R połączonych szeregowo i źródła napięcia 0 bądź 2,5 V. Dodając jeszcze jeden bit, okaże się, że nadal rezystancja zastępcza wynosi 2R. Poprzez indukcję dla n bitów można uzyskać równanie opisujące napięcie na wyjściu:

    $$\frac{1}{2} \cdot a_{n-1} + \frac{1}{4} \cdot a_{n-2} + \cdots + \frac{1}{2}^{n} \cdot a_{0}$$

    Generując programowo przebiegi, warto zauważyć, że podanie stanu wysokiego na pin PB0 – z wykorzystaniem 6-bitowej drabinki R-2R – spowoduje pojawienie się na jej wyjściu napięcia równego 1/64 wartości napięcia zasilania. Stan wysoki pinu PB1 spowoduje pojawienie się dwa razy wyższego napięcia na wyjściu drabinki, aż wreszcie – stan wysoki pinu PB5 spowoduje pojawienie się na wyjściu drabinki napięcia równego połowie napięcia zasilania. Oznacza to po prostu, że wartość w systemie binarnym wystawiana na porty PB0 ... PB5 jest konwertowana na wartość analogową – napięcie. Pozwala to generować przebiegi piłokształtne przy użyciu bardzo prostego kodu (w języku C):





    Kod: c
    Zaloguj się, aby zobaczyć kod


    DDS z wykorzystaniem ATMega88 i drabinki R-2R

    Należy zauważyć, że dwa „najwyższe” bity licznika są tracone, ponieważ do pinów procesora PB6 i PB7 przyłączony jest zewnętrzny oscylator kwarcowy. Po uruchomieniu kodu można łatwo, za pomocą oscyloskopu, sprawdzić, że na wyjściu drabinki pojawia się przebieg piłokształtny o częstości 62,5 kHz (wynika to z faktu, że procesor taktowany jest zegarem 16 MHz, pełen zakres napięcia wyjściowego 6-bitowej drabinki może być uzyskany w 64 krokach, a wykonanie kodu zajmuje 4 cykle zegarowe, więc 16 MHz / 64 / 4 = 62,5 kHz).

    Do wygenerowania przebiegu sinusoidalnego może być wykorzystana uprzednio wyliczona tablica próbek (256 wartości z zakresu 0 ... 63). Zmiany wymaga jedynie fragment kodu w wewnętrznej pętli.

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Za pomocą oscyloskopu potwierdzono, że taki sposób generowania przebiegu również działa.

    DDS z wykorzystaniem ATMega88 i drabinki R-2R

    Ostatnią rzeczą, którą można zrealizować z wykorzystaniem powyższych przykładów, jest regulacja częstotliwości generowanego przebiegu – zrealizowana programowo, bez konieczności wymiany zewnętrznego oscylatora. Może być to zrealizowane za pomocą arytmetyki stałoprzecinkowej, gdzie w 16-bitowym liczniku wyższe bity używane są do przechowywania całkowitej części próbki generowanego sygnału, a niższe bity – do części ułamkowej. Zaimplementowanie tej funkcji obrazuje poniższy kod:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Dla łatwiejszego zrozumienia jego działania, rozpatrzeć można kilka przykładu. Na początek należy przyjąć, że zadana wartość kroku (step) wynosi 256 (0x0100). Po kilku pierwszych iteracjach wartości counter będą następujące: 0x0000 | 0x0100 | 0x0200, a odpowiadające im wartości counter >> 8: 0x00 | 0x01 | 0x02. Używając kroku równego 256, po każdej iteracji generowany punkt przebiegu jest większy niż w poprzedniej iteracji. A co w przypadku wartości mniejszych od 256? Jeśli obrać krok równy 0x0080, wartości zmiennej counter będą następujące: 0x0000 | 0x0080 | 0x0100 | 0x0180 | 0x0200 | 0x0280, a odpowiadające im wartości counter >> 8: 0x00 | 0x00 | 0x01 | 0x01 | 0x02 | 0x02. Jak widać, niższe bity zmiennej counter, odpowiedzialne za część ułamkową, przyczyniają się do zmiany wartości części „całkowitej” co drugą iterację. Skutkuje to wzrostem generowanego na wyjściu drabinki R-2R napięcia co drugą iterację. Jeśli za krok zadać by wartość równą ¼ z 256, napięcie na wyjściu drabinki wzrastałoby dopiero co 4-tą iterację. Generalnie, wartość X zadana jako krok spowoduję zmianę napięcia co X/256 iteracji.

    Aby uzyskać konkretną wartość częstotliwości przebiegu na wyjściu, za wartość kroku należy wstawić odpowiednio wyliczoną wartość. Jako że cała funkcja odpowiadająca za zmianę częstości zajmuje 11 cykli zegarowych, a zmiany napięcia na wyjściu drabinki R-2R zachodzą co X/256 iterację, częstotliwość na wyjściu może być opisana wzorem:

    $$Freq = F_{CPU} / 11 / 256 \cdot \frac{X}{256}$$, po przekształceniu względem X otrzymuje się zależność:

    $$X = Freq \cdot 256^{2} \cdot \frac{1}{2}{F_{CPU}}$$

    I tak, dla częstości 150 kHz wartość kroku wynosi 0x1A66 (6758). Można to łatwo sprawdzić za pomocą oscyloskopu lub multimetru z miernikiem częstości – rzeczywiście, generowany jest przebieg o częstości 150 kHz.

    DDS z wykorzystaniem ATMega88 i drabinki R-2R

    Jeśli jednak spojrzeć na powyższy przebieg, wygenerowany funkcją napisaną w języku C, można stwierdzić, że nie jest on gładki. Jest to spowodowane faktem, że funkcja regulująca częstotliwość zajmuje 11 cykli zegara, co powoduje, że jedna, pełna zmiana przebiegu to zaledwie 10 próbek – skutkuje to bardzo poszarpanym kształtem przebiegu. Z wykorzystaniem języka assembler można zredukować niezbędną liczbę cykli zegara do 7, co spowoduje zwiększenie liczby próbek do 15 przy 150 kHz. Nie jest to zbyt wiele, ale różnica w wyglądzie przebiegu jest wyraźna.

    DDS z wykorzystaniem ATMega88 i drabinki R-2R

    Kod: asm
    Zaloguj się, aby zobaczyć kod


    Tak napisana funkcja może być wywołana w kodzie C w sposób następujący:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Autor zapewnia, że wykorzystująca 7 cykli zegara funkcja jest o 22% szybsza, niż znane do tej pory i popularne w Internecie rozwiązanie autorstwa Jespera Hansena. Wzrost szybkości działania uzyskano dzięki stosowaniu 16-bitowej wartości kroku (8 bitów-8 bitów) zamiast 24-bitowej (8 bitów-16 bitów) i używaniu pamięci SRAM zamiast pamięci programu do przechowywania próbek przebiegu.

    Na stronie autora dostępne są pełne źródła oraz dokładne objaśnienie poszczególnych poleceń wykorzystanych w napisanej w języku assembler funkcji.


    Fajne!
  • Arrow Multisolution Day
  • #2 09 Gru 2012 01:14
    miszcz310
    Poziom 19  

    Wow. Bawiłem się kiedyś właśnie w robienie DDS ze stronki Jaspera, ale zniechęciłem się jakoś. Może teraz odgrzeje ten temat jeszcze raz...
    W każdym razie dzięki bardzo za artykulik. :P

    P.S. Nie wiem czy Ci się nie rozjechały wzory w latexu. Do ułamków polecam polecenie ,,\frac {licznik} {mianownik}``

    P.S.2 Jak dobrze rozumiem to program po wejściu do funkcji asmloop(coś tam) już nigdy z niej nie wyjdzie, bo w tej fukcji jest nieskończona pętla objawiająca się poprzez rjmp loop. Dobrze to rozumiem?

  • Arrow Multisolution Day
  • #3 09 Gru 2012 09:57
    remiorn
    Poziom 18  

    Kubald napisał:
    Z wykorzystaniem języka assembler można zredukować niezbędną liczbę cykli zegara do 7, co spowoduje zwiększenie liczby próbek do 15 przy 150 kHz. Nie jest to zbyt wiele, ale różnica w wyglądzie przebiegu jest wyraźna.


    W jednym z projektów generowałem przebieg sinusoidalny z wykorzystaniem drabinki R-2R i ATTiny 2313. Udało mi się zejść do generowania kroku w 2 cyklach zegara.
    Oczywiście pojedyncza pętla zawierała generację "po kolei" wszystkich wartości całego okresu sinusa.
    Aby minimalizować zniekształcenia przebiegu pętla zamykana była w szczycie sinusoidy, gdy zmiany przebiegu są najmniejsze niejako zamiast generowania kolejnego kroku.
    Program oczywiście miał dość dużą objętość, ale procesor nie robił nic więcej, więc nie byłą to znacząca wada..
    Dodatkowo, aby uniknąć żmudnego wpisywania kolejnych poleceń program został wygenerowany w arkuszu kalkulacyjnym.

  • #4 09 Gru 2012 11:30
    glutek
    Poziom 13  

    Ciekawym rozwiązaniem odnośnie generowania sygnału sinusoidalnego jest zastosowanie filtru cyfrowego na granicy stabilności, wtedy nie trzeba zapisywać próbek w tablicy. Tak jak tutaj: http://ep.com.pl/files/2752.pdf

  • #5 09 Gru 2012 12:38
    miszcz310
    Poziom 19  

    @remiorn
    Czyli z tego co piszesz to rozumiem, że wywalałeś na port stałe w jednej pętli, tak?
    W sensie ciurkiem w jednej pętli cały okres sinusa, czyli np 256 przypisań do portu i rmjp do początku przypisywania?
    W sumie całkiem sprytnie bo w zasadzie traci się tylko czas na ustawienie danych na port.
    Gorzej bo ciężko by było zrobić sobie taki generator z wczytywaniem naszej zadanej funkcji (w sensie tablicy wartości).
    Jednak mimo wszystko ciekawe rozwiązanie.
    Chociaż z drugiej strony w niektórych HAMEGAch jest tak że prostokąt i sinus można generować na wyższych częstotliwościach niż trójkąt i przebieg definiowany przez użytkownika.

    @up
    No nie trzeba zapisywać próbek w tablicy, ale zobacz jak cyklochłonne jest to rozwiązanie. Musisz mieć odpowiednią precyzję żeby się nie rozjechało rozwiązanie, i masz tam mnożenia co wcale nie przyspieszają obliczeń.

  • #6 09 Gru 2012 15:58
    glutek
    Poziom 13  

    Racja, tam wykorzystano fpga, więc operacje wykonywane były sprzętowo. W przypadku atmegi może jednak znacznie wpłynie na fmax generowanego sygnału.