I am attempting to achieve high-speed +10 KSPS with 16 bits resolution analog-to-digital conversion by using the AD7606 ADC with an Arduino Uno. My intention is to use the ADC in a serial configuration via SPI. I have purchased the following ADC "AD7606".
and did the wiring as follows:
Hi Kolaha,
I understand that he attempted to use AD7606 with a Teensy board, but it should work similarly with an Arduino board. However, it appears that he did not utilize the CLK signal in his code, despite claiming that the latest version of his code works correctly.
Any advice how can i edit the code ?
Is the wiring right?
regard the PAR/SER/BYTE SEL and V_Drive, PAR/SER/BYTE SEL is configured by welding the resistor R1 in Serial mode in the ad7606 board i have.
Vdrive is also hard wired with 5V pin.
With this code you can read from ad7606 with arduino mega
#include <SPI.h>
uint32_t startTime, elapsedTime, old_res;
#define SCALE_FACTOR 0.000152587890625
/* D14 and D15 should be grounded if you use this ad7606 board
* https://www.amazon.de/RELAND-SUN-Multi-Channel-Datenerfassungsmodul-Synchronisation/dp/B0B4HKSK8B/ref=sr_1_2?keywords=ad7606&qid=1681803018&sr=8-2
* i do not use oversampling in this example
* i set range to the ground in this example so the range is +/-5V
*/
#define BUSY 32 // you can use any digital pin
#define RESET 30 // you can use any digital pin
#define START_CONVERSION 34 // you can use any digital pin
#define CHIP_SELECT 53 // SPI CS
#define D7_out 50 // SPI MISO there is no need to use MOSI port with the ad7606
#define RD 52 // SPI SCLK
// #define RANGE 36 // you can use any digital pin
#define TOTAL_RAW_BYTES 16
SPISettings _spiSettings;
int bytesToRead = TOTAL_RAW_BYTES;
byte raw[TOTAL_RAW_BYTES];
uint16_t parsed[8];
//--------------SETUP-UP---------------------------
void setup()
{
initial();
Serial.begin(2000000);
while(!Serial){} // wait for usb connection
SPI.begin();
}
//---------------LOOP--------------------------
void loop()
{
startTime = micros();
readData();
elapsedTime = micros() - startTime;
if (elapsedTime != old_res)
{
Serial.print("Conversion time:\t");
Serial.print(elapsedTime);
Serial.println(" microseconds");
old_res = elapsedTime;
}
parseRawBytes();
for (int i = 0; i < 8; i++) {
Serial.print((float)parsed[i] * SCALE_FACTOR, 5);
Serial.print(",");
}
Serial.print("\r\n");
}
//-----------------------------------------
void initial()
{
pinMode(BUSY, INPUT);
pinMode(RESET, OUTPUT);
pinMode(START_CONVERSION, OUTPUT);
pinMode(CHIP_SELECT, OUTPUT);
pinMode(D7_out, OUTPUT);
pinMode(RD, OUTPUT);
digitalWrite(START_CONVERSION, HIGH);
digitalWrite(CHIP_SELECT, HIGH);
reset(RESET);
}
//-----------------------------------------
void parseRawBytes() {
for(int i = 0; i<(sizeof(parsed) / sizeof(int));i++)
{
parsed[i] = (raw[i*2] << 8) + raw[(i*2)+1];
}
}
//-----------------------------------------
/*reset signal*/
void reset(uint8_t port)
{
digitalWrite(port, HIGH);
// delayMicroseconds(1);
digitalWrite(port, LOW);
// delayMicroseconds(1);
}
//-----------------------------------------
void conversionPulse(uint8_t port)
{
digitalWrite(port, LOW);
// delayMicroseconds(1);
digitalWrite(port, HIGH);
}
//-----------------------------------------
/*
1- start conversion START_CONVERSION HIGH
2- wait until the busy is LOW again
3- put the CS to LOW
4- Read a byte from the SPI
*/
void readData()
{
conversionPulse(START_CONVERSION);
while (digitalRead(BUSY) == HIGH) {
// delayMicroseconds(1);
}
SPI.beginTransaction(_spiSettings);
digitalWrite(CHIP_SELECT, LOW);
while (bytesToRead > 0) {
raw[TOTAL_RAW_BYTES - bytesToRead] = SPI.transfer(0x00);
bytesToRead--;
}
digitalWrite(CHIP_SELECT, HIGH);
SPI.endTransaction();
bytesToRead = TOTAL_RAW_BYTES;
}
//-----------------------------------------
/*
0 +/- 5V
1 +/- 10V
*/
void setRange(bool range)
{
pinMode(RANGE, OUTPUT);
digitalWrite(RANGE,range);
}
//-----------------------------------------
/*OS2 OS1 OS0
oversampling
000 No oversampling Maximum sampling rate is 200KSPS
001 2 times 100 KSPS
010 4 times 50 KSPS
011 8 times 25 KSPS
100 16 times 12.5 KSPS
101 32 times 6.25 KSPS
110 64 times 3.125 KSPS
*/
void setOversampling(uint8_t OS0,uint8_t OS1,uint8_t OS2){
pinMode(_OS0,OUTPUT);
pinMode(_OS1,OUTPUT);
pinMode(_OS2,OUTPUT);
digitalWrite(_OS0,bitRead(B001,OS0));
digitalWrite(_OS1,bitRead(B010,OS1));
digitalWrite(_OS2,bitRead(B100,OS2));
}
This code works, however, I can only get the data for the first 4 channels. The data for the last 4 channels are always zero, why? And how to improve? please help!
Thanks for your reply! I used the Arduino named the Portanta H7 with its breakout board. And the ADC is AD7606. The SPI1 with several other GPIO pins on the board is used for connections, I paste the code as follows.
#include <Arduino_PortentaBreakout.h>
// Pins PortentaBreakout
#define BUSY GPIO_5 // you can use any digital pin
#define RESET GPIO_3 // you can use any digital pin
#define START_CONVERSION GPIO_4 // you can use any digital pin
#define CHIP_SELECT SPI1_CS // SPI CS
#define D7_out SPI1_CIPO // SPI MISO there is no need to use MOSI port with the ad7606
#define RD SPI1_CK // SPI SCLK
// #define RANGE 36 // you can use any digital pin
I figured the problem should be here in the function of parseRawBytes. The sizeof(int) is 4 in Portanta and also Giga. This results in the value of (sizeof(parsed) / sizeof(int)) is 4 not 8, so only the data for the first 4 channels can be obtained. I modify the maximum value of loop, eight channels data can be obtained.
void parseRawBytes() {
for(int i = 0; i < 8;i++)
{
parsed[i] = (raw[i*2] << 8) + raw[(i*2)+1];
}
}
Yes AD7606 is 16 bit ADC.
If you use the same AD7606 board as in post 6 then it is already configured to be used in Serial mode with SPI.
if you use another Board then you may need to change the resister position from R2 to R1 on the board.
After that you can follow the steps and schematic in post 6
thx for your reply, I have repeated the steps in post 6 and modifed a little, btw thx again for your code&kindness, but the data I got is unaccurate for my sample, the output valtage is 10 times as I expected, the code I'll show below, would you mind have a look on my code, I cannot find the error.
#include <SPI.h>
uint32_t start, stop;
#define BUSY 2
#define RESET 4
#define START_CONVERSION 5
#define OS0 3
#define OS1 3
#define OS2 3
#define CS 10
#define MISO 12
//No need to use MOSI of uno pin11
#define SCLK 13
#define RANGE 3
#define TOTAL_RAW_BYTES 16//num
SPISettings _settings(20000000,LSBFIRST,SPI_MODE0);
int bytesToRead = TOTAL_RAW_BYTES;
int pre_data=0;
float data;
int tmp;
void setup()
{
Serial.begin(115200);
pinMode(BUSY, INPUT);
//attachInterrupt(0,ReadAD7606,FALLING);//pin2
pinMode(RESET, OUTPUT);
pinMode(START_CONVERSION, OUTPUT);
pinMode(CS, OUTPUT);
pinMode(RANGE,OUTPUT);
pinMode(OS0,OUTPUT);
pinMode(OS1,OUTPUT);
pinMode(OS2,OUTPUT);
digitalWrite(RANGE,LOW);
digitalWrite(CS, HIGH);
digitalWrite(RESET, HIGH);delay(1);digitalWrite(RESET, LOW);delay(1);
digitalWrite(OS0,LOW); //设置为1次平均采样
digitalWrite(OS1,LOW);
digitalWrite(OS2,LOW);
digitalWrite(START_CONVERSION,HIGH); //默认高电平,上升沿开启测量AD
SPI.setClockDivider(SPI_CLOCK_DIV8);//divide the clock by 8
// SPI.attachInterrupt(); // turn on interrupt
while(!Serial); // wait for usb connection
SPI.begin();
}
void loop()
{
start = micros();
int i;
digitalWrite(START_CONVERSION, LOW);
delayMicroseconds(1);
digitalWrite(START_CONVERSION, HIGH);
//RECEIVE DATA FOR AD7606 VIA SPI
while (digitalRead(BUSY) == HIGH);
SPI.beginTransaction(_settings);
digitalWrite(CS, LOW);
while (bytesToRead > 0) {
tmp = SPI.transfer(0x00) * pow( 2 , 16 - bytesToRead );
// tmp = SPI.transfer(0x00);
pre_data += tmp;
bytesToRead--;
}
digitalWrite(CS, HIGH);
SPI.endTransaction();
bytesToRead = TOTAL_RAW_BYTES;
//END OF RECEPTION
//DISPLAY THE DATA
data=(double)pre_data * 5000.0 / 65536.0;
Serial.print(data);
Serial.println("mV");
stop = micros();
Serial.print("time:\t");
Serial.print(stop - start);
Serial.println("us");
pre_data=0;
start=0;stop=0;
delay(1000);
}
The ADC has a resolution of 16 bits 2^16 (65536) different voltage levels.
Therefore, the voltage resolution of the ADC is given by the scale range divided by the number of voltage levels, which is:
voltage resolution = (2 * 5 V) / 65536 = 0.000152587890625 V
or
voltage resolution = (2 * 10 V) / 65536 = 0.00030517578125V for full-scale
in your case, you set the range to LOW which means you use 5V range
so change your calculation accordingly.
voltage resolution = (2 * 10 V) / 65536 = 0.00030517578125V for full-scale
Yes AD7606 is 16 bit ADC.
If you use the same AD7606 board as in post 6 then it is already configured to be used in Serial mode with SPI.
then go to knowledgerock
So you mean when the master chip sends the command 0x00 to the AD7606, then the AD will return a value as the byte you need to trans and add it up, okok, I think I get you point.
About the resolution, I have a prob, why i need to multiple 2 like "2*5/65536"? It makes little confused.
Thx for the kind people replied to my prob.
I use AD7606 on Nano33 Arduino through SPI, and send the read data through WIFI UDP. In order to improve the loop rate, I move the parse date part into the host PC. And only left the adc read function and the UDP sending function in the MCU loop. However, the actual sampling rate measured in the host PC software (LabVIEW) is only about 500 Hz, which is much lower than expected. The method of measurement is to input a standard 1 Hz sinusoidal signal, and the number of points collected in one cycle is about 500. So How can the actual sampling rate be further increased? Please Help!
I tested a similar program with serial port, and set the baud rate to a very high value like 460800. The actual sampling rate can reach about 12.4 kHz, and the test method is the same as above.
void loop() {
// ADC Read
readData();
// transfer raw data
Serial.write(raw,16);
// read multiple times and write once might be helpful
}