www.mikrocontroller.net

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


Autor: Hegy (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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
#include <avr/io.h>

.section .text

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

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

.global dds
.func dds

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

  ; setup adder registers
  ldi   28,0
  ldi   29,0

  ; setup Phasenakku
  ldi   24,0xE4
  ldi   25,0x18
  ldi   26,0x00
  cli

; 200Hz Endlosschleife
LOOP1:
  nop           ; 1 Takt
  nop           ; 1 Takt
  add   28,24   ; 1 Takt
  adc   29,25   ; 1 Takt
  adc   30,26   ; 1 Takt
  lpm           ; 3 Takte
  out   _SFR_IO_ADDR(PORTD),0
  rjmp  LOOP1

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

Autor: Ludger (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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

Autor: Torsten S. (tse)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
etwa hier?
out   _SFR_IO_ADDR(PORTD),0

sollte bestimmt
out   _SFR_IO_ADDR(PORTD), r0

sein.

Autor: Torsten S. (tse)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Ludger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Hegy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Ludger (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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 :-)

Autor: Hegy (Gast)
Datum:

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

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

Autor: Ludger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.