SPI with ESP32 using Arduino

Hi all,

i am using this code to work with external ADC with arduino mega and it is work fine. However, the total Sample rate is lower than i need.
I achieved 10 KSPS with Arduino mega. But ad7606 has the capablity of 100KSPS with SPI.
therefore, i tried to use esp32 instead in order to get faster conversion time, However, i could not get reading from ad7606 maybe because i need to set the right spi (HSPI/VSPI) to the esp32
i tried out some codes but it does not yet worked for me.
could anyone help
thanks in advance

#include <SPI.h>

uint32_t startTime, elapsedTime, old_res;

/*  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 SCALE_FACTOR 0.000152587890625 // (2*5V(volt range) / 2^16 bit)
#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 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(115200);
  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(8000000, MSBFIRST, SPI_MODE2));
  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;
}
//-----------------------------------------

Your ESP32 has pin 50 and 52 and 53? Which ESP32 are you using that has more that 40 GPIO pins?

Hi,

No, this code is for Arduino Mega.

Here are the spi pins in esp32

.

Best regards

Why not post the code you are using with the ESP32 that you are trying to use? Or are you wanting someone just to write the ESP32 code from your posted MEGA code?

i tested different thing with same result therfore i wanted to share a worked version of my code but sure here is one of the codes i tried on esp32.

#include <SPI.h>
#include <Arduino.h>
//#include "digitalWriteFast.h"
uint32_t startTime, elapsedTime, old_res; 
#define SCALE_FACTOR 0.000152587890625  // 10v / 2^16 = 0.000152587890625
/* D14 and D15 should be grounded if you use this ad7606 boaSCK  
 *  https://www.amazon.de/RELAND-SUN-Multi-Channel-Datenerfassungsmodul-Synchronisation/dp/B0B4HKSK8B/ref=sr_1_2?keywoSCKs=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
*/

//SPIClass SPI(HSPI);
//SPI1.setHwCs(true);

#define BUSY 26              
#define RESET 25            
#define START_CONVERSION 5
#define SS 15     
#define MISO 12            
#define SCK 14                
#define MOSI 13
#define TOTAL_RAW_BYTES 16


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


//--------------SETUP-UP---------------------------
void setup() {
   Serial.println("setup start");
  initial();
  Serial.begin(115200);
  while (!Serial) {}  // wait for usb connection
//  SPI = SPIClass((uint8_t)HSPI);
  SPI.begin(SCK, MISO, MOSI, SS);
 // SPI.setHwCs(true);
 
  startTime = micros();
  Serial.println("setup end");
}
//---------------LOOP--------------------------
void loop() {
 //  Serial.println("start loop");
  static int loopCount = 0;
  // startTime = micros();
  readData();

  if (loopCount % 1000 == 0 ) {
    uint32_t newStartTime = micros();
    elapsedTime = newStartTime - startTime;
    startTime = newStartTime;
    Serial.print("Conversion time:\t\t\t\t\t\t\t");
    Serial.print(elapsedTime / 1000);
    Serial.println(" microseconds");
  }

  parseRawBytes();
  if (loopCount % 1000 == 0) {
    for (int i = 0; i < 8; i++) {
      Serial.print((float)parsed[i] * SCALE_FACTOR, 5);
      Serial.print(",");
    }

    Serial.print("\r\n");
  }
  loopCount++;
  // Serial.println("loop end");
}
//-----------------------------------------
void initial() {
  pinMode(BUSY, INPUT);
  pinMode(RESET, OUTPUT);
  pinMode(START_CONVERSION, OUTPUT);
  pinMode(SS, OUTPUT);
  pinMode(MISO, OUTPUT);
  pinMode(SCK, OUTPUT);
  digitalWrite(START_CONVERSION, LOW);
  digitalWrite(SS, 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() {
 //  static int readLoop = 0;
 // startTime = micros();
  conversionPulse(START_CONVERSION);  // 4 micro

  while (digitalRead(BUSY) == HIGH) { //  return ((GPIO.in & (1 << pinBUSY)) != 0);
    //  delayMicroseconds(1);
  }
  /*
  elapsedTime = micros() - startTime;
  if (readLoop % 1000 == 0) {
    Serial.print("pulse:\t");
    Serial.print(elapsedTime);
    Serial.println(" microseconds");
  }
  readLoop++;*/
  SPI.beginTransaction(SPISettings(26000000, MSBFIRST, SPI_MODE2));   
  digitalWrite(SS, LOW);

  while (bytesToRead > 0) {
    raw[TOTAL_RAW_BYTES - bytesToRead] = SPI.transfer(0x00);
    bytesToRead--;
  }

  digitalWrite(SS, HIGH);
  SPI.endTransaction();

  bytesToRead = TOTAL_RAW_BYTES;

}
//-----------------------------------------


results
Conversion time: 46 microseconds
0.81741,2.33902,0.82413,0.82672,0.00000,0.00000,0.00000,0.00000,

i connect the potentiometer with channal 2
when i change it i got value from ~0 to 2.3V !

For 100KSPS, there is 100x1000x16 (1600000) bits/sec which is only 1.6 MBits/sec and can be easily handled by MEGA.

You are already operating the MEGA at 8 MBits/sec transfer rate and yet you want to use ESP32 -- why?

so according to my Debugging

time for one spi transmission: 84 microseconds with 8MBits/sec

time for one spi transmission: 208 microseconds with 1MBits/sec

so i though with teensy or esp32 i can get up to 40MBits/sec therefore i will get faster sample rate.

Note: i used digitalWriteFast lib to get faster digitalRead/digitalWrtie and i could get almost 10-20 us less.

but the problem that SPI takes alot of time between beginTransaction and end

ADC conversion time for a sample is: 4 us.
Allowable sampling: 200x1000 samples/sec
Time allocation for each sample is: 5 us (1/200000)

After issuing conversion command to the ADC, there must be a delay of 4 us and then the 16-bit ADC data is to read in the next 1 us before taking the next sample (assume 200 ksps).

The SPI data transfer rate stands as: 16 MBits/sec which can be handled by MEGA.

What is the sampling rate (number of samples are being taken in 1-sec)?

according to code above the number of samples per seconds is
1second /84 micorsecond = 11904.76 Samples Per Second

Hi again,

the code i provided for esp32 works the problem was that the ground of esp32 was not really connected :sweat_smile:

However, i could not get faster than a cycle time of 46 microseconds with 26 MHz SPISettings(26000000, MSBFIRST, SPI_MODE2).

i can save some more time using register manipulation instead of digitalWrite/read but still, i will not be able to achieve 7 us cycle time.

Does using DMA help?

Best regards

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.