AD7606 with arduino via SPI

Hello everyone,

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:

I am not sure if ad7606 has a MOSI port.

I found this code
to use ad7606 with Arduino but i could not read any value from the ADC

#include <SPI.h>

uint32_t start, stop;

#define SCALE_FACTOR 0.000152587890625

#define BUSY 3
#define RESET 4
#define START_CONVERSION 5
#define OS0 6
#define OS1 7
#define OS2 8
#define CHIP_SELECT 10
#define MISO 12
#define MOSI 11
#define LED 13
#define TOTAL_RAW_BYTES 16

SPISettings _spiSettings;

int bytesToRead = TOTAL_RAW_BYTES;
byte raw[TOTAL_RAW_BYTES];
uint16_t parsed[8];
int x = 0;

void setup()
{
  pinMode(BUSY, INPUT);
  pinMode(RESET, OUTPUT);
  pinMode(START_CONVERSION, OUTPUT);
  pinMode(CHIP_SELECT, OUTPUT);

  Serial.begin(115200);

  SPI.begin();
  digitalWrite(START_CONVERSION, HIGH);
  digitalWrite(CHIP_SELECT, HIGH);
  digitalWrite(RESET, HIGH);
  delay(100);
  digitalWrite(RESET, LOW);
  delay(100);
}

void loop()
{
  start = micros();
  int i;
  digitalWrite(START_CONVERSION, LOW);
  delayMicroseconds(100);
  digitalWrite(START_CONVERSION, HIGH);  
  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;

  parseRawBytes();

  for (int i = 0; i < 8; i++) {
    Serial.print((float)parsed[i] * SCALE_FACTOR, 5);
    Serial.print(",");
  }
  Serial.print("\r\n");
  stop = micros();

  Serial.print("time:\t\t");
  Serial.println(stop - start);
}

void parseRawBytes() {
  parsed[0] = (raw[0] << 8) + raw[1];
  parsed[1] = (raw[2] << 8) + raw[3];
  parsed[2] = (raw[4] << 8) + raw[5];
  parsed[3] = (raw[6] << 8) + raw[7];
  parsed[4] = (raw[8] << 8) + raw[9];
  parsed[5] = (raw[10] << 8) + raw[11];
  parsed[6] = (raw[12] << 8) + raw[13];
  parsed[7] = (raw[14] << 8) + raw[15];
}

could anyone help !

Best regards
MD

no CLK ?

and they wrote:

The problem is , I can not get the AD7606 to run on my Teensy
I tried with a 2nd one but also not running.
I have the feeling it is a SPI problem

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?

Best,
MD

Hi Kolaha,

i could make it work
here is the schematic

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!

Could you tell me which Arduino and which ADC are you using?

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];
    }
}
1 Like

Great to hear that
The same applies in case of esp32

Best regards

Is ad7606 able to transfer 16-bit data via SPI? How should I set up the AD7606?

Hi,

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.

Best reagrds

1 Like

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.

Because the range is -/+5V and -/+10V :slight_smile:
So in case of range set to LOW the range actually is -/+5 V

Thx! Completely got, thx for ur answer, I've made it.

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!

void loop() {
    //
    Udp.beginPacket("192.168.1.100",61556);
    //
    readData();
    //
    Udp.write(raw,16);
    //
    Udp.endPacket();
}

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
}