Forum: Mikrocontroller und Digitale Elektronik Berechnung der Frequenzwörter eines AD9850 auf einem Atmega in ASM


von asmfreak (Gast)


Lesenswert?

Hi,

ich habe eine Funktion in Assembler geschrieben, die es erlaubt, von 
einer beliebigen Frequenz die Steuerwörter für den DDS Baustein zu 
bilden. Augenmerk lag dabei auf die Ausführungsgeschwindigkeit. Mit 67 
bis 74 Takten dürfte dies mit die schnellste Version sein (bei 16MHz 
sind das nur 4,2 bis 4,6µs). Die maximale Abweichung vom exakten 
Ergebnis sollte bei 1 Bit liegen (dürfte nur selten auftreten).

Ich würde nun gerne wissen, wie man diese Funktion platzsparend als 
Schleife ausführen könnte. Mein Ansatz wäre, den Abschnitt calcAA über 
alle Bereiche laufen zu lassen (ggf. mit einer weiteren internen 
Schleife). Die "magischen Zahlen" könnten doch mittels Pointer zugeführt 
werden. Man könnte auch einen zweiten Pointer über die Register laufen 
lassen (oder über den Ram), wo die Frequenz hinterlegt ist. Allerdings 
komme ich da auf die dreifache Laufzeit. Lässt sich hier Speicherplatz 
überhaupt sinvoll einsparen?

Das sind meine ersten Schritte mit Assembler und Atmega, Kommentare sind 
also gerne erwünscht. Als größeres Ziel habe ich mir gesetzt, einen 
kleinen Signalgenerator zu bauen, der auch simple Modulationsverfahren 
beherrscht (erst einmal Sachen wie OOK, FSK). Der Code kann gerne 
kopiert werden.
1
;table:
2
;you could get another bit of resolution out of this, if you shift all bits in the table one time to the left (the AD9850 accepts words up to 7FFFFFFF). 
3
;if you want to sacrifice the X0Mhz range, you could get even further
4
;if you want to gain more speed, you can drop the rounding and the .XX Hz range 
5
;12 34 56 78.90 Hz                                                                     / 2^8               calculated
6
;.. .. .. .. EE                                     01010111  x  90  =           7830  30,5859375          30,9237645312
7
;.. .. .. DD ..                            00100010 01011100  x  78  =         686088  2680,03125          2680,059592704
8
;.. .. CC .. ..                   00001101 01101011 11111001  x  56  =       49258104  192414,46875        192414,5348608
9
;.. BB .. .. ..          00000101 00111110 00101101 01100010  x  34  =     2990671620  11682311,015625     11682311,04512
10
;AA .. .. .. .. 00000010 00001100 01001001 10111010 01011110  x  12  =   105553116264  412316860,40625     412316860,416
11
;                                                                   +=   108593739906  424194296,5078125   424194296,9793380352
12
13
.def rFreqE = r16
14
.def rFreqD = r17 ;Word 4
15
.def rFreqC = r18 ;Word 3
16
.def rFreqB = r19 ;Word 2
17
.def rFreqA = r20 ;Word 1
18
.def rPhase = r21
19
.def rTemp = r22
20
.def rZero = r23
21
.def rAA = r24 ;XX000000.00Hz
22
.def rBB = r25 ;00XX0000.00Hz
23
.def rCC = r26 ;0000XX00.00Hz
24
.def rDD = r27 ;000000XX.00Hz
25
.def rEE = r28 ;00000000.XXHz
26
27
calcWord:
28
calcAA:
29
  ldi rTemp,0b01011110
30
  mul rTemp,rAA
31
;  adc rFreqE,r0
32
;  adc rFreqD,r1
33
;saves 1 instruction
34
  movw rFreqE,r0
35
  ldi rTemp,0b10111010
36
  mul rTemp,rAA
37
  adc rFreqD,r0
38
  adc rFreqC,r1
39
  ldi rTemp,0b01001001
40
  mul rTemp,rAA
41
  adc rFreqC,r0
42
  adc rFreqB,r1
43
  ldi rTemp,0b00001100
44
  mul rTemp,rAA
45
  adc rFreqB,r0
46
  adc rFreqA,r1
47
;  ldi rTemp,0b00000010
48
;  mul rTemp,rAA
49
;  adc rFreqA,r0
50
;saves 1 instruction
51
  mov rTemp,rAA
52
  lsl rTemp
53
  adc rFreqA,rTemp
54
calcBB:
55
  ldi rTemp,0b01100010
56
  mul rTemp,rBB
57
  adc rFreqE,r0
58
  adc rFreqD,r1
59
  ldi rTemp,0b00101101
60
  mul rTemp,rBB
61
  adc rFreqD,r0
62
  adc rFreqC,r1
63
  ldi rTemp,0b00111110
64
  mul rTemp,rBB
65
  adc rFreqC,r0
66
  adc rFreqB,r1
67
  ldi rTemp,0b00000101
68
  mul rTemp,rBB
69
  adc rFreqB,r0
70
  adc rFreqA,r1
71
calcCC:
72
  ldi rTemp,0b11111001
73
  mul rTemp,rCC
74
  adc rFreqE,r0
75
  adc rFreqD,r1
76
  ldi rTemp,0b01101011
77
  mul rTemp,rCC
78
  adc rFreqD,r0
79
  adc rFreqC,r1
80
  ldi rTemp,0b00001101
81
  mul rTemp,rCC
82
  adc rFreqC,r0
83
  adc rFreqB,r1
84
calcDD:
85
  ldi rTemp,0b01011100
86
  mul rTemp,rDD
87
  adc rFreqE,r0
88
  adc rFreqD,r1
89
  ldi rTemp,0b00100010
90
  mul rTemp,rDD
91
  adc rFreqD,r0
92
  adc rFreqC,r1
93
;calcEE:;optional
94
;  ldi rTemp,0b01010111
95
;  mul rTemp,rEE
96
;  adc rFreqE,r0
97
;  adc rFreqD,r1
98
;rounding:;optional
99
;  rol rFreqE
100
;  adc rFreqD,rZero

von W.S. (Gast)


Lesenswert?

Gratulation..

W.S.

von Karl M. (Gast)


Lesenswert?

Hallo,

und auf welcher DDS-Taktfrequenz basiert der Ansatz ?
Wie kann die DDS-Taktfrequenz korrigiert werden ?
Wenn die Taktfrequenz etwas daneben liegt ?

von Arduinoquäler (Gast)


Lesenswert?

Hinausgeschieben müssen die 32 Bit ja auch noch. Und da das
nicht beliebig schnell geht bietet es sich vielleicht an
geschachtelt (interleaved) zu rechnen. Also ein Byte rechnen
und gleich rausschreiben, wieder ein Byte rechnen usw. Dann
kann man - während die SPI aktiv ist - ein Byte rechnen ohne
auf das Busy Flag zu warten. Das muss man aber später noch
nachholen ....

So haben wir das früher auf dem Apple (II/IIGS) gemacht.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.