Code Review for Interfacing external ADC chip ADS131M08 with Teensy 4.1

I have some code which reads the raw data inputs from all 8 channels of my ADC simultaneously and writes it to the serial monitor.

This is the datasheet for my ADC:

Right now I don't get any data displayed to the serial monitor. I thought this could be an issue with the external clock I'm using: https://www.digikey.ca/en/products/detail/ecs-inc/ECS-2520MVLC-081-92-CN-TR/16688217. I got this clock generator breakout board and was hoping I could get some help interfacing it with my system, which I think could solve my issue. https://learn.adafruit.com/adafruit-si5351-clock-generator-breakout/wiring-and-test

The clock signal I need to produce for my ADC is 8.192 Mhz.


Code:
#include <SPI.h>

// Pin Definitions
const int ADC_DRDY_PIN = 9;       // Data Ready Pin, falling edge indicates data is ready
const int ADS131_CS_PIN = 10;     // Chip Select for ADS131
const int DEBLED = 14;            // Debug LED pin

// Global Settings
const int sdel = 20;              // Serial pause time
const int NCH = 8;                // Number of ADC channels per chip
const int NDEV = 1;               // Number of ADC chips
volatile uint8_t DRDY_FLAG = 0;   // Data Ready Flag

// Function Prototypes
void ADS131_SETUP(uint8_t unit);
void ADS131_READFRAME();
void ADC_DATA_READY();

// ADC Data Arrays
volatile uint32_t AD131_RAW[NCH];

// Interrupt Service Routine for Data Ready Pin
void ADC_DATA_READY() {
  ADS131_READFRAME(); // Read a frame of data
  DRDY_FLAG = 1;      // Set the data ready flag
}

void setup() {
  pinMode(DEBLED, OUTPUT);
  pinMode(ADS131_CS_PIN, OUTPUT);
  digitalWrite(ADS131_CS_PIN, HIGH); // Set CS high (inactive)
  SPI.begin();
  SPI.beginTransaction(SPISettings(36000000, MSBFIRST, SPI_MODE1));
  Serial.begin(1000000);
  delay(100);
  ADS131_SETUP(0);
  delay(100);
  attachInterrupt(digitalPinToInterrupt(ADC_DRDY_PIN), ADC_DATA_READY, FALLING);
}

void loop() {
  if (DRDY_FLAG) {
    for (int i = 0; i < NCH; i++) {
      Serial.print(AD131_RAW[i]);
      delayMicroseconds(sdel);
      Serial.print("\t");
      delayMicroseconds(sdel);
    }
    Serial.print("\n");
    delayMicroseconds(100);
    DRDY_FLAG = 0;
  }
}

void ADS131_READFRAME() {
  digitalWriteFast(DEBLED, HIGH);
  digitalWriteFast(ADS131_CS_PIN, LOW); // Activate CS

  SPI.transfer(0x00); // Dummy transfer to initiate SPI communication
  SPI.transfer(0x00); // Read status byte (2 bytes total, but not used here)

  for (int i = 0; i < NCH; i++) {
    AD131_RAW[i] = SPI.transfer(0x00) << 16; // Read ADC data (24 bits)
    AD131_RAW[i] |= SPI.transfer(0x00) << 8;
    AD131_RAW[i] |= SPI.transfer(0x00);
  }

  SPI.transfer(0x00); // Read CRC (2 bytes total, but not used here)
  SPI.transfer(0x00);

  digitalWriteFast(ADS131_CS_PIN, HIGH); // Deactivate CS
  digitalWriteFast(DEBLED, LOW);
}

void ADS131_SETUP(uint8_t unit) {
  uint16_t dd = 0b0000000000000000;
  delay(300);

  digitalWrite(ADS131_CS_PIN, LOW); // Activate CS

  // Configuration register setup
  dd = 0b0110000110000010; // Write register command
  SPI.transfer(dd >> 8);
  SPI.transfer(dd);
  SPI.transfer(0);

  dd = 0b0111111100000010 + (0x03 << 2); // Set OSR (Over Sampling Rate)
  SPI.transfer(dd >> 8);
  SPI.transfer(dd);
  SPI.transfer(0);

  dd = 0b0000000000000000; // Set channel gain (default to 0)
  SPI.transfer(dd >> 8);
  SPI.transfer(dd);
  SPI.transfer(0);

  for (int ii = 0; ii < 4; ii++) {
    SPI.transfer(0);
    SPI.transfer(0);
    SPI.transfer(0);
  }

  digitalWrite(ADS131_CS_PIN, HIGH); // Deactivate CS
}
 
I updated the code with the added pinMode call. I also added code to interface the adafruit clock generator board with it. I verified the clock generator board produces the 8.192MHz signal I need with an oscilloscope and connected that output to the ADC XTAL/clock in port. Still no readings on my serial monitor. Is there any way I can test and debug this chip, hardware wise I have access to the scope and on the software side if I could get some help adding debugging statements or something to the code to see what the issue is. I think what I'm expecting to see is an array with all the input values printed for all 8 channels simultaneously. Even if I have no inputs connected, I would at least expect to see all zeroes or something but right now no data gets printed to the monitor.

Code:
#include <SPI.h>
#include <Adafruit_SI5351.h>

//clock generator object
Adafruit_SI5351 clockgen = Adafruit_SI5351();

// Pin Definitions
const int ADC_DRDY_PIN = 9;       // Data Ready Pin, falling edge indicates data is ready
const int ADS131_CS_PIN = 10;     // Chip Select for ADS131
const int DEBLED = 14;            // Debug LED pin

// Global Settings
const int sdel = 20;              // Serial pause time
const int NCH = 8;                // Number of ADC channels per chip
const int NDEV = 1;               // Number of ADC chips
volatile uint8_t DRDY_FLAG = 0;   // Data Ready Flag

// Function Prototypes
void ADS131_SETUP(uint8_t unit);
void ADS131_READFRAME();
void ADC_DATA_READY();

// ADC Data Arrays
volatile uint32_t AD131_RAW[NCH];

// Interrupt Service Routine for Data Ready Pin
void ADC_DATA_READY() {
  ADS131_READFRAME(); // Read a frame of data
  DRDY_FLAG = 1;      // Set the data ready flag
  digitalWriteFast(DEBLED, LOW);
  Serial.println("Frame Read");
}

void setup() {
  Serial.begin(1000000);
  pinMode(DEBLED, OUTPUT);
  pinMode(ADS131_CS_PIN, OUTPUT);
  pinMode(ADC_DRDY_PIN, INPUT_PULLUP);
  digitalWrite(ADS131_CS_PIN, HIGH); // Set CS high (inactive)

  SPI.begin();
  SPI.beginTransaction(SPISettings(36000000, MSBFIRST, SPI_MODE1));
  delay(100);

  CLOCK_SETUP();

  ADS131_SETUP(0);
  delay(100);

  attachInterrupt(digitalPinToInterrupt(ADC_DRDY_PIN), ADC_DATA_READY, FALLING);
  Serial.println("Setup complete");
}

void loop() {
  if (DRDY_FLAG) {
    for (int i = 0; i < NCH; i++) {
      Serial.print(AD131_RAW[i]);
      delayMicroseconds(sdel);
      Serial.print("\t");
      delayMicroseconds(sdel);
    }
    Serial.print("\n");
    delayMicroseconds(100);
    DRDY_FLAG = 0;
  }
}

void ADS131_READFRAME() {
  digitalWriteFast(DEBLED, HIGH);
  digitalWriteFast(ADS131_CS_PIN, LOW); // Activate CS

  SPI.transfer(0x00); // Dummy transfer to initiate SPI communication
  SPI.transfer(0x00); // Read status byte (2 bytes total, but not used here)

  for (int i = 0; i < NCH; i++) {
    AD131_RAW[i] = SPI.transfer(0x00) << 16; // Read ADC data (24 bits)
    AD131_RAW[i] |= SPI.transfer(0x00) << 8;
    AD131_RAW[i] |= SPI.transfer(0x00);
  }

  SPI.transfer(0x00); // Read CRC (2 bytes total, but not used here)
  SPI.transfer(0x00);

  digitalWriteFast(ADS131_CS_PIN, HIGH); // Deactivate CS
  digitalWriteFast(DEBLED, LOW);
}

void ADS131_SETUP(uint8_t unit) {
  uint16_t dd = 0b0000000000000000;
  delay(300);

  digitalWrite(ADS131_CS_PIN, LOW); // Activate CS

  // Configuration register setup
  dd = 0b0110000110000010; // Write register command
  SPI.transfer(dd >> 8);
  SPI.transfer(dd);
  SPI.transfer(0);

  dd = 0b0111111100000010 + (0x03 << 2); // Set OSR (Over Sampling Rate)
  SPI.transfer(dd >> 8);
  SPI.transfer(dd);
  SPI.transfer(0);

  dd = 0b0000000000000000; // Set channel gain (default to 0)
  SPI.transfer(dd >> 8);
  SPI.transfer(dd);
  SPI.transfer(0);

  for (int ii = 0; ii < 4; ii++) {
    SPI.transfer(0);
    SPI.transfer(0);
    SPI.transfer(0);
  }

  digitalWrite(ADS131_CS_PIN, HIGH); // Deactivate CS
}


void CLOCK_SETUP(){
  if (clockgen.begin() != ERROR_NONE) {
   
    /* There was a problem detecting the IC ... check your connections */
      Serial.print("Ooops, no Si5351 detected ... Check your wiring or I2C ADDR!");
      while(1);
  }

  clockgen.setupPLL(SI5351_PLL_B, 35, 3009, 3125);
  clockgen.setupMultisynth(1, SI5351_PLL_B, 109, 3, 4);
  clockgen.enableOutputs(true);
  Serial.println("Si5351A initialized and clock set to 8.192 MHz");
}
 
Your sketch will only print if the DATA_RDY is set, and that will only happen if Teensy gets a falling edge on the ADC_DRDY_PIN. So I think there are two possibilities. One is that the ADC is generating DATA_RDY signals and your Teensy is not receiving them, but I would say more likely that the ADC is not producing DATA_RDY because it's not fully configured.

Have you verified that you have working SPI communication with the ADS131? Your setup code only writes to the ADC, so how do you know the communication is working? I haven't read the data sheet, but whenever I'm working with a new SPI or I2C device, the first step is to establish communication and confirm that Teensy can both read and write registers in the device.

With a new device, I definitely read the data sheet, but with the Arduino world you have the possibility of using libraries that others have already written, which I find using google. For this chip, I tried "github Teensy ADS131M08". There doesn't seem to be anything specific to Teensy, but there are libraries for Arduino, including the one below that has both a library and a test application, which seems promising.

https://github.com/joshbrew/ADS131M08_Arduino

The M08 library above is derived from the M04 library below, which contains a good README file

https://github.com/icl-rocketry/ADS131M04-Lib

And finally there is this library, which seems well-written, but is also for the M04 and doesn't have a test application, so I would recommend starting with the ones above.

https://github.com/LucasEtchezuri/Arduino-ADS131M04
 
I got chatgpt to give me some basic code to verify communication with my chip. Currently the registers I read give me this output when I run the code:
Device ID: 0x0
Status Register: 0x0

I assume this means the chip and the Teensy are not communicating via SPI, if this code is correct. I have another ADC and SOIC breakout board so I might try with another chip to see if its a hardware issue.

For the library, I followed a tutorial to install them from Github but when I try to import the library from the first link, I get this error. Error: 13 INTERNAL: Library install failed: moving extracted archive to destination dir: library not valid. Does this mean I cannot import the whole library as a zip and need to bring in individual files? How would I go about doing this?

Code:
#include <SPI.h>

// Define SPI settings
#define SPI_SPEED 1000000 // 1 MHz
#define CS_PIN 10         // Chip Select pin

#include <Adafruit_SI5351.h>
Adafruit_SI5351 clockgen = Adafruit_SI5351();


void setup() {
  CLOCK_SETUP();
    Serial.begin(115200);
    pinMode(CS_PIN, OUTPUT);
    digitalWrite(CS_PIN, HIGH);
    SPI.begin();
    SPI.beginTransaction(SPISettings(SPI_SPEED, MSBFIRST, SPI_MODE1));

    // Read and print Device ID
    uint16_t deviceID = readRegister(0x00);
    Serial.print("Device ID: 0x");
    Serial.println(deviceID, HEX);

    // Read and print Status Register
    uint16_t status = readRegister(0x01);
    Serial.print("Status Register: 0x");
    Serial.println(status, HEX);
}

void loop() {
    // Main loop can be used for further processing
}

// Function to read a 16-bit register from the ADS131M08
uint16_t readRegister(uint8_t reg) {
    digitalWrite(CS_PIN, LOW);
    // Send RREG command (101a aaaa annn nnnn)
    SPI.transfer(0x20 | (reg >> 1));  // 1010 0000 | (reg >> 1)
    SPI.transfer((reg << 7) & 0x80);  // (reg << 7) & 1000 0000
    // Dummy byte to receive the register value in the next frame
    SPI.transfer(0x00);
    digitalWrite(CS_PIN, HIGH);

    delayMicroseconds(10); // Small delay to ensure the command is latched

    digitalWrite(CS_PIN, LOW);
    uint16_t result = SPI.transfer(0x00) << 8; // Receive MSB
    result = SPI.transfer(0x00);              // Receive LSB
    digitalWrite(CS_PIN, HIGH);

    return result;
}

void CLOCK_SETUP(){
  if (clockgen.begin() != ERROR_NONE) {
    
    /* There was a problem detecting the IC ... check your connections */
      Serial.print("Ooops, no Si5351 detected ... Check your wiring or I2C ADDR!");
      while(1);
  }

  clockgen.setupPLL(SI5351_PLL_B, 35, 3009, 3125);
  clockgen.setupMultisynth(1, SI5351_PLL_B, 109, 3, 4);
  clockgen.enableOutputs(true);
  Serial.println("Si5351A initialized and clock set to 8.192 MHz");
}
 
What I do:
Unzip the library folder.
Place the unzipped folder (which should contain the library code) into the LIBRARIES directory.
 
Back
Top