Skyduino:~#
Articles
arduino, programmation

[Arduino] MCP4725 + wavetable = générateur de signaux

Bonjour tout le monde !

Aujourd’hui je vous ai concocté un article au sujet d’un microscopique mais fort utile composant : le MCP4725.

(J’ai zoomé comme un gros porc, le composant fait en réalité un demi centimètre ;))

Le MCP4725 est un convertisseur numérique -> analogique 12 bits.
On lui envoi par I2C (avec la librairie Wire sur arduino) une valeur sur 12 bits, et il génère aussitôt une tension analogique correspondant à la valeur envoyé sur sa sortie.

Le principe est le même qu’avec analogRead() sur arduino mais dans le sens inverse.
0 correspond à 0v, et 4095 correspond à VCC (+5v dans notre cas), pour toute valeur entre les deux il suffit de faire un bête produit en croix 😉

Pour transmettre une valeur il faut procéder comme suit (en mode classique, pas en mode « Fast Write ») :
– Commencer la communication I2C (envoi du bit de start + adresse I2C) (adresse I2C du MCP4725 : 96 en décimal, ou 0x60 en héxa)
– Envoyer la commande « Update DAC register » : 64 en décimal, ou 0x40 en héxa
– Envoyer les 8 bits de poids fort de la valeur sur 12 bits
– Envoyer les 4 bits de poids faible, en les décalant de 4 bits vers la gauche
– Envoyer le bit de stop

C’est pas forcement évident à comprendre, donc voici le schéma tiré du datasheet de microchip pour mieux si retrouver :

Comme toujours je vous ai aussi préparé un petit montage d’exemple 😉
Le montage en question est un « bête » générateur de signaux utilisant une « wave table », en gros le programme lit un tableau contenant les valeurs du signal et les transmet au MCP4725.

Le câblage :
Arduino -> MCP4725
+5v -> VCC
GND -> GND
A4 -> SDA
A5 -> SCL

Analog -> oscilloscope

Voici le code d’exemple qui génère une sinusoïde (quasi) parfaite :

/* Includes */
#include <Wire.h>
#include <avr/pgmspace.h>

/* Wavetables */
#include "sin360.h"

/* setup() */
void setup()
{
  /* Active les résistances de pull-up software (pas obligatoire avec un seul module I2C sur le bus) */
  pinMode(A4, OUTPUT);
  digitalWrite(A4, HIGH);
  pinMode(A5, OUTPUT);
  digitalWrite(A5, HIGH);

  /* Initialise le bus I2C */
  Wire.begin();
}

/* loop() */
void loop(){

  /* Variables d'usage */
  static uint16_t sample, i;

  /* Parcours du tableau (aka wavetable) */
  for(i = 0; i < 360; ++i) {

    /* Lit un échantillon de la wavetable */
    sample = pgm_read_word(sin360 + i);

    /* Démarre la communication avec le MCP4725 */
    Wire.beginTransmission(B1100000);

    /* Envoi la commande "DAC Register Update" */
    Wire.write(B1000000);

    /* Envoi les 12 bits de données */
    Wire.write((sample & 0xFF0) >> 4); // Les 8 bits de poids fort en premier
    Wire.write((sample & 0xF) << 4); // Puis les 4 bits de poid faible

    /* Stop la communication avec le MCP4725 */
    Wire.endTransmission();
  }
}

Le contenu de sin360.h (la wavetable qui contient les valeurs de la sinusoïde) :

uint16_t sin360[] PROGMEM = {
2047, 2082, 2118, 2154, 2189, 2225, 2260, 2296, 2331, 2367, 
2402, 2437, 2472, 2507, 2542, 2576, 2611, 2645, 2679, 2713, 
2747, 2780, 2813, 2846, 2879, 2912, 2944, 2976, 3008, 3039, 
3070, 3101, 3131, 3161, 3191, 3221, 3250, 3278, 3307, 3335, 
3362, 3389, 3416, 3443, 3468, 3494, 3519, 3544, 3568, 3591, 
3615, 3637, 3660, 3681, 3703, 3723, 3744, 3763, 3782, 3801, 
3819, 3837, 3854, 3870, 3886, 3902, 3917, 3931, 3944, 3958, 
3970, 3982, 3993, 4004, 4014, 4024, 4033, 4041, 4049, 4056, 
4062, 4068, 4074, 4078, 4082, 4086, 4089, 4091, 4092, 4093, 
4094, 4093, 4092, 4091, 4089, 4086, 4082, 4078, 4074, 4068, 
4062, 4056, 4049, 4041, 4033, 4024, 4014, 4004, 3993, 3982, 
3970, 3958, 3944, 3931, 3917, 3902, 3886, 3870, 3854, 3837, 
3819, 3801, 3782, 3763, 3744, 3723, 3703, 3681, 3660, 3637, 
3615, 3591, 3568, 3544, 3519, 3494, 3468, 3443, 3416, 3389, 
3362, 3335, 3307, 3278, 3250, 3221, 3191, 3161, 3131, 3101, 
3070, 3039, 3008, 2976, 2944, 2912, 2879, 2846, 2813, 2780, 
2747, 2713, 2679, 2645, 2611, 2576, 2542, 2507, 2472, 2437, 
2402, 2367, 2331, 2296, 2260, 2225, 2189, 2154, 2118, 2082, 
2047, 2011, 1975, 1939, 1904, 1868, 1833, 1797, 1762, 1726, 
1691, 1656, 1621, 1586, 1551, 1517, 1482, 1448, 1414, 1380, 
1346, 1313, 1280, 1247, 1214, 1181, 1149, 1117, 1085, 1054, 
1023, 992, 962, 932, 902, 872, 843, 815, 786, 758, 731, 704, 
677, 650, 625, 599, 574, 549, 525, 502, 478, 456, 433, 412, 
390, 370, 349, 330, 311, 292, 274, 256, 239, 223, 207, 191, 
176, 162, 149, 135, 123, 111, 100, 89, 79, 69, 60, 52, 44, 
37, 31, 25, 19, 15, 11, 7, 4, 2, 1, 0, 0, 0, 1, 2, 4, 7, 11, 
15, 19, 25, 31, 37, 44, 52, 60, 69, 79, 89, 100, 111, 123, 
135, 149, 162, 176, 191, 207, 223, 239, 256, 274, 292, 311, 
330, 349, 370, 390, 412, 433, 456, 478, 502, 525, 549, 574, 
599, 625, 650, 677, 704, 731, 758, 786, 815, 843, 872, 902, 
932, 962, 992, 1023, 1054, 1085, 1117, 1149, 1181, 1214, 1247, 
1280, 1313, 1346, 1380, 1414, 1448, 1482, 1517, 1551, 1586, 
1621, 1656, 1691, 1726, 1762, 1797, 1833, 1868, 1904, 1939, 
1975, 2011, 2046 
};

Et voila ce que ça donne sur un oscilloscope :

(Oui j’ai du utiliser mon reflex en exposition manuelle pour pouvoir photographier l’écran … la loose …)

Remarque : Pour booster la vitesse du bus I2C il suffit d’augmenter la valeur de TWI_FREQ qui se trouve dans ../libraries/Wire/utility/twi.h
Le MCP4725 peut tourner en mode « Fast I2C » soit à une vitesse maximum de 100KHz, or par défaut Wire tourne à 10KHz 😉

Note : Depuis Arduino 1.0.1 il est possible d’envoyer un bit de stop sans libérer le bus I2C, et donc d’utiliser le mode « Fast Write » du MCP4725.

Avec ce montage et les « wave tables » qui vont bien il est tout à fait possible de fabriquer un générateur de signaux « low cost », voir même de « lire » des fichiers wav (fichiers audio) encodaient en 12bits @8KHz.

Pour ceux qui voudrait s’amuser, il doit être possible sans trop de difficulté d’afficher des graphisme sur un oscilloscope en mode XY avec deux MCP4725 😉

Voila voila, Enjoy 🙂

Advertisements

Discussion

Une réflexion sur “[Arduino] MCP4725 + wavetable = générateur de signaux

  1. Merci pour cette article.
    J’ai testé et ca marche très bien mais si on veut faire en Fast Write on modifie quoi dans la sequence ?

    Publié par David | 14 janvier 2013, 14 h 30 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.