logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

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

Qbik 20 Lip 2010 14:35 2851 10
  • #1 8311694
    Qbik
    Poziom 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).

     #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
  • #2 8312373
    Andrzej__S
    Poziom 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:

    
    //na początku dodaj
    #include <avr/pgmspace.h>
    
    //zmień
    const uint8_t trianglewave[] PROGMEM =
    {
       ...
    }
    
  • #3 8312379
    tmf
    VIP Zasłużony dla elektroda
    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 8314418
    Qbik
    Poziom 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 8314510
    Andrzej__S
    Poziom 28  
    Qbik napisał:
    Dalej mam ten sam obraz.


    Bo wykraczasz poza rozmiar tablicy. Żeby Twój program działał poprawnie musisz po linijce
    
    "adc %A3, %2   ;1 cycle"         "\n\t"
    

    sprawdać, czy wskaźnik w rejestrze z nie przekroczył rozmiaru tablicy.
  • #6 8314554
    Qbik
    Poziom 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 8314809
    Andrzej__S
    Poziom 28  
    Spróbuj tak:
    
    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 8314866
    Qbik
    Poziom 10  
    Niestety jest dokładnie to samo co było w poprzednim kodzie :( Tablica ma na pewno mniej elementów niz 255.
  • #9 8315484
    Andrzej__S
    Poziom 28  
    Spieszyłem się trochę i zrobiłem jeden drobny błąd. Zamiast:
    
                "ldi r21, 0x51   ;r21<-rozmiar tablicy + 1"   "\n\t"
    


    powinno być:
    
                "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 napisał:

    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 napisał:

    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 napisał:

    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 8318309
    Qbik
    Poziom 10  
    Witam, przepraszam, że dopiero teraz odpowiadam ale miałem dużo na głowie.
    Andrzej__S napisał:
    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 napisał:
    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.
    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 napisał:
    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 8318523
    Andrzej__S
    Poziom 28  
    Qbik napisał:

    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:
    
                "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).

    
    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 napisał:

    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.
REKLAMA