Forum: Projekte & Code AD9833 DDS in c ohne SPI


von Christian (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,


ich habe mal meinen Code zur Ansteuerung eines AD9833 angehängt.
Er verwendet bewusst nicht SPI sondern kann an einen belibigen Port 
angeschlossen werden.


Lg


Christian / DF1CWQ

von Florian L. (jesus)


Lesenswert?

Hallo,

Vielen Dank für den tollen Code! Ich hab den DDS-Chip sofort zum Laufen 
bekommen.
Nun möchte ich jedoch auch ein Rampen- und Rechtecksignal erzeugen.
Leider finde ich nicht heraus, wo sich die Steuerbits im Code befinden.
Könntest du mir bitte sagen, wie ich das D1 (Mode) und das D5 (OPBITEN) 
Bit umschalte.

Schöne Grüße,
Florian

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


Lesenswert?

leiche Ausgrab
Nutz einfach seine void DDS_WriteWord(int16_t wValue) und bastel die in 
meine Library ein: http://www.fritzler-avr.de/HP/Librarys/AD9833_his.php

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


Lesenswert?

Mein Webserver Log sagt mir, dass die Nachfrage recht hoch ist.
Daher habe ich die Library erweitert um einen Software SPI.
Link: http://www.fritzler-avr.de/HP/Librarys/AD9833_his.php

von eProfi (Gast)


Lesenswert?

Vielen Dank für Deine Mühen, vielleicht findest Du noch Zeit, die 
Berechnung des FTW ohne float zu schaffen.
Beitrag "Re: Frage zur C Syntax"
Beitrag "Re: Rechnen mit AVR"

Außerdem ist es ein leichtes, die Restriktion aufzuheben, dass die 
SPI-Pins auf einem Port liegen müssen:
MOSIport, SSport und SCKport definieren.

Schieben für SPI (mask ist zugleich Bitzähler):
  mask=0x80;do if(data&mask)setData;else rstData;while((mask/=2));

hier könnte auch ein else stehen:
  if (reg == FREQ0){tosend |= (1<<14);}
  if (reg == FREQ1){tosend |= (1<<15);}
und das AND braucht man bei unsigned nicht, schieben allein reicht:
  tosend = (regist & ~16383)>>14;

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


Lesenswert?

>Schieben für SPI (mask ist zugleich Bitzähler):
>mask=0x80;do if(data&mask)setData;else rstData;while((mask/=2));
Kannste das mal in C highlighten? Mir verknoten grade die Augen.

Wollts erst mit uint32_t machen, aber der AVR GCC mag wohl das 
Multiplizieren von 2 32bit Variablen nicht. Jedenfals kam nur Mumpitz 
bei raus.

Natürlich ist die Restriktion aufzuheben, wird nur nicht oft vorkomen, 
dass der AD9833 an 2 - 3 Ports hängt.

Hm ja das und ist da sinnfrei, schieb die nicht ausgewählten bits ja eh 
raus.

Danke für die Kritik, wenn du mir die Knoten aus den Augen nimmst, wird 
das umgesetzt.

von eProfi (Gast)


Lesenswert?

dem PI2 würde ich ein paar Stellen mehr genehmigen:
#define pi2    6,2831853


> Wollts erst mit uint32_t machen, aber der AVR GCC mag wohl
> das Multiplizieren von 2 32bit Variablen nicht.
> Jedenfals kam nur Mumpitz bei raus.
Kann sein, dass man die 64-bit erst aktivieren muss.
Suche mal danach, ich weiß es nicht auswendig.
Damals habe ich es in Asm gelöst.

Aber Du kannst zumindest die Division wegsparen, da konst/MCLK konstant 
ist und zur Compiletime berechnet werden kann. Also:

#define konst1 ((double)konst/(double)MCLK)
void DDS_freq(uint32_t freq, uint8_t reg){
  uint32_t regist = freq * konst1;
Da stellt sich die Frage, ob man freq nicht mit einem Bruchteil eines Hz 
angeben will, z.B. 1/8 Hz, d.b. konst1 muss dann noch mit 8 
multipliziert werden.


void DDS_write(uint16_t data){
  SPIPORT &= ~(1<<SS);
  DDS_writebyte((uint8_t)(data>>8));
  DDS_writebyte((uint8_t)(data & 255));
  SPIPORT |= (1<<SS);
}
wird zu

#define SPIssPORT PORTB
#define SPImoPORT PORTB
#define SPIscPORT PORTB

void DDS_write(uint16_t data){
  uint16_t mask = 0x8000; //Maske und Bytezähler in einem
  SPIssPORT &= ~(1<<SS); //SSEL low
  do{  if(data&mask)SPImoPORT |=  (1<<MOSI); //SDATA high
    else         SPImoPORT &= ~(1<<MOSI); //SDATA low
    SPIscPORT &= ~(1<<SCK); //CLK low
    SPIscPORT |=  (1<<SCK); //CLK high
  }while((mask/=2)!=0);
  SPIssPORT |=  (1<<SS); //SSEL high
}
(data&mask) ist eine Kurzform für ((data&mask)!=0)
und writebyte entfällt ganz.

und noch was wichtiges:
void DDS_phase(uint16_t phase, uint8_t reg){
  uint16_t regist = (uint16_t) (phase*konst2)/pi2;
  tosend |= (1<<15) | (1<<14);
  if (reg == PHASE1){tosend |= (1<<13);}
  DDS_write(tosend | regist);
}
Das kann falsch sein, wenn vorher in der globalen Variable tosend etwas 
drinsteht!
also entweder
  tosend = (1<<15) | (1<<14);  (ohne |= )

oder kürzer

  tosend  = (uint16_t) (phase*konst2)/pi2;
  tosend |= (1<<15) | (1<<14);
  if (reg == PHASE1){tosend |= (1<<13);}
  DDS_write(tosend);

von mojtaba (Gast)


Lesenswert?

pleas: SPI COMMUNICATION DRIVER FOR AD9833 DDS WITH FRAME SYNC

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


Lesenswert?

Sicher, dass ers dann schon zusammenfasst?
Der Vorcompiler setzt doch nur den Text ein.

von eProfi (Gast)


Lesenswert?

> Der Vorcompiler setzt doch nur den Text ein.
Richtig.
Und der Compiler berechnet den Quotienten, da beide Operanden bekannt 
und konstant sind. Das #define ändert an der Berechnung nichts, Du 
könntest genauso gut direkt hinschreiben und richtig klammern.
Oder eine echte Konstante deklarieren.

Das Zusammenfassen gilt übrigens auch beim Berechnen der Phasen:
  tosend  = (uint16_t) (phase*konst2)/pi2;
besser:
  tosend  = (uint16_t) phase*(konst2/pi2);

Bitte sei so gut und verbessere den Code auf Deiner Seite, damit 
zumindest der Fehler bei der Berechnung der Phase berichtigt ist, bevor 
sich der Code zu stark verbreitet.

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


Lesenswert?

Sitz ja schon drann, muss nurnoch das Gerät zum Testen finden...

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.