ADC – ADS8689 Interface

ADS8689 Interface

Standard microcontrollers are generally not equipped to handle input voltages to their internal ADCs that exceed the microcontroller's supply voltage. The absolute maximum input rating for an ADC is typically linked to the microcontroller's supply voltage (VDDA).

This issue could be addressed by adding external resistors before the ADC to extend the input ranges. However, this approach introduces challenges such as gain error and gain drift.

To address this, one possible solution is to explore integrating external ADCs with the microcontroller. Some external ADCs support software-configurable input ranges (e.g., 0V to 5V, ±5V, and ±10V), though this comes at the cost of using digital communication protocols, such as SPI or I2C, to interface with the ADC.

This article explore the ADS8689 from Texas Instruments.

I developed a simple PCB board that allows testing the ADS8689 with different types of microcontrollers.

Schematic (Zoom)

Layout (Zoom)

3D Rendering

Interactive BOM (Link)

The boards were manufactured by PCBWay. As always a wonderful job.

Assembled in house.

I kept the driver code simple and wrote a basic program to read the ADC values within the range of ±12V, send the data over UART, and plot the results using the Processing Grapher Program (Link)

#include "ADS8689.h"

/* ******************************
// Global Variables
****************************** */
uint16_t gADC_Data = 0;
float gADC_Voltage = 0.0;

void setup() {
  uint16_t answer = 0;

  // Init User Pins
  pinMode(CS_PIN, OUTPUT);
  digitalWrite(CS_PIN, HIGH);

  // Start Serial
  Serial.begin(115200);

  // Start SPI
  SPI.begin();

  // ADS8689_DEVICE_ID_REG
  answer = ADS8689_SendCommand(ADS8689_READ_HWORD_CMD, ADS8689_DEVICE_ID_REG, 0x0000);
  Serial.print("Device ID: ");
  Serial.println(answer);

  // ADS8689_RANGE_SEL_REG
  answer = ADS8689_SendCommand(ADS8689_READ_HWORD_CMD, ADS8689_RANGE_SEL_REG, 0x0000);
  Serial.print("RANGE_SEL_REG: ");
  Serial.println(answer);

  // INTREF_DIS[6] = 0b = Internal Reference is enabled -- RANGE_SEL[3:0] = 0000b = +/- 3xVref 
  ADS8689_SendCommand(ADS8689_WRITE_CMD, ADS8689_RANGE_SEL_REG, 0b0000000000000000);
  // INTREF_DIS[6] = 0b = Internal Reference is enabled -- RANGE_SEL[3:0] = 1000b = 3xVref
  //ADS8689_SendCommand(ADS8689_WRITE_CMD, ADS8689_RANGE_SEL_REG, 0b0000000000001000);
}

void loop() {

  gADC_Data = ADS8689_SendCommand(ADS8689_NOP_CMD, ADS8689_NO_OP_REG, 0x0000);
  //Serial.println(gADC_Data);

  gADC_Voltage = (gADC_Data - 32768) * (24.576/65536); // RANGE_SEL[3:0] = 0000b = +/- 3xVref
  //gADC_Voltage = (gADC_Data) * (12.288/65536);  // RANGE_SEL[3:0] = 1000b = 3xVref
  
  Serial.println(gADC_Voltage); 

  delay(1);  // 1ms
}

Since I don't have a power supply with me, I connected two 9V batteries to a potentiometer to create +/-9V and linked it to the ADC for testing.

KiCad Files

Arduino IDE Project Files

Sponsor

Leave a Reply

Your email address will not be published.

Index