Arduino Forum

Topics => Science and Measurement => Topic started by: terrence on Aug 08, 2013, 09:39 am

Title: 12 bits of sweet resolution
Post by: terrence on Aug 08, 2013, 09:39 am
Hallo all.

I'm trying to upgrade my Uno to have 12-bits of resolution, 1024 just isn't quite cutting it hey.
But I am having trouble getting the AD-Converter to work.

I've added a picture, to show how everything is connected. (Tried making it as clear as possible).'
The IC is a MCP3202.
Then I have my code, which I found on the web.

Code: [Select]

// MCP3202 2 channel ADC
// 3202 is different software-wise from 3204/3208

#define SELPIN 10
#define DATAOUT 11
#define DATAIN 12
#define SPICLOCK 13

/////////////////////////////////////////////////////////////////////////////

void setup(){
  pinMode(DATAOUT, OUTPUT);
  pinMode(DATAIN, INPUT);
  pinMode(SPICLOCK, OUTPUT);
  pinMode(SELPIN, OUTPUT);

  digitalWrite(SELPIN, HIGH);
  digitalWrite(DATAOUT, LOW);
  digitalWrite(SPICLOCK, LOW);

  Serial.begin(9600);
}

void loop(){
  byte i;
  int ain[2]; //creating a small array to save into
 
  ain[0] = read_adc(SELPIN, 2);  //calling the read function and saving in the array
  ain[1] = read_adc(SELPIN, 1);

  Serial.println(ain[0]);   //printing the different array value
  Serial.println(ain[1]);
 
  Serial.print('\n');  //making it look pretty
  delay(500);
}

int read_adc(byte cs, byte channel) 
{
  int adcvalue = 0;
//it gets a little fuzzy from here
 
byte commandbits = B11010000; //command bits - start, mode, chn, MSBF //preparing command bits

  //allow channel selection
  commandbits|=(channel<<5);  //shifting the selected channel into the command bits.(probably?)

  digitalWrite(cs, LOW); //Select adc

  // setup bits to be written //
  for (int i=7; i>=4; i--){
    digitalWrite(DATAOUT,commandbits&1<<i);
    //cycle clock
    digitalWrite(SPICLOCK, HIGH);
    digitalWrite(SPICLOCK, LOW);   
  }

  digitalWrite(SPICLOCK, HIGH);    //ignores 1 null bit
  digitalWrite(SPICLOCK, LOW);

  //read bits from adc
  for (int i=11; i>=0; i--){
    adcvalue+=digitalRead(DATAIN)<<i;
    //cycle clock
    digitalWrite(SPICLOCK, HIGH);
    digitalWrite(SPICLOCK, LOW);
  }
  digitalWrite(cs, HIGH); //turn off device
  return adcvalue;
}


This is what I've tried so far and when I open the Serial Monitor...
All I get is the Max value then zeros. And every now and again some random value.

Does anyone know where I've gone wrong?
Title: Re: 12 bits of sweet resolution
Post by: pito on Aug 08, 2013, 01:37 pm
The minimal SPI clock is 10kHz with this device - do check that when bitbanging it..
I would use normal SPI communication instead..
Title: Re: 12 bits of sweet resolution
Post by: terrence on Aug 08, 2013, 03:04 pm
I was under the impression I was doing normal SPI??
Title: Re: 12 bits of sweet resolution
Post by: CrossRoads on Aug 08, 2013, 03:19 pm
If you were using real SPI you would be connected to D10-11-12-13 and the code would look more like this:

http://ww1.microchip.com/downloads/en/DeviceDoc/21034F.pdf

See figure 6-1 & 6-2
Code: [Select]

digitalWrite (SSpin, LOW);
SPI.transfer(0x01); // 1 is the start bit
upperDAC = SPI.transfer(Bxxx000000); // xxx are the configuration bits, lower 4 bits of upperDAC are D11-D8 from the chip
lowerDAC = SPI.transfer (0x00); // to data to ADC is ignored, lowerDAC contains the D87-D0 from the chip
digitalWrite (SSpin, HIGH;
dataDAC =  (upperDAC<<8) + lowerDAC; // put the data together
Title: Re: 12 bits of sweet resolution
Post by: CrossRoads on Aug 08, 2013, 03:23 pm
Instead of all this in setup()

  pinMode(DATAOUT, OUTPUT);
  pinMode(DATAIN, INPUT);
  pinMode(SPICLOCK, OUTPUT);
  pinMode(SELPIN, OUTPUT);

  digitalWrite(SELPIN, HIGH);
  digitalWrite(DATAOUT, LOW);
  digitalWrite(SPICLOCK, LOW);

you would only have

pinMode(SELPIN, OUTPUT);
SPI.begin();
(and whatever the command is to set the SPI clock divisor to 16 - see the SPI libray page)
Title: Re: 12 bits of sweet resolution
Post by: robtillaart on Aug 09, 2013, 12:34 pm
alternative? - http://www.atmel.com/images/doc8003.pdf -
Title: Re: 12 bits of sweet resolution
Post by: kg4wsv on Aug 10, 2013, 02:09 am
Be careful with hardware SPI - the max clock rate on the 3202 is 1.8MHz.

-j
Title: Re: 12 bits of sweet resolution
Post by: kg4wsv on Aug 10, 2013, 02:14 am
Did you put a meter on the ADC input to verify?

-j
Title: Re: 12 bits of sweet resolution
Post by: terrence on Aug 10, 2013, 03:34 pm
Okay... Taken awhile to really search through these alternatives.

The oversampling just adds way to much noise. I can't use it. But thank you for the suggestion.

I looked into using SPI and I still get screwy readings. bunch of zeros. Sometimes a really low negative value.

This is my revised code:

Code: [Select]

// MCP3202 2 channel ADC
// 3202 is different software-wise from 3204/3208 (which are identical)
#include <SPI.h>

#define SELPIN 10
#define DATAOUT 11
#define DATAIN 12
#define SPICLOCK 13


/////////////////////////////////////////////////////////////////////////////

void setup(){
  pinMode(SELPIN, OUTPUT);
  SPI.begin();
  SPI.setClockDivider(16);
  Serial.begin(9600);
}

void loop(){
  byte i;
  int ain[2];
 
  ain[0] = read_adc(SELPIN, 2);
  ain[1] = read_adc(SELPIN, 1);

  Serial.println(ain[0]);   
  Serial.println(ain[1]);
 
  Serial.print('\n');
  delay(500);
}

int read_adc(byte cs, byte channel)
{
  int upperDAC = 0;
  int lowerDAC = 0;
  int dataDAC = 0;
 
//  byte commandbits = B11000000; //command bits - start, mode, chn (3), dont care (3)
  byte goof = B11000000; //command bits - start, mode, chn, MSBF

  digitalWrite(cs, LOW); //Select adc
  SPI.transfer(0x01); //1 is the start bit
  upperDAC = SPI.transfer(goof);
  lowerDAC = SPI.transfer(0x00);
  digitalWrite(cs, HIGH);

dataDAC = (upperDAC<<8) + lowerDAC;
return dataDAC;
}


Is it something wrong in my code? Is the board wired wrong?
I tried switching Arduino pin 11 and 12 around in an act of desperation.
Title: Re: 12 bits of sweet resolution
Post by: terrence on Aug 10, 2013, 06:31 pm
So I took a good hard look at my code and realized some pretty important things.

First it is code for a DAC and I'm trying to achieve an ADC. (Facepalm.)
I've taken out the DATAOUT, DATAIN and SPICLOCK define in the beginning. (using SPI makes that redundant)
I've taken out the "upperDAC = transfer(goof)" out. and made the lowerDAC into dataDAC.
I am also no longer shifting it.

So after all these changes I loaded up my code and presto!!
Nothing works! now I'm no longer getting garbage, but super garbage!!

I really don't get this chip.
please help.
Here's my code for in case.

Code: [Select]

// MCP3202 2 channel ADC
// 3202 is different software-wise from 3204/3208 (which are identical)
#include <SPI.h>

#define SELPIN 10

/////////////////////////////////////////////////////////////////////////////

void setup(){
  pinMode(SELPIN, OUTPUT);
  SPI.begin();
//  SPI.setClockDivider(16); // I don't really understand this line.
  Serial.begin(9600);
}

void loop(){
  byte i;
  int ain[2];
 
  ain[0] = read_adc(SELPIN, 2);
  ain[1] = read_adc(SELPIN, 1);

  Serial.println(ain[0]);   
  Serial.println(ain[1]);
 
  Serial.print('\n');
  delay(500);
}

int read_adc(byte cs, byte channel)
{
  int upperADC = 0;
  int lowerADC = 0;
  int dataADC = 0;
 
//  byte commandbits = B11000000; //command bits - start, mode, chn (3), dont care (3)
  byte goof = B11000000; //command bits - start, mode, chn, MSBF

  digitalWrite(cs, LOW); //Select adc
  SPI.transfer(goof);
  SPI.transfer(0x01); //1 is the start bit
  dataADC = SPI.transfer(0x00); //receiving the ADC value.
  //lowerADC = SPI.transfer(0x00);
  digitalWrite(cs, HIGH);

//dataADC = (upperADC<<8) + lowerADC;
return dataADC;
}
Title: Re: 12 bits of sweet resolution
Post by: pito on Aug 10, 2013, 07:33 pm
See the Figure 6.1. and 6.2. of the datasheet - there is depicted exactly what needs to be done when operating it over SPI (3x8bit transfer)..
For example (not tested):
Code: [Select]

// Pito 8/2013 for MCP3202
..
unsigned int adc_value0, adc_value1;  // 12bit ADC values
unsigned char dummy, adc_h4, adc_l8;  // 4 high and 8 low bits

SPI.begin();

SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
SPI.setClockDivider(SPI_CLOCK_DIV16);    // 16MHz/16 = 1MHz SPI clock

// from datasheet figure 6.2
// channel 0
digitalWrite(cs, LOW);    // Select adc
dummy = SPI.transfer(0x01);
adc_h4 = SPI.transfer(0xA0) & 0x0F;    // unipolar, channel=0, msb first=0, returns B11-B8 in lower nibble
adc_l8 = SPI.transfer(0x00);    // returns B7-B0
digitalWrite(cs, HIGH);    // Deselect adc
adc_value0 = (adc_h4 << 8) + adc_l8;  //   fixed: brackets required

// channel 1
digitalWrite(cs, LOW);    // Select adc
dummy = SPI.transfer(0x01);
adc_h4 = SPI.transfer(0xE0) & 0x0F;    // unipolar, channel=1, msb first=0, returns B11-B8 in lower nibble
adc_l8 = SPI.transfer(0x00);    //returns B7-B0
digitalWrite(cs, HIGH);    // Deselect adc
adc_value1 = (adc_h4 << 8) + adc_l8;   //   fixed: brackets required


Some bitbanging stuff when SPI is difficult:
http://forum.arduino.cc/index.php?topic=55466.msg398068#msg398068
Title: Re: 12 bits of sweet resolution
Post by: terrence on Aug 10, 2013, 09:17 pm
Thank you Pito for all the help, I really appreciate it.. It was really cool of you to write out a section of code for me. Helped to understand the chip better.. But I'm afraid I still can't get the little bugger to work...

I changed up my code yet again. now I have this:

Code: [Select]

// Pito 8/2013 for MCP3202
// MCP3202 2 channel ADC
// 3202 is different software-wise from 3204/3208 (which are identical)
#include <SPI.h>

#define SELPIN 10

unsigned long adc_value0, adc_value1;  // 12bit ADC values
unsigned char dummy, adc_h4, adc_l8;  // 4 high and 8 low bits

/////////////////////////////////////////////////////////////////////////////

void setup(){
  pinMode(SELPIN, OUTPUT);
  SPI.begin();
  Serial.begin(9600);
 
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE0);
  SPI.setClockDivider(SPI_CLOCK_DIV16); //1MHz clock
}

void loop(){
  int alpha = 0;
  int omega = 0;
 
  alpha = read_adc0();
  omega = read_adc1();

  Serial.println(alpha);   
  Serial.println(omega); 
   
  Serial.print('\n');
  delay(500);
}

int read_adc0(){
// from datasheet figure 6.2
// channel 0

digitalWrite(SELPIN, LOW); // Select adc
dummy = SPI.transfer(0x01);
adc_h4 = SPI.transfer(0xA0); // unipolar, channel=0, msb first=0, returns B11-B8 in lower nibble
adc_l8 = SPI.transfer(0x00); // returns B7-B0
digitalWrite(SELPIN, HIGH); // DeSelect adc
adc_h4 = (adc_h4 & 0x0F);
adc_value0 = adc_h4 << 8 + adc_l8;

return adc_value0;
}

int read_adc1(){
// channel 1
digitalWrite(SELPIN, LOW); // Select adc
dummy = SPI.transfer(0x01);
adc_h4 = SPI.transfer(0xE0); //  unipolar, channel=1, msb first=0, returns B11-B8 in lower nibble
adc_l8 = SPI.transfer(0x00); //returns B7-B0
digitalWrite(SELPIN, HIGH); // DeSelect adc
adc_h4 = (adc_h4 & 0x0F);
adc_value1 = adc_h4 << 8 + adc_l8;

return adc_value1;
}


Still no good. Just get some really odd values. But I can't even link it to something... Just random jibberish.
That link you put it... That's actually where I got my original code from.

Any other ideas that I could try?
Title: Re: 12 bits of sweet resolution
Post by: pito on Aug 10, 2013, 09:33 pm
Double check your wiring (MISO, MOSI, SCK, SS). You need a decoupling capacitor on 3202' Vdd (against gnd).
Connect adc inputs to ground (or Vcc) and print out adc_4h, adc_8l, and adc_value0 and 1.
PS: if you let the analog adc inputs float, you will read garbage..
Title: Re: 12 bits of sweet resolution
Post by: terrence on Aug 10, 2013, 09:59 pm
!!!!!!!!!!!!!!Thank you so much!!!!!!!!!!

It works now!
It was a math fault.

Code: [Select]

//Pito 10/8/2013
// MCP3202 2 channel ADC
#include <SPI.h>

#define SELPIN 10

unsigned long adc_value0, adc_value1;  // 12bit ADC values
unsigned char dummy, adc_h4, adc_l8;  // 4 high and 8 low bits

/////////////////////////////////////////////////////////////////////////////

void setup(){
 pinMode(SELPIN, OUTPUT);
 SPI.begin();
 Serial.begin(9600);
 
 SPI.setBitOrder(MSBFIRST);
 SPI.setDataMode(SPI_MODE0);
 SPI.setClockDivider(SPI_CLOCK_DIV16); //1MHz clock
}

void loop(){
 int alpha = 0;
 int omega = 0;
 
 alpha = read_adc0();
 omega = read_adc1();

 Serial.println(alpha);  
 Serial.println(omega);  
   
 Serial.print('\n');
 delay(500);
}

int read_adc0(){
// from datasheet figure 6.2

// channel 0
digitalWrite(SELPIN, LOW); // Select adc
dummy = SPI.transfer(0x01);
adc_h4 = SPI.transfer(0xA0); // unipolar, channel=0, msb first=0, returns B11-B8 in lower nibble
adc_l8 = SPI.transfer(0x00); // returns B7-B0
digitalWrite(SELPIN, HIGH); // DeSelect adc
adc_h4 = (adc_h4 & 0x0F);
adc_value0 = (adc_h4 << 8) + adc_l8;    //adding the brackets over here is what made the difference.

return adc_value0;
}

int read_adc1(){
// channel 1
digitalWrite(SELPIN, LOW); // Select adc
dummy = SPI.transfer(0x01);
adc_h4 = SPI.transfer(0xE0); //  unipolar, channel=1, msb first=0, returns B11-B8 in lower nibble
adc_l8 = SPI.transfer(0x00); //returns B7-B0
digitalWrite(SELPIN, HIGH); // DeSelect adc
adc_h4 = (adc_h4 & 0x0F);
adc_value1 = (adc_h4 << 8) + adc_l8;

return adc_value1;
}

This code works beautifully.
Thank you so much Pito
Title: Re: 12 bits of sweet resolution
Post by: pito on Aug 10, 2013, 10:44 pm
Welcome :)
Title: Re: 12 bits of sweet resolution
Post by: CrossRoads on Aug 11, 2013, 12:28 am
Code: [Select]
dataDAC =  (upperDAC<<8) + lowerDAC; // put the data together
I suggested that back in #3, altho I had DAC names sprinkled in with ADC for some reason.