SPI ATmega32 mit AD9833

Gast #3038535
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
}
#3040044
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.
Gast #3052855
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
Gast #3074518
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..
Angehängte Dateien:

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