Sunday, February 22, 2015

DACs, part 1

I've been thinking of building a signal generator based on an Arduino and a DAC. As an experiment, I got hold of a MCP4921 12-bit SPI interface DAC. Connecting this up to an Arduino is really simple:

  • pins 1 and 6 to 5V.
  • pin 2 to Arduino pin 10 (or any other - this is the select line).
  • pin 3 to Arduino pin 13.
  • pin 4 to Arduino pin 11.
  • pins 5 and 7 to ground.
  • and the output is on pin 8.
My first question is how fast you can drive this. It's limited by the capabilities of the DAC and how quickly the Arduino can send data to it. The datasheet says that the MCP4921 takes about 4.5uS to settle, and to see how fast I can make the code go, I wrote a minimal sketch that toggles between a high and a low value. All values in the code are constants and there are no function calls other than setup() and loop(). So the code looks like this:

#include "SPI.h"

#define DAC1SS 10

void setup() {
  pinMode(DAC1SS, OUTPUT);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
}

void loop() {
  digitalWrite(DAC1SS, LOW);
  SPI.transfer(0x30);
  SPI.transfer(0);
  digitalWrite(DAC1SS, HIGH);
  digitalWrite(DAC1SS, LOW);
  SPI.transfer(0x3f);
  SPI.transfer(0xff);
  digitalWrite(DAC1SS, HIGH);
}

Looking at the output on a scope, the first thing to notice is that it isn't square:


The timebase here is 5us per division, so the rise time is worse than the settling time of the DAC would suggest. It shows that the minimum time for a cycle is about 31us, so limiting the frequency to around 32kHz. For anything other that square waves, you would need multiple steps, further reducing the effective frequency. The frequency seems consistent with this project, which is working with 22kHz samples. You might be able to squeeze a little but more by running the SPI interface faster, using SPI.setClockDivider(SPI_CLOCK_DIV2) in setup(). This does make a difference, but a tiny one.

No comments: