Forum: Compiler & IDEs Lookup-Table (AVR-Assembler) funktioniert nicht


von Hegy (Gast)


Angehängte Dateien:

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();

von Ludger (Gast)


Angehängte Dateien:

Lesenswert?

Hi,

habe mir >Deinen< Code nicht wirklich angesehen, sondern die 
Sinustabelle kopiert und den Rest angepasst.

Ausserdem hab ichs bei assembler belassen.

Gruss,
 Ludger

von Torsten S. (tse)


Lesenswert?

etwa hier?
out   _SFR_IO_ADDR(PORTD),0

sollte bestimmt
out   _SFR_IO_ADDR(PORTD), r0

sein.

von Torsten S. (tse)


Lesenswert?

Huch, ich sehe gerade Du hast ja alle r's weg gelassen. Wußte gar nicht 
das das geht. Und ob das sinnvoll ist.

von Gast (Gast)


Lesenswert?

vielleicht liegt es hieran?

ldi   r31,hi8(sine<<1) ; setup Z pointer hi
ldi   r30,lo8(sine<<1) ; setup Z pointer lo
                  --
Falls die Tabelle im Flash liegt.

von Ludger (Gast)


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.

von Hegy (Gast)


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!

von Ludger (Gast)


Angehängte Dateien:

Lesenswert?

Nichts zu danken!

Ich erzeuge mir in der Regel mit OBJDUMP ein Linker Listing. Da kann man 
sehen, was der Linker an Assembler Code generiert hat und an welche 
Stelle es gelinkt wurde.

Siehe makefile im angehaengten zip :-)

von Hegy (Gast)


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

von Ludger (Gast)


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.

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.