Witam !
Znalazłem w sieci projekt uniwersalnego generatora przebiegów sinus, trójkąt, piła etc. o nazwie "Mini DDS" Link
Kod źródłowy do tego projektu napisany jest w asemblerze:
Pętla główna zajmuje 9 cykli zegara.
Algorytm jest dość prosty: do akumulatora fazy dodawana jest stała wartość. Gdy ta wartość jest odpowiednia - pobierane są odpowiednie wartości z tablicy przebiegów (sinus, trójkąt, piła) etc.
Po przeanalizowaniu projektu chciałem wykonać swój (podobny) z tym że napisany w C a nie asemblerze.
Ogólnie w C cała pętla główna składa się z kilku linijek:
U mnie zajmuje to 11 cykli zegara (wg. AVR Studio).
W chwili obecnej symulowałem oba projekty w Proteusie.
I tu zaczyna się sedno sprawy:
Projekt oryginalny - asemblerowy - generuje zadaną częstotliwość.
Mój projekt - z uwzględnieniem większej ilości cykli zegara i po przeliczeniach również generuje sygnał - jednak częstotliwość odbiega od tej która powinna być. Jakie są odchyłki ? np. dla zadanego 20kHz dostaję koło 17.5kHz etc.
Różnica w obu projektach jest w wielkości akumulatora - ja zastosowałem 16 bitowy zamiast 24 bitowego - jednak teoretycznie wpływać powinno to tylko na rozdzielczość ustawiania częstotliwości.
Zrobiłem również eksperyment - w oryginalnym projekcie dodałem 2 operacje "nop" - tak aby liczba cykli również była 11 - jednak tutaj częstotliwość sygnału generowanego zgadza się z tą obliczoną.
Nie mam już zbytnio pomysłu dlaczego tak się dzieje. W proteusie liczyłem nawet ile wykonują się instrukcje z dekompilowanego hex'a z mojego projektu - wychodzi 11 - więc wszystko powinno być ok.
Jeżeli ktoś ma jakieś sugestię będę wdzięczny. W załączniku oba projekty w AVR Studio
Znalazłem w sieci projekt uniwersalnego generatora przebiegów sinus, trójkąt, piła etc. o nazwie "Mini DDS" Link
Kod źródłowy do tego projektu napisany jest w asemblerze:
; main loop
;
; r28,r29,r30 is the phase accumulator
; r24,r25,r26 is the adder value determining frequency
;
; add value to accumulator
; load byte from current table in ROM
; output byte to port
; repeat
;
LOOP1:
add r28,r24 ; 1
adc r29,r25 ; 1
adc r30,r26 ; 1
lpm ; 3
out PORTB,r0 ; 1
rjmp LOOP1 ; 2 => 9 cycles
Pętla główna zajmuje 9 cykli zegara.
Algorytm jest dość prosty: do akumulatora fazy dodawana jest stała wartość. Gdy ta wartość jest odpowiednia - pobierane są odpowiednie wartości z tablicy przebiegów (sinus, trójkąt, piła) etc.
Po przeanalizowaniu projektu chciałem wykonać swój (podobny) z tym że napisany w C a nie asemblerze.
Ogólnie w C cała pętla główna składa się z kilku linijek:
int main(void)
{
R2RDDR = 0xff;
uint16_t akumulator=0 ,deltaPhase=1200;
while(1)
{
akumulator += deltaPhase ;
R2RPORT = sinewave[akumulator >> 8] ;
}
return 0;
} U mnie zajmuje to 11 cykli zegara (wg. AVR Studio).
W chwili obecnej symulowałem oba projekty w Proteusie.
I tu zaczyna się sedno sprawy:
Projekt oryginalny - asemblerowy - generuje zadaną częstotliwość.
Mój projekt - z uwzględnieniem większej ilości cykli zegara i po przeliczeniach również generuje sygnał - jednak częstotliwość odbiega od tej która powinna być. Jakie są odchyłki ? np. dla zadanego 20kHz dostaję koło 17.5kHz etc.
Różnica w obu projektach jest w wielkości akumulatora - ja zastosowałem 16 bitowy zamiast 24 bitowego - jednak teoretycznie wpływać powinno to tylko na rozdzielczość ustawiania częstotliwości.
Zrobiłem również eksperyment - w oryginalnym projekcie dodałem 2 operacje "nop" - tak aby liczba cykli również była 11 - jednak tutaj częstotliwość sygnału generowanego zgadza się z tą obliczoną.
Nie mam już zbytnio pomysłu dlaczego tak się dzieje. W proteusie liczyłem nawet ile wykonują się instrukcje z dekompilowanego hex'a z mojego projektu - wychodzi 11 - więc wszystko powinno być ok.
Jeżeli ktoś ma jakieś sugestię będę wdzięczny. W załączniku oba projekty w AVR Studio
