PSU Project #3 – MCP4822

(Transplanted from old website)

August 31st 2015:

In this episode we investigate the MCP4822 12-Bit DAC.
This is another digital building block for the PSU design, this component will allow us to set the voltage level and the current limit for the circuit digitally.
Below is the schematic used in this episode. It builds upon the one from episode #1
In the episode, I explain how the internals of the DAC work and introduce the concept of an R-2R ladder.

PSU Project #3 – MCP4822

Sketch used in the episode (can be downloaded here):

/*
 Test sketch for the MCP3304 and MCP4822
 Both are bit-banged to get them working.
 In this demo:
 DAC channel A will count up from 0v to 4.096V
 DAC Channel B will mirror what is being read on ADC Channel 0
 Arduino   MCP3304   MCP4822
 */
 #define ADC_CS 10    // ADC chip-select
 #define DAC_CS 9    // DAC chip-select
 #define ADC_MOSI 11   // ADC_MOSI
 #define ADC_MISO 12    // ADC_MISO
 #define SPI_CLK 13  // Clock
 #define MCP4822_DAC_A_BUFFERED_GAIN_1X_NON_SHDN      0x70  // DAC A, Buffered, Gain 1x, Output power control
 #define MCP4822_DAC_A_BUFFERED_GAIN_2X_NON_SHDN      0x50  // DAC A, Buffered, Gain 2x, Output power control
 #define MCP4822_DAC_A_NON_BUFFERED_GAIN_1X_NON_SHDN  0x30  // DAC A, Non buffered, Gain 1x, Output power control
 #define MCP4822_DAC_A_NON_BUFFERED_GAIN_2X_NON_SHDN  0x10  // DAC A, Non buffered, Gain 2x, Output power control
 #define MCP4822_DAC_B_BUFFERED_GAIN_1X_NON_SHDN      0xF0  // DAC B, Buffered, Gain 1x, Output power control
 #define MCP4822_DAC_B_BUFFERED_GAIN_2X_NON_SHDN      0xD0  // DAC B, Buffered, Gain 2x, Output power control
 #define MCP4822_DAC_B_NON_BUFFERED_GAIN_1X_NON_SHDN  0xB0  // DAC B, Non buffered, Gain 1x, Output power control
 #define MCP4822_DAC_B_NON_BUFFERED_GAIN_2X_NON_SHDN  0x90  // DAC B, Non buffered, Gain 2x, Output power control
int test2=0;
 long test3=0;
void pulse_MCP_clock(void)
 {
 digitalWrite(SPI_CLK, LOW); delayMicroseconds(50);
 digitalWrite(SPI_CLK, HIGH); delayMicroseconds(50);
 }
long read_MCP(int channel)
 {
 long value=0;
 signed int x=0;
 digitalWrite(ADC_CS, LOW);
 digitalWrite(DAC_CS, HIGH);
 delayMicroseconds(50);
 digitalWrite(ADC_CS, LOW);
 delayMicroseconds(50);
 digitalWrite(ADC_MOSI, HIGH); //start pulse
 pulse_MCP_clock();
 digitalWrite(ADC_MOSI, HIGH); //single mode
 pulse_MCP_clock();
 for(x=2; x>=0; --x)
 {
 if(bitRead(channel,x))
 {
 digitalWrite(ADC_MOSI, HIGH);
 }
 else
 {
 digitalWrite(ADC_MOSI, LOW);
 }
 pulse_MCP_clock();
 }
 digitalWrite(ADC_MOSI, LOW);//put low throughout
 for(x=1;x<=3;++x)
 {
 //blank, Null, and sign bit (always 0 in single mode)
 pulse_MCP_clock();
 }
 //now get twelve bits
 for(x=11; x>=0; --x)
 {
 pulse_MCP_clock();
 if (digitalRead(ADC_MISO))
 {
 bitSet(value,x);
 }
 else
 {
 bitClear(value,x);
 }
 }
 digitalWrite(ADC_CS, HIGH);
 digitalWrite(DAC_CS, HIGH);
 return value;
 }
void init_ADC(void)
 {
 digitalWrite(SPI_CLK,HIGH); //clock
 digitalWrite(ADC_MISO, LOW); //output -- supposed to be float but not sure how to do this on Arduino
 digitalWrite(ADC_MOSI, HIGH); //input
 digitalWrite(ADC_CS, HIGH);
 delayMicroseconds(50);
 digitalWrite(ADC_CS, LOW);
 delayMicroseconds(50);
 digitalWrite(ADC_CS, HIGH);
 digitalWrite(DAC_CS, HIGH);
 }
int get_adc_avg(int channel)
 {
 long tempx = 0;
 byte ax = 0;
 for (ax=0;ax<10;ax++)
 {
 tempx+=read_MCP(channel);
 }
 tempx/=10;
 return (tempx);
 }
void mcp4822_init() {
 digitalWrite(DAC_CS,HIGH);
 digitalWrite(SPI_CLK, LOW);
 digitalWrite(ADC_CS,HIGH);
 digitalWrite(ADC_MOSI, LOW);
 }
void mcp4822_write(byte control,int data) {
 byte i;
 int tempx=0x00;
 tempx = data|(control<<8);
 digitalWrite(ADC_CS,HIGH);
 delayMicroseconds(10);
 digitalWrite(SPI_CLK,LOW);
 delayMicroseconds(10);
 digitalWrite(DAC_CS,LOW);
 delayMicroseconds(10);
 digitalWrite(ADC_MOSI,LOW);
 for(i=16;i>0;--i)
 {
 digitalWrite(SPI_CLK,LOW);
 digitalWrite(ADC_MOSI,bitRead(tempx,i-1));
 digitalWrite(SPI_CLK,HIGH);
 }
 digitalWrite(DAC_CS,HIGH);
 delayMicroseconds(10);
 }
void setup() {
 //set pin modes
 pinMode(ADC_CS, OUTPUT);
 pinMode(DAC_CS, OUTPUT);
 pinMode(ADC_MOSI, OUTPUT);
 pinMode(ADC_MISO, INPUT);
 pinMode(SPI_CLK, OUTPUT);
 init_ADC();
 mcp4822_init();
 digitalWrite(ADC_CS, HIGH);
 digitalWrite(DAC_CS, HIGH);
 Serial.begin(115200);
 Serial.print("Hello2"); // Just to show the serial is working
 }
void loop() {
 int tempx2 = 0;
 if (test3++>0xFFF) test3=0;
 tempx2 = read_MCP(0);
 mcp4822_write(MCP4822_DAC_A_NON_BUFFERED_GAIN_2X_NON_SHDN, test3);
 mcp4822_write(MCP4822_DAC_B_NON_BUFFERED_GAIN_2X_NON_SHDN, tempx2);
 delay(10);
 }

Leave a Reply