Étiquette : VFO

Code source ultra-simpliste pour Arduino/MSP430 d’un VFO à AD9850/AD9851

Prototype kit Balise WSPR DDS XV4Y (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2012/12/100_3339 NULL.jpg)Dans un commentaire Sylvain F6GGX m’a demandé après ce bout de code. Il était disponible gratuitement dans la boutique mais comme j’ai désactivé cette dernière il a disparu du site…
Voici donc le code source d’un VFO très simpliste à base de AD9850/AD9851 qui utilise les librairies que j’ai écrites ou adaptées (http://xv4y NULL.radioclub NULL.asia/docs/). Honnêtement je pense pas que ce code soit très utile, rien de particulièrement compliqué et l’ergonomie à 4 boutons n’est pas super. C’est utile en dépannage avec le kit balise WSPR que je produisais mais c’est tout. Le code est écrit pour Energia sur MSP430, le porter sur Arduino (ATMega328) ne devrait poser aucun problème.

/* Simple VFO with DDS for MSP430G2553
 * Code for Energia 009
 
 * By Yannick DEVOS - XV4Y - March 2013
    http://xv4y.radioclub.asia/

    Copyright 2012-2013 Yannick DEVOS under GPL 3.0 license
    Any commercial use or inclusion in a kit is subject to author approval

====
 * Agile Frequency generation using AD9850/9851 DDS
 * Output to Nokia 5110 compatible LCD
 * Check if P2_2 has changed state and switch VFO (like when PTT is pressed to operate split)

Usage for short press of buttons :
- Up / Down      increase or decrease the frequency following the choosen digit
- Left / Right   increase or decrease the digit
- OK             validate the frequency and send it to the DDS
Long press of buttons :
- Left           Set the current VFO to the next band bottom frequency
- Right          VFO A = VFO B
- OK             Switch between VFO A and VFO B

====
Revision history :
v1.00    2013-03-18
         First release

====
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You can download a copy of the GNU General Public License at <http://www.gnu.org/licenses/>
*/

// Here modify to your taste or needs

#define PTT_key          P2_2
#define ANALOG_BUTTONS   A5
#define AUTO_VALID       // Uncomment if you want the DDS frequency to be udapted automatically after each value change

#define DEFAULT_FREQ    8            // Value 8 in Frequencies array is 14000000
// Here under don't touch anything unless you know what you do

#include <legacymsp430.h>
#include <AD9850.h> // Library for AD9850 control by MSP430

#include <LCD_5110.h>

              // Frequencies (1 Hz precision) you can select
const unsigned long int frequencies[] = {
  137000, 471000, 501000, 1830000, 3500000, 5200000, 7000000, 10100000,
  14000000, 18068000, 21000000, 24890000, 28000000, 50000000, 70000000};
  
const byte Analog_Noise = 5;    // Margins for reading analog buttons

boolean   vfo=0, saved_PTT;  // VFO A or B and PTT input state
char      multiplier, aff_multiplier, freq_select=DEFAULT_FREQ;
unsigned  long int frequency_A=frequencies[DEFAULT_FREQ], frequency_B=frequencies[DEFAULT_FREQ], debounce;

char chaine_txt[6] = {' ', ' ', ' ', ' ', ' ', 0x00};


AD9850 myDDS (P1_0, P1_1, P1_2, P1_4);  // Call the AD9850 Library, AD9850 pins for CLOCK, LOAD, DATA and RESET
//AD9850 myDDS (P1_1, P1_2, P1_0, P1_4);  // Call the AD9850 Library, AD9851 pins for CLOCK, LOAD, DATA and RESET

LCD_5110 myScreen(P2_3,    // Chip Select *
         P1_6,    // Serial Clock *
         P2_5,    // Serial Data *
         P2_4,    // Data/Command *
         NULL,    // Reset *
         P1_7,    // Backlight
         NULL);  // Push Button 0

//******************************************************************
// Defining pins mode and initializing hardware

void setup() {
  pinMode(PTT_key, INPUT_PULLUP);

  myDDS.begin();
  
   
  pinMode(ANALOG_BUTTONS, INPUT);

  myScreen.begin();
  myScreen.setBacklight(1);
    
  myScreen.setFont(1);
  myScreen.text(0, 0, "sVFO");
  myScreen.text(0, 2, "AD9850");
  myScreen.setFont(0);
  myScreen.text(0, 4, "v1.00 - XV4Y");
  myScreen.text(0, 5, "Init...");
  
  delay(1000);
  
  myDDS.reset();
  
  myDDS.SetFrequency( frequency_A, 0, false );

  digitalWrite( PTT_key, LOW );

};

//******************************************************************
// Here starts the actual sequence sending

void loop() {
    myScreen.clear();
    myScreen.setBacklight(1);
    myScreen.setFont(1);
    if (vfo == 0) {
      myScreen.text(0, 0, "VFO A");
      myDDS.SetFrequency( frequency_A, 0, false );
    } else {
      myScreen.text(0, 0, "VFO B");
      myDDS.SetFrequency( frequency_B, 0, false );
    };

    myScreen.setFont(0);
    display_freq (frequency_A, 3);
    display_freq (frequency_B, 5);

    while (read_buttons()==5 || read_buttons()==4 || read_buttons()==2) delay(10); // Debounce except for UP/DWN

    while (1) {
      // Update the frequencies display
      if (multiplier > 5) {
        aff_multiplier = multiplier + 2;
      } else if (multiplier > 2) {
        aff_multiplier = multiplier + 1;
      } else {
        aff_multiplier = multiplier;
      };
      myScreen.text(0, 4, "          ");
      if (vfo == 0) {
        myScreen.text(9-aff_multiplier, 4, "^");
      } else {
        myScreen.text(9-aff_multiplier, 4, "v");
      }
      display_freq (frequency_A, 3);
      display_freq (frequency_B, 5);
  
      // Read the analog buttons input
      if(read_buttons()==1) {            // Up we increase frequency
        delay(200);  // Debounce
        if (vfo == 0) {
          frequency_A = frequency_A + powf(10,(float)multiplier);
        } else {
          frequency_B = frequency_B + powf(10,(float)multiplier);
        };
#if defined AUTO_VALID
        break;
#endif

      } else if (read_buttons()==3) {    // Down we decrease frequency
        delay(200);  // Debounce
        if (vfo == 0) {
          frequency_A = frequency_A - powf(10,(float)multiplier);
        } else {
          frequency_B = frequency_B - powf(10,(float)multiplier);
        };
#if defined AUTO_VALID
        break;
#endif

      } else if (read_buttons()==2) {    // Left we increase multiplier
        debounce = millis();
        while (read_buttons()==2) {  //Debounce
          if ((millis()-debounce)>1000) {  // Long press we do "Band UP"
            freq_select++;
            if (freq_select > 14) freq_select = 0;
            if (vfo == 1) frequency_B = frequencies[freq_select]; else frequency_A=frequencies[freq_select];
            multiplier--;
            break;
          };
        };
        multiplier++;
        if (multiplier > 7) multiplier = 7;

      } else if (read_buttons()==4) {    // Right we decrease multiplier
        debounce = millis();
        while (read_buttons()==4) {  //Debounce
          if ((millis()-debounce)>1000) {  // Long press we do VFO A=B
            if (vfo == 1) frequency_A = frequency_B; else frequency_B=frequency_A;
            multiplier++;
            break;
          };
        };
        multiplier--;
        if (multiplier < 0) multiplier = 0;

      } else if (read_buttons()==5) {    // OK we go out
        debounce = millis();
        while (read_buttons()==5) {  //Debounce
          if ((millis()-debounce)>1000) {  // Long press we switch VFO A/B
            if (vfo == 1) vfo=0; else vfo=1;
            break;
          };
        };
        break;   // Short press we just leave the loop so the frequency is transmitted to the AD9850
      }

      // Check if we are transmitting split (momentaneous VFO A->B switch)
      if (saved_PTT != digitalRead(PTT_key)) {
        saved_PTT = digitalRead(PTT_key);
        if (vfo == 1) vfo=0; else vfo=1;
        break;
      };
    }

};


//******************************************************************
// Display the frequency
void display_freq (unsigned long freq, char ligne) {
  myScreen.text(10, ligne, " Hz ");
  chaine_txt[5] = 0x00;
  chaine_txt[4] = 0x30 + (((freq)/1)%10);
  chaine_txt[3] = 0x30 + (((freq)/10)%10);
  chaine_txt[2] = 0x30 + (((freq)/100)%10);
  chaine_txt[1] = '.';
  chaine_txt[0] = 0x30 + (((freq)/1000)%10);
  myScreen.text(5, ligne, chaine_txt);
  chaine_txt[5] = 0x00;
  chaine_txt[4] = 0x30 + (((freq)/10000)%10);
  chaine_txt[3] = 0x30 + (((freq)/100000)%10);
  chaine_txt[2] = '.';
  chaine_txt[1] = 0x30 + (((freq)/1000000)%10);
  chaine_txt[0] = 0x30 + (((freq)/10000000)%10);
  myScreen.text(0, ligne, chaine_txt); 
}

//******************************************************************
// Display a 2 digits number
void display_number (byte number, char column, char ligne) {
  chaine_txt[2] = 0x00;
  chaine_txt[1] = 0x30 + (number%10);
  chaine_txt[0] = 0x30 + ((number/10)%10);
  myScreen.text(column, ligne, chaine_txt);
}

//******************************************************************
// Return a button value depending on the analog reading
byte read_buttons () {
  int value = analogRead(ANALOG_BUTTONS);
  if ( value<(1+Analog_Noise) ) {
    return 1;
  } else if ( value<(78+Analog_Noise) ) {
    return 2;
  } else if ( value<(146+Analog_Noise) ) {
    return 3;
  } else if ( value<(205+Analog_Noise) ) {
    return 4;
  } else if ( value<(255+Analog_Noise) ) {
    return 5;
  } else {
    return 0;
  }
}

Code source VFO avec DDS AD9850/AD9851 et LaunchPad MSP430

sVFO DDS AD9850 MSP430 XV4Y (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2013/03/100_3446 NULL.jpg)J’ai eu le temps de mettre la main à une première version d’un programme simple de VFO pour mon kit à base de DDS AD9850 ou AD9851 (http://xv4y NULL.radioclub NULL.asia/boutique/?slug=product_info NULL.php&products_id=33).

Cette première mouture reste assez simple avec juste un système VFO A et VFO B mais pas de mémoires. Les fonctionnalités des boutons suivent la description ci-dessous.

 

Pour une pression brève sur le bouton :

  • UP : Augmente la valeur du chiffre sélectionné (pour le VFO sélectionné)
  • DOWN : Diminue la valeur du chiffre sélectionné (pour le VFO sélectionné)
  • LEFT : Sélectionne le chiffre de rang supérieur (plus à gauche)
  • RIGHT : Sélectionne le chiffre de rang inférieur (plus à droite)
  • OK : Valide la fréquence et la transmet au DDS

Pour une pression longue (supérieure à 1 seconde) sur le bouton :

  • LEFT : Positionne la fréquence sur la limite basse de la bande suivante
  • RIGHT : Egalise les fréquences des deux VFO (VFO A = VFO B)
  • OK : Change le VFO sélectionné (VFO A/B)

A noté que la broche P2_2 du MSP430 (celle connectée à la broche 3 du connecteur 4 pins) est maintenant utilisée en entrée. Si son état change (passant à 0V par exemple), le VFO actuellement utilisé est momentanément interverti. Cela permet donc de trafiquer en split avec la fréquence transmise par le DDS qui change du VFO A vers VFO B (ou l’inverse) tant que la PTT est pressée.

/* Simple VFO with DDS for MSP430G2553
 * Code for Energia 009

 * By Yannick DEVOS - XV4Y - March 2013
    http://xv4y.radioclub.asia/

    Copyright 2012-2013 Yannick DEVOS under GPL 3.0 license
    Any commercial use or inclusion in a kit is subject to author approval

====
 * Agile Frequency generation using AD9850/9851 DDS
 * Output to Nokia 5110 compatible LCD
 * Check if P2_2 has changed state and switch VFO (like when PTT is pressed to operate split)

Usage for short press of buttons :
- Up / Down      increase or decrease the frequency following the choosen digit
- Left / Right   increase or decrease the digit
- OK             validate the frequency and send it to the DDS
Long press of buttons :
- Left           Set the current VFO to the next band bottom frequency
- Right          VFO A = VFO B
- OK             Switch between VFO A and VFO B

====
Revision history :
v1.00    2013-03-18
         First release

====
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You can download a copy of the GNU General Public License at <http://www.gnu.org/licenses/>
*/

// Here modify to your taste or needs

#define PTT_key          P2_2
#define ANALOG_BUTTONS   A5
//#define AUTO_VALID       // Uncomment if you want the DDS frequency to be udapted automatically after each value change

#define DEFAULT_FREQ    8            // Value 8 in Frequencies array is 14000000
// Here under don't touch anything unless you know what you do

#include <legacymsp430.h>
#include <AD9850.h> // Library for AD9850 control by MSP430

#include <LCD_5110.h>

              // Frequencies (1 Hz precision) you can select
const unsigned long int frequencies[] = {
  137000, 471000, 501000, 1830000, 3500000, 5200000, 7000000, 10100000,
  14000000, 18068000, 21000000, 24890000, 28000000, 50000000, 70000000};

const byte Analog_Noise = 5;    // Margins for reading analog buttons

boolean   vfo=0, saved_PTT;  // VFO A or B and PTT input state
char      multiplier, aff_multiplier, freq_select=DEFAULT_FREQ;
unsigned  long int frequency_A=frequencies[DEFAULT_FREQ], frequency_B=frequencies[DEFAULT_FREQ], debounce;

char chaine_txt[6] = {' ', ' ', ' ', ' ', ' ', 0x00};

//AD9850 myDDS (P1_0, P1_1, P1_2, P1_4);  // Call the AD9850 Library, AD9850 pins for CLOCK, LOAD, DATA and RESET
AD9850 myDDS (P1_1, P1_2, P1_0, P1_4);  // Call the AD9850 Library, AD9851 pins for CLOCK, LOAD, DATA and RESET

LCD_5110 myScreen(P2_3,    // Chip Select *
         P1_6,    // Serial Clock *
         P2_5,    // Serial Data *
         P2_4,    // Data/Command *
         NULL,    // Reset *
         P1_7,    // Backlight
         NULL);  // Push Button 0

//******************************************************************
// Defining pins mode
// Encoding the WSPR sequence

void setup() {
  pinMode(PTT_key, INPUT_PULLUP);

  myDDS.begin();

  pinMode(ANALOG_BUTTONS, INPUT);

  myScreen.begin();
  myScreen.setBacklight(1);

  myScreen.setFont(1);
  myScreen.text(0, 0, "sVFO");
  myScreen.text(0, 2, "AD9850");
  myScreen.setFont(0);
  myScreen.text(0, 4, "v1.00 - XV4Y");
  myScreen.text(0, 5, "Init...");

  delay(1000);

  myDDS.reset();

  myDDS.SetFrequency( frequency_A, 0, false );

  digitalWrite( PTT_key, LOW );

};

//******************************************************************
// Here starts the actual sequence sending

void loop() {
    myScreen.clear();
    myScreen.setBacklight(1);
    myScreen.setFont(1);
    if (vfo == 0) {
      myScreen.text(0, 0, "VFO A");
      myDDS.SetFrequency( frequency_A, 0, false );
    } else {
      myScreen.text(0, 0, "VFO B");
      myDDS.SetFrequency( frequency_B, 0, false );
    };

    myScreen.setFont(0);
    display_freq (frequency_A, 3);
    display_freq (frequency_B, 5);

    while (read_buttons()==5 || read_buttons()==4 || read_buttons()==2) delay(10); // Debounce except for UP/DWN

    while (1) {
      // Update the frequencies display
      if (multiplier > 5) {
        aff_multiplier = multiplier + 2;
      } else if (multiplier > 2) {
        aff_multiplier = multiplier + 1;
      } else {
        aff_multiplier = multiplier;
      };
      myScreen.text(0, 4, "          ");
      if (vfo == 0) {
        myScreen.text(9-aff_multiplier, 4, "^");
      } else {
        myScreen.text(9-aff_multiplier, 4, "v");
      }
      display_freq (frequency_A, 3);
      display_freq (frequency_B, 5);

      // Read the analog buttons input
      if(read_buttons()==1) {            // Up we increase frequency
        delay(200);  // Debounce
        if (vfo == 0) {
          frequency_A = frequency_A + powf(10,(float)multiplier);
        } else {
          frequency_B = frequency_B + powf(10,(float)multiplier);
        };
#if defined AUTO_VALID
        break;
#endif

      } else if (read_buttons()==3) {    // Down we decrease frequency
        delay(200);  // Debounce
        if (vfo == 0) {
          frequency_A = frequency_A - powf(10,(float)multiplier);
        } else {
          frequency_B = frequency_B - powf(10,(float)multiplier);
        };
#if defined AUTO_VALID
        break;
#endif

      } else if (read_buttons()==2) {    // Left we increase multiplier
        debounce = millis();
        while (read_buttons()==2) {  //Debounce
          if ((millis()-debounce)>1000) {  // Long press we do "Band UP"
            freq_select++;
            if (freq_select > 14) freq_select = 0;
            if (vfo == 1) frequency_B = frequencies[freq_select]; else frequency_A=frequencies[freq_select];
            multiplier--;
            break;
          };
        };
        multiplier++;
        if (multiplier > 8) multiplier = 8;

      } else if (read_buttons()==4) {    // Right we decrease multiplier
        debounce = millis();
        while (read_buttons()==4) {  //Debounce
          if ((millis()-debounce)>1000) {  // Long press we do VFO A=B
            if (vfo == 1) frequency_A = frequency_B; else frequency_B=frequency_A;
            multiplier++;
            break;
          };
        };
        multiplier--;
        if (multiplier < 0) multiplier = 0;

      } else if (read_buttons()==5) {    // OK we go out
        debounce = millis();
        while (read_buttons()==5) {  //Debounce
          if ((millis()-debounce)>1000) {  // Long press we switch VFO A/B
            if (vfo == 1) vfo=0; else vfo=1;
            break;
          };
        };
        break;   // Short press we just leave the loop so the frequency is transmitted to the AD9850
      }

      // Check if we are transmitting split (momentaneous VFO A->B switch)
      if (saved_PTT != digitalRead(PTT_key)) {
        saved_PTT = digitalRead(PTT_key);
        if (vfo == 1) vfo=0; else vfo=1;
        break;
      };
    }

};

//******************************************************************
// Display the frequency
void display_freq (unsigned long freq, char ligne) {
  myScreen.text(10, ligne, " Hz ");
  chaine_txt[5] = 0x00;
  chaine_txt[4] = 0x30 + (((freq)/1)%10);
  chaine_txt[3] = 0x30 + (((freq)/10)%10);
  chaine_txt[2] = 0x30 + (((freq)/100)%10);
  chaine_txt[1] = '.';
  chaine_txt[0] = 0x30 + (((freq)/1000)%10);
  myScreen.text(5, ligne, chaine_txt);
  chaine_txt[5] = 0x00;
  chaine_txt[4] = 0x30 + (((freq)/10000)%10);
  chaine_txt[3] = 0x30 + (((freq)/100000)%10);
  chaine_txt[2] = '.';
  chaine_txt[1] = 0x30 + (((freq)/1000000)%10);
  chaine_txt[0] = 0x30 + (((freq)/10000000)%10);
  myScreen.text(0, ligne, chaine_txt); 
}

//******************************************************************
// Display a 2 digits number
void display_number (byte number, char column, char ligne) {
  chaine_txt[2] = 0x00;
  chaine_txt[1] = 0x30 + (number%10);
  chaine_txt[0] = 0x30 + ((number/10)%10);
  myScreen.text(column, ligne, chaine_txt);
}

//******************************************************************
// Return a button value depending on the analog reading
byte read_buttons () {
  int value = analogRead(ANALOG_BUTTONS);
  if ( value<(1+Analog_Noise) ) {
    return 1;
  } else if ( value<(78+Analog_Noise) ) {
    return 2;
  } else if ( value<(146+Analog_Noise) ) {
    return 3;
  } else if ( value<(205+Analog_Noise) ) {
    return 4;
  } else if ( value<(255+Analog_Noise) ) {
    return 5;
  } else {
    return 0;
  }
}

Mesure de bruit de phase dans des oscillateurs

Bruit de phase VFO Bitx20 - Nicolae (http://xv4y NULL.radioclub NULL.asia/2013/01/03/mesure-de-bruit-de-phase-dans-des-oscillateurs/farhan_bitx20/)Nicolae, après s’être penché aux mélangeurs équilibrés du Bitx (http://xv4y NULL.radioclub NULL.asia/2012/12/28/comparaison-de-melangeurs-a-diodes-om-et-commerciaux/) en les comparant à d’autres composants commerciaux, s’est maintenant attaqué au VFO mis au point par Farhan VU2ESE. Il a donc effectué une série de mesure de bruit de phase d’abord sur un générateur de signal Rohde & Schwarz, puis sur 3 VFO (http://users NULL.tpg NULL.com NULL.au/nfieraru/Electronics/RF_Oscillators/Phase%20Noise%20in%20RF%20Oscillators NULL.htm) dont celui du Bitx et deux autres issus de sources diverses. Les résultats sont surprenants puisque l’oscillateur du Bitx, bien que conçu de manière un peu empirique par VU2ESE, présente de très belles caractéristiques. Le bruit de phase est même meilleur que celui du générateur de laboratoire, ce qui n’est pas si étonnant pour un oscillateur à circuit LC comparé à un synthétiseur mais reste très flatteur. Le VFO présente l’inconvénient d’avoir un niveau d’harmoniques très élevé. Elles sont en parties filtrées dans le transceiver et surtout le mélangeur à diode demande lui à être alimenté par un signal rectangulaire ou du moins avec des pentes abruptes pour fonctionner de manière optimale. Tout dépend donc de vos besoins…

Au passage, l’article sur les mélangeurs (http://users NULL.tpg NULL.com NULL.au/nfieraru/Electronics/RF_Mixers/Double%20Balanced%20Mixers NULL.htm) a été complété avec les mesures de compression à 1dB qui sont encore favorables au mélangeur avec diodes 1N4148…

Prototype balise WSPR à DDS

Prototype kit Balise WSPR DDS XV4Y (http://xv4y NULL.radioclub NULL.asia/2012/12/21/prototype-balise-wspr-a-dds/100_3339/)Je suis plutôt satisfait de ma semaine! En grappillant quelques heures entre mes occupations professionnelles j’ai réussi à finaliser la mise au point de ma balise WSPR avec un DDS AD9850 (http://xv4y NULL.radioclub NULL.asia/boutique/?slug=product_info NULL.php&products_id=33). Le prototype fonctionne parfaitement et les séquences sont reçues à 100% sur mon ordinateur de contrôle. Les tests sur l’air se sont révélés décevant mais avec moins de 10mW sur 20 mètres, les conditions hivernales et aucune station proche il ne fallait pas non plus rêver. Je vais essayer de bricoler un petit PA d’appoint pour valider les tests.

Un des points sur lequel je bloquais était la quantité de mémoire très restreinte du MSP430G2553. Avec 512 octets on est vite à cours de place pour les variables, d’autant plus que la génération de la séquence de symboles WSPR en consomme plus de 350 à elle seule! Devoir contrôler calculer la séquence WSPR, contrôler le DDS, et l’écran graphique posait pas mal de stress sur le micro-contrôleur. J’ai du réécrire une partie du code et économiser les variables. Les méthodes de programmation moderne nous apprennent à favoriser la lisibilité et la réutilisabilité du code en découpant en fonction ou en créant des classes d’objets. C’est bien beau mais même si les compilateurs modernes optimisent tout cela très bien, cela consomme quand même beaucoup de mémoire. Pas grave sur un micro-ordinateur, mais vite contraignant sur un micro-contrôleur. Les purs et durs programment toujours en assembleur, pour ma part même après 20 ans en ayant débuté à 11 ans sur le microprocesseur 6803 de mon Alice 90 (http://alice NULL.system-cfg NULL.com/) monté à partir de pièces en vrac par F1GUM, la mayonnaise n’a jamais pris…

100_3341

Si maintenant le code fonctionne parfaitement et que le hardware rempli son rôle, il me reste maintenant à voir comment tout agencer pour en faire un kit facile à reproduire et à monter, et à écrire la documentation! Dernier point technique à valider, l’ajout de 4 boutons pour pouvoir le transformer facilement en VFO ou générateur de signal.

Librairie pour piloter un DDS AD9850 avec un LaunchPad/MSP430 ou un Arduino

[GTranslate]

Je partage avec vous un de mes premiers résultats dans la mise au point d’une balise WSPR autonome agile avec générateur de signal à DDS (http://xv4y NULL.radioclub NULL.asia/boutique/?slug=product_info NULL.php&products_id=33). Voici en effet une petite librairie qui simplifiera vos projets pour piloter un DDS de chez Analog Devices comme le AD9850. Vous pouvez aussi facilement concevoir un VFO pour vos montages personnel Bitx (http://xv4y NULL.radioclub NULL.asia/category/ham-radio/materiel/bitx/) ou Bingo.

Cette librairie est assez simple puisqu’elle comporte quelques fonctions pour initialiser le circuit et lui programmer une fréquence. Un paramètre permet de passer le circuit en mode Power Down et de le réveiller au cas où. Cela permet d’économiser de l’énergie et même de faire une forme de CW si votre DDS génère le signal directement.

La communication se fait en mode série via 4 broches d’un micro-contrôleur MSP430G2553 par exemple. Bien entendu il faut aussi fournir l’alimentation et la masse. Fait intéressant, l’AD9850 est très flexible et supporte 3,3V ou 5V pour son alimentation. Comme la librairie est aussi très simple et n’utilise qu’un mode de communication logicielle elle est virtuellement portable sur toutes les familles de micro-contrôleurs. Le code est écrit pour les environnement de développements basés sur Wiring comme par exemple Arduino ou Energia.

Vous pouvez télécharger la librairie complète sur la page de téléchargements (http://xv4y NULL.radioclub NULL.asia/boutique/docs/).

Le code pour le fichier de header AD9850.h

/*
 AD9850.h - Library for adding simple AD9850 control capabilities on MSP430

 Copyright 2012 Yannick DEVOS under GPL 3.0 license
 Any commercial use or inclusion in a kit is subject to author approval

 ====
 Revision history :
 v1.00    2012-12-16
 First release

 ====
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You can download a copy of the GNU General Public License at <http://www.gnu.org/licenses/>

 ///////////////////////////////// How to use the lib

 * Create an instance of the object with the pin for CLOCK, LOAD, DATA and RESET

 AD9850 myDDS (P1_5, P2_0, P2_1, P2_2);	 Example for LaunchPad

 * Initialize the AD9850 and do a reset

 myDDS.begin();
 myDDS.reset();

 */

// Core library
#if defined (__AVR_ATmega328P__) || defined(__AVR_ATmega2560__) // Arduino specific
#include "WProgram.h" // #include "Arduino.h" for Arduino 1.0
#elif defined(__32MX320F128H__) || defined(__32MX795F512L__) // chipKIT specific 
#include "WProgram.h"
#elif defined(__AVR_ATmega644P__) // Wiring specific
#include "Wiring.h"
#elif defined(__MSP430G2452__) || defined(__MSP430G2553__) || defined(__MSP430G2231__) // LaunchPad specific
#include "Energia.h"
#elif defined(MCU_STM32F103RB) || defined(MCU_STM32F103ZE) || defined(MCU_STM32F103CB) || defined(MCU_STM32F103RE) // Maple specific
#include "WProgram.h"	
#endif

// ensure this library description is only included once
#ifndef AD9850_h
#define AD9850_h

// library interface description
class AD9850
{
	// user-accessible "public" interface
public:
	AD9850(uint8_t pinClock, uint8_t pinLoad, uint8_t pinData, uint8_t pinReset);
	void begin();
	void reset();
	void SetFrequency(unsigned long frequency, boolean powerdown);	// Set the frequency and send PowerDown command if needed
	// A few private methods
private:
};

#endif

Le code pour le fichier de déclaration des routines AD9850.cpp

/*
 AD9850.h - Library for adding simple AD9850 control capabilities on MSP430

 Copyright 2012 Yannick DEVOS under GPL 3.0 license
 Any commercial use or inclusion in a kit is subject to author approval

 Based on work by G7UVW

 ====
 Revision history :
 v1.00    2012-12-16
 First release

 ====
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You can download a copy of the GNU General Public License at <http://www.gnu.org/licenses/>

 */

// include this library's description file
#include <AD9850.h>
//#include <legacymsp430.h>

#define DDS_CLOCK 125000000

// Constructor /////////////////////////////////////////////////////////////////
uint8_t _DDSpinClock;
uint8_t _DDSpinLoad;
uint8_t _DDSpinData;
uint8_t _DDSpinReset;

AD9850::AD9850(uint8_t pinClock, uint8_t pinLoad, uint8_t pinData, uint8_t pinReset)
{
	_DDSpinClock = pinClock;
	_DDSpinLoad = pinLoad;
	_DDSpinData = pinData;
	_DDSpinReset = pinReset;

};

// Methods /////////////////////////////////////////////////////////////////

void AD9850::begin()
{
    pinMode (_DDSpinClock, OUTPUT); 
    pinMode (_DDSpinLoad,  OUTPUT); 
    pinMode (_DDSpinData,  OUTPUT); 
    pinMode (_DDSpinReset, OUTPUT);

	digitalWrite(_DDSpinReset, LOW);
	digitalWrite(_DDSpinClock, LOW);
	digitalWrite(_DDSpinLoad, LOW);
	digitalWrite(_DDSpinData, LOW);		
}

void AD9850::reset()
{
	//reset sequence is:
	// CLOCK & LOAD = LOW
	//  Pulse RESET high for a few uS (use 5 uS here)
	//  Pulse CLOCK high for a few uS (use 5 uS here)
	//  Set DATA to ZERO and pulse LOAD for a few uS (use 5 uS here)

	// data sheet diagrams show only RESET and CLOCK being used to reset the device, but I see no output unless I also
	// toggle the LOAD line here.

    digitalWrite(_DDSpinClock, LOW);
    digitalWrite(_DDSpinLoad, LOW);

	digitalWrite(_DDSpinReset, LOW);
	delay(5);
	digitalWrite(_DDSpinReset, HIGH);  //pulse RESET
	delay(5);
	digitalWrite(_DDSpinReset, LOW);
	delay(5);

	digitalWrite(_DDSpinClock, LOW);
	delay(5);
	digitalWrite(_DDSpinClock, HIGH);  //pulse CLOCK
	delay(5);
	digitalWrite(_DDSpinClock, LOW);
	delay(5);
	digitalWrite(_DDSpinData, LOW);    //make sure DATA pin is LOW

	digitalWrite(_DDSpinLoad, LOW);
	delay(5);
	digitalWrite(_DDSpinLoad, HIGH);  //pulse LOAD
	delay(5);
	digitalWrite(_DDSpinLoad, LOW);
	// Chip is RESET now
}

void AD9850::SetFrequency(unsigned long frequency, boolean powerdown)
{
	unsigned long tuning_word = (frequency * 4294967296 ) / (DDS_CLOCK*10);  // As frequency is in tens of Hertz, we need to multiply by 10
	digitalWrite (_DDSpinLoad, LOW); 

	shiftOut(_DDSpinData, _DDSpinClock, LSBFIRST, tuning_word);
	shiftOut(_DDSpinData, _DDSpinClock, LSBFIRST, tuning_word >> 8);
	shiftOut(_DDSpinData, _DDSpinClock, LSBFIRST, tuning_word >> 16);
	shiftOut(_DDSpinData, _DDSpinClock, LSBFIRST, tuning_word >> 24);
	if (powerdown)
		shiftOut(_DDSpinData, _DDSpinClock, LSBFIRST, B00000100);	// If powerdown is true then send PowerDown command
	else
		shiftOut(_DDSpinData, _DDSpinClock, LSBFIRST, 0x0);

	digitalWrite (_DDSpinLoad, HIGH); 
}

Si570 ou DDS, le dilemne de G0UPL – Partie 3

Suite des précédentes parties 1 (http://xv4y NULL.radioclub NULL.asia/2011/08/24/si570-ou-dds-le-dilemne-de-g0upl/) et parties 2 (http://xv4y NULL.radioclub NULL.asia/2011/08/30/si570-ou-dds-le-dilemne-de-g0upl-partie-2/) de cet article sur une comparaison entre DDS et Si570.

Consommation électrique

Ni le Si570 ni un DDS ne sont réellement économes quand on parle de la consommation électrique. Les deux vont essayer de vider votre batterie avec gloutonnerie, si vous opérez sur batteries bien entendu.

Le Si570 est annoncé avec une consommation de 120 mA à 3,3 V pour la versions LVPECL, ce qui fait 396 mW. Un ADD9912 d’un autre côté demande deux tensions séparées de 1,8 V et 3,3 V pour ses différentes sections (analogiques et numériques). Chaque tension a différentes consommations, mais la datasheet liste des consommations typiques pour différentes configurations. La consommation électrique est entre 637 mW et 747 mW. L’AD9912 a même une plaque de cuivre exposée à l’extérieur pour aider la chaleur à s’en extraire! N’oubliez pas, ceci est avant même que vous ne preniez en compte que le Si570 intègre déjà sa propre horloge de référence, alors qu’un circuit DDS aura besoin que vous lui en fournissiez une, ce qui ajoutera encore une charge sur l’alimentation électrique.

Quelques uns des DDS plus anciens, moins puissants, ont des besoins plus réduits. Mais comme tout mon comparatif s’est fait autour des circuits DDS du haut du panier, en particulier l’AD9912, je dirais qu’ici le Si570 prend l’avantage.

Coût

Aucun des deux n’est bon marché. Le Si570 a un prix comparable à celui de certains DDS bas de gamme mais pour un DDS haut de gamme comme l’AD9910 ou l’AD9912 que j’ai cité auparavant, vous débourserez nettement plus que pour un Si570. De plus, le DDS demande plus de circuits périphériques comme l’horloge externe, qui a peu de chance de se trouver dans un fond de tiroir. D’un autre côté, si vous êtes un radioamateur rusé (et radin), vous avez l’habitude de demande à Analog Device des échantillons gratuits. Vous n’obtiendrez jamais d’échantillons du Si570 par SiLabs. Tout bien pensé, je pense qu’on peut dire que globalement le Si570 gagne sur le plan du coût.

Autres fonctionnalités

Le Si570 est juste un oscillateur basique. Si vous voulez plus de fonctionnalités, vous voulez un DDS. Regardez les datasheets et vous serez plus qu’étonnés! Contrôlez l’amplitude, contrôlez  la phase et même ajoutez une réductions des spurs. Certains circuits DDS contiennent deux coeurs et sorties, qui peuvent être réglées pour être décalées de 90 degrés en phase (pratique pour un mélangeur à conversion directe de type phasing, regardez l’AD9854 (http://www NULL.analog NULL.com/en/rfif-components/direct-digital-synthesis-dds/ad9954/products/product NULL.html)). Automatisez votre modulation d’amplitude, modulation de fréquence, modulation de phase, balayage de fréquence automatique, et tout un tas d’autres possibilités dont je ne peux même pas souvenir ou comprendre. Vous n’en avez probablement pas besoin, ce sont peut-être juste des paillettes et strass pour faire vendre, mais du point de vue fonctionnalités je pense que vous serez d’accord pour dire le DDS est clairement vainqueur.

Complexité globale

Un Si570 est plutôt simple à utiliser. Donnez lui une tension de 3,3 V, connectez-y votre microcontrôleur, ça y est vous êtes prêt.

C’est pas trop ça avec le DDS! Avec un DDS, vous devez avoir quatre sources d’alimentation séparées, propres et bien régulées, certaines à 1,8 V et d’autres à 3,3 V. Vous avez besoin d’une horloge de référence. Certains composants DDS ont un oscillateur intégré où vous pouvez juste y connecter votre quartz. Toutefois pour les meilleures performances vous voudrez clairement concevoir et construire un oscillateur à 1 GHz, ce qui n’est pas un jeu d’enfant, et l’avoir correctement couplé avec les entrées de la puce. Ensuite vous nécessiterez le filtre de reconstruction (typiquement un passe-bas) à la sortie, et ce dernier doit aussi être soigneusement conçu. La carte par elle-même demande pas mal de soins aussi car il y a beaucoup de circuits HF tout autour de votre DDS.

Oui, utiliser un DDS demande beaucoup plus d’efforts qu’un Si570. Donc du point de vue de la complexité, je dirais que le Si570 est là aussi définitivement gagnant.

En résumé

Après tout cela, voici un résumé de mon avis sur les différents critères par lesquels juger ces deux types d’oscillateur. Gardez à l’esprit que chaque application est différente! Dans certaines, certains de ces critères ne sont pas importants du tout, ou bien vos propres priorités sont claires (et opposées à ma conclusion). Dans d’autres applications, vous devez faire face à des compromis inévitables. Performances et complexité, fonctionnalités et coûts, etc. Pour conclure quand même, je vais donc généraliser et travailler de manière bipolaire en donnant mon gagnant pour chaque catégorie sans tenir compte des autres. Je vous laisse juge des priorités selon vos applications.

Catégorie Gagnant
Facilité de construction Si570
Forme d’onde en sortie DDS
Gamme de fréquence Si570
Précision et stabilité en fréquence DDS
Agilité en fréquence DDS
Interface de programmation DDS
Performances : Pureté spectrale Si570
Performances : Bruit de phase DDS
Consommation électrique Si570
Coût Si570
Autres fonctionnalités DDS
Complexité glogale Si570

D’autres lectures

Pour une saine lecture pleine d’inspiration à propos d’un projet de récepteur aux performances ultimes, décrivant les raisons pour lesquelles Martein de PA3AKE a choisi le DDS AD9910 pour son oscillateur, merci de visiter son site (http://www NULL.xs4all NULL.nl/~martein/pa3ake/hmode/). Pour les kits Si570 jetez un oeil chez SDR Kits (http://www NULL.sdr-kits NULL.net/). Il y a des tas de kits DDS disponibles sur la toile, utilisez votre moteur de recherche préféré pour les trouver. Pour d’autres informations intéressantes et des discussions à propos du Si570, aller sur la page Si570 d’Andy G4OEP (http://g4oep NULL.atspace NULL.com/si570index/si570index NULL.htm); tout comme Martein PA3AKE, Andy ne fait jamais les choses à moitié.

Mon favori

Ce qui est le mieux dépend vraiment de vos besoins. Mais si vous êtes toujours en train de me lire, et que vous pensez que je dois quand même donner ma préférence globale, je dirais le DDS. C’est juste comme une couleur préférée, ou un chiffre porte-bonheur, il n’y a aucune vraie raison. C’est juste celui que je préfère!

Si570 ou DDS, le dilemne de G0UPL – Partie 2

Suite du précédent article (http://xv4y NULL.radioclub NULL.asia/2011/08/24/si570-ou-dds-le-dilemne-de-g0upl/) sur une comparaison entre DDS et Si570.

Performances : Pureté spectrale (spurs)

Le Si570 est un oscillateur avec boucle à verrouillage de phase numérique (DPLL) qui produit un signal de sortie rectangulaire. Comme tous les signaux rectangulaires, il est composé d’une fondamentale plus un “peigne” très riche formé par ses nombreuses harmoniques impaires. Si une forme d’onde sinusoïdale est nécessaire et que la plage d’opération est étroite, les composantes indésirables (spurs) peuvent être éliminées par filtrage, et elles seront bien entendu à une distance raisonnable de la fréquence centrale (i.e. à 3, 5, 7… fois la fréquence de la fondamentale). Il y a aussi un peu de puissance présente aux harmoniques paires car la sortie n’est pas garantie pour être une forme d’onde carrée parfaite avec un rapport cyclique de 50%. Les autres composantes indésirables sont très faibles pour le Si570 et ne sont normalement pas considérées comme problématiques.

Les puces DDS ont une mauvaise réputation pour les composantes indésirables! Ceci parce que la forme d’onde en sortie est obtenue par approximation à partir d’une série de niveaux discrets, qui sont ensuite filtrés extérieurement au circuit par votre filtre passe-bas. Le process est de manière inhérente une approximation de la sinusoïde idéale , ce qui génère une réponse impure. Les composantes indésirables sont nombreuses et de différentes amplitudes, elles peuvent aussi se présenter très proche de la porteuse, donc vous ne pourrez pas totalement les éliminer par filtrage.

Certains des DDS Analog Device les plus modernes incluent une technologie “SpurKiller”, comme sur le AD9912 avec deux canaux SpurKiller. Ceci sont en fait deux coeurs DDS en parallèle, dont les fréquences, amplitudes de sortie et phases peuvent être réglées de telle manière que si votre application peut prédire ou mesurer la localisation des impuretés, vous pouvez choisir les deux plus gênantes et les éliminer par annulation. Je pense que la gamme de possibilités pour lesquelles ceci sera réellement utile est quelque peu limitée. La datasheet mentionne que cette fonctionnalité agit de manière optimale avec une légère différence entre chaque circuit, ce qui limiterait son efficacité dans beaucoup d’applications pratiques.

L’importance des problèmes de pureté spectrale dépend principalement de deux facteurs : la résolution du CNA (DAC) et la proportion de la fréquence de sortie relativement à la fréquence de l’oscillateur de référence. Les CNA vont typiquement de 10 bits dans les composants plus anciens jusqu’à 14 bits dans un circuit haut de gamme comme le AD9912. Un CNA de meilleure résolution produira moins de composantes indésirables. De la même manière, si la fréquence de l’oscillateur de référence est très haute vis-à-vis de celle de sortie, les impuretés sont réduites. Le AD9912 peut fonctionner avec une référence montant jusqu’à 1 GHz. Pour une sortie dans la gamme HF de 0 à 30MHz, les impuretés sont très minimes. Pour les VHF ou UHF, elles peuvent être plus gênantes bien sûr. Pour un usage radioamateur, même sur un DDS bas de gamme, les composantes indésirables ont peu de chance d’être un problème dans un usage en émission seule, parce qu’elles sont de niveaux inférieurs aux seuils réglementaires pour les équipements radioamateurs. Dans des applications de réception, les impuretés vont se manifester sous forme de birdies (porteuses fantômes) dans le récepteur et sont un problème plus sérieux. Toutefois, pour un récepteur HF et si vous utilisez un DDS moderne comme l’AD9912 avec une horloge de référence à 1 GHz, alors les composantes indésirables seront très faibles et il est peu probable qu’elles soient audibles dans la plupart des cas.

Un DDS haut de gamme avec une conception soignée ne présentera pas de réponses indésirables dans un cadre limité de circonstances (c-a-d en HF). Le Si570 gagne cette fois car lui il n’a aucun problème de pureté spectrale du tout.

Performances : Bruit de phase

Le bruit de phase peut être vu comme un élargissement de la ligne verticale parfaite que vous devriez voir avec un analyseur de spectre si vous regardez le signal de sortie d’un oscillateur. Une raison pour laquelle c’est si important dans récepteur, c’est qu’il se mélange avec les signaux forts quelques kHz plus loin que le signal désiré pour produire un bruit de fond (plancher de bruit) élevé, qui peut alors facilement cacher un signal faible que vous voudriez écouter. Pour un récepteur de haute performance, il est primordial d’avoir un oscillateur au bruit de phase le plus faible possible.

Les performances des DSS en terme de bruit de phase sont généralement vraiment bonnes. Il y a un peu de jigue (jitter) ajoutée par les imperfections inhérente à l’approximation numérique de la forme d’onde et un peu de bruit de phase ajouté dans des proportions limitées par les imperfections du circuit numérique. Par ailleurs, le bruit de phase d’un DDS ne peut être qu’aussi bon (en réalité un brin moins bon) que celui de l’horloge de référence. Typiquement ce serait un oscillateur à quartz, et les quartz, ayant un Q très élevé, ont de très bonnes performances en terme de bruit de phase. Donc en général, le DDS est considéré comme une technologie à faible bruit de phase.

Beaucoup de puces DDS intégrent un multiplicateur à PLL pour l’horloge de référence. Ce dernier peut être utilisé pour fournir une référence interne à très haute fréquence, jusqu’à la limite donnée pour le composant (c-à-d 1GHz pour l’AD9910), à partir d’une horloge en entrée bien plus faible. Rappelez-vous qu’une horloge de fréquence élevée est meilleure pour une meilleure pureté spectrale, donc le multiplicateur peut être utile dans ce but. Cela peut simplifier grandement votre architecture, mais au prix d’un bruit de phase additionnel dans le processus interne de multiplication par la PLL. Une multiplication de fréquence dans chaque cas comporte un minimum théorique de 6dB par octave (ou 20dB/decade) de pénalité en terme de bruit de phase, mais si vous utilisez la PLL interne vous serez au dessus de ça. En conclusion pour de meilleures performances en bruit de pahse, laissez la PLL en dehors de cette affaire et construisez votre propre oscillateur externe de référence à haute fréquence.

Le Si570 est construit sur une technologie à PLL, qui en principe a un bruit de phase bien plus élevé. Toutefois, dans le Si570, ils minimisent le bruit de phase grace à un design soigné et en utilisant une boucle à bande très étroite. C’est la raison de la présence du long délai (10ms) de sélection de la fréquence. En conséquence le bruit de phase du Si570 est plutôt respectable est sera adéquat pour beaucoup d’usages.

Que dire d’une comparaison entre DDS et Si570 ? Les informations sur les performances en terme de bruit de phase dans certaines des datasheets de DDS sont plutôt limitées. Souvent ils montre le “bruit de phase résiduel”, ce qui veut dire le bruit de phase additionnel qui est ajouté à celui du à l’horloge de référence par le fonctionnement du DDS lui-même. Ce n’est pas le même que le bruit de phase réel que vous observerez sur le signal de sortie – pour cela vous devez aussi ajouter le bruit de phase de l’oscillateur de référence – et donc ce n’est pas directement comparable au bruit de phase d’un Si570. Néanmoins, certaines datasheet de composants DDS donnent un graphique de bruit de phase absolu, et un exemple de ceci est l’AD9912 qui montrent le bruit de phase en sortie pour différentes fréquences de sortie en assumant l’utilisation d’un oscillateur haute performance de Wenzel (http://www NULL.wenzel NULL.com/) à 1 GHz. La datasheet du Si570 a une table de bruit de phase pour trois fréquences de sortie (120 MHz, 156,25 MHz, 622,08 MHz).

Il est important de se rappeler que quand une fréquence est divisée, le bruit de phase lui aussi diminue de 6dB par octave (ou 20dB par décade). Alors dans n’importe quelle comparaison, nous devons prendre ceci en compte si les fréquences mesurées ne sont pas les mêmes. Dans notre exemple de comparaison, j’ai choisi de mettre en regard les données du Si570 à 156,25 MHz avec un graphique de la datasheet de l’AD9912 à 171 MHz. Pour être rigoureux, je devrait faire un ajustement pour cette différence en fréquence (i.e. 156,25 MHz et 171 MHz) en faisant quelques calculs pour les 6 dB/octave. Cela dit, elles sont suffisament proches pour que cela ne fasse qu’environ 1 dB de différence, ce qui dans tous les cas reste dans les marges d’erreur de la précision que je peux avoir en lisant les valeurs depuis le graphique de la datasheet de l’AD9912. En conséquence je vais ignorer cette compensation. Cette petite imprécision pourrait pencher en faveur du Si570 qui a ici la fréquence la plus basse.

Voilà donc une table des valeurs pour 156,25 MHz issues de la datasheet du Si570, et les valeurs correspondantes lues depuis le graphique de la datasheet de l’AD9912. Ces résultats peuvent être considérés comme étant reproductibles avec les deux composants à d’autres fréquences, une fois proprement mis à l’échelle avec 6 dB par octave (20 dB par décade). Les unités du bruit de phase sont en dBc/Hz.

Décalage Si570 AD9912
100 Hz -105 -125
1 kHz -122 -138
10 kHz -128 -148
100 kHz -135 -157
1 MHz -144 -162
10 MHz -147 -163

Ici, les mêmes résultats, présentés sur un graphique :

Comparaison du bruit de phase entre AD9912 et Si570

Ici, la conclusion est qu’un DDS de haut de gamme avec un oscillateur de référence de haute qualité et un bon design (AD9912 avec horloge à 1 GHz), peut dépasser les performances du Si570 de 20 dBc/Hz. Toutefois, je dirais que pour la majorité des applications les performances de bruit de phase du Si570 seront suffisantes, et probablement meilleures que celles de beaucoup de transceiver commerciaux “boîte noire” proposés sur le marché.

Finalement, grace aux excellentes performances de la technologie DDS, je déclare le DDS vainqueur pour cette épreuve.

La suite dans la partie 3. Pour les plus impatients vous pouvez lire la version originale en anglais (http://hanssummers NULL.com/ddssi570 NULL.html), sinon il faudra attendre la semaine prochaine…

Si570 ou DDS, le dilemne de G0UPL – Partie 1

Je vous propose ici une petite traduction d’un article original écrit par Hans Summers de G0UPL (http://www NULL.hanssummers NULL.com/ddssi570 NULL.html). J’ai bien aimé cet article dont le contenu est instructif et j’en ai surtout apprécié le ton décontracté. Lorsque je lui ai demandé son autorisation, Hans a souhaité me préciser qu’il s’agissait plus d’un genre de pied de nez plutôt qu’un article sérieux et théorique. Le débat semble passionner certains et même si ses arguments sont justifiés il ne tient pas à établir son choix personnel comme un dogme. Je laisse la parole à Hans…

Le Si570 est un circuit relativement récent fait par Silicon Labs. C’est un composant très petit contenant un oscillateur de référence à quartz, une boucle à vérouillage de phase (PLL), et une interface I2C afin qu’il puisse être programmé pour n’importe quelle fréquence entre 10MHz et 945MHz (fréquences au choix jusque 1.4GHz). Les circuits à synthèse digitale directe (DDS), comme ceux du leader du marché Analog Devices, sont dans la place depuis plus longtemps. Ils représente un type très différent de composant, même si les deux sont des oscillateurs. En conséquence le meilleur choix dépend grandement de l’application. Voici mon avis à propos des avantages et inconvénients relatifs qui peuvent être des facteurs importants de décision.

Projets

DDS expérimental de G0UPL (http://www NULL.hanssummers NULL.com/dds NULL.html)

DDS expérimental de G0UPL

Emetteur QRSS à base de Si570 par G0UPL (http://www NULL.hanssummers NULL.com/qrss570 NULL.html)

Emetteur QRSS à base de Si570 par G0UPL

Données de référence (bibliographie)

Analog Devices DDS page (http://www NULL.analog NULL.com/en/rfif-components/direct-digital-synthesis-dds/products/index NULL.html)

Analog Devices AD9910 DDS datasheet (http://www NULL.analog NULL.com/static/imported-files/data_sheets/AD9910 NULL.pdf)

Analog Devices AD9912 DDS datasheet (http://www NULL.analog NULL.com/static/imported-files/data_sheets/AD9912 NULL.pdf)

Silicon Labs (http://www NULL.silabs NULL.com/)

Si570 datasheet (http://www NULL.silabs NULL.com/Support%20Documents/TechnicalDocs/si570 NULL.pdf)

Facilité de construction

Comparaison du format des circuits (les photos ne sont pas à l’échelle).

DDS ADD9910 (QFP 100)

DDS ADD9910 (QFP 100)

Si570 (package 7x5 mm)

Si 570 (package 7x5 mm)

Le Si570 est gagnant ici. Il a 8 broches, et bien que ce soit une composant à montage en surface de petite taille, vous pouvez le souder de manière raisonnablement facile même sans circuit imprimé. D’un autre côté, tous les circuits DDS modernes sont en format CMS seulement, par exemple ce DDS AD9910 de 100 broches. Souder celui-ci pattes en l’air serait un vrai défit. Même les générations précédentes de DDS avec des CMS à 28 broches n’étaient pas si faciles que ça à manipuler.

Allure du signal de sortie

Le Si570 a un signal de sortie rectangulaire. Souvent ça convient, par exemple, si vous voulez alimenter un mélangeur : beaucoup de mélangeur opère dans de meilleures conditions si le VFO a un signal rectangulaire. Si vous voulez une belle sinusoïde, il vous faudra alors beaucoup de filtrage passe-bas pour éliminer toute la suite de riches harmoniques.

Les circuits DDS ont une sortie sinusoïdale : elle est générée en sortie par une succession rapide de tension analogiques grâce à un Convertisseur Numérique-Analogique (CNA ou DAC en anglais), qui simule une sinusoïde. Beaucoup de circuits DDS ont un comparateur intégré qui peut être facilement utilisé pour changer la sinusoïde en signal carré si c’est ce dont vous avez besoin. Gardez toutefois à l’esprit que vous aurez d’un filtre passe-bas d’anti-crénelage (ou anti-aliasing) sur la sortie du DDS pour produire un signal propre.

Déclarer le gagnant… dépend de votre application. Si vous voulez une forme d’onde de sortie rectangulaire, le Si570 est parfait. Le DDS convient aussi (s’il est équipé d’un comparateur), pour cette raison mon gagnant c’est le DDS.

Gamme de fréquence

Un DDS descendra jusqu’au courant continu ou presque. La limite haute pratique d’un DDS étant normalement considérée à 40% de son horloge de référence à quartz. C’est une limitation de la synthèse numérique de la forme d’onde, qui est un processus d’échantillonage (voir théorème de Shannon-Nyquist). Les fréquences plus hautes que 40% de l’horloge de référence sont aussi possible en sortie du DAC qui n’est pas filtré, et un signal peut en être extrait avec un filtrage passe-bande adéquat au lieu d’un filtrage passe-bas traditionnel. Les sorties comme celle-ci demande un design plus soigné et les performances ne sont jamais aussi bonnes.

A l’opposé, le Si570 autorise n’importe quelle fréquence entre 10MHz et 945MHz, et une sélection plus limitée de fréquences jusqu’à 1,4GHz. J’ai entendu dire que l’utilisation en dessous des 10 MHz donnés par le constructeur est possible, mais je ne l’ai pas confirmé moi-même.

Ici je dirais que le DDS pourrait gagner si vous voulez être libre de descendre jusqu’à des fréquences très basses, mais le Si570 gagnerait si votre utilisation demande des fréquences très hautes, ou une plage de fréquences continue jusqu’au delà des UHF. Cela dit, parce que le Si570 a une gamme si large et pratique, je le déclare vainqueur.

Stabilité en fréquence

Un DDS a besoin d’une horloge de référence, qui lui est normalement fournie au travers d’un oscillateur à quartz à haute stabilité. C’est à vous de prévoir l’oscillateur de référence. Vous pouvez le faire aussi stable que vous le voulez. L’asservir à un GPS, à un étalon au Rubidium, le mettre dans un four à température constante… comme vous le souhaitez.

Le Si570 a son propre oscillateur à quartz intégré. La différence c’est que vous n’avez pas beaucoup de contrôle sur celui-ci. Vous ne pouvez pas l’ajuster pour être pile sur la fréquence, vous ne pouvez pas l’asservir à une référence GPS (http://www NULL.hanssummers NULL.com/gpsref NULL.html). (Il dispose tout de même d’un petit ajustement de fréquence via l’entrée ADC, mais c’est à vous de mesurer la fréquence réelle, la comparer à un standard et estimer une tension de correction – ce n’est donc pas une vraie solution sauf avec un effort important). Dans ma balise QRSS contrôle par Si570 (http://www NULL.hanssummers NULL.com/qrss570 NULL.html) j’ai trouvé que le Si570 était déjà plutôt précis et stable. Quelques Hertz à côté de la fréquence à 10.140MHz et il ne semblait pas dériver de manière perceptible avec les variations de la température ambiance de la pièce, je n’ai toutefois pas fait de mesures rigoureuses.

A mon avis, si vous avez besoin de stabilité et précision, le DDS gagne ici, parce que vous pouvez le rendre aussi stable et précis que vous le voulez.

Agilité en fréquence

La fréquence d’un DDS peut-être fixée quasi instantanément (tout du moins, aussi vite que vous pouvez la transmettre au circuit intégré)! La plupart des DDS ont une résolution de syntonisation sur 32 bits, et certains même sur 48 bits (comme l’AD 9912) ce qui vous donne une résolution proche de quelques micro-Hz, si vous en avez un jour besoin!

Le Si570 peut aussi être syntonisé par pas très petits mais la fréquence ne change pas instantanément. Quand vous faites un changement de fréquence, il y a un délai qui peut aller jusqu’à 10ms (0,01s) pendant que la PLL interne se vérouille sur la nouvelle fréquence. Cela peut produire un petit clic ou piaillement dans la BF, par exemple, si vous utilisez le Si570 comme un VFO pour votre récepteur. Le Si570 peut aussi être syntonisé beaucoup plus rapidement (100 fois plus vite) pour de petits pas compris dans les  3 500 parties par million (ppm) de la fréquence centrale (NDT : Soit 49KHz à 14 MHz). Dans cas, le temps de verrouillage est inférieur à  0,1ms (100µs).

Ce réglage retardé du Si570 peut le rendre impropre à certaines applications comme les modes de communication numériques où la fréquence doit être changée très vite, ou l’opération en mode “SPLIT”, ou même la télégraphie QSK avec un décalage entre émission et réception (bien que ceci a peu de chances de dépasser les 3 500 ppm).

En conséquence pour l’agilité en fréquence c’est le DDS qui gagne largement si votre usage le demande : changement de fréquence parfait en un clin d’oeil!

Interface de programmation

Les circuits DSS ont une interface de programmation série, et la programmation est aisée. Certains supportent aussi une interface de commande parallèle (un octet à la fois). J’ai construit un générateur DDS qui peut se faire sans micro-contrôleur du tout (voir ici (http://www NULL.hanssummers NULL.com/dds NULL.html)) mais en principe vous utiliserez un micro-contrôleur.

Le Si570 a une interface I2C, et programmer la fréquence est un peu plus délicat, mettant en oeuvre certains calculs de différentes valeurs de diviseur/multiplicateur et la fréquence de l’oscillateur interne contrôlé numériquement. C’est un peu plus complexe que l’envoi d’un simple mot octal pour programmer le DDS, qui est juste une fraction de la fréquence de l’horloge de référence.

Le Si570 n’est quoi qu’il en soit pas un problème si vous êtes raisonnablement compétent pour programmer des micro-contrôleurs, mais un DDS est plus simple et je pense qu’il prend la tête ici.

La suite dans la partie 2. Pour les plus impatients vous pouvez lire la version originale en anglais, sinon il faudra attendre la semaine prochaine…

Contrôleur pour Si570 de K5BCQ

Ce kit fait l’objet d’un article détaillé dans Radioamateur Magazine (http://radioamateur-magazine NULL.over-blog NULL.com/) numéro 18 (à paraître en juin 2010).

Je l’ai déjà dit, comme cadeau d’anniversaire je me suis offert un kit électronique pour monter un contrôleur pour Si570 (http://www NULL.qsl NULL.net/k5bcq/Kits/Kits NULL.html). Ce circuit me servira de générateur de signal et donc principalement de source pour le VFO du BitX. De manière générale ce kit est un excellent compagnon pour un montage QRP tel que BitX ou Bingo car il produit un signal stable, dispose d’un affichage de grande taille, d’un encodeur rotatif, consomme peu et surtout est très bon marché (47 USD port compris). Kees a toujours été très réactif et agréable dans nos échanges. Le colis est arrivé très rapidement (moins de 2 semaines) et en bon état même si les douanes ont pour une fois manqué de soin à l’ouverture.

Le kit par lui même est plutôt simple et ne comporte pas plus de vingt composants et pièces. Pas de réglage à faire, tout doit marcher du premier coup. La difficulté tient au fait que les composants sont des CMS de gabarit 805. C’est petit, très petit. Le circuit imprimé est bien fait, laissant de la place pour travailler, mais ça reste un challenge pour moi car c’est la première fois que je monte des CMS.

Je me suis donc documenté sur le montage des composants CMS et les méthodes pour réussir ses circuits par un amateur. J’ai acheté un nouveau fer à souder à pointe fine et faible puissance (32W). Je voulais un faire thermo-contrôlé, mais ce n’est pas trouvable ici. Le vendeur m’a refilé un variateur (hacheur) à la place, et finalement ça le fait quand même! Je me suis aussi bricolé un support avec un gros clip à papier, et fixé une loupe sur la troisième main pour aider à la lecture des composants et vérifier les soudures. Dernière précaution, je me suis aussi fixé de prendre mon temps, ne travailler que le matin et sous une bonne lumière.

Finalement la soudure des CMS est plutôt facile. On chauffe un des pads (plot de soudure) et on y met une goutte d’étain. Ensuite on positionne le composant au bord et on le maintient pas trop fermement. On rechauffe pour souder en positionnement doucement le composant. Une fois que la soudure est refroidie et le composant au bon endroit, on fait la deuxième soudure. S’il faut, on corrige un peu la première. Une fois qu’on a pris le coup ça va bien. Même pour les circuits intégrés c’est faisable mais il faut être soigneux et patient. Le Si570 par lui même était le plus difficile, surtout les deux plots latéraux.

La plus grande difficulté finalement c’était pour les composants traditionnels (connecteurs, support de CI…) car la pastille de soudure est très petite. Surtout on a toujours peur de toucher les autres composants car le PCB n’est pas très grand tout de même.

A la mise sous-tension, sueurs froides! Le circuit démarre bien mais l’afficheur affiche “8.8.     0”. J’essaye une remise à zéro de la mémoire en appuyant sur l’encodeur rotatif à la mise sous-tension, mais il affiche bien un code puis revient à “88    0″… Je vérifie toutes les soudures avec le LCD, puis une par une les pattes du micro-contrôleur, celle de la mémoire… Tout est bon! Je m’apprête alors à écrire à Kees, le fournisseur du kit, mais juste avant j’essaye une dernière remise à zéro en restant appuyé plus de 10 secondes. Miracle! Ca marche!

Ensuite j’y connecte un fréquencemètre et le signal est bien là. Il doit être d’un niveau juste un peu faible pour le fréquencemètre de l’ANTAN. A 4MHz la mesure est stable, ensuite il semble y avoir un peu de jigue, mais le Si570 étant réputé très stable (http://www NULL.cliftonlaboratories NULL.com/si570_kit_from_k5bcq NULL.htm#Frequency_Stability_and_Accuracy), je pense que ça vient de la mesure.

Conclusion : je recommande ce circuit à tout le monde. Pas cher et facile à monter pour peu qu’on y prenne beaucoup de soin. Ensuite l’ergonomie est bonne, et selon tous les avis, la qualité du signal excellente.

Kit BitX – 11 : Huff & Puff et VFO synthétisé

Pas beaucoup le temps de bricoler en ce moment, enfin juste le minimum pour me détendre un peu.

Il y a quelques semaines j’ai reçu les composants pour faire quelques montages pour améliorer le BitX. Tout d’abord j’ai construit un circuit de stabilisation du VFO de type Huff & Puff en m’inspirant des montages de Hans Summers G0UPL (http://www NULL.hanssummers NULL.com/huffpuff/minimalist/2chip NULL.html) et Olivier F5LVG (http://oernst NULL.f5lvg NULL.free NULL.fr/oscil/stab/stab NULL.html). Le montage a l’air de “fonctionner”, par contre son efficacité ne me paraît pas suffisante pour compenser la dérive trop rapide de mon VFO. J’essaye de jouer sur les différents paramètres mais je n’arrive pas à obtenir une stabilité suffisante sur le long terme. Je pense que l’approche “Fast” serait nécessaire dans mon cas… Enfin, je vais continuer à faire des essais en réduisant le pas du synthétiseur (en augmentant la fréquence).

J’ai aussi reçu mon cadeau d’anniversaire mais promis je n’y touche pas avant le 29 avril. C’est un kit électronique encore une fois : un Générateur HF synthétisé à base de Si570 conçu et distribué par K5BCQ et K5JHF (http://www NULL.qsl NULL.net/k5bcq/Kits/Kits NULL.html). Le Si570 est à l’origine un circuit prévu pour générer les fréquences d’horloge pour la micro-informatique. Il est peu onéreux, facilement disponible et permet de générer des fréquences très élevé. Par chance, il est aussi très stable et produit un signal carré mais d’une très grande pureté et avec peu de bruit de phase comme l’indiquent ces mesures de K8ZOA (http://www NULL.cliftonlaboratories NULL.com/si570_kit_from_k5bcq NULL.htm). Ce circuit a d’abord été rendu populaire sur le récepteur SDR SoftRock (http://kb9yig NULL.com/). Ce n’est un DDS mais un synthétiseur à PLL. Après un bon filtrage ou avec un mélangeur équilibré comme sur le BitX c’est même parfait pour en faire un VFO. Le prix est aussi très très attractif offrant les caractéristiques d’un VFO à DDS pour la moitié du prix (45 USD port compris).

Le kit est techniquement très simple en soit, le Si570, quelques résistances et condensateurs, un régulateur de tension, un encodeur rotatif, un écran LCD et surtout le micro-contrôlleur contenant le programme qui finalement fait tout le travail. On peut choisir différentes options et différentes “qualités” de Si570. La moins onéreuse permet de générer des signaux de 3,5MHz à 160MHz environ : largement suffisant pour mes besoins. La difficulté vient du fait que 99% des composants sont en CMS de gabarit 805. C’est soudable à la main, mais il faut beaucoup de patience et de dextérité… On verra si j’en suis capable.