Forum: Mikrocontroller und Digitale Elektronik SPI ATmega32 mit AD9833


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Benedikt (Gast)


Lesenswert?

Hallo zusammen,

ich habe vor, einen AD9833 mit SPI an einem ATmega32 zu betreiben. Dazu 
habe ich im Internet eine Lib von fritzler-avr.de gefunden.

Ich habe mir auch gleich ein kleines Testprogramm geschrieben, mit dem 
ich den AD9833 initialisiern möchte und dessen Frequenz einstellen 
möchte.
Leider gibt mein SPI nichts aus. Alle drei Pins (SCK, MOSI, SS) gehen 
während ich eine LED, die an einem ganz anderen Port hängt anschalte, 
auf low und beim ausschalten wieder auf high (siehe Kommentare im 
Quellcode). Aber sonst gibt der SPI nichts aus. Eigentlich müsste ich 
doch beim Takt und Daten jeden Menge Flanken sehen oder?
Zur Info: an dem SPI hängt nichts dran, kein AD9833....auch der 
ISP-Programmer ist abgesteckt. Nur das Oszi hängt dran
Habe ich irgendwas vergessen?

Gruß
Benedikt

1
#include <util/delay.h>
2
#include <avr/interrupt.h>
3
#include <avr/io.h>
4
#include <util/delay.h>
5
6
7
//eigene defines, nicht verändern!
8
#define DDR(x) (*(&x - 1))
9
#define AUS       0
10
#define SINUS     1
11
#define RECHTECK  2
12
#define RECHTECK2 3
13
#define DREIECK   4
14
#define B28       13
15
#define HLB       12
16
#define FSELECT   11
17
#define PSELECT   10
18
#define RESET     8
19
#define SLEEP1    7
20
#define SLEEP12   6
21
#define OPBITEN   5
22
#define DIV2      3
23
#define MODE      1
24
#define FREQ0     18
25
#define FREQ1     28
26
#define PHASE0    38
27
#define PHASE1    48
28
#define pi2       6.2832
29
30
/*************************************Konfiguration***************************************/
31
//MasterClock des AD9833
32
#define MCLK 25000000
33
34
//SPI - SS muss den gleichen Port haben wie der Hardware SPI
35
#define SPIPORT PORTB
36
#define MOSI    5
37
#define SCK     7
38
#define SS      4
39
/*************************************Konfiguration***************************************/
40
41
//enthält den momentanen Status des AD9833
42
uint16_t stats = 0;
43
uint16_t tosend = 0;
44
double konst = 268435456; //2^28, (1<<28)
45
float konst2 = 4096; //2^12, (1<<12);
46
47
//schreibt ein Wort in den AD9833
48
void DDS_write(uint16_t data){
49
  SPIPORT &= ~(1<<SS);
50
  SPDR = (uint8_t)(data>>8);
51
  while(!(SPSR & (1<<SPIF)))
52
    ;
53
  SPDR = (uint8_t)(data & 255);
54
  while(!(SPSR & (1<<SPIF)))
55
    ;
56
  SPIPORT |= (1<<SS);
57
}
58
59
//resettet den Zähler des AD9833 und schaltte ihn ab, DAC getrennt
60
void DDS_off(void){
61
  //complete word write, Counter reset, MCLK Off, DAC disconnected, SINROM bypass
62
  stats = (1<<B28) | (1<<RESET) | (1<<SLEEP1) | (1<<OPBITEN) | (1<<MODE);
63
  DDS_write(stats);
64
  stats &= ~(1<<RESET);
65
  _delay_ms(1);
66
  DDS_write(stats);
67
}
68
69
//initilaisiert den Hardware SPI und den AD9833
70
void DDS_init(void){
71
  //SPI Init
72
  DDR(SPIPORT) |= (1<<MOSI) | (1<<SCK) | (1<<SS);
73
  SPIPORT |= (1<<SS);
74
  //MSB zuerst, Master, SCK Idle High, CLK/16
75
  SPCR = (1<<SPE)| (1<<MSTR) | (1<<CPOL) | (1<<SPR0);
76
  //DDS Init
77
  DDS_off();
78
}
79
80
//schaltet die Signalform des AD9833 um
81
//SINUS, DREIECK, RECHTECK, RECHTECK2, AUS
82
void DDS_signal (uint8_t signal){
83
  switch (signal){
84
    case AUS:
85
      DDS_off();
86
      break;
87
    case SINUS:
88
      stats &=  ~((1<<OPBITEN) | (1<<MODE) | (1<<SLEEP1));
89
      break;
90
    case RECHTECK2:
91
      stats &=  ~((1<<MODE) | (1<<DIV2) | (1<<SLEEP1));
92
      stats |= (1<<OPBITEN);
93
      break;
94
    case RECHTECK:
95
      stats |= (1<<OPBITEN) | (1<<DIV2);
96
      stats &= ~((1<<MODE) | (1<<SLEEP1));
97
      break;
98
    case DREIECK:
99
      stats &= ~((1<<OPBITEN) | (1<<SLEEP1));
100
      stats |= (1<<MODE);
101
      break;
102
    default:
103
      stats |= (1<<OPBITEN) | (1<<MODE);
104
  }
105
  DDS_write(stats);
106
}
107
108
//Auswahl des AD9833 Registers, welches für die Frequenz/Phase zuständig ist
109
//FREQ0, FREQ1, PHASE0, PHASE1
110
void DDS_reg(uint8_t reg){
111
  switch (reg){
112
    case FREQ0:
113
      stats &= ~(1<<FSELECT);
114
      break;
115
    case FREQ1:
116
      stats |= (1<<FSELECT);
117
      break;
118
    case PHASE0:
119
      stats &= ~(1<<PSELECT);
120
      break;
121
    case PHASE1:
122
      stats |= (1<<PSELECT);
123
      break;
124
    default:
125
      stats &= ~((1<<FSELECT) | (1<<PSELECT));
126
  }
127
  DDS_write(stats);
128
}
129
130
//stellt den AD9833 auf die gewünschte Freqenz in Hz ein
131
//der Wert wird in das angegebene Register geschrieben (FREQ0, FREQ1)
132
void DDS_freq(uint32_t frequenz, uint8_t reg){
133
  double temp = ((double)frequenz/(double)MCLK);
134
  uint32_t regist = temp * konst;
135
  tosend = regist & 16383;
136
  if (reg == FREQ0){tosend |= (1<<14);}
137
  if (reg == FREQ1){tosend |= (1<<15);}
138
  DDS_write(tosend);
139
  tosend = (regist & ~16383)>>14;
140
  if (reg == FREQ0){tosend |= (1<<14);}
141
  if (reg == FREQ1){tosend |= (1<<15);}
142
  DDS_write(tosend);
143
}
144
145
//stellt den AD9833 auf die gewünschte Phase ein
146
//der Wert wird in das angegebene Register geschrieben (PHASE0, PHASE1)
147
void DDS_phase(uint16_t phase, uint8_t reg){
148
  uint16_t regist = (uint16_t) (phase*konst2)/pi2;
149
  tosend = (1<<15) | (1<<14);
150
  if (reg == PHASE1){tosend |= (1<<13);}
151
  DDS_write(tosend | regist);
152
}
153
154
155
156
157
158
int main()
159
{
160
  DDRD |= (1 << 6);
161
  PORTD |= (1 << 6);    //hier gehen die SPI-Pins auf low
162
  _delay_ms(200);
163
  PORTD &= ~(1 << 6);   //und hier wieder auf high
164
165
  DDS_init();
166
167
  DDS_signal(SINUS);
168
169
  DDS_phase(0, PHASE0);
170
171
  DDS_freq(1000, FREQ0);
172
173
174
  PORTD |= (1 << 6);
175
  _delay_ms(200);
176
  PORTD &= ~(1 << 6);
177
178
}

von Benedikt (Gast)


Lesenswert?

Hat denn keiner eine Idee was ich vergessen haben könnte?

von nonplusultra (Gast)


Lesenswert?

Beim kurzen überfliegen von Deinem Sourcecode und der Fehlerbeschreibung 
(anderer Pin zuckt) sieht das nach einem Pin-Assignment Problem aus. 
Such mal danach im Manual.

von nonplusultra (Gast)


Lesenswert?

Nochmal kurz: wenn die Kommentare in der main() stimmen, dann wohl auch 
sowas wie dass die Pins noch als GPIO konfiguriert sind und nicht als 
SPI. In diesem Fall heisst das Schlagwort: Pin function register

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Wenn SS auf LOW geht, dann gibt meine Lib doch was aus ;)
Das Ganze passiert nur recht fix, sodass mans aufm Oszi nicht sieht.
Pack das DDS_freq doch mal in eine while(1) Schleife.

Wenn nix gesendet wird, sind SCK und SS high.

von Benedikt (Gast)


Lesenswert?

Also meine Meinung nach dürfte das so passen. In der DDS_init werden die 
Pins SS, SCK und MOSI als Ausgang definiert.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Martin Wende schrieb:
> Pack das DDS_freq doch mal in eine while(1) Schleife.

Und dann Oszi an SCK/MOSI halten.

von Karl H. (kbuchegg)


Lesenswert?

Martin Wende schrieb:
> Martin Wende schrieb:
>> Pack das DDS_freq doch mal in eine while(1) Schleife.
>
> Und dann Oszi an SCK/MOSI halten.

Ich würd sogar noch weiter gehen.
Für meine Begriffe ist das erst mal schon wieder viel zu viel Code, der 
nichts mit der SPI zu tun hat
1
int main()
2
{
3
  DDS_init();
4
5
  while( 1 ) {
6
    DDS_write( 0xAAAA );
7
  }
8
}

Oszi an SCK/MOSI.
Dann muss sich an den Pins was tun.

von Benedikt (Gast)


Lesenswert?

Habe es gerade noch mal mit der Schleife versucht, aber auch kein 
Erfolg.
Dann anderen Controller aus der Schachtel geholt...reingesteckt, 
programmiert, geht! Also Controller (teilweise) kaputt gewesen...

Aber die Routine ist verdammt schnell, wie ich finde...in knapp 1 ms 
landet eine neue Frequenz im Bauteil!

Danke!

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

So schnell is die nun auch wieder nich wegen der Floatingpoint Library 
die eingebunden wird.

Aber mit Festkomma wurde der Code komischerweise größer als mit FP 
kopfkratz

von Benedikt (Gast)


Lesenswert?

Ich habe nochmal eine Frage:
Habe nun endlich einen Quarzoszillator (25MHz, 
http://www.reichelt.de/Oszillatoren/OSZI-25-000000/3/index.html?;ACTION=3;LA=2;ARTICLE=13699;GROUPID=3174;artnr=OSZI+25%2C000000;SID=10UJ1@Nn8AAAIAABxwDWE94af91845118464afa2636b78838a035). 
Ich habe die ganze Schaltung auf einem Steckbrett aufgebaut (AD9833 auf 
einer Adapterplatine).
Selbst wenn das alles fliegende Verdrahtung ist, müsste der AD9833 doch 
irgendwas ausgeben oder? (Ich verwende den Code aus dem 1. Beitrag)
Die Leitung vom Quarzoszillator zum AD ist nicht länger als 5cm.

Ich habe mal die Spannung am Quarzoszillatorausgang gemessen. Das ganze 
sieht ja eher nicht mehr rechteckig aus. Bei mir liegt das Minimum bei 
1,12V und das Maximum bei 3,68V (mit dem Oszi gemessen).
Bin mir natürlich nicht ganz sicher, ob das alles so hundertprozentig 
genau ist, da es ja schon 25MHz sind.

Die Eingangsspannungen für die Digitalpegel sind laut Datenblatt:
High:   2,8V    @Vdd = 4,5 to 5,5V
Low:    0,8V    @Vdd= 4,5 to 5,5V

Könnte es daran liegen, dass der AD nichts ausgibt?
Was stimmt da mit dem Oszillator nicht?

Gruß
Benedikt

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Angehängte Dateien:

Lesenswert?

Wenn der Oszilator nicht mehr unter 0,8V kommt, dann erkennt der AD eben 
kein Takt mehr.
Pulldown mal versuchen oder das Kabel schön kürzen.

Hier mal mein Layout im Anhang.

von Benedikt (Gast)


Angehängte Dateien:

Lesenswert?

Bin erst heute wieder dazu gekommen, mich ein bisschen damit zu 
beschäftigen..
Das Oszilloskopbild im Anhang zeigt das gemessene Signal am 
Quarzoszillatorausgang. Ich bin mir allerdings nicht sicher, ob das 
ganze jetzt der Realität entspricht, da es sich ja um 25MHz handelt und 
mein Oszilloskop eine Eingangskapazität von 24pF hat. Also könnte das 
eine Kondensatorlade/entladekurve sein. Ob die Pegel (0,8V für Low) 
eingehalten werden kann ich somit nicht wirklich sagen.

Hat jemand noch eine Idee, warum das ganze nicht funktioniert?

@fritzler: Kannst du mir evtl. mal nen Schaltplan/µC-Programm/Layout 
zukommen lassen?

Ich verwende ein Programm, das periodisch, alle 200ms eine neue Frequenz 
zum Baustein schickt..

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?


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.