Timing with external ADC via SPI

Momchilo

New member
Hi,
for my hobby project I need a voltage measurement from a 14Bit ADC with around 500kSamples/s. I also want to understand what is going on.
I am using a TI ADS 7279 (Datasheet). The data is sent via SPI from the ADC to the Teensy 4.1.
I use the Arduino IDE with the normal included SPI library.

With my code I see the correct analog voltage in the Serial Monitor of my Teensy. So the basic stuff works and the wiring on the breadboard should be fine.
For the Teensy EOC Pin input (pin 14) I am using a 10k pull up resistor.

The ADC is configured for an external clock (SCK from Teensy) and a manual trigger (Convst Pin falling edge).
The EOC (End of Conversion) Pin is always low during a conversion and high when the conversion is finished.
The SPI interface, CONVST and EOC signal can be seen in the attached screenshot of my scope.

You can also see my issue in the screenshot. Every 2nd data transfer the Teensy is not waiting for the rising edge of the EOC input.
So the same two readings are taken for each conversion because the Teensy does not wait for the finished conversion of the ADC.
I guess it is a timing/logic issue in my code.

I would be grateful if someone with more knowledge could help me with that. Thank you very much :)

My Code:

C:
#include <SPI.h>
const int ADC_convstPin = 9;      // CONVST Pin to trigger Conversion for ADS7279 ADC -- GPIO7 Bit 11
const int ADC_csPin = 10;         // Chip Select Pin for ADS7279 ADC -- GPIO7 Bit0
const int ADC_eocPin = 14;        // EOC/INT Pin for finished conversion of ADS7279 ADC -- GPIO6 Bit 18
const int numSamples  = 32000;    // Number of Samples to calculate Current ADC Average Measurement
const float VREF = 4.9997;        //Reference Voltage for ADC
const uint32_t SPI_CLK_FREQ = 20000000;  // SPI-CLK = 20MHz, max 50MHz
void setup() {
  pinMode(ADC_csPin, OUTPUT);
  digitalWriteFast(ADC_csPin, HIGH);
  pinMode(ADC_convstPin, OUTPUT);
  digitalWriteFast(ADC_convstPin, HIGH);
  pinMode(ADC_eocPin, INPUT);
 
  SPI.begin();
  // Configuration:
  // Opcode   (D15-D12): 1110 (Write CFR Register)
  // Mode     (D11):     1    (Auto Channel Select)
  // Channel  (D10):     0    (ADC CLK from SCK/Teensy CLK=SCK/2)
  // Trigger  (D9):      1    (Manual Trigger start with falling edge of CONVST pin)
  // EOC    (D6):        1 (Configure Pin as EOC Pin)
  // --> 1110 1011 1111 1101 =  EBFD
  delay(1);
  writeADS7279Register(0xEBFD);
}
void writeADS7279Register(uint16_t ADC_config) {
  // ADS7279 uses SPI Mode 0, MSB first, up to 50 MHz
  SPI.beginTransaction(SPISettings(SPI_CLK_FREQ, MSBFIRST, SPI_MODE0));
  digitalWriteFast(ADC_csPin, LOW);
  // Transfer configuration 0xEBFD
  SPI.transfer16(ADC_config);
  // Transfer end
  digitalWriteFast(ADC_csPin, HIGH);
  SPI.endTransaction();
}
int16_t readADS7279Register() {
  uint8_t b1, b2, b3;
  // Trigger for conversion start
  digitalWriteFast(ADC_convstPin, LOW);
  delayNanoseconds(100); // at least 40ns Delay regarding ADC datasheet
  digitalWriteFast(ADC_convstPin, HIGH);
  delayNanoseconds(100);
  //Wait until EOC Pin is low from Conversion Start Trigger CONVST
  while (digitalReadFast(ADC_eocPin) == HIGH) {
  }
  // Start ADC SPI Data Transfer
  SPI.beginTransaction(SPISettings(SPI_CLK_FREQ, MSBFIRST, SPI_MODE0));
  digitalWriteFast(ADC_csPin, LOW);
  // Reading 24Bit, one Sample (3CCLKs) and one Conversion (18 CCLKs) takes all in all 21 CCLKs
  b1 = SPI.transfer(0x00);
  b2 = SPI.transfer(0x00);
  b3 = SPI.transfer(0x00);
  // Finish ADC Reading
  digitalWriteFast(ADC_csPin, HIGH);
  SPI.endTransaction();
  // Combine 1. and 2. Byte
  uint16_t raw16 = (b1 << 8) | b2;
  // 14 Bit ADC but 16 Bit read, so 2 Bits must be shifted
  return (raw16 >> 2) & 0x3FFF;
}
void loop() {
  uint32_t  SumOfMeas       = 0;    // Sum of all measurements
  uint16_t  bitValue        = 0;    // Shifted 14Bit Measurement from 14Bit ADC ADS7279
  float     bitValueAverage = 0;    // Average of several Measurements in Bits
  float     voltageMeas     = 0;    // Average Voltage Measurement - used for Control       
  // Calculate Average of Measurement over numSamples
  for (int i = 0; i < numSamples; i++) {
    bitValue = readADS7279Register();
    SumOfMeas += bitValue;
  }
  bitValueAverage = float(SumOfMeas)/(float)numSamples;
 
  // 14-Bit value to Voltage conversion
  voltageMeas = (float)bitValueAverage * VREF / 16384.0;
  Serial.print("Voltage: ");
  Serial.println(voltageMeas, 5);
}
 

Attachments

  • ADC Timing Issue.png
    ADC Timing Issue.png
    21.7 KB · Views: 28
Back
Top