Forum: Mikrocontroller und Digitale Elektronik AD9833 will einfach nicht.


von Karsten K. (karsten42)


Angehängte Dateien:

Lesenswert?

Moin Moin!

Ich habe mir ein AD9833 Modul aus der Bucht gekauft um damit einen 
genauen 1Khz Sinus zu erzeugen. Später auch Frequenzen von 200Hz - 
10Khz. Dazu habe ich den Quarzoszillator von 25Mhz ausgelötet und einen 
externen mit 4.194304Mhz angeschlossen.

Aus einigen Beiträgen habe ich entnommen, das das Timing der SPI nicht 
"ganz ohne" ist.Pro Beitrag wurde auch eine unterschiedliche 
Initialisierung vom AD9833 vorgeschlagen die sich alle nicht mit dem 
Datenblatt oder der AN decken.

Aus dem Teil kommt entweder sporadisch ein Sinus zwischen 3Khz und 1Khz, 
schwer verrauscht, heraus oder nichts.

Anbei mein Code der eigentlich eine Kopie von Martin Wende ist. Dazu 
noch zwei Bilder vom SPI timing. Ich kann einfach keinen Grund sehen 
warum das Teil ( zumindest wegen des SPI timings ) nicht laufen soll.

Hat jemand von euch einen Tipp oder einen tatsächlich laufenden 
Code-snipsel als Beispiel??

100000*10^12 Daaanke

Karsten
1
#include <avr/io.h>
2
#include <inttypes.h>
3
#include <stdint.h>
4
#include <util/delay.h>
5
#include "utils.h"
6
7
//----------------------------------------------------------------------------
8
// control register bit definitions for DDS
9
// Register 16Bit
10
//
11
// DB15|DB14|DB13|DB12|DB11|DB10|DB9|DB8| |DB7|DB6|DB5|DB4|DB3|DB2|DB1|DB0|
12
//   0 |  0 | B28| HLB|FSEL|PSEL| 0 |RST| |SL1|SL2|OPB| 0 |DV2| 0 |MOD| 0 |
13
//----------------------------------------------------------------------------
14
#define B28      13
15
#define HLB      12
16
#define FSELECT  11
17
#define PSELECT  10
18
#define DDRESET  8
19
#define SLEEP1    7
20
#define SLEEP2    6
21
#define OPTBITEN  5
22
#define DIV2    3
23
#define MODE    1
24
25
//----------------------------------------------------------------------------
26
// Chip select for SPI data of DDS
27
//----------------------------------------------------------------------------
28
#define CS_AD9833  B,2
29
30
//----------------------------------------------------------------------------
31
// ATMEGA88  SPI
32
//----------------------------------------------------------------------------
33
#define  P_MOSI  B,3
34
#define  P_MISO  B,4
35
#define  P_SCK  B,5
36
#define  P_SS  B,2
37
38
//Debug Port
39
#define DBG B,1
40
41
// Prototypes
42
void spi_init(void);
43
void DDS_write(uint16_t data);
44
void DDS_off(void);
45
void DDS_freq(uint32_t frq);
46
47
48
// current state bites of control register
49
static uint16_t state = 0;
50
51
int
52
main(void)  {
53
54
  _delay_ms(1000); // only for debugging
55
  SET(DBG);
56
  SET_OUTPUT(DBG); // Marker to trigger logic analyser
57
58
  spi_init();
59
  DDS_off();
60
  DDS_freq(1000);
61
62
  // MAIN loop
63
  while(1)  {
64
65
  }
66
}
67
68
69
void
70
spi_init(void) {
71
72
73
  // init SS to ensure SPI will work!
74
  SET(P_SS);
75
  SET_OUTPUT(P_SS);
76
77
  RESET(P_SCK);
78
  RESET(P_MOSI);
79
  RESET(P_MISO);
80
  
81
  SET_OUTPUT(P_SCK);
82
  SET_OUTPUT(P_MOSI);
83
  SET_INPUT(P_MISO);
84
85
  // activate SPI, set master, MODE 2 (CPHA=0,CPOL=1) , fosc/16 
86
  SPCR = (1<<SPE) | (1<<MSTR) | (1<<CPOL) | (1<<SPR0);  
87
88
}
89
90
91
void
92
DDS_write(uint16_t data)  {
93
94
95
  RESET(CS_AD9833);
96
97
  SPDR = (uint8_t)(data >> 8);  //Left 8 Bit
98
  while( !( SPSR & (1<<SPIF) ) );
99
100
  SPDR = (uint8_t)data;      //Right 8 Bit
101
  while( !( SPSR & (1<<SPIF) ) );
102
103
  SET(CS_AD9833);
104
}
105
106
void
107
DDS_off(void)  {
108
109
  state = (1<<B28) | (1<<DDRESET) | (1<<SLEEP1) | (1<<OPTBITEN) | (1<<MODE);
110
  DDS_write(state);
111
  state &= ~(1<<DDRESET);
112
  _delay_ms(1);
113
  DDS_write(state);
114
}
115
116
117
void
118
DDS_freq(uint32_t frq)  {
119
120
  //calculate FREQ register value 
121
  //for given frequence in Hz
122
  // 2^28 / 4194304Mhz = 64
123
  uint32_t regval = frq * 64;
124
125
  //Split 32Bit value in two 14Bit transfers
126
  //D15 and D14 define the frequency register. 
127
  //Fixed to D15 D14 = 01  means using FREQ0
128
  DDS_write(0x4000 | (regval & 0x3FFF));
129
  DDS_write(0x4000 | ((uint32_t)(regval >> 14) & 0x3FFFL));
130
}

von Jens W. (jensw)


Lesenswert?

Ich vermute den Fehler bei deinem Aufruf von DDS_write in der Funktion 
DDS_freq()

Da rufst du die Funktion mit einem Wert auf, den du explizit auf 32bit 
castest. Schau mal ob da die richtigen Werte geschrieben werden.
Mein Tip:
Verwende Variablen in uint16_t und caste deine Frequenz darauf. Wenn das 
fertig ist rufst du die Funktionen mit den Variablen auf.
Das ist ja nicht zeitkritisch, da kann man sich den Overhead leisten.

von Jens W. (jensw)


Lesenswert?

Ich habe nochmal ins Datenblatt geschaut. Du schreibst scheinbar keine 
Control-Bits. Wenn du Daten auf den Chip schreibst musst du doch 
mitteilen in welches Register das soll. Das machst du aber nicht. Oder 
täusche ich mich?
Schau dir mal die Flussdiagramme an wie so eine Geschichte gemacht 
werden soll. Diese Struktur ist bei dir im Programm noch nicht zu 
finden.
Datenblatt Seite 18/19

Gruß

von Karsten K. (karsten42)


Lesenswert?

Hallo Jens,

Daanke für deine Überlegungen.

Jens W. schrieb:
> ..Du schreibst scheinbar keine
> Control-Bits.

Im Zweiten Bild vom Analyser sieht man welche Bits gesendet werden.


Byte 1:
D15 und D14 = 0 was meint das das FREQ0 Register beschieben wird ( 
Datenblatt Seite 15 ). Danach noch B28 auf 1 für das laden von zwei 
Bytes. Im Weiteren sind SLEEP1, OPBITEN und MODE gesetzt.

Byte 3 und 4:
Enthalten den Wert für die Frequenz exakt so wie´s laut Datenblat für 
den Wert 0xFA00 sein soll.

Humm: SLEEP1, OBITEN, MODE.... Sieht irgendwie falsch aus oder?
Ich lese hier nochmal genau nach und probiere das gleich aus....

4 Augen sehen einfach mehr!!!!!!!!!!

Daaanke
Karsten

von Karl H. (kbuchegg)


Lesenswert?

Die SPI Einstellung sieht für mich gut aus. Clock Idle Polarity und 
Sample dürften richtig sein.

Wenn du das Timing in Verdacht hast, würde ich erst mal alles so langsam 
wie möglich machen. D.h. beim SPI den Vorteiler ganz hoch auf Anschlag. 
Nach dem Anlegen des Select erst mal eine kleine Pause. Eben alles so 
langsam wie es geht und alle Zeiten sehr grosszügig bemessen. Getreu dem 
Motto: zu langsam ist meistens kein Problem, zu schnell aber schon.

Das einzige was mir aufgefallen ist, das ist, dass du einen SLEEP1 
programmierst. Laut Doku sorgt das aber dafür, dass MCL disconnected 
wird und damit wird die ganze Generierung lahm gelegt. Das ist aber auch 
schon das einzige, was mir seltsam vorgekommen ist.
Was du da jetzt mit OBITEN und Mode für einr Waveform selektiert hast, 
hab ich jetzt nicht genauer nachgeforscht. Meinem Verständnis nach 
sollte überhaupt erst mal irgendwas rauskommen, egal wie die beiden 
stehen.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Jens W. schrieb:
> Ich habe nochmal ins Datenblatt geschaut. Du schreibst scheinbar keine
> Control-Bits.

Doch. ist da.
D15 und D14 sind 0. Damit ist das Control Register addressiert.

von Karsten K. (karsten42)


Lesenswert?

Jungs Ihr seid einfach wie immer GROßARTIG!

Es lag am SLEEP1 das ich nach dem setzten des FREQ0 Registers wieder auf 
0 setzen muss.
Ich hatte dies gesetzt um beim eventuellen Wechsel der 
Frequenz/Wellenform keinen "Schrott" am Ausgang zu haben.

Die Frequenz stimmt nun. Jedoch ist das Signal extrem verrauscht.... Ich 
hatte so in meinem Leichtsinn gedacht das ich da etwas chönes und 
exaktes aus dem Chip erwarten darf...
O.K. Da muss ich dann noch mal ran :-)

10000000000000000000000*10^12 Danke!

Gruß
Karsten

P.S. Hier der Code der funktioniert...
1
//----------------------------------------------------------------------------
2
// control register bit definitions for DDS
3
// Register 16Bit
4
//
5
// DB15|DB14|DB13|DB12|DB11|DB10|DB9|DB8| |DB7|DB6|DB5|DB4|DB3|DB2|DB1|DB0|
6
//   0 |  0 | B28| HLB|FSEL|PSEL| 0 |RST| |SL1|SL2|OPB| 0 |DV2| 0 |MOD| 0 |
7
//----------------------------------------------------------------------------
8
#define B28      13
9
#define HLB      12
10
#define FSELECT  11
11
#define PSELECT  10
12
#define DDRESET  8
13
#define SLEEP1    7
14
#define SLEEP2    6
15
#define OPBITEN  5
16
#define DIV2    3
17
#define MODE    1
18
19
#define OFF      0
20
#define ON      1
21
#define SINE    3
22
#define TRI      4
23
#define REC      5
24
#define REC2    6
25
26
27
//----------------------------------------------------------------------------
28
// Chip select for SPI data of DDS
29
//----------------------------------------------------------------------------
30
#define CS_AD9833  B,2
31
32
//----------------------------------------------------------------------------
33
// ATMEGA88  SPI
34
//----------------------------------------------------------------------------
35
#define  P_MOSI  B,3
36
#define  P_MISO  B,4
37
#define  P_SCK  B,5
38
#define  P_SS  B,2
39
40
//Debug Port
41
#define DBG B,1
42
43
// Prototypes
44
void spi_init(void);
45
void DDS_write(uint16_t data);
46
void DDS_reset(void);
47
void DDS_freq(uint32_t frq);
48
void DDS_signal(uint8_t mode);
49
50
51
// current state bites of control register
52
static uint16_t state = 0;
53
54
int
55
main(void)  {
56
57
  _delay_ms(1000); // only for debugging
58
  SET(DBG);
59
  SET_OUTPUT(DBG); // Marker to trigger logic analyser
60
61
  spi_init();
62
  DDS_reset();
63
  DDS_freq(400);
64
  DDS_signal(SINE);
65
66
  // MAIN loop
67
  while(1)  {
68
69
  }
70
}
71
72
73
void
74
spi_init(void) {
75
76
77
  // init SS to ensure SPI will work!
78
  SET(P_SS);
79
  SET_OUTPUT(P_SS);
80
81
  RESET(P_SCK);
82
  RESET(P_MOSI);
83
  RESET(P_MISO);
84
  
85
  SET_OUTPUT(P_SCK);
86
  SET_OUTPUT(P_MOSI);
87
  SET_INPUT(P_MISO);
88
89
  // activate SPI, set master, MODE 2 (CPHA=0,CPOL=1) , fosc/16 
90
  SPCR = (1<<SPE) | (1<<MSTR) | (1<<CPOL) | (1<<SPR0);  
91
92
}
93
94
95
void
96
DDS_write(uint16_t data)  {
97
98
99
  RESET(CS_AD9833);
100
101
  SPDR = (uint8_t)(data >> 8);  //Left 8 Bit
102
  while( !( SPSR & (1<<SPIF) ) );
103
104
  SPDR = (uint8_t)data;      //Right 8 Bit
105
  while( !( SPSR & (1<<SPIF) ) );
106
107
  SET(CS_AD9833);
108
}
109
110
void
111
DDS_reset(void)  {
112
113
  state = (1<<B28) | (1<<DDRESET) | (1<<SLEEP1) | (1<<OPBITEN) | (1<<MODE);
114
  DDS_write(state);
115
  state &= ~(1<<DDRESET);
116
  _delay_ms(1);
117
  DDS_write(state);
118
}
119
120
121
void
122
DDS_freq(uint32_t frq)  {
123
124
  //calculate FREQ register value 
125
  //for given frequence in Hz
126
  // 2^28 / 4194304Mhz = 64
127
  uint32_t regval = frq * 64;
128
129
  //Split 32Bit value in two 14Bit transfers
130
  //D15 and D14 define the frequency register. 
131
  //Fixed to D15 D14 = 01  means using FREQ0
132
  DDS_write(0x4000 | (regval & 0x3FFF));
133
  DDS_write(0x4000 | ((uint32_t)(regval >> 14) & 0x3FFFL));
134
}
135
136
void
137
DDS_signal(uint8_t mode)  {
138
139
  switch(mode)  {
140
141
    case OFF:
142
        state |= (1<<SLEEP1);
143
        break;
144
    case ON:
145
        state &= ~(1<<SLEEP1);
146
        break;
147
    case SINE:
148
        state &=  ~((1<<OPBITEN) | (1<<MODE) | (1<<SLEEP1));
149
        break;
150
    case REC2:
151
        state &=  ~((1<<MODE) | (1<<DIV2) | (1<<SLEEP1));
152
        state |= (1<<OPBITEN);
153
        break;
154
    case REC:
155
        state |= (1<<OPBITEN) | (1<<DIV2);
156
        state &= ~((1<<MODE) | (1<<SLEEP1));
157
        break;
158
    case TRI:
159
        state &= ~((1<<OPBITEN) | (1<<SLEEP1));
160
        state |= (1<<MODE);
161
        break;
162
    default:
163
        state |= (1<<OPBITEN) | (1<<MODE);
164
  }
165
166
  DDS_write(state);
167
}

: Bearbeitet durch User
von Felix A. (madifaxle)


Lesenswert?

Vielleicht hilft dir diese Info noch:

ich nutze den AD9834. Zum Starten und Stoppen lösche bzw. setze ich das 
Reset-Bit. Dieses bezieht sich nämlich nicht auf die internen Frequenz- 
und Phase-Register, in welchen man Frequenz und Phase einstellt, sondern 
nur auf die Register, die für das Ausgeben der Frequenz und Phase 
verantwortlich sind.
So kann man immer sauber bei quasi 0 starten und stoppen.

von W.S. (Gast)


Lesenswert?

Karsten K. schrieb:
> Dazu habe ich den Quarzoszillator von 25Mhz ausgelötet und einen
> externen mit 4.194304Mhz angeschlossen.

Karsten K. schrieb:
> Die Frequenz stimmt nun. Jedoch ist das Signal extrem verrauscht.... Ich
> hatte so in meinem Leichtsinn gedacht das ich da etwas chönes und
> exaktes aus dem Chip erwarten darf...

Was erwartest du da noch?
Setze den 25 MHz Oszillator wieder ein und bedenke, daß der Chip nur 
eine Amplitudenauflösung von 10 Bit hat. Selbstverständlich sieht man da 
die Stufigkeit des Ausgangssignales - und die ist nicht statisch, 
sondern verteilt, weil Takt und Ausgangsfrequenz in keinem ganzzahligen 
Verhältnis zueinander stehen. Also siehst du das auf dem Oszi als 
Quasi-Rauschen.

Falls du lediglich am Sinus interessiert bist, hilft ein ordentlicher 
Tiefpaß ein wenig weiter. Aber ganz beseitigen kann auch der beste 
Tiefpaß die Folgen der recht geringen Amplitudenauflösung nicht. Wenn du 
an einem wirklich sauberen NF-Sinus interessiert bist, dann hilft nur 
ein analoger Oszillator. Phasenschieber oder Wien-Robinson.

W.S.

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.