12-Bit Digital-Analog-Converter (DAC) MCP4725

Arduinos, wie der Uno oder der Mega besitzen keinen "echten" Analogausgang (Spannungsausgang), sondern nur Quasi-Analogausgänge mittels Pulsweitenmodulation PWM, wo durch schnelles Ein- und Ausschalten von Digitalausgängen mit definierten Impuls- und Pausenlängen sich ein über die Zeit gemittelter Spannungswert ergibt. Ab einer gewissen PWM-Frequenz können z.B. durch die Trägheit des Auges oder der Massenträgheit eines DC-Motors damit LEDs gedimmt oder DC-Motoren drehzahlgeregelt werden, ohne dass funktionell ein Unterschied zu einer echten Analogspannung ersichtlich ist.

Wird allerdings als Ausgangssignal eine "echte" Analogspannung benötigt, muss man auf einen Digital-Analog-Converter (DAC) zurückgreifen. DACs sind in verschiedenen Ausführungen (z.B. Ansteuerung parallel - je Bit eine Anschlussleitung oder seriell über SPI oder I2C-Bus, Auflösung 8, 10, 12, 14 Bit oder höher, ein- oder mehrkanalig, etc.) erhältlich.

Für meine "Spielereien" verwende ich den DAC MCP4725 auf einem Breakout Board, ein Converter mit I2C-Schnittstelle, 12 Bit Auflösung, einer typischen Wandlungszeit von 6 us und einem integrierten 14 Bit EEPROM zur Speicherung des Power-Down-Modus und des Start-Spannungswertes (ohne I2C-Verbindung zum Arduino). Der MCP4725 kann in 4 Moden betrieben werden:

  • DAC-Normal-Modus
  • DAC-Normal-Modus mit Beschreiben des EEPROMs
  • DAC-Fast-Modus
  • Power-Down-Modus (wird derzeit in meiner Library nicht unterstützt)


Bild: MCP4725 auf Breakout Board


  • Die Wandlungszeit von 6 us hört sich ja recht gut an, wären das ja immerhin 166.666 Wandlungen pro Sekunde, wäre da nicht die Zeit, die zur Übertragung des auszugebenden Wertes über die I2C-Schnittstelle noch zu addieren ist und die ist um ein Vielfaches höher. Wobei gesagt werden muss, dass der MCP4725 laut Datenblatt für eine I2C-Datenrate von 3,4 MBit/s (High-Speed-Modus) geeignet ist, der Arduino Uno (und/oder die Wire.Library) allerdings nur für Standard-Modus (100 kBit/s) und Fast-Modus (400 kBit/s) geeignet ist. Bei meinem Testaufbau (wie nachfolgend gezeigt) erreichte ich im Fast-Modus eine Übertragungsrate von 800 kBit/s. Die von mir ermittelten Übertragungszeiten in Abhängigkeit des DAC-Modus und der Übertragungsfrequenz zeigt nachfolgende Tabelle:

  • Die Übertragungszeit für den DAC-Normal-Modus mit Beschreiben des EEPROMs habe ich nicht ermittelt, da dieser Modus ja nur jeweils als Einzelereignis stattfinden sollte (begrenzte EEPROM-Lebensdauer im Schreibmodus, siehe nachfolgenden Hinweis unter" Library MyMCP4725").


  • Achtung: Sowohl bei den Betriebsmoden des DAC als auch bei den Moden der I2C-Übertragung gibt es den "Fast-Modus". Sollte es aus dem Text nicht eindeutig hervergehen, verwende ich für den Fast-Modus die Bezeichnung "I2C-Fast Modus" oder "DAC-Fast-Modus".


  • Ohne weitere Beschaltung ist die I2C-Adresse des Converters auf 0x62 eingestellt und kann durch Beschalten des A0-Pins auf VDD auf 0x63 geändert werden.


  • Testaufbau:

  • Verwendete Bauteile:

    • 1 Arduino Uno
    • 1 DAC MCP4725 Breakout Board
    • 1 LM358
    • 1 Poti 10 kOhm
    • 1 Netzgerät 7 - 12 V
    • 1 Voltmeter bzw. Oszilloskop



    Da der Ausgang des DAC MCP4725 strommäßig kaum belastbar ist (1 - 3 mA), habe ich dem DAC-Ausgang einen Operationsverstärker LM358 als Spannungsfolger (Impedanzwandler) nachgeschaltet. Dieser hat als Ausgangsspannung dieselbe Spannung wie der DAC, allerdings kann er strommäßig etwas höher, mit ca. 20 - 35 mA, abhängig von der Höhe der DAC-Spannung belastet werden, ohne das die Ausgangsspannung merkbar einbricht. Damit der Spannungsfolger allerdings die Spannung des DAC-Ausgangs über den ganzen Bereich (0 - 5 V) wiedergeben kann, muss die Versorgungsspannung des LM358 mindestens um ca. 1,5 V höher sein, als die auszugebende Spannung.


    Library MyMCP4725:

    Obwohl es von Adafruit eine Library für den MCP4725 gibt (github.com/adafruit/Adafruit_MCP4725) habe ich für mich eine neue Lib geschrieben und ihren Funktionsumfang gegenüber der genannten Library etwas erweitert:


    • Abfrage, ob der Baustein über I2C ansprechbar ist
    • Setzen der I2C-Frequenz (z.B. 400 kHz anstelle von 100 kHz) 1)
    • Setzen des DAC-Registers (= Ausgangsspannung) im Fast-Modus
    • Setzen des DAC-Registers (= Ausgangsspannung) im Normal-Modus mit oder ohne Beschreiben des EEPROMs 2)
    • Rücklesen des DAC-Registers und des EEPROMs


    1)  Die mit dieser Funktion geänderte I2C-Frequenz gilt nur während der Übertragung der Datenbytes zum DAC. Danach wird die ursprüngliche Übertragungsrate wieder hergestellt, da ja am I2C-Bus auch Komponenten vorhanden sein können, die nicht I2C-Fast-Mode tauglich sind. Wird die Funktion nicht aufgerufen, so erfolgt die Übertragung mit der im Standard-Mode festgelegten Frequenz (100 kHz) oder einer im Setup festgelegten Frequenz für alle I2C-Komponenten.

    2)  Achtung: Das Setzen des DAC-Register im Normalmodus mit Beschreiben des EEPROMs sollte nur ganz geziehlt erfolgen. Laut Datenblatt kann das EEPROM ca. 1 Million mal beschrieben werden. Vergißt man den Schreibmodus auszuschalten ist bei 100 Schreibzyklen pro Sekunde diese Anzahl nach ca. 3 Stunden bereits überschritten!!


    Die Library kann hier heruntergeladen werden:

    Sollte die Library jemand verwenden oder testen, würde ich mich über eine Rückmeldung sehr freuen!

    Version 1.1

    MyMCP4725.cpp.txt

    MyMCP4725.h.txt

    keywords.txt

    Leider kann ich hier keine "cpp"- oder "h"-Files hochladen, daher zum Verwenden der Library ".txt" aus den Dateinamen entfernen und in einem neuen Verzeichnis mit dem Namen "MyMCP4725" dort speichern, wo eure anderen Libraries gespeichert sind.


    Zur Auflistung der Funktionen der Library geht es hier: Funktionen


    Programmbeispiel MyMCP4725:

    Das nachfolgende Testprogramm liest den Wert des Potentiometer ein (Auflösung 10 Bit => Wertebereich 0 bis 1023) und gibt die auf einen Bereich von 0 bis 4095 "gemappte" Zahl (12 Bit) als Analogwert (Spannungsbereich 0 bis VDD) wieder aus. Der eingelesene Wert sowie die Zeit für die Übertragung zum DAC über den I2C-Bus wird am Seriellen Monitor angezeigt. Ebenso wird der Wert des DAC-Registers und des EEPROMs ausgelesen und am Seriellen Monitor angezeigt.

    //Testprogramm fuer DAC MCP4725
    //Code fuer Arduino
    //Author Retian
    //Version 2.0


    #include <MyMCP4725.h>
    MyMCP4725 DAC(0x62); //I2C-Adress = 0x62


    #define potiPin 0


    uint16_t potiWert;
    unsigned long startTime, endTime;
    bool dacStatus = false;


    void setup() {
      Serial.begin(115200);
      if (DAC.isReady())
      {
        Serial.println("\nDAC in Ordnung!");
        dacStatus = true;
        //I2C-Frequenz für DAC auf 400 kHz setzen
        DAC.setWireClock(400);
      }
      else Serial.println("DAC Fehler!");
      //Startausgabewert des DAC auf 0 V (Grundeinstellung = VDD/2)
      //DAC.setVoltage(0, true); //true = EEPROM wird beschrieben!!
    }


    void loop() {
      if (dacStatus)
      {
        //Einlesen des Poti
        potiWert = analogRead(potiPin);
        potiWert = map(potiWert, 0, 1023, 0, 4095);
        Serial.print("\nPotiwert: ");
        Serial.println(potiWert);
        startTime = micros();
       

        //Ausgabe des Potiwertes im Normal-Modus
        DAC.setVoltage(potiWert, false); //false = EEPROM wird nicht beschrieben
        endTime = micros();
        Serial.print("Zeit: ");
        Serial.print(endTime - startTime);
        Serial.println(" us");
       

        //Rücklesen des DAC-Register
        Serial.print("DAC   : ");
        Serial.println(DAC.readRegister(dac));
       

        //Rücklesen des EEPROM
        Serial.print("EEPROM: ");
        Serial.println(DAC.readRegister(eeprom));


        delay(1000);
      }
    }