DDS mit R/2R-Netzwerk, Output unsauber

#1661414
Lesenswert?

Mein Signalgenerator hat Fortschritte gemacht und ich habe jetzt ein 
Ausgangssignal, dieses sieht aber aus wie in signal.jpg. Die Sinuskurve 
ist erkennbar, aber leider eben auch nur etwa die Hälfte davon.

Ich habe keine Ahnung, was diese Störung genau verursachen könnte. Die 
Schaltung mit dem R/2R-Netz ist auf schematic.gif und die Routine, die 
die Welle ausgibt, sieht so aus:
1
void static inline Signal_OUT(const uint8_t *signal, uint8_t ad2, uint8_t ad1, uint8_t ad0) {
2

3
  asm volatile(  "eor r18, r18       ;r18<-0"                     "\n\t"
4
          "eor r19, r19              ;r19<-0"                     "\n\t"
5
          "1:"                                                    "\n\t"
6
          "add r18, %0               ;1 cycle"                    "\n\t"
7
          "adc r19, %1               ;1 cycle"                    "\n\t"  
8
          "adc %A3, %2               ;1 cycle"                    "\n\t"
9
          "lpm                       ;3 cycles"                   "\n\t"
10
          "out %4, __tmp_reg__       ;1 cycle"                    "\n\t"
11
          "sbis %5, 1                ;1 cycle if no skip"         "\n\t"
12
          "rjmp 1b                   ;2 cycles. Total 10 cycles"  "\n\t"
13
          :
14
          :"r" (ad0),"r" (ad1),"r" (ad2),"z" (signal),
15
                "I" (_SFR_IO_ADDR(PORTE)), "I" (_SFR_IO_ADDR(PINA))
16
          :"r18", "r19" 
17
  );
18
}

Wenn sich da jemand einen Reim darauf machen kann wäre ich wirklich sehr 
froh, ich hab mir schon den Kopf zerbrochen aber kenne mich mit der 
Materie wohl einfach noch zu wenig aus.

Grüsse
Martin
Angehängte Dateien:
#1661430
Lesenswert?

Hi Falk

Dies ist die Sinustabelle:

const uint8_t sinewave[] PROGMEM = { //256 values
  0x80,0x83,0x86,0x89,0x8c,0x8f,0x92,0x95,0x98,0x9c,0x9f,0xa2,0xa5,0xa8,0x 
ab,0xae,
  0xb0,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4,0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0x 
d5,0xd8,
  0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xed,0xef,0xf0,0xf2,0x 
f3,0xf5,
  0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfc,0xfd,0xfe,0xfe,0xff,0xff,0xff,0x 
ff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfd,0xfc,0xfc,0xfb,0xfa,0xf9,0x 
f8,0xf7,
  0xf6,0xf5,0xf3,0xf2,0xf0,0xef,0xed,0xec,0xea,0xe8,0xe6,0xe4,0xe2,0xe0,0x 
de,0xdc,
  0xda,0xd8,0xd5,0xd3,0xd1,0xce,0xcc,0xc9,0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0x 
b6,0xb3,
  0xb0,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x98,0x95,0x92,0x8f,0x8c,0x89,0x 
86,0x83,
  0x80,0x7c,0x79,0x76,0x73,0x70,0x6d,0x6a,0x67,0x63,0x60,0x5d,0x5a,0x57,0x 
54,0x51,
  0x4f,0x4c,0x49,0x46,0x43,0x40,0x3e,0x3b,0x38,0x36,0x33,0x31,0x2e,0x2c,0x 
2a,0x27,
  0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x12,0x10,0x0f,0x0d,0x 
0c,0x0a,
  0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x03,0x02,0x01,0x01,0x00,0x00,0x00,0x 
00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x05,0x06,0x 
07,0x08,
  0x09,0x0a,0x0c,0x0d,0x0f,0x10,0x12,0x13,0x15,0x17,0x19,0x1b,0x1d,0x1f,0x 
21,0x23,
  0x25,0x27,0x2a,0x2c,0x2e,0x31,0x33,0x36,0x38,0x3b,0x3e,0x40,0x43,0x46,0x 
49,0x4c,
  0x4f,0x51,0x54,0x57,0x5a,0x5d,0x60,0x63,0x67,0x6a,0x6d,0x70,0x73,0x76,0x 
79,0x7c
};

Kannst du das bestätigen? Ich verstehe, was du meinst, aber meiner 
Meinung nach geht die Welle nie "unter Null". Oder doch?

Grüsse
Martin
#1661488
Lesenswert?

Hi Spess

Kannst du das bitte etwas genauer erläutern? Ich habe die Routine nicht 
selbst entwickelt und bin überhaupt kein Assembler-Spezialist. Könnte 
das diesen Effekt hervorrufen und wie (genau) wäre der Code 
umzuschreiben?

Die Routine und die Sinustabelle stammen vom selben Autor und haben bei 
ihm offenbar funktioniert, aber vielleicht muss ja doch noch etwas 
geändert werden.

Grüsse
Martin
Gast #1661502
Lesenswert?

Hi

Das funktioniert nur wenn die Tabelle in einem Adressbereich von 
$XX00-$XXFF liegt. Also ZH für die gesamte Tabelle einen konstanten Wert 
hat. Wenn das nicht der Fall ist, werden die Werte aus Speicheradressen, 
die nicht zur Tabelle gehören, gelesen.

Beispiel: Deine Tabelle liegt im Speicher ab $1F80 dann wäre ZH=$1F. 
Wenn auf einen Tabellenoffset von $90 zugegriffen werden soll wäre das 
die Speicheradresse $2010. Tatsächlich greift der obige Programmteil 
aber auf $1F10 zu.

MfG Spess
#1662028
Lesenswert?

Hallo ihr beiden

Coole Sache, dank dem Hinweis habe ichs hinbekommen, aber darauf wäre 
ich sonst im Leben nie gekommen als C-Programmierer ;-)

Das dauerte noch etwas bis ich den Speicherbereich auch im AVRStudio 
zuweisen konnte mit der automatischen Makefile-Erzeugung, aber bei 
richtigem Eintrag unter "Project" > "Configuration Options" > "Memory 
Settings" funktionierts.

Vielen Dank!

Grüsse
Martin
Angehängte Dateien:
#1733679
Lesenswert?

Am einfachsten schreibt man sich am PC dafür ein Programm :-)

Im Prinzip kann man auch zb mit Excel die Werte ganz einfach erzeugen, 
allerdings ist dann bei der Übernahme in den C-Code wieder Handarbeit 
abgesagt.

Daher: den C Compiler am PC anwerfen und die Kurvenform programmieren.
Die meisten Kurvenformen sind ja trivial. Die meiste Arbeit geht für das 
anständige Formatieren der Ausgabe drauf :-)
1
#include <stdio.h>
2
#include <math.h>
3

4
int main()
5
{
6
  FILE * outFile;
7
  double alpha, increment;
8
  int nrValues, value;
9

10
  outFile = fopen( "wave.h", "w" );
11

12
  increment = 2 * PI / 256;
13
  nrValues = 0;
14

15
  for( alpha = 0.0; alpha < 2 * PI + increment / 2.0; alpha += increment ) {
16

17
    value = (int)( sin( alpha ) * 128.0 + 128.0 + 0.5 );
18
    fprintf( outFile, "%02x", value );
19

20
    nrValues++;
21
    if( nrValues == 16 ) {
22
      fprintf( outFile, "\n" );
23
      nrValues = 0;
24
    }
25
    else
26
      fprintf( outFile, ", " );
27
  }
28

29
  fclose( outFile );
30
}

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