Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] Problem ADC 16bit with Arduino using SPI.h Library

Status
Not open for further replies.

oneitusatu

Junior Member level 3
Joined
Apr 9, 2012
Messages
30
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,286
Activity points
1,569
i am using arduino uno and try to interfacing with adc16 bit max 1416 datasheet >> **broken link removed**

but i still cant get the right value for reading adc,instead of -1 appears at output for reading 5volt

here is my code

Code:
#include "SPI.h"

int ss=10;
int adcValue;
byte highByte;
byte lowByte;

void setup(){
  pinMode(ss, OUTPUT);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  Serial.begin(9600);
}

void loop()
{
  //series of commandbit	
  digitalWrite(ss,LOW);
  SPI.transfer(32);//command for comm reg to select ch1 and write to clock register
  SPI.transfer(165);//command for clock reg to set 2,4576Mhz 
  SPI.transfer(16);//command for comm reg to write setup register
  SPI.transfer(69);//command for setup reg to self calibration,unipolar,unbuffered,
  SPI.transfer(8);//command for comm reg to read
  SPI.transfer(56);//command for the comm to read data register
  digitalWrite(ss,HIGH);
  int adcValue = 0;
  
  //read 16bit of data ADC
  highByte = 0;
  lowByte = 0;
  highByte = SPI.transfer(0x00);
  lowByte = SPI.transfer(0x00);
  adcValue = highByte << 8;
  adcValue = adcValue | lowByte;
  
  digitalWrite(ss,HIGH);
  Serial.print("analog value =");
  Serial.println(adcValue, DEC) );
  Serial.print('\n');
  delay(1000);
}

so according to pin configuration (attached image)
image.png
heres my configuration:
sclk to pin 13
cs to pin 10
ain+ to 5v
ain- to gnd
ref+ to 5v
ref- to gnd
dout to pin 11
din to pin 12
vdd to 5v
gnd to gnd

thanks,

oneitusatu
 
Last edited:

well... I see at least two problems... You need to check status of DRDY bit or pin to perform reading operations... you are turning FSync high on your code.. and that stops the conversion...
furter reading how to use FSYNC page 30

... also you are not having CS LOW before the reading... I just don't know if you need to hop cs betwin read and write... see FIG.9 of page 23 of the manual you indicated...
DRDY
Active-Low Data Ready Output. DRDY goes low when a new conversion result is available in the data
register. When a read operation of a full output word completes, DRDY returns high.

Any way... if you don't poll this, at least give it a delay..

more...
to read data register you need to specify the read operation of the data register (witch is 16bit) on the specified channel... meaning that before reading data you need to send B(0 011 1 0 00) for channel one... so the next two operations will be data read

check the diagram of page 29 implementation

Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include "SPI.h"
 
int ss=10;
unsigned int adcValue;
byte highByte;
byte lowByte;
 
void setup(){
  pinMode(ss, OUTPUT);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  Serial.begin(9600);
}
void loop()
{
  //series of commandbit    
  digitalWrite(ss,LOW);
  SPI.transfer(0x20);//command for comm reg to select ch1 and write to clock register ( dec     32)
  SPI.transfer(0xA5);//command for clock reg to set 2,4576Mhz                                  ( dec    165)
  SPI.transfer(0x10);//command for comm reg to write setup register                          (dec      16)
  SPI.transfer(0x44);//command for setup reg to self calibration,unipolar,unbuffered,     (dec      68)
  //digitalWrite(ss,HIGH);
  
 
  while(1)
  {
      char DataNotReady = 0x80;
      while(DataNotReady) // wait for end of conversion 
      {
          SPI.transfer(0x08);//command for comm reg to read  (dec   8)
          DataNotReady =SPI.transfer(0x00); // Read comm register
          DataNotReady &= 0x80;
      }
      
      
      SPI.transfer(0x38);//command for the comm to read data register for channel 1 (dec  56)
      //read 16bit of data ADC
      highByte = SPI.transfer(0x00);
      lowByte = SPI.transfer(0x00);
      
      adcValue = highByte << 8;
      adcValue = adcValue | lowByte;
      
      //digitalWrite(ss,HIGH);
      Serial.print("analog value =");
      Serial.println(adcValue, DEC) );
      Serial.print('\n');
      delay(1000);
  }
}




------------------------

Also Keep in mind that you are using SELF-CALIBRATION MODE.... as the code above...

I suggest you to do a better reading of the datasheet
 
Last edited:
Hmmm..... a quick look at your problem seems to point to just one obvious trouble area.

According to you, you are trying to convert +5V into a 16bit via ADC. I suppose the ADC has a Vref of 5V ? In that case we would expect a value of 0xFFFF from the ADC. However the variable is declared as "int". So naturally you are seeing an output of " -1 " which is in fact correct !! In fact you will see increasing -ve values right down to 2.5V, and then magically it should start showing +ve values below 2.5V.

Try fixing this by typecasting ADCvalue to unsigned int and see what you get.

cheers!
 

.... In that case we would expect a value of 0xFFFF from the ADC. However the variable is declared as "int". So naturally you are seeing an output of " -1 " ...
From the manual
Drive CS high to force DOUT high impedance and cause the MAX1415/MAX1416 to ignore any signals on SCLK and DIN

He is reading 0xFFFF because the ADC is ignoring is SPI commands as he have set CS pin HIGH... So the Spi routine form arduino library is returning 0xFF...

Or maybe not...

_________________________

Try fixing this by typecasting ADCvalue to unsigned int and see what you get.

I Agree it needs to be unsigned int
 
Last edited:

Hmmm..... a quick look at your problem seems to point to just one obvious trouble area.

According to you, you are trying to convert +5V into a 16bit via ADC. I suppose the ADC has a Vref of 5V ? In that case we would expect a value of 0xFFFF from the ADC. However the variable is declared as "int". So naturally you are seeing an output of " -1 " which is in fact correct !! In fact you will see increasing -ve values right down to 2.5V, and then magically it should start showing +ve values below 2.5V.

Try fixing this by typecasting ADCvalue to unsigned int and see what you get.

cheers!
i try it with 3 volt also it reads on -1
i want the reading in decimal,so it gets a 65536 for 5 volt
okay thax for the unsigned things,i am gonna try that

He is reading 0xFFFF because the ADC is ignoring is SPI commands as he have set CS pin HIGH... So the Spi routine form arduino library is returning 0xFF...

Or maybe not...

_________________________



I Agree it needs to be unsigned int

take a look at my code i already set the ss in the low state before i put a command and data there,
yes i miss on drdy there,thanks ill try that
but i still have in mind,if this drdy will changing automatically after the data ready,or we have to triger it manually?because it have a pin for drdy and in communication register have a part for drdy,which one i should trigger?
 

oneitusatu,

take a look at my code i already set the ss in the low state before i put a command and data there,

You are turning it back high before reading...
Code:
.......
SPI.transfer(56);//command for the comm to read data register
  digitalWrite(ss,HIGH);

also, you are not performing the read correctly.. after setting up the read in the communication register you need to perform the two reads.. check my code above...

yes i miss on drdy there,thanks ill try that
but i still have in mind,if this drdy will changing automatically after the data ready,or we have to triger it manually?because it have a pin for drdy and in communication register have a part for drdy,which one i should trigger?

DRDY will change automatically.. is like an ADC Busy flag.... the DRDY pin, and the DRDY bit on the communication register is the same.. meaning you can check it either by software or hardware... you only check it, you don't trigger it... in order to start conversions you need to set FSYNC bit low... check the manual on how to use FSYNC page 25, and page 30... also try my code... you can change the operation mode in line 21 of my code to mode zero (normal mode), but you can alo use it as it is because after the self calibration it will run on the normal mode automatically, and perform normal adc conversions... check the manual on the working modes page 26
 
Last edited:

thank you mgate for correcting me,i just following the command flow in page 29

but now i get 0 in reading,
here is my new code


Code:
#include "SPI.h"

int ss=10;
unsigned int adcValue=0;
byte highByte;
byte lowByte;

void setup(){
  pinMode(ss, OUTPUT);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  Serial.begin(9600);
}

void loop()
{
  //series of commandbit	
  digitalWrite(ss,LOW);
  SPI.transfer(32);
  SPI.transfer(165);
  SPI.transfer(16);
  SPI.transfer(68);
  SPI.transfer(56);
  while(1)
  {
      char DataNotReady = 128;
      while(DataNotReady) // wait for end of conversion 
      {
          SPI.transfer(8);//command for comm reg to read  (dec   8)
          DataNotReady =SPI.transfer(0); // Read comm register
          DataNotReady &= 80;
      }
  
	 //read 16bit of data ADC
	 highByte = 0;
	 lowByte = 0;
	 highByte = SPI.transfer(0);
	 lowByte = SPI.transfer(0);
	 adcValue = highByte << 8;
	 adcValue = adcValue | lowByte; 
	 digitalWrite(ss,HIGH);
	 Serial.print("analog value =");
	 Serial.println(adcValue, DEC);
	 Serial.print('\n');
	 delay(1000);

  }
}

any ideas?:roll:
 

have you even tried my code? You could at least try it as I had to write it for you...

you are doing the read wrong... and also, you are still setting CS HIGH... .. wrongly changed the value 0x80 to decimal 80 ....( by the way... 0x80 is binary 1000 0000, a mask for the "busy flag")

Code:
#include "SPI.h"

int ss=10;
unsigned int adcValue=0;
byte highByte;
byte lowByte;

void setup(){
  pinMode(ss, OUTPUT);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  Serial.begin(9600);
}

void loop()
{
  //series of commandbit	
  digitalWrite(ss,LOW);
  SPI.transfer(32);
  SPI.transfer(165);
  SPI.transfer(16);
  SPI.transfer(68);
[COLOR="#FF0000"][B]//  SPI.transfer(56); // this line here is wrong............................. you can only start reading after polling the "busy flag",
                                                                                         // and imediatly before reding data register[/B][/COLOR]
  while(1)
  {
      char DataNotReady = 128;
      while(DataNotReady) // wait for end of conversion 
      {
          SPI.transfer(8);//command for comm reg to read  (dec   8)
          DataNotReady =SPI.transfer(0); // Read comm register
          [B]DataNotReady &= [COLOR="#008000"]0x80[/COLOR]; // if you want decimal, try [COLOR="#008000"]128 [/COLOR]as above[/B]
      }
  
	 //read 16bit of data ADC
	 highByte = 0;
	 lowByte = 0;

[B][COLOR="#008000"]         SPI.transfer(56);[/COLOR] // you need to "inform" the adc that you will be  reading the data register in the next operation 
                                //each time you want to read data[/B]

	 highByte = SPI.transfer(0);
	 lowByte = SPI.transfer(0);
	 adcValue = highByte << 8;
	 adcValue = adcValue | lowByte; 

[COLOR="#FF0000"][B]//	 digitalWrite(ss,HIGH); // IF  you set CS HIGH the adc WILL IGNORE YOUR SPI PACKETS[/B][/COLOR]

	 Serial.print("analog value =");
	 Serial.println(adcValue, DEC);
	 Serial.print('\n');
	 delay(1000);

  }
}
 
Last edited:

sory for late reply,ive got problem w/ my internet connection,

thank you,your code work perfectly,
but now new problem appears,

the reading of adc are unreliable,when i gave 5 volt for reading,it gives me 32768 then 400 then 1000 then its random and its in wide range,
but when i give some delay it gives me right value 65536,,but when i try to read 3volt it keeps give me 65536,it wont change,i give to gnd and its still give 65536 and sometimes 0,,any explanation for this?

and i try to read to 2nd channel too,but it wont read anything,

here is my new code


Code:
#include "SPI.h"

int ss=10;
unsigned int adcValue;
unsigned int adcValue2;
byte highByte;
byte lowByte;

void setup(){
  pinMode(ss, OUTPUT);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  Serial.begin(9600);
}

void loop()
{
  //series of commandbit	
  for (int ch=1; ch<=2; ch++)
  {
	digitalWrite(ss,LOW);
	if(ch=1)
	{
	SPI.transfer(0x20);
	}
	else
	{
	SPI.transfer(0x21);
	}
	SPI.transfer(0xA5);
	if(ch=1)
	{
	SPI.transfer(0x10);
	}
	else
	{
	SPI.transfer(0x11);
	}
	SPI.transfer(0x44);		  

	while(1)
      {
      char DataNotReady = 0x80;
      while(DataNotReady) // wait for end of conversion 
        {
	  if(ch=1)
	  {
          SPI.transfer(0x08);//command for comm reg to read  (dec   8)
	  }
	  else
	  {
	  SPI.transfer(0x9);
	  }
        DataNotReady =SPI.transfer(0); // Read comm register
        DataNotReady &= 0x50;
	}

  
	 //read 16bit of data ADC
	 if(ch=1)
         {
	 SPI.transfer(0x38);
	 }
	 else
	 {
	 SPI.transfer(0x39);
	 }
	 
	 highByte = 0;
	 lowByte = 0;
	 highByte = SPI.transfer(0);
	 lowByte = SPI.transfer(0);
	 if(ch=1)
	 {
 	 adcValue = highByte << 8;
	 adcValue = adcValue | lowByte;
	 }
	 else
	 {
 	 adcValue2 = highByte << 8;
	 adcValue2 = adcValue | lowByte;	 
	 }
	 digitalWrite(ss,HIGH);
	 Serial.print("analog value =");
	 Serial.println(adcValue, DEC);
         Serial.print("analog value 2 =");
	 Serial.println(adcValue2, DEC);
	 Serial.print('\n');
	 delay(3000);
     }
  }
}
 

I just given a kick look... I will only be able to study the problem latter

You are not waiting for the data to be ready on the data register because you have an error at the busy flag poling loop, in the "busy flag" mask , so change it;

is not DataNotReady &= 0x50;

Is DataNotReady &= 0x80;

(basically the objective is to read the communication register, then extract only the DRDY bit with the mask B10000000 , and then check if is 1 or 0 ...)

Latter I will give it a better look, but you can change it already
 

(basically the objective is to read the communication register, then extract only the DRDY bit with the mask B10000000 , and then check if is 1 or 0 ...)

i just try it following ur instructions with my code

Code:
{
          SPI.transfer(0x08);//command for comm reg to read  (dec   8)
          DataNotReady =SPI.transfer(0x00); // Read comm register
	  DataNotReady &= 0x80;
          msb=bitRead(DataNotReady,7);
          Serial.print("MSB = ");
          Serial.println(msb,DEC);
      }

and the msb keep showing 1,,and i also try it with hardware loop and the DRDY pin also giving 1,
but when i try without it,theres some values on output,sometimes near the expected value sometimes 65536,
whats the problems now?

is there something with delay?or we have to capture the data with exact time before the next data comes?
 

The DRDY value will be one when the ADC is still performing operations, and will be zero when data is available on the data register ... If you attempt to read the data register while the ADC is busy, you will get incomplete values... I don't know enough to be able to say anything about timing...

You should configure the adc only once so that you won't be continuously performing calibrations.. this way you can get a higher sample rate
 

yes,i understand that,
but the point of my previous code is the data not even ready as the msb bit /drdy bit still 1,and if its not ready why would they sometimes could give an output value?

i'd already doing the normal mode and its still give the same
 

I guess the answer is because it can be almost ready... keep in mind that conversions are iterative process
 
Last edited:

so whats your solution?giving the delay doesnt solve anything
 

hey mgate,
i think the problems is in this part of code
Code:
while(1)
  {
      char DataNotReady = 0x80;
      while(DataNotReady) // wait for end of conversion 
      {
          SPI.transfer(0x08);//command for comm reg to read  (dec   8)
          DataNotReady =SPI.transfer(0x00); // Read comm register
		  DataNotReady &= 0x80;
      }
      
      
      SPI.transfer(0x38);//command for the comm to read data register for channel 1 
      
	  //read 16bit of data ADC
      highByte = SPI.transfer(0x00);
      lowByte = SPI.transfer(0x00);
      
      adcValue = highByte << 8;
      adcValue = adcValue | lowByte;
      
      digitalWrite(ss,HIGH);

because in output i see the value of 32896 are frequently appear ,which is in binary 1000000010000000
it means data that i read is the communication register state that telling the data has not been ready.
how to overcome this?
 

Hello, I was googling for some answers and I've found a few hints...
I will post the quotes and the links...

https://www.ccsinfo.com/forum/viewtopic.php?t=47085
This is a convertor with multiplexed input, it is not a pair of convertors side by side in the same chip. This mean you cannot select one channel, read it and then immediately read the other channel. You have to set up the first channel, wait for data ready, read it then select the second channel, wait for data ready then read.

Delta-sigma convertors work by filtering over time. They are primarily intended for continuous high resolution conversion, and have a high level of noise rejection, and the filtration is optimised to reject the line/mains frequencies, i.e. 50 or 60Hz. They are especially useful to measure slowly changing small signals in the presence of mains derived noise, such as strain gauge signals. They are of limited use as single shot general purpose convertors, which is what you are trying to do. Basically every time you change anything you must wait for the convertor to go through a full acquisition cycle. So in pseudo-code its always:

Code:
Code:
while (true)
{
    set up channel or filtering settings or anything
    while (settings don't change)
    {
        wait for data ready
        read data
        do something with data just read
    }
}


RF Developer
As I understood, we are using the wrong approach for scanning multiple channels... And it should be as quoted above

**broken link removed**
Gary,

Thanks for the clarification. I found out my problem .... I left the RESET pin floating, after I tied it to GND DRDY was going LOW like it should.
I am now in the process of using the example TX_BYTE subs with the SHIFTIN command to read the data on my terminal.

Thanks

mikey

I don't really think that you are having this problem, because you said that worked well with my test code... anyway, you can always try it...

---------- Post added at 23:29 ---------- Previous post was at 23:17 ----------

Also, please read this thread,

https://www.ccsinfo.com/forum/viewtopic.php?t=46768
 

thank you mgate,that was such a great info,
but now i dont get my reading at all,
what ive already done according your post:
1) wait for value drdy to 0 before drop the cs
2) give cs high & low in every phase write & read
3) give a reset state when initialization
4) using hardware pooling in while loops

here's my new code

Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include "SPI.h"
 
int ss=10;
int drdy=9;
int reset=8;
unsigned int adcValue;
byte highByte;
byte lowByte;
 
void setup(){
  pinMode(ss, OUTPUT);
  pinMode(drdy,INPUT);
  pinMode(reset, OUTPUT);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  Serial.begin(9600);
}
 
int ready=1;
void DataNotReady()
    {
          while(true)
            {
            while(ready=1)
              {
              delayMicroseconds(1);
              ready=digitalRead(drdy);
              } 
            }
    }
 
void SeriesCommandBit()
  {
  DataNotReady();
  digitalWrite(ss,LOW);
  SPI.transfer(0x20);//command for comm reg to select ch1 and write to clock register ( dec     32)
  SPI.transfer(0xA5);//command for clock reg to set 2,4576Mhz                                  ( dec    165)
  SPI.transfer(0x10);//command for comm reg to write setup register                          (dec      16)
  SPI.transfer(0x44);//command for setup reg to self calibration,unipolar,unbuffered,     (dec      68)
  digitalWrite(ss,HIGH);
  }
 
void loop()
{
    DataNotReady();
        digitalWrite(reset,LOW);
    digitalWrite(ss,LOW);
    delay(100);
    digitalWrite(reset,HIGH);
    digitalWrite(ss,HIGH);
    SeriesCommandBit();   
    DataNotReady();
    digitalWrite(ss,LOW);
    SPI.transfer(0x38);
    delayMicroseconds(1);
    digitalWrite(ss,HIGH);
    DataNotReady();
        digitalWrite(ss,LOW);   
    highByte = SPI.transfer(0x00);
    lowByte = SPI.transfer(0x00);
    adcValue = highByte << 8;
    adcValue = adcValue | lowByte;
    digitalWrite(ss,HIGH);
    Serial.print("analog value =");
    Serial.println(adcValue, DEC);
    Serial.print('\n');
    delay(1000);
}

 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top