Experimental interfacing to ADS8885 ADC on T4

Status
Not open for further replies.

MarkT

Well-known member
I'm got some proof-of-concept code to interface to these ADCs, which are SAR 18 bit 400kSPS (ie
_not_ sigma-delta so have very low latency, and a 1.2µs settling time to 18 bits) They are not I2S,
note.

datasheet: https://www.ti.com/lit/ds/sbas568a/sbas568a.pdf

I already had a test board for these I'd been using on another microcontroller for playing around with
spectrum analysis (cut down dynamic signal analyzer, basically).

To get them working at the highest speed for audio sampling (384kSPS), the timing is tight as there is
a 1.3µs conversion time before 18 bits can be clocked out at a maximum of 16MHz, all having to fit
in about 2.5µs.

And of course for spectral analysis the aperture jitter is crucial at 18 bit resolution, so its vital to trigger
the start-conversion pin precisely regularly.

I thus have figured out how to use FLEXPWM to drive the start-conversion pin and trigger an interrupt
from which the bits can be clocked out.

Thought I'd share the method I've used, which involved figuring out how FLEXPWM is driven in pwm.c
in the runtime, and how to get PWM compare interrupts:


Code:
#include <Audio.h>  // seem to need this to get at imxrt_hw.h, build logic perhaps?
#include "utility/imxrt_hw.h"


/*
 * PWM driven regular sampling via a pair of ADS8885 SAR 18-bit ADCs.  PWM hardware
 * ensures the aperture timinng is consistent (the chip has jitter of only 5ps, which is good 
 * to 19 bits resolution if driven from low-jitter CONVST clock)
 * 
 * The PWM compare interrupt is used to then drive the serial transfer once the 1.3us acquisition
 * time is complete - this should be done with SPI hardware really.
 * 
 * This sort of ADC has enough resolution for audio, is fast enough for 384kSPS, and has an
 * 18-bit settling time of 1.2us, so could be useful for ultra-low latency processing if coupled
 * with a non-sigma-delta DAC
 * 
 * TODO:  
 * * feed samples into a circular buffer
 * * turn into an audio library input class
 */

#if !defined(__IMXRT1062__)
#error Needs Teensy4
#endif

// ADS8885 pins
#define ADS8885_DIN        2
#define ADS8885_SCLK       3
#define ADS8885_CONVST     4
#define ADS8885_DOUTleft   5  // two ADS8885's on the test pcb, so two outputs.
#define ADS8885_DOUTright  6


#define ADS8885_ACQ_TIME_US  1.3            // from datasheet, max acquisition time
#define FREQ                 (8 * 48000.0)  // 384kSPS, close to the 400kSPS max for ADS8885


// FLEXPWM setup for pin 4, gleaned from the file pwm.c in the Teensy4 runtime,
// unit FLEXPWM2, submodule 0, channel 1 (which is VAL3 counter)
#define PWM_unit     IMXRT_FLEXPWM2
#define PWM_irq      IRQ_FLEXPWM2_0
#define PWM_submodule 0 
#define PWM_counter  VAL3   // channel 1
#define PWM_cntbit   3      // 
#define PWM_status   FLEXPWM2_SM0STS
#define PWM_int_en   FLEXPWM2_SM0INTEN


void read_ADC (void)  // single conversion, for standalone use (not used here)
{
  digitalWriteFast (ADS8885_CONVST, HIGH) ;
  delayNanoseconds (1300) ;
  digitalWriteFast (ADS8885_CONVST, LOW) ;
  delayNanoseconds (20) ;
  inner_read_ADC () ;
}


volatile int32_t datawordL = 0, datawordR = 0  ;   // results from conversion stored here

inline void inner_read_ADC (void)   // does the SPI-like part of transaction, currently bit-banged
{
  int count = 18 ;
  int32_t dataL, dataR ;
  do
  {
    digitalWriteFast (ADS8885_SCLK, HIGH) ;
    int nextbitL = digitalReadFast (ADS8885_DOUTleft) ;
    int nextbitR = digitalReadFast (ADS8885_DOUTright) ;
    //delayNanoseconds (6) ;  
    digitalWriteFast (ADS8885_SCLK, LOW) ;
    delayNanoseconds (16) ;
    dataL = (dataL << 1) | nextbitL ;
    dataR = (dataR << 1) | nextbitR ;
  } while (--count > 0) ;
  datawordL = dataL << 14 >> 14 ;  // produced signed output
  datawordR = dataR << 14 >> 14 ;
}


// The ISR - at this point the PWM'd CONVST pulse has just ended.
void pwm_irq (void)
{
  PWM_status = 1<<PWM_cntbit ;  // clear interrupt flag
  inner_read_ADC() ;
}

uint32_t time_to_PWM_counter (float microsecs)
{
  return (uint32_t) (F_BUS_ACTUAL * microsecs / 1e6);
}

uint32_t freq_to_PWM_counter (float Hz)
{
  return (uint32_t) ((float)F_BUS_ACTUAL / Hz + 0.5f);
}


void setup() 
{
  Serial.begin (115200) ;

  // setup pins for ADS8885
  pinMode (ADS8885_DIN, OUTPUT) ;
  pinMode (ADS8885_SCLK, OUTPUT) ;
  pinMode (ADS8885_CONVST, OUTPUT) ;
  pinMode (ADS8885_DOUTleft, INPUT) ;
  pinMode (ADS8885_DOUTright, INPUT) ;
  digitalWrite (ADS8885_DIN, HIGH) ;

  // setup PWM
  // Use analogWrite machinery to setup the basic pin4 PWM, which will be partly be redefined
  analogWriteFrequency (ADS8885_CONVST, FREQ) ;
  analogWrite (ADS8885_CONVST, 31) ;
  
  uint32_t period = freq_to_PWM_counter (FREQ);
  int prescale = 0 ;
  while (period > 0xFFFF && prescale < 7) 
  {
    period >>= 1;
    prescale += 1;
  }
 
  PWM_unit.MCTRL                 |= FLEXPWM_MCTRL_CLDOK (1<<PWM_submodule);
  PWM_unit.SM[PWM_submodule].CTRL = FLEXPWM_SMCTRL_FULL | FLEXPWM_SMCTRL_PRSC (prescale);
  PWM_unit.SM[PWM_submodule].VAL1 = period ;  // PWM frequency
  PWM_unit.SM[PWM_submodule].PWM_counter = time_to_PWM_counter (ADS8885_ACQ_TIME_US) ;
  PWM_unit.OUTEN                 |= FLEXPWM_OUTEN_PWMA_EN (1<<PWM_submodule);
  PWM_unit.MCTRL                 |= FLEXPWM_MCTRL_LDOK (1<<PWM_submodule);

  // finally fire up PWM compare interrupt on pin 4 (CONVST pin).
  attachInterruptVector (PWM_irq, pwm_irq) ;
  NVIC_SET_PRIORITY (PWM_irq, 127);   // higher prio than standard as timing critical
  NVIC_ENABLE_IRQ (PWM_irq);
  PWM_int_en |= 1<<PWM_cntbit ;

}

void loop()
{
  noInterrupts () ;
  int left = datawordL ;
  interrupts () ;
  Serial.println (left) ;
  delay(200) ;
}

ADS8885_384kSPS.png
ADS8885_detail.png

Not being sigma-delta these ADCs can be calibrated accurately to a voltage reference, which allows
precision measurements to be made in a way most audio conversion chips cannot. I think the spec on
the chip is +/-0.01% accuracy given a good reference. The thermal gain drift is 0.15ppm/C, and THD
- 115dB (despite being SAR technology, its no-missing-codes and ultra low distortion)
 
I am following too. What would you suggest if I want a "variant" (I meant having similar specs, 18 bit, SAR, ~100 kSPS) of ADS8885 which has 2 independent ADCs which can be simultaneously sampled? My primary goal is to sample I and Q channels of a baseband signal after demodulation.
 
I2S port also works.
done that years ago with a 1 MHz ADS SAR chip.
However, as it needs good AA filter, I dropped it.
 
I am following too. What would you suggest if I want a "variant" (I meant having similar specs, 18 bit, SAR, ~100 kSPS) of ADS8885 which has 2 independent ADCs which can be simultaneously sampled? My primary goal is to sample I and Q channels of a baseband signal after demodulation.

If you look at the code you'll see there are two output pins, and my test pcb has two 8885's (they are single channel ADCs - I forgot to mention).
So yes, this would be suitable for I/Q sampling. I think you mean "after downconversion" rather than "after demodulation"?
 
I2S port also works.
done that years ago with a 1 MHz ADS SAR chip.
However, as it needs good AA filter, I dropped it.

Ah, I'd be interested in how you made that work with standard I2S hardware. I'm also thinking about
interfacing other SPI style ADCs/DACs which are 4-wire (use MOSI to select channel and options). If you
have tips for this I'd be grateful, trawling through the i.MX RT1060 manual is fairly heavy going (!)

Yes, indeed the downside to such an ADC is that there is no anti-aliasing built in, so it makes sense to
oversample with it for audio so the AA filter isn't over-complex. However from an analog audio source
with mechanical transducers there won't be problematic spurs present (in a bat-free space!) - but EMI
can produce breakthrough into audio sources/cables, so AA is usually needed for top performance. Over-
sampling at 384kSPS with 8-fold decimation raises the ENOB by 1.5 bits, as well as allowing a fairly simple
filter scheme.

For my purposes, spectral analysis in the DC to ~ 100kHz, you have the issue that you might need several
AA filters for different sampling rates, so it does get complicated.
 
If you look at the code you'll see there are two output pins, and my test pcb has two 8885's (they are single channel ADCs - I forgot to mention).
So yes, this would be suitable for I/Q sampling. I think you mean "after downconversion" rather than "after demodulation"?

Thanks a lot, I will have a look. Do you think that there is any technical advantage of using dual SAR ADC on a single chip over using 2 x ADS8885 (apart from the cost) ? And yes, I meant downconversion.
 
If you can find a suitable dual ADC its worth having - I don't think I found one (most multi-channel ADCs are multiplexed, not
truly dual - I wanted synchronous sampling anyway so that was ruled out)
 
There is the Texas Instruments ADS1278, 8 ch , 144kHz, simultanious ADC and the Analog Devices AD7768, 8 ch, 256kHz, simultanious ADC both 24 bit, but not as fast as the ADS8885.
 
Both are sigma-delta. But the AD7768 has a low-latency filter option (sinc5), which gives it much more
flexibility for data acquisition at the expense of a flat frequency response. With the 8885 you can add
a low-latency AA filter (such as Bessel), or none at all, if you are more interested in accurate voltage
measurements in a waveform than spectral purity.

The AD7768 is looking interesting - its gain accuracy (+/-70ppm) is _much_ better than any "audio" sigma-delta
I've seen for instance (+/-7% isn't unusual for an audio sigma-delta!)

I quite like the compactness of the ADS8885 with its 10 pin VSSOP footprint, although it is expensive to start
using in quantity!
 
Status
Not open for further replies.
Back
Top