Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[Attiny2313][C/AVR Studio] Problem z DDSem na Attiny2313

Qbik 20 Jul 2010 14:35 2746 10
Tespol
  • #1
    Qbik
    Level 10  
    Witam, próbuje zrobić prosty generator DDS na procesorze ATtiny2313.
    Do mikrokontrolera podpinam drabinke R2R (nie gotową tylko polutowaną z rezystorów), dokładnie tak jak przedstawia to rys.:
    http://www.scienceprog.com/wp-content/uploads/2008i/DDS2/AVR_DDS_2_0_circuit.png (zamiast portu A jest B).
    Za drabinką w miejsce DDS_OUT zamiast tego układu ze wzmacniaczami wrzucam rezystor podpięty do masy. I to na nim robie pomiary na oscyloskopie. Na wyjście portu wyrzucam poszczególne liczby z tabeli, wg. kodu znalezionego w necie (załącznik). Wszystko jest w porządku do pewnego momentu. Najpierw rośnie mi napięcie, a gdy dochodzi do wartości szczytowej i mam od początku wysyłać dane (kolejny przebieg sygnału) powstają jakieś krzaki. Później znów się stabilizuje i napięcie narasta, po czym znów są krzaki i tak w kółko (rysunek).

    Code:
     #define F_CPU 8000000UL  
    
    #include <avr/io.h>
    #include <avr/delay.h>
    #include <avr/interrupt.h>
    #include <stdlib.h>

    const uint8_t trianglewave[] = //triangle wave
    {
    0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e,0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e,
    0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e,0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e,
    0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e,0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e,
    0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e,0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e,
    0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e,0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e
    };

    void static inline signalOUT(const uint8_t *signal, uint8_t ad2, uint8_t ad1, uint8_t ad0)
    {
       asm volatile
       (   
                "eor r18, r18    ;r18<-0"   "\n\t"
                "eor r19, r19    ;r19<-0"   "\n\t"
                "1:"                  "\n\t"
                "add r18, %0   ;1 cycle"         "\n\t"
                "adc r19, %1   ;1 cycle"         "\n\t"   
                "adc %A3, %2   ;1 cycle"         "\n\t"
                "lpm          ;3 cycles"    "\n\t"
                "out %4, __tmp_reg__   ;1 cycle"   "\n\t"
                "rjmp 1b      ;2 cycles. Total 9 cycles"   "\n\t"
                :
                :"r" (ad0),"r" (ad1),"r" (ad2),"e" (signal),"I" (_SFR_IO_ADDR(PORTB))
                :"r18", "r19"
       );
    }

    uint32_t temp;
    uint8_t freq1, freq2, freq3;

    int main()
    {

       DDRB = 0xFF; 
       PORTB = 0x00;

       temp = 0x00BD;
       freq1 = (uint8_t)(temp);
       freq2 = (uint8_t)(temp >> 8);
       freq3 = (uint8_t)(temp >> 16);
       
       while(1)
       {
          signalOUT(trianglewave, freq3, freq2, freq1);
       }
    }


    [Attiny2313][C/AVR Studio] Problem z DDSem na Attiny2313
  • Tespol
  • #2
    Andrzej__S
    Level 28  
    Jeśli dobrze rozumiem, ma to działać następująco:
    Pobierasz po kolei dane z tablicy trianglewave do rejestru r0 (__tmp_reg__) i później wyprowadzasz tę wartość na PORTB.

    Skoro dane z tablicy pobierasz za pomocą polecenia assemblera lpm, to nie powinieneś czasami zadeklarować tablicy do zapisania we flash'u:

    Code:

    //na początku dodaj
    #include <avr/pgmspace.h>

    //zmień
    const uint8_t trianglewave[] PROGMEM =
    {
       ...
    }
  • Tespol
  • #3
    tmf
    Moderator of Microcontroller designs
    trianglewave umieść we FLASH a nie SRAM - raz, że marnujesz pamięć RAM (sama tablica wykorzystuje 80 ze 128 dostępnych bajtów) to potem próbujesz czytać dane z niej przez lpm, które to odnosi się do FLASH.
  • #4
    Qbik
    Level 10  
    Zrobiłem tak jak zaproponowaliście. Dane z tabelki są rzeczywiście zapisywane w pamięci programu, ale nie ma żadnej poprawy na oscyloskopie. Dalej mam ten sam obraz.
  • #5
    Andrzej__S
    Level 28  
    Qbik wrote:
    Dalej mam ten sam obraz.


    Bo wykraczasz poza rozmiar tablicy. Żeby Twój program działał poprawnie musisz po linijce
    Code:

    "adc %A3, %2   ;1 cycle"         "\n\t"

    sprawdać, czy wskaźnik w rejestrze z nie przekroczył rozmiaru tablicy.
  • #6
    Qbik
    Level 10  
    Słabo rozumiem asemblera. Mógłbyś mi zmodyfikować ten kod?

    Zauważyłem jeszcze, że przy wybraniu różnych częstotliwości, np. 100 Hz lub 1000 Hz zawsze mierze 1 Hz. Coś tu nie gra. ;/


    edit: ok z częstotliwością jest wszystko ok. Wykorzystywałem wewnętrzny zegar. W kodzie było zapisane 8000000, wyłączałem dzielnik częstotliwości ale widocznie to wyłączanie nie działało.

    Natomiast dalej jest problem z tym szumem ;/ proszę o pomoc bo próbuje coś zdziałać już długo a nie wychodzi ;/
  • #7
    Andrzej__S
    Level 28  
    Spróbuj tak:
    Code:

    void static inline signalOUT(const uint8_t *signal, uint8_t ad2, uint8_t ad1, uint8_t ad0)
    {
       asm volatile
       (   
                "eor r18, r18    ;r18<-0"   "\n\t"
                "eor r19, r19    ;r19<-0"   "\n\t"
                "mov r20, %A3    ;r19<-0"   "\n\t"
                "ldi r21, 0x51   ;r21<-rozmiar tablicy + 1"   "\n\t"
                "add r21, r20    ;r19<-0"   "\n\t"
                "L_dl1%=:"                  "\n\t"
                "add r18, %0   ;1 cycle"         "\n\t"
                "adc r19, %1   ;1 cycle"         "\n\t"
                "adc %A3, %2   ;1 cycle"         "\n\t"
                "cp r21, %A3   ;1 cycle"         "\n\t"
                "brne L_dl2%=  ;1|2 cycles"      "\n\t"
                "mov %A3, r20  ;1 cycle"         "\n\t"
                "L_dl2%=:"
                "lpm          ;3 cycles"    "\n\t"
                "out %4, __tmp_reg__   ;1 cycle"   "\n\t"
                "rjmp L_dl1%=      ;2 cycles. Total 9 cycles"   "\n\t"
                :
                :"r" (ad0),"r" (ad1),"r" (ad2),"e" (signal),"I" (_SFR_IO_ADDR(PORTB))
                :"r18", "r19", "r20", "r21"
       );
    }


    Oczywiście będzie to działać przy założeniu, że wskaźnik do ostatniego elementu tablicy będzie mniejszy od 255(0xFF). U Ciebie można tak założyć, ale kod może nie być uniwersalny w innych przypadkach.
  • #8
    Qbik
    Level 10  
    Niestety jest dokładnie to samo co było w poprzednim kodzie :( Tablica ma na pewno mniej elementów niz 255.
  • #9
    Andrzej__S
    Level 28  
    Spieszyłem się trochę i zrobiłem jeden drobny błąd. Zamiast:
    Code:

                "ldi r21, 0x51   ;r21<-rozmiar tablicy + 1"   "\n\t"


    powinno być:
    Code:

                "ldi r21, 0x50   ;r21<-rozmiar tablicy"   "\n\t"


    Tak czy inaczej Twój kod był niepoprawny, bo wskaźnik w rejestrze z osiągał wartości wskazujące poza tablicę.

    Qbik wrote:

    Niestety jest dokładnie to samo co było w poprzednim kodzie.


    Czy tablica ma dokładnie taki sam rozmiar, jak w kodzie, który podałeś na początku? Niczego nie zmieniałeś? U mnie w symulatorze wszystko działa OK, chyba że masz jakiś problem po stronie sprzętowej (np. coś z drabinką).

    Qbik wrote:

    Tablica ma na pewno mniej elementów niz 255.


    Nie chodzi o rozmiar tablicy, tylko o wskaźnik do ostatniego elementu tablicy. To nie to samo, bo jeśli wskaźnik na pierwszy element to 0x00C0(192) a tablica ma np. 80 elementów, to ostatni element będzie miał wskaźnik 0x010F, czyli powyżej 255. Sprawdź adres tablicy trianglewave np. w pliku z rozszerzeniem *.lss (u mnie jest 00000026 <trianglewave>:). Nie masz tam jakichś innych tablic zadeklarowanych?

    Zmień linijkę, którą podałem powyżej i sprawdź wszystko jeszcze raz dokładnie, bo to powinno działać. Jeśli nie będzie, podaj dokładny kod, jaki kompilujesz.

    Dodano po 9 [minuty]:

    Qbik wrote:

    Za drabinką w miejsce DDS_OUT zamiast tego układu ze wzmacniaczami wrzucam rezystor podpięty do masy.


    Tak z ciekawości: Jaka wartość tego rezystora?
  • #10
    Qbik
    Level 10  
    Witam, przepraszam, że dopiero teraz odpowiadam ale miałem dużo na głowie.
    Andrzej__S wrote:
    Czy tablica ma dokładnie taki sam rozmiar, jak w kodzie, który podałeś na początku? Niczego nie zmieniałeś? U mnie w symulatorze wszystko działa OK, chyba że masz jakiś problem po stronie sprzętowej (np. coś z drabinką).

    Przyznam się bez bicia, że dodałem kilka elementów do tablicy i to mogło zaważyć na nie działaniu. Zmieniłem tablicę do pierwotnego rozmiaru.

    Andrzej__S wrote:
    Sprawdź adres tablicy trianglewave np. w pliku z rozszerzeniem *.lss (u mnie jest 00000026 <trianglewave>:). Nie masz tam jakichś innych tablic zadeklarowanych?


    W pliku lss mam to co poniżej (czyli dokładnie to co Ty). Żadnych innych tablic nie ma w kodzie.
    Code:
    00000026 <trianglewave>:
    
      26:   00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e     ................
      36:   20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e      "$&(*,.02468:<>
      46:   40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e     @BDFHJLNPRTVXZ\^
      56:   60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e     `bdfhjlnprtvxz|~
      66:   80 82 84 86 88 8a 8c 8e 90 92 94 96 98 9a 9c 9e     ................


    Andrzej__S wrote:
    Tak z ciekawości: Jaka wartość tego rezystora?

    Rezystor na którym robię pomiary ma 10k (tolerancja 5%). Wszystkie użyte rezystory są standardowe z tolerancją 5%.

    Drabinkę zrobiłem jeszcze raz na płytce uniwersalnej, bo tamta była na pająka i może coś się zwierało czasami.

    Pomiary zrobię za kilka godzin, bo dopiero wtedy będę mieć dostęp do oscyloskopu.
  • #11
    Andrzej__S
    Level 28  
    Qbik wrote:

    Przyznam się bez bicia, że dodałem kilka elementów do tablicy i to mogło zaważyć na nie działaniu.


    Zwiększenie tablicy raczej nie powinno wiele zmienić, co najwyżej nie byłby generowany cały przebieg. Gorzej, gdybyś zmniejszył. WAŻNE, żeby w przypadku zmiany rozmiaru tablicy zmienić w linijce:
    Code:

                "ldi r21, 0x50   ;r21<-rozmiar tablicy"   "\n\t"

    wartość 0x50 (80) na inną, zgodną z nowym rozmiarem. W assemblerze sizeof nie zadziała, więc trzeba zmieniać ręcznie. Oczywiście należy pamiętać, aby przestrzegać reguły z tym wskaźnikiem do ostatniego elementu tablicy (musi być mniejszy od 0x00FF(255).

    Code:

    00000026 <trianglewave>:
      26:   00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e     ................
      36:   20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e      "$&(*,.02468:<>
      46:   40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e     @BDFHJLNPRTVXZ\^
      56:   60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e     `bdfhjlnprtvxz|~
      66:   80 82 84 86 88 8a 8c 8e 90 92 94 96 98 9a 9c 9e     ................

    W tym przypadku jest OK, bo adres ostatniej komórki to 0x0075(117).
    Można by oczywiście napisać bardziej uniwersalną procedurę nie mającą takich ograniczeń, ale to wymagałoby więcej czasu, którego niestety nie mam za dużo. Poza tym uważam, że lepszym rozwiązaniem byłoby to zrobić przy użyciu przerwań timera.

    Qbik wrote:

    Rezystor na którym robię pomiary ma 10k (tolerancja 5%).

    No to zdecydowanie nie to samo co wysokoimpedancyjne wejście wzmacniacza operacyjnego. Drabinka działa na zasadzie dzielnika napięcia i tak mała rezystancja obciążenia na pewno spowoduje nieprawidłową pracę przetwornika. Myślę, że spokojnie możesz ten rezystor pominąć lub przynajmniej daj coś w okolicach 200k lub nawet więcej.