Lookup-Table (AVR-Assembler) funktioniert nicht

Gast #786525
Lesenswert?

Hallo,

wegen definierter Schleifendurchlaufzeit will ich Werte aus einer 
Lookup-Table (Sinuskurve) nacheinander ausgeben. Allerdings funktioniert 
das nicht. Von den 256 Werten werden nur die ersten 50 ausgegeben und 
die restlichen Werte sind immer 0. Das ganze basiert übrigens auf Jesper 
Hansen MiniDDS (http://www.myplace.nu/avr/minidds/index.htm).

Aufgerufen wird die DDS-Fkt. aus der main()-Fkt., ist also alles 
eigentlich in C programmiert und wegen definierter 
Endlosschleifendurchlaufzeit habe ich die DDS-Geschichte in Assembler 
von o.g. Seite übernommen.

Der Code, separate Datei dds.S
1
#include <avr/io.h>
2

3
.section .text
4

5
; force table to begin at 256 byte boundary
6
.org 0x100
7

8
sine: ; 256 step sinewave table
9
.byte 0x80,0x83,0x86,0x89,0x8c,0x8f,0x92,0x95,0x98,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae
10
.byte 0xb0,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4,0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0xd5,0xd8
11
.byte 0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xed,0xef,0xf0,0xf2,0xf3,0xf5
12
.byte 0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfc,0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff
13
.byte 0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfd,0xfc,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7
14
.byte 0xf6,0xf5,0xf3,0xf2,0xf0,0xef,0xed,0xec,0xea,0xe8,0xe6,0xe4,0xe2,0xe0,0xde,0xdc
15
.byte 0xda,0xd8,0xd5,0xd3,0xd1,0xce,0xcc,0xc9,0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0xb6,0xb3
16
.byte 0xb0,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x98,0x95,0x92,0x8f,0x8c,0x89,0x86,0x83
17
.byte 0x80,0x7c,0x79,0x76,0x73,0x70,0x6d,0x6a,0x67,0x63,0x60,0x5d,0x5a,0x57,0x54,0x51
18
.byte 0x4f,0x4c,0x49,0x46,0x43,0x40,0x3e,0x3b,0x38,0x36,0x33,0x31,0x2e,0x2c,0x2a,0x27
19
.byte 0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x12,0x10,0x0f,0x0d,0x0c,0x0a
20
.byte 0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x03,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00
21
.byte 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08
22
.byte 0x09,0x0a,0x0c,0x0d,0x0f,0x10,0x12,0x13,0x15,0x17,0x19,0x1b,0x1d,0x1f,0x21,0x23
23
.byte 0x25,0x27,0x2a,0x2c,0x2e,0x31,0x33,0x36,0x38,0x3b,0x3e,0x40,0x43,0x46,0x49,0x4c
24
.byte 0x4f,0x51,0x54,0x57,0x5a,0x5d,0x60,0x63,0x67,0x6a,0x6d,0x70,0x73,0x76,0x79,0x7c
25

26
.global dds
27
.func dds
28

29
dds:
30
  ldi   31,hi8(sine) ; setup Z pointer hi
31
  ldi   30,lo8(sine) ; setup Z pointer lo
32

33
  ; setup adder registers
34
  ldi   28,0
35
  ldi   29,0
36

37
  ; setup Phasenakku
38
  ldi   24,0xE4
39
  ldi   25,0x18
40
  ldi   26,0x00
41
  cli
42

43
; 200Hz Endlosschleife
44
LOOP1:
45
  nop           ; 1 Takt
46
  nop           ; 1 Takt
47
  add   28,24   ; 1 Takt
48
  adc   29,25   ; 1 Takt
49
  adc   30,26   ; 1 Takt
50
  lpm           ; 3 Takte
51
  out   _SFR_IO_ADDR(PORTD),0
52
  rjmp  LOOP1
53

54
.endfunc
55
.end

Diese Endlosschleife ergibt einen Teil der Sinuskurve aus der 
Loopkup-Table, nämlich exakt die ersten 50 Werte, also erster Wert = 
0x80,  letzter Wert = 0xF7. Auf dem Oszilloskop habe ich mir das 
angesehen und festgestellt, daß es 200,00 Hz sind bei 7,3728 Mhz, bin 
mir aber da nicht so sicher. Kurve übrigens im Anhang, die Schräge Linie 
im Bild ist Teil der Sinuskurve, also nicht linear.

Wo ist der Rest der Werte?

Der Aufruf aus der C-Funktion ist einfach nur dds();
Angehängte Dateien:
Gast #787456
Lesenswert?

Der Code an sich sollte eigentlich funktionieren.

Das .org 0x100 ist vermutlich das Problem, wenn Du C und Assembler 
mischen willst.

Um den Code an 256 Byte Grenzen auszurichten wird align 8 verwendet.
Gast #787486
Lesenswert?

@Ludger
!!!! Volltreffer !!!!
Es ist das ".align 8" nötig und nicht ".org 0x100" oder ".org 0x200". 
Ich habe es gerade mal geändert und der Scope malt mir einen richtig 
runden Sinus. Jetzt muß ich den ganzen Krams nochmal durchrechnen wegen 
Grundfrequenz und Variation in festen, ganzen Schritten und dann wieder 
aus der Endloschleife eine abbrechbare Schleife machen. Aber das hatte 
ich schon, habs nur wegen des Fehlers rausgeschmissen.

@Torsten S.
Wenn du dir mal asm-Beispielcode in GCC und in einer separaten Datei 
ankukkst, dan iwrst du sehen, das die Register ohne 'r' geschrieben 
werden. Ist zwar ungewöhnlich, weil so Dingers wie "mov 16,24" und "ldi 
16,24" zwei verschiedene Dingers sind ("mov Reg,Reg" vs. "ldi 
Reg,Konst").

Danke an euch, vorallen Ludger!
Gast #788883
Lesenswert?

So wie's aussieht, wird die Sinus-Tabelle ab Adresse 0x400 hingepackt.
1
 ....
2
 3c0:   80 93 0d 01     sts     0x010D, r24
3
 3c4:   10 92 0a 01     sts     0x010A, r1
4
 3c8:   0e 94 80 02     call    0x500 <dds>
5
 3cc:   5b cf           rjmp    .-330           ; 0x284 <main+0xac>
6
        ...
7

8
00000400 <sinus>:       vvvvvvvvvvvvvvvvv Codemüll
9
 400:   80 83           st      Z, r24
10
 402:   86 89           ldd     r24, Z+22       ; 0x16
11
 404:   8c 8f           std     Y+28, r24       ; 0x1c
12
 406:   92 95           swap    r25
13
 ...    ^^^^^ Sinuswerte
Auszug aus .lss-Datei
Gast #789280
Lesenswert?

Das .align 8 bewirkt nur, dass das Folgende an einer >runden< Page 
Adresse beginnt. Je nachdem wieviel Code noch vorher gelinkt wird, ist 
das dann eben 0x200, 0x300, ..., 0x1f500, ..., 0x1ff00, usw.

Fuer die Sinustabelle in der dds ist es aber nur wichtig, genau eine 
Page zu belegen, da dann das ZH Register beim Zugriff auf die 
Sinustabelle immer gleich bleibt.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren