Forum: Mikrocontroller und Digitale Elektronik AD9850 braucht Hilfe


von Pete K. (pete77)


Angehängte Dateien:

Lesenswert?

Hallo,
ich wollte mir einen Frequenzgenerator mit dem AD9850 Modul bauen.
Leider stimmt wohl noch etwas mit der Software oder Hardware nicht.
Auf jeden Fall zappelt das Oszi in einem Bereich von ca. 80-110mV Vpp 
munter umher.
Klare Sinuskurven sind nicht erkennbar.

Anbei die main.c mit der Ansteuerung.

Das ganze ist auf Experimentierplatine aufgebaut und wird mit einem 9V 
Netzteil sowie einem TL780-05C Linearregler versorgt.

Hardware: 8Mhz Atmega328, AD9850 Modul, 2x16 LCD, ALPS Drehencoder.
Verschaltung: siehe main.c Listing

von Frank L. (Firma: Flk Consulting UG) (flk)


Lesenswert?

Hallo,

schau Dir mal das Ergebnis dieser Rechnung im LCD an. Meiner Meinung 
fehlt hier ein Cast.
1
int32_t freq = frequency * 4294967295UL/125000000UL;
1
int32_t freq = (int32_t)(frequency * 4294967295UL/125000000UL);

gruß
Frank

von Pete K. (pete77)


Lesenswert?

Ok, die Werte von freq stimmen jetzt. Aber nach Sinus sieht das immer 
noch nicht aus.
Ist die Ansteuerung des AD9850 denn ok? Wäre prima, wenn da jemand mal 
draufschauen könnte. Ich sehe hier den Wald vor lauter Bäumen nicht 
mehr...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Pete K. schrieb:
> Aber nach Sinus sieht das immer noch nicht aus.

Ist ja auch keiner, ist ja eine Treppe. ;-)

Damit die annähernd nach Sinus aussieht, darf die Frequenz nicht zu
hoch sein.  Bei höheren Frequenzen entsteht der Sinus erst nach dem
Antialiasing-Filter.

Warum machst du die Ansteuerung im Bitbang-Modus?  Kannst du denn den
normalen SPI-Port nicht benutzen?

Hier mal ein Codeschnipsel, welches ich bei einem AD9850-Projekt mal
benutzt habe:
1
static void
2
init_ad9850(void)
3
{
4
  /*
5
   * Disable SPI, and reset the DDS circuitry.
6
   */
7
  SPCR = 0;
8
  PORTC |= _BV(0);
9
  PORTC &= ~_BV(0);
10
11
  /*
12
   * After reset, initiate one W_CLK pulse followed by one FQ_UD pulse
13
   * to activate the serial configuration control word.
14
   */
15
  PORTB |= _BV(7);
16
  PORTB &= ~_BV(7);
17
  PORTC |= _BV(1);
18
  PORTC &= ~_BV(1);
19
20
  /*
21
   * Now, we're ready to hand over the data transmission to SPI.
22
   */
23
  SPCR = _BV(SPE) | _BV(DORD) | _BV(MSTR);
24
  SPSR = _BV(SPI2X);
25
}
26
27
static void
28
fq_ud(uint32_t fq)
29
{
30
  union
31
  {
32
    uint32_t l;
33
    uint8_t b[5];
34
  }
35
  u;
36
  uint8_t i;
37
38
  u.l = fq;
39
  /*
40
   * W32..W39: no phase angle, no power-down, control bits = 0
41
   */
42
  u.b[4] = 0;
43
44
  for (i = 0; i < 5; i++)
45
    {
46
      SPDR = u.b[i];
47
      while ((SPSR & _BV(SPIF)) == 0)
48
        /* wait */;
49
    }
50
51
  /* Update now. */
52
  PORTC |= _BV(1);
53
  PORTC &= ~_BV(1);
54
}

Ist nicht sehr gut abstrahiert, gebe ich zu. ;-)

von Frank L. (Firma: Flk Consulting UG) (flk)


Lesenswert?

Hallo,
dann schau Dir mal Dein Bit geschubse an, das kann so auch nicht 
stimmen.
1
for (int i=0; i<8; i++, data>>=1) {
2
  if ((data & 0x01)==0) {Port(D7_PORT) &= ~(1<<i);} //clear
3
  if ((data & 0x01)==1) {Port(D7_PORT) |= (1<<i);} //set

Entweder Du setzt ein Bit oder Du löscht es. Aber das komische ~(1<<i) 
ist komplett überflüssig.

Gruß
Frank

von Pete K. (pete77)


Lesenswert?

Jörg W. schrieb:
> Ist ja auch keiner, ist ja eine Treppe. ;-)

Aktuell teste ich mit 100Hz - 10kHz. Das sollte noch gehen.

Der Abschnitt oben sieht jetzt so aus:
for (int i=0; i<8; i++) {
  if ((data & 0x01)==0) {Port(D7_PORT) &= ~(1<<D7_PIN);} //clear
  if ((data & 0x01)==1) {Port(D7_PORT) |= (1<<D7_PIN);} //set
        data>>=1;

Der Ausgang bleibt auf 1,08V mit einem "Ripple" von ca. 80-100mVpp

von --- (Gast)


Lesenswert?

Hast keinen LA?
Zu geizig für Sechs Euro Fuffzich?

Sollen nun alle die main.c auf ihren 9859 loslassen
und dann mit ihrem LA nach dem Fehler suchen?

Fragen über Fragen.

von Pete K. (pete77)


Lesenswert?

Nein, ich habe keinen LA.

von Christian S. (vivus)


Lesenswert?


von Dieter F. (Gast)


Lesenswert?

Sag mal woher Du es kopiert hast (Link), dann kann man es zumindest mit 
dem Original vregleichen. War das Original für einen anderen AVR-MC 
geschrieben - oder ggf. für den Arduino?

von Frank L. (Firma: Flk Consulting UG) (flk)


Lesenswert?

Hallo
Schau nochmal ins Handbuch Seite 10 Timing Diagramm für Fq_ud dort steht 
eindeutig Low vor dem schieben, dann einmal High und dann wieder Low. 
Dann werden die Daten übernommen.

Gruß
Frank

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Pete K. schrieb:
> Der Abschnitt oben sieht jetzt so aus:

Nochmal die Frage: warum keine Hardware-SPI?

Der von mir gepostete Code ist “known to work”.

von Pandur S. (jetztnicht)


Lesenswert?

Bei Analog Devices ist man oft im Bitbang Mode weil das Hardware SPI 
Timing nicht ganz passt. Dann kann man's auch gleich so lassen. Zudem 
ist Hardware SPI nicht sonderlich effizient. Weder mit Interrupts, noch 
mit Pollen.

: Bearbeitet durch User
von Holm T. (Gast)


Lesenswert?

Sapperlot W. schrieb:
> Bei Analog Devices ist man oft im Bitbang Mode weil das Hardware SPI
> Timing nicht ganz passt. Dann kann man's auch gleich so lassen. Zudem
> ist Hardware SPI nicht sonderlich effizient. Weder mit Interrupts, noch
> mit Pollen.

Fakenews?

Gruß,

Holm

von Beo Bachta (Gast)


Lesenswert?

Sapperlot W. schrieb:
> weil das Hardware SPI Timing nicht ganz passt.

Das schlechte SPI Timing sitzt dann wie üblich vor der Tastatur.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Sapperlot W. schrieb:
> Bei Analog Devices ist man oft im Bitbang Mode weil das Hardware SPI
> Timing nicht ganz passt.

Nochmal ganz langsam: das da oben ist ein Codeschnipsel aus einem
AD9850-Projekt von mir, welches nachweislich funktioniert.

An Einfachheit und Geschwindigkeit ist es durch manuelle Bitbangerei
sowieso nicht zu übertreffen.

von Dieter F. (Gast)


Lesenswert?

Dieter F. schrieb:
> Sag mal woher Du es kopiert hast (Link)

Nicht mehr nötig, habe es - glaube ich - gefunden. Eine Portierung eines 
Arduino-Programms.

http://www.ad7c.com/projects/ad9850-dds-vfo/

von Pete K. (pete77)


Lesenswert?

Hatte mich eher hier orientiert:
https://electronicfreakblog.wordpress.com/2014/01/29/dds-signalgenerator-mit-ad9850/

@Jörg: Für Hardware-SPI müsste ich das neu verkabeln. Daher möchte ich 
das gerne erst einmal mit bit banging versuchen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Pete K. schrieb:
> Daher möchte ich das gerne erst einmal mit bit banging versuchen.

Spätestens jetzt ist allerdings wirklich der Zeitpunkt gekommen, wo
du einen LA benutzen solltest.

von Dieter F. (Gast)


Lesenswert?

Pete K. schrieb:
> Hatte mich eher hier orientiert:
> 
https://electronicfreakblog.wordpress.com/2014/01/29/dds-signalgenerator-mit-ad9850/

Wenn Du es schreibst :-) merkwürdige Korrealtion der Kommentare ...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Darüber solltest du wohl nochmal nachdenken:
1
  // set FQUP low
2
  Port(FQUP_PORT) |= (1<<FQUP_PIN);
3
4
  // ...
5
6
  // set FQUP high and take new frequency
7
  Port(FQUP_PORT) &= ~(1<<FQUP_PIN);

Ganz davon abgesehen, vergleich' das mal mit meinem Code: dort kommt
ein (kurzer) FQUD-Puls nach dem Schreiben des Datenworts.

von Dieter F. (Gast)


Lesenswert?

Jörg W. schrieb:
> dort kommt
> ein (kurzer) FQUD-Puls nach dem Schreiben des Datenworts.

In der von mir erwähnten Vorlage auch:
1
#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }
2
3
...
4
5
// frequency calc from datasheet page 8 = <sys clock> * <frequency tuning word>/2^32
6
void sendFrequency(double frequency) {  
7
  if (GoIF == 1){frequency=frequency-iffreq;}; //If pin = low, subtract the IF frequency.
8
  int32_t freq = frequency * 4294967295/125000000;  // note 125 MHz clock on 9850.  You can make 'slight' tuning variations here by adjusting the clock frequency.
9
  for (int b=0; b<4; b++, freq>>=8) {
10
    tfr_byte(freq & 0xFF);
11
  }
12
  tfr_byte(0x000);   // Final control byte, all 0 for 9850 chip
13
  pulseHigh(FQ_UD);  // Done!  Should see output
14
}

von Pete K. (pete77)


Angehängte Dateien:

Lesenswert?

Ihr seit die Besten! Jetzt funktioniert es.

Ich hatte noch einen dicken Bug in der init/reset Routine drin. Man 
sollte so etwas nicht spät abends programmieren ;-)

Anbei das aktuelle Ergebnis.

Danke!

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.