Skip to content

Commit

Permalink
Rework the output*() function for the dual DACs, and reduce code dupl…
Browse files Browse the repository at this point in the history
…ication; update keywords.txt and the README
  • Loading branch information
exscape committed Oct 1, 2012
1 parent 5b17744 commit c28bd01
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 66 deletions.
84 changes: 23 additions & 61 deletions Arduino/Libraries/DAC_MCP49xx/DAC_MCP49xx.cpp
Expand Up @@ -140,12 +140,9 @@ void DAC_MCP49xx::shutdown(void) {
digitalWrite(ss_pin, HIGH);
}

// MCP49x1 (single DAC) only.
// Send a new value for the DAC to output.
// Note that the output is only actually changed when latch() is called,
// if that functionality is used. If it's not, that pin (LDAC) can be
// shorted to ground, and the above note doesn't apply.
void DAC_MCP49xx::output(unsigned short data) {
// Private function.
// Called by the output* set of functions.
void DAC_MCP49xx::_output(unsigned short data, Channel chan) {
// Truncate the unused bits to fit the 8/10/12 bits the DAC accepts
if (this->bitwidth == 12)
data &= 0xfff;
Expand All @@ -160,12 +157,12 @@ void DAC_MCP49xx::output(unsigned short data) {
else
digitalWrite(ss_pin, LOW);

// bit 15: always 0 (1 means "ignore this command" for MCP49x1 models)
// bit 15: 0 for DAC A, 1 for DAC B. (Always 0 for MCP49x1.)
// bit 14: buffer VREF?
// bit 13: gain bit; 0 for 1x gain, 1 for 2x (thus we NOT the variable)
// bit 12: shutdown bit. 1 for active operation
// bits 11 through 0: data
uint16_t out = (0 << 15) | (this->bufferVref << 14) | ((!this->gain2x) << 13) | (1 << 12) | (data << (12 - this->bitwidth));
uint16_t out = (chan << 15) | (this->bufferVref << 14) | ((!this->gain2x) << 13) | (1 << 12) | (data << (12 - this->bitwidth));

// Send the command and data bits
SPI.transfer((out & 0xff00) >> 8);
Expand All @@ -178,61 +175,26 @@ void DAC_MCP49xx::output(unsigned short data) {
digitalWrite(ss_pin, HIGH);
}

// MCP49x2 (dual DAC) only.
// Send a new value for the DAC to output.
void DAC_MCP49xx::output2(unsigned short data_A, unsigned short data_B) {
// Truncate the unused bits to fit the 8/10/12 bits the DAC accepts
if (this->bitwidth == 12) {
data_A &= 0xfff;
data_B &= 0xfff;
}
else if (this->bitwidth == 10) {
data_A &= 0x3ff;
data_B &= 0x3ff;
}
else if (this->bitwidth == 8) {
data_A &= 0xff;
data_B &= 0xff;
}
// For MCP49x1
void DAC_MCP49xx::output(unsigned short data) {
this->_output(data, CHANNEL_A);
}

// Drive chip select low
if (this->port_write)
PORTB &= 0xfb; // Clear PORTB pin 2 = arduino pin 10
else
digitalWrite(ss_pin, LOW);
// For MCP49x2
void DAC_MCP49xx::outputA(unsigned short data) {
this->_output(data, CHANNEL_A);
}

// bit 15: 1 => B channel, 0 => A channel
// bit 14: buffer VREF?
// bit 13: gain bit; 0 for 1x gain, 1 for 2x (thus we negate the wariable)
// bit 12: shutdown bit. 1 for active operation
// bits 11 through 0: data
uint16_t out_A = (0 << 15) | (this->bufferVref << 14) | ((!this->gain2x) << 13) | (1 << 12) | (data_A << (12 - this->bitwidth));
uint16_t out_B = (1 << 15) | (this->bufferVref << 14) | ((!this->gain2x) << 13) | (1 << 12) | (data_B << (12 - this->bitwidth));

// Send the command and data bits for DAC A
SPI.transfer((out_A & 0xff00) >> 8);
SPI.transfer(out_A & 0xff);

// Latch A register by setting CS high
if (this->port_write) {
PORTB |= (1 << 2);
asm volatile("nop");
PORTB &= 0xfb;
}
else {
digitalWrite(ss_pin, HIGH);
digitalWrite(ss_pin, LOW);
}

// Send the command and data bits for DAC B
SPI.transfer((out_B & 0xff00) >> 8);
SPI.transfer(out_B & 0xff);

// Return chip select to high
if (this->port_write)
PORTB |= (1 << 2); // set PORTB pin 2 = arduino pin 10
else
digitalWrite(ss_pin, HIGH);
// For MCP49x2
void DAC_MCP49xx::outputB(unsigned short data) {
this->_output(data, CHANNEL_B);
}

// MCP49x2 (dual DAC) only.
// Send a set of new values for the DAC to output in a single function call
void DAC_MCP49xx::output2(unsigned short data_A, unsigned short data_B) {
this->_output(data_A, CHANNEL_A);
this->_output(data_B, CHANNEL_B);

// Update the output, if desired.
// The reason this is only in the dual-output version is simple: it's mostly useless
Expand Down
11 changes: 11 additions & 0 deletions Arduino/Libraries/DAC_MCP49xx/DAC_MCP49xx.h
Expand Up @@ -24,19 +24,30 @@ class DAC_MCP49xx {
MCP4912, /* dual, 10-bit */
MCP4922 /* dual, 12-bit */
};

enum Channel {
CHANNEL_A = 0,
CHANNEL_B = 1
};

DAC_MCP49xx(Model _model, int _ss_pin, int _ldac_pin = -1);
void setBuffer(boolean _buffer) { this->bufferVref = _buffer; }
void setPortWrite(boolean _port_write) { this->port_write = _port_write; }
boolean setGain(int _gain);
boolean setSPIDivider(int _spi_divider);
void shutdown(void);

/* All of these call _output() internally */
void output(unsigned short _out);
void outputA(unsigned short _out); /* same as output(), but having A/B makes more sense for dual DACs */
void outputB(unsigned short _out);
void output2(unsigned short _out, unsigned short _out2); // For MCP49x2

void latch(void); // Actually change the output, if the LDAC pin isn't shorted to ground
boolean setAutomaticallyLatchDual(bool _latch);

private:
void _output(unsigned short _out, Channel _chan);
int ss_pin;
int LDAC_pin;
int bitwidth;
Expand Down
33 changes: 29 additions & 4 deletions Arduino/Libraries/DAC_MCP49xx/README.txt
Expand Up @@ -34,6 +34,21 @@ void loop() {

See the example sketches for slightly more detailed examples.

A note on latching/LDAC:
The way these DACs work is as follows: when a value is sent to them via
the output*() methods, the output does not instantly change.
Instead, the DAC waits until the LDAC pin has been pulled low. Therefore,
if that pin is tied to ground, the output *will* instantly change.
However, if that pin is connected to the Arduino, you will need to latch
the output in order for a change to happen. There are two ways to do this:
1) Call latch(), which creates a low pulse
2) MCP49x2 only: call output2(), with the automaticallyLatchDual option set
(true by default), which will then call latch() for you

The main usage of this functionality is to synchronize multiple DACs (2 or more),
to make their outputs change at the same moment, despite having the data sent
to them one at a time.

Simple function overview:

Constructor (DAC_MCP49xx, int SS_pin, int LDAC_pin = -1)
Expand Down Expand Up @@ -70,18 +85,28 @@ shutdown(void)
Settling time after calling set() increases from ~5 to ~10 µs when in standby.

output(unsigned short)
MCP49x1 (single DAC) only.
Sends the value to the DAC. If the LDAC pin is tied to ground, Vout will change "instantly".
If the LDAC pin is connected to the Arduino, nothing will change until latch() is called.

outputA(unsigned short)
MCP49x2 (dual DAC) only.
Sends the value to DAC A. Same as output().

outputB(unsigned short)
MCP49x2 (dual DAC) only.
Sends the value to DAC B. Otherwise same as output().

output2(unsigned short, unsigned short)
Sends the two output values to the two outputs of the dual DACs.
Latches the output automatically unless setAutomaticallyLatchDual has been
Latches the output automatically unless setAutomaticallyLatchDual() has been
called with 'false' as the argument.

latch(void)
Changes the output voltage based on the last value sent using output().
Creates a low pulse on the DACs LDAC pin (pin 5 on the DAC chip).
The LDAC pin can be tied to ground instead, to update automatically ASAP.
Changes the output voltage based on the last value(s) sent using the output*() methods.
Creates a low pulse on the DAC's LDAC pin (pin 5 on the DAC chip).
The LDAC pin can be tied to ground instead, to update automatically ASAP, in
which case this method does nothing.

setPortWrite(bool)
Note: PortWrite is not supported on the Arduino Leonardo, but should work on
Expand Down
Empty file.
5 changes: 5 additions & 0 deletions Arduino/Libraries/DAC_MCP49xx/examples/MCP49x2_dual_demo/MCP49x2_dual_demo.ino 100644 → 100755
Expand Up @@ -42,4 +42,9 @@ void loop() {
delay(2500);
dac.output2(0, 4095);
delay(2500);

// Or, to update one channel at a time:
// dac.outputA(1023);
// dac.outputB(384);
// dac.latch(); // To synchonize the two outputs
}
8 changes: 7 additions & 1 deletion Arduino/Libraries/DAC_MCP49xx/keywords.txt
Expand Up @@ -3,7 +3,10 @@ Model KEYWORD1

MCP4901 LITERAL1
MCP4911 LITERAL1
MCP4921 LITERAL1
MCP4921 LITERAL1
MCP4902 LITERAL1
MCP4912 LITERAL1
MCP4922 LITERAL1

setBuffer KEYWORD2
setPortWrite KEYWORD2
Expand All @@ -12,4 +15,7 @@ setGain KEYWORD2
setSPIDivider KEYWORD2
shutdown KEYWORD2
output KEYWORD2
output2 KEYWORD2
outputA KEYWORD2
outputB KEYWORD2
latch KEYWORD2

0 comments on commit c28bd01

Please sign in to comment.