Programming an external ADC(AD7921) - Page 1
Forum section: electronics / general

author: brendan
author_rank: Contributor
timestamp: February 11, 2015, 12:23:32 pm
content: Hey ,I am programming an SPI communication between my AD7921 and the microcontroller Arduino DUE.the Datasheet of my ADC is :http://www.analog.com/static/imported-files/data_sheets/AD7911_7921.pdfhere is the Programm i wrote for both channels. but there is a mistake, that i cant see:#include <SPI.h>int cs = 4;void setup(){pinMode(cs, OUTPUT);digitalWrite(cs, HIGH);SPI.begin();SPI.setDataMode(SPI_MODE3);SPI.setClockDivider(cs,21);SPI.setBitOrder(MSBFIRST);Serial.begin(9600);}void loop(){int adcWert0 = readAdc(0);int adcWert1 = readAdc(1);delay(1000);}int readAdc(int channel){byte adcPrimaryByteMask=00101111;byte adcPrimaryRegister=channel<<5;digitalWrite(cs, LOW);byte adcPrimarybyte = SPI.transfer(adcPrimaryRegister);byte adcSecondarybyte = SPI.transfer(0x00);digitalWrite(cs, HIGH);adcPrimarybyte &= adcPrimaryByteMask;adcPrimarybyte = adcPrimarybyte << 8;int adcValue = adcPrimarybyte|adcSecondarybyte;return adcValue;}in Attachements you can see the result of the conversion. it is working only for channel 0.please i Need you help.

author: mikerj
author_rank: Super Contributor
timestamp: February 11, 2015, 03:16:13 pm
content: I can see quite a few mistakes here:Code:int readAdc(int channel){byte adcPrimaryByteMask=00101111;You can not specify a binary value like this, I'm surprised the compiler didn't give a warning about the value being loaded into adcPrimaryByteMask (you did check the compiler warnings didn't you?). Specify it as a hex value, adcPrimaryByteMask=0x2F; However in this case there's little point loading a literal into a local variable since you never modify it and it's used only once in the function.Code:byte adcPrimaryRegister=channel<<5;digitalWrite(cs, LOW);byte adcPrimarybyte = SPI.transfer(adcPrimaryRegister);byte adcSecondarybyte = SPI.transfer(0x00);digitalWrite(cs, HIGH);adcPrimarybyte &= adcPrimaryByteMask;adcPrimarybyte = adcPrimarybyte << 8;You are left shifting an 8 bit value by 8 bits, and then assigning the result to an 8 bit variable. What do you think the result is going to be?Since your 8 bit value will be integer promoted, you can simply do this:Code:return ((adcPrimarybyte & 0x2F) << 8) | adcSecondarybyte;Another issue is I suspect you haven't read the datasheet properly. The outgoing 16 bit word that holds the channel address bit specifies the channel for the NEXT conversion, not the current one. This means that in your loop() that adcWert0 will hold the value for channel 1 and adcWert1 will hold the value for channel 0.

author: brendan
author_rank: Contributor
timestamp: February 11, 2015, 04:09:02 pm
content: Hey mikerj,Thank you very much for your Help. I changed all the mistakes that you mentioned, but i still have a Problem. I just want to be sure that my Programm is ok with the descriptions of the datasheet. could you please check my (void Setup) and tell mee if my Programm is ok?Thank you for your Help.

author: diyaudio
author_rank: Frequent Contributor
timestamp: February 11, 2015, 07:31:15 pm
content: Quote from: brendan on February 11, 2015, 12:23:32 pmThe problem is you haven't really read the datasheet thoroughly. I recently started working with Analogue Devices ADC`s and looking at that datasheet their data frames are all the same.Are you using 16 SCLK cycles during each frame transaction. ?

author: brendan
author_rank: Contributor
timestamp: February 11, 2015, 07:35:42 pm
content: I think yes. You can check it on the Attachment i posted.

author: AndreasF
author_rank: Frequent Contributor
timestamp: February 11, 2015, 07:50:41 pm
content: Quote from: brendan on February 11, 2015, 07:35:42 pmBut there is a pause between the first set of 8 and the second set, which may upset the ADC, since this ADC appears to use the SPI clock to drive the conversion.

author: brendan
author_rank: Contributor
timestamp: February 11, 2015, 08:43:40 pm
content: Yes i also saw it. But i dont know why i get this pause. I didnt include it in my Program.may bee it is a standard of arduino due.

author: AndreasF
author_rank: Frequent Contributor
timestamp: February 11, 2015, 09:30:17 pm
content: I highly doubt it's a problem with the chip on the Due itself, but rather one of those limitations that come with using a provided library instead of working directly with the hardware. The delay likely comes from the fact that a) there is some time between calling SPI.transfer() and the actual begin of the transmission of the data, and b) there is some delay between the time the actual SPI transfer has finished and the time the SP.transfer() method returns to the calling function.There seems to be a different call to SPI.transfer() that allows you to transfer more than one byte at a time (at least in the most recent version of the Arduino libraries for the Due), but it doesn't seem to be mentioned on their website. Seems fairly straight forward to use though (but maybe not for a beginner).Code:void SPIClass::transfer(byte _pin, void *_buf, size_t _count, SPITransferMode _mode)

author: dannyf
author_rank: Super Contributor
timestamp: February 11, 2015, 09:36:29 pm
content: you may not have sufficient timing between the first and 2nd conversion - the datasheet must have some spec on that. I would insert some delays there to try it out.Or the 2nd channel is indeed grounded.

author: brendan
author_rank: Contributor
timestamp: February 11, 2015, 10:05:26 pm
content: Ok thank you for your advices. I will try to insert a delay tomorow and see what will happen.sorry again if i disturbed you, i am a beginner with spi and arduino.

author: dannyf
author_rank: Super Contributor
timestamp: February 11, 2015, 10:58:05 pm
content: Alternatively, you can simply read ch1 first and then ch0.

author: neslekkim
author_rank: Super Contributor
timestamp: February 12, 2015, 10:23:01 am
content: Why do you want to use this ADC?, since the DUE already have 12bit adc?

author: brendan
author_rank: Contributor
timestamp: February 12, 2015, 10:33:42 am
content: I have to use an external ADC, because it is part of my project. i didnt have the choice.

author: mikerj
author_rank: Super Contributor
timestamp: February 12, 2015, 06:05:54 pm
content: Quote from: dannyf on February 11, 2015, 09:36:29 pmMinimum 30ns, so I doubt that's the problem.OP, can you post the current version of the code you are using?

author: DesertTechie
author_rank: Newbie
timestamp: February 13, 2015, 12:40:40 am
content: byte adcPrimaryByteMask=00101111;should be defined this way if you want to use binary:byte adcPrimaryByteMask=0b00101111;or in hex:byte adcPrimaryByteMask=0x2F;

author: AndreasF
author_rank: Frequent Contributor
timestamp: February 13, 2015, 12:09:22 pm
content: I would think that sure adcPrimaryByteMask should be 0x0F since bit 5 of the first MSbyte is only a reflection of the converted channel and is not really part of the conversion result. I doub't that solves your original problem though.Also, please put any code in the correct code markup - the # symbol in the post editor so it looks nicer:Code:#include <SPI.h>int cs = 4;void setup(){pinMode(cs, OUTPUT);digitalWrite(cs, HIGH);SPI.begin();SPI.setDataMode(SPI_MODE3);SPI.setClockDivider(cs,21);SPI.setBitOrder(MSBFIRST);Serial.begin(9600);}void loop(){int adcWert0;int adcWert1;adcWert1 = readAdc(1);adcWert0 = readAdc(0);delay(1000);}...}EditWhoa - I made this reply in response to the post of the OT directly below mine.

author: brendan
author_rank: Contributor
timestamp: February 13, 2015, 12:13:43 pm
content: hier is my actual code. i also changed the adc(i took a new), but i still have a Problem. may be in the program.#include <SPI.h>int cs = 4;void setup(){pinMode(cs, OUTPUT);digitalWrite(cs, HIGH);SPI.begin();SPI.setDataMode(SPI_MODE3);SPI.setClockDivider(cs,21);SPI.setBitOrder(MSBFIRST);Serial.begin(9600);}void loop(){int adcWert0;int adcWert1;adcWert1 = readAdc(1);adcWert0 = readAdc(0);delay(1000);}int readAdc(int channel){int adcValue;byte adcPrimaryByteMask;byte adcPrimaryRegister;int adcPrimarybyte;byte adcSecondarybyte;adcPrimaryByteMask=0x2F;adcPrimaryRegister=channel<<5;digitalWrite(cs, LOW);adcPrimarybyte = SPI.transfer(adcPrimaryRegister);adcSecondarybyte = SPI.transfer(0x00);digitalWrite(cs, HIGH);adcPrimarybyte &= adcPrimaryByteMask;adcValue = (adcPrimarybyte <<8 )|adcSecondarybyte;return adcValue;}i just want to be sure that this code is correct. if yes, i will check my platine again.