Skyduino:~#
Articles
arduino, programmation, tutoriel

[Arduino] Code de démo pour chipset LTC6903

Bonjour tout le monde !

Après une grosse semaine bien chargée me revoilà ! 🙂
Pour cet article je continu sur ma lancée en vous proposant un troisième code de test, ou plutôt de démonstration cette fois ci.
Par contre pas de chipset old-school en provenance d’une quelconque console jeu rétro pour cet article, désolé 😉

Chipset LTC6903

Vous vous demandez surement : « qu’est-ce que c’est que ce LTC6903 ? » et c’est bien normal 🙂

Pour faire simple le LTC6903 est un oscillateur programmable, on lui donne une fréquence et il là génère.
Le LTC6903 peut générer un signal d’horloge d’une fréquence comprise entre 1kHz et 68MHz avec une résolution d’environ 0.1%.

Soit, mais à quoi ça sert concrètement ?
Pour répondre à cette question rien ne vaut un bon schéma (tiré du datasheet du LTC6903 comme la plupart des images ci dessous) 😉

schematic

Vous ne rêvez pas, c’est bien un microcontrôleur contrôlant sa propre fréquence d’horloge.
(ça fait un peu « Clockception » sur les bords)

Les champs d’applications de ce circuit sont très vastes : ajustement de fréquence en temps réel, générateur de signal d’horloge, etc.
Pour ma part je compte utiliser ce circuit pour générer deux fréquences d’horloges bien précises (fréquences d’horloges des consoles en PAL et en NTSC) que j’injecterai par la suite dans mon montage musical « old-school ».

Parenthèse rapide : Comment est-il possible de contrôler sa propre fréquence d’horloge ?
En réalité c’est super simple.
Au démarrage le LTC6903 génère de base un signal à ~1KHz, juste de quoi exécuter quelques instructions à très basse vitesse pour initialiser la « vrai » fréquence d’horloge.

Parenthèse rapide n°2 :
Avec une fréquence maximale de 64Mhz il serait intéressant de faire un test d’overclock sur un microcontrôleur, AVR ou autre.
Je serai curieux de voir jusqu’à combien on peut monter en fréquence sans que le processeur ne s’emmêle les pinceaux.

LTC6903 / LTC6904

diagram

Il existe deux versions du LTC690x :
– le LTC6903 qui se contrôle en SPI
– le LTC6904 qui se contrôle en I2C

Personnellement j’ai pris la version SPI mais si vous voulez utiliser la version I2C les calculs ci dessous sont strictement identiques.

I want to play a game : « MS8 Package »

package

Héhéhé …
Avant de pouvoir jouer avec un LTC6903 fraichement sorti de son blister il faut le souder … et là, outch !
Le LTC6903 est disponible uniquement en boitier « MS8 ». Comme son nom l’indique ce boitier contient 8 broches, mais cela n’empêche pas la puce de faire 2mm de large et 4mm de long.

DSCF0637

Pas de solution miracle pour souder ce composant, il faut beaucoup de patience, un fer à souder avec une tête très fine et de la soudure elle aussi très fine.
Pour ceux qui seraient intéressé vous pouvez trouver des petits adaptateurs « MS8 vers DIP8 » sur ebay par lot de 5 pour moins de 2€ (fdp compris).
C’est ce que j’ai utilisé personnellement pour ne pas me prendre la tête avec un circuit fait maison.

Formules mathématiques // vadé rétro satanas !

Pour fonctionner le LTC6903 requières trois valeurs : OCT, DAC et CNF.

cnf_table

CNF est en quelque sort un registre de configuration qui permet de choisir quelles broches de sorties doivent être utilisés ou non.
Désactiver les sorties inutilisés augmente fortement la précision de l’oscillateur, ce n’est donc pas un point négligeable.

f_formula

Ceci est la formule de base régissant le fonctionnent de l’oscillateur. Ne vous inquiétez pas elle est donnée dans le datasheet uniquement pour faire jolie 😉

Les « vrais » formules à implémenter sont les suivantes :

oct_formula

dac_formula

A noter que pour OCT il est possible de pré-calculer le résultat en fonction de la fréquence :

oct_table

Format des données en SPI

Comme je l’avais précisé plus tôt j’utilise la version SPI du LTC6903.

Voici donc le format des données à transmettre … en SPI :

serial_table

Rien de bien compliqué, juste 2 octets à transmettre avec un peu de bricolage pour mettre les bits aux bon endroits.

Montage de démonstration

DSCF0642

Le câblage est trivial :
Arduino -> LTC6903
GND -> GND
5v -> V+
5v -> OE (/!\ contrairement à toute logique cette broche « Output Enable » est active à l’état haut)
D13 -> SCK
D11 -> SDI
D10 -> SEN

Remarque important :
Le LTC6903 a besoin d’une alimentation extrêmement stable. Toute la précision de la fréquence en sortie est basé sur la stabilité de l’alimentation.
Pour éviter tout probléme un condensateur de 100nF et un autre de 1µF sont de rigueur entre les broches V+ et GND.

Le code de test

Pour cet article j’ai décidé de faire une version Arduino uniquement de mon code.

/* Dépendances */
#include <SPI.h>

/* Pin mapping */
const byte CS_LTC6903 = 10; // Broche SEN

/**
 * Retourne la valeur adéquate de OCT pour la fréquence voulue.
 *
 * @param frequency La fréquence cible.
 * @return La valeur adéquate de OCT pour la fréquence spécifié.
 */
static unsigned char getOCT(unsigned long frequency) {

  // Table de lookup
  const unsigned long freqOCT[15] = {
    2076UL,
    4152UL,
    8304UL,
    16610UL,
    33220UL,
    66430UL,
    132900UL,
    265700UL,
    531400UL,
    1063000UL,
    2126000UL,
    4252000UL,
    8503000UL,
    17010000UL,
    34010000UL
  };
  
  // Cherche la fréquence dans la table de lookup
  for(byte i = 0; i < 15; ++i) {
    if(frequency < freqOCT[i])
      return i;
  }
  
  // Retourne la valeur max d'OCT si la fréquence n'est pas trouvée
  return 15;
}

/**
 * Retourne la valeur adéquate de DAC pour la fréquence voulue.
 *
 * @param oct La valeur du registre OCT pré-calculé pour la fréquence voulue.
 * @param frequency La fréquence cible.
 * @return La valeur adéquate de DAC pour la fréquence spécifié.
 */
static unsigned int getDAC(unsigned char oct, unsigned long frequency) {

  // Table de lookup
  const unsigned long pow2[16] = {
    1024UL,
    2048UL,
    4096UL,
    8192UL,
    16384UL,
    32768UL,
    65536UL,
    131072UL,
    262144UL,
    524288UL,
    1048576UL,
    2097152UL,
    4194304UL,
    8388608UL,
    16777216UL,
    33554432UL
  };
  
  // Calcul la valeur de DAC en fonction de OCT
  unsigned long long tmp = 2078UL; // Calcul sur 64 bits OBLIGATOIRE !
  tmp *= pow2[oct]; // pow(2, 10 + oct) en utilisant la table de lookup
  tmp /= frequency;
  return 2048 - (unsigned int) tmp;
}

/**
 * Modifie le contenu des registres du LTC6903 pour générer la fréquence voulue.
 *
 * @param frequency La fréquence cible.
 */
void updateClockFrequency(unsigned long frequency) {

  unsigned char oct = getOCT(frequency);
  unsigned int dac = getDAC(oct, frequency);
  
  // Debug
  Serial.print(F("F = "));
  Serial.println(frequency);
  Serial.print(F("OCT = "));
  Serial.println(oct);
  Serial.print(F("DAC = "));
  Serial.println(dac);
  
  // Format : OCT3 OCT2 OCT1 OCT0 DAC9 DAC8 DAC7 DAC6 DAC5 DAC4 DAC3 DAC2 DAC1 DAC0 1 0
  digitalWrite(CS_LTC6903, LOW);
  SPI.transfer((oct << 4) | ((dac & 0x03C0) >> 6));
  SPI.transfer(((dac & 0x3F) << 2) | 0b10);
  digitalWrite(CS_LTC6903, HIGH);
}

/* Fonction setup() */
void setup() {

  /* Initialisation du hardware */
  SPI.begin();
  Serial.begin(115200);
  SPI.setClockDivider(SPI_CLOCK_DIV4);

  pinMode(CS_LTC6903, OUTPUT);
  digitalWrite(CS_LTC6903, HIGH);

  /* Code de démo */
  //updateClockFrequency(6500000UL);
  updateClockFrequency(1337000UL);
}

/* Fonction loop() */
void loop() {
}

Comme vous pouvez le voir j’utilise une table de lookup (= tableau de correspondance) pour trouver la valeur adéquate de OCT.
Si la fréquence est trop élevé (OCT > 14) je retourne directement 15 (valeur max de OCT).

J’utilise le même type de table pour pré-calculer le résultat de 2 ^ (10 + OCT).
OCT pouvant prendre uniquement les valeurs comprises entre 0 et 15 il est plus rapide de pré-calculer les 16 résultats possibles que d’utiliser la fonction pow() directement.

Vous remarquerez aussi que je fait des calculs sur 64 bits pour le calcul de DAC !
C’est une première, jamais un code ne m’avais demandé d’utiliser le type « long long » pour un calcul.
Juste pour information : un calcul sur 64 bits demande 8 instructions processeurs rien que pour faire une simple addition.

Résultat

oscilo_screen

Dans le code je demande au LTC6903 de générer une fréquence de 1.337MHz.
En réalité j’obtiens 1.348MHz, soit 11KHz de différence par rapport à la théorie.

Ça fait beaucoup (~1% d’erreur), d’âpres mes divers tests cela vient en parti de ma sonde d’oscilloscope qui a une charge capacitive bien trop élevé et de l’alimentation des cartes Arduino qui est juste … complétement pourrie.
La longueur des fils et le montage sur breadboard doit lui aussi faire un petit quelque chose, mais qu’importe je ne suis pas à quelques Khz prés pour mon montage final 😉

Advertisements

Discussion

6 réflexions sur “[Arduino] Code de démo pour chipset LTC6903

  1. et maintenant tu vas regarder le SI570 et tu dis OMG!

    http://www.silabs.com/Support%20Documents/TechnicalDocs/si570.pdf

    (explications sympas!)

    j’te laisse rêver avec une multiplication long long / long long…

    les float sont aussi pas mal dans leur genre en lourdeur de calcul.

    Publié par f4grx | 4 octobre 2013, 12 h 32 min
    • Pas mal ce OX, je garde la référence sous le coude ça pourrait m’être utile.
      (dans l’idéal faudrait que je choppe des samples … mais en tant que particulier ça va surement pas le faire)

      Sinon sur AVR les multiplications sur 64 bits prennent 8 instructions comme les additions 😉

      Publié par skywodd | 4 octobre 2013, 12 h 49 min
  2. ceci dit, la capacité de ta sonde pourrait déformer ton signal, mais difficilement en changer la fréquence.
    L’alimentation aussi d’ailleurs… Ca reste possible, mais peu probable d’après moi.

    Je vote pour la résolution limitée (ou la (non)-qualité) du DAC.

    Si tu veux faire joujou avec des oscillateurs à f variable il y a aussi les DDS d’analog devices. Je te laisse découvrir 😉

    Publié par f4grx | 4 octobre 2013, 12 h 36 min
    • La capacité de ma sonde lisse fortement le signal, du coup c’est ma mesure qui s’en retrouve erroné, pas la fréquence du circuit en elle même.

      Pour l’alimentation c’est salaud, regarde bien la fréquence « MO » (Master Oscillator) sur l’image n°2, elle est compensée par l’alimentation, à la moindre fluctuation de tension la fréquence perd les pédales.

      Le probléme des circuits de DDS d’AD c’est que pour générer un signal d’horloge précis dans la plage 3-4MHz c’est franchement pas la joie (et avec le Si570 c’est carrément pas possible).

      Publié par skywodd | 4 octobre 2013, 12 h 55 min
      • Je vois. Effectivement le coup de la compensation par l’alim, c’est relou.

        Le DDS est normalement adapté pour générer ce genre de signal. On en trouve des modèles en boitier ~TSSOP18, qui se pilotent par spi et prennent une freq d’entrée de 50 MHz max. ça te le fait pédaler à moins d’un dixième de sa clock, c’est très jouable. Y’a des samples. Avec un modèle dont l’accumulateur fait 32 bits, t’aurais une résolution de 1/4 milliards de Fclk. Aucun PLL ne peut rivaliser. Y’a quelques spurs, mais pour une horloge TTL on s’en fout, et un filtre passe-bas peut presque tout virer.

        Publié par f4grx | 4 octobre 2013, 23 h 34 min
  3. Alala mettre les bits aux bon endroits, y’a que ça de vrai

    Publié par Samio | 10 octobre 2013, 20 h 06 min

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

Skyduino devient Carnet du Maker

Le site Carnet du Maker remplace désormais le blog Skyduino pour tout ce qui touche à l'Arduino, l'informatique et au DIY.