I've been experimenting with an AD7175-8 and I've encountered a problem regarding register writting/reading.
I'm setting up a register with a certain HEX value, yet when reading it back (to verify that the writing was successful) the ADC responds with that HEX value + 1. Why so?
Console output:
Succesfully connected to ADC
ID=3CDE
ADCMODE Register READ ERROR!
ADCMODE = 8001
Expected 8000
SETUPCON0 Register READ ERROR!
SETUPCON0 = 1321
Expected 1320
FILTCON0 Register READ ERROR!
FILTCON0 = 505
Expected 504
SETUP complete
Waveform capture from a Saleae logic level analyzer:
You can find it attached bellow.
The code that's running on the main uC:
#include <SPI.h>
#include <AD8555.h>
#define ENABLE_OP_AMP_SETUP 0
#define ENABLE_VERBOSE_OUTPUT 1
//op-amp related
int outputpin = 23; //op-amp data in pin
int inputpin = 15; //op-amp data out pin
byte opAmpData; //stores op-amp register values
//intialize op-amp handle
AD8555 opamp(outputpin, inputpin);
//ADC hook-up lines
//ARDUINO
/*
#define SCK 13
#define MOSI 11
#define MISO 12
#define CS 10
*/
//ESP32
#define SCK 26
#define MOSI 14
#define MISO 27
#define CS 25
//SPI bus settings
#define SPISPEED 4000000
byte received[3];
int i = 0;
//ADC commands
#define READ_REG 0B01000000
#define WRITE_REG 0B00000000
//ADC Register Adressess
#define IDREG 0B00000111
#define ADCMODE 0B00000001
#define FILTCON0 0B00101000
#define IFMODE 0B00000010
#define SETUPCON0 0B00100000
//sample rates
#define SPS5 0B00010100
#define SPS10 0B00010011
#define SPS100 0B00001110
#define SPS1000 0B00001010
#define SPS5000 0B00001000
#define SPS10000 0B00000111
#define SPS31250 0B00000100
#define SPS50000 0B00000011
#define SPS250000 0B00000000
uint16_t id;
uint16_t register16 = 0;
uint16_t dataRegister;
unsigned long raw;
byte adcData[3];
bool ok = false;
void setup() {
Serial.begin(2000000);
if (ENABLE_OP_AMP_SETUP) {
pinMode(outputpin, OUTPUT);
pinMode(inputpin, INPUT);
opAmpSetup();
}
//SPI pins
pinMode(MISO, INPUT);
pinMode(MOSI, OUTPUT);
pinMode(SCK, OUTPUT);
pinMode(CS, OUTPUT);
digitalWrite(CS, HIGH);
SPI.begin(SCK, MISO, MOSI, CS); //start the spi-bus
SPI.beginTransaction(SPISettings(SPISPEED, MSBFIRST, SPI_MODE3));
//terminate CONTINUOUS READ MODE
exitContinuous();
//read device ID
id = readID();
checkID(id);
dataRegister = 0B1000000000000000;
writeRegister16(ADCMODE, dataRegister);
register16 = readRegister16(ADCMODE);
checkRegisterData(register16, dataRegister, "ADCMODE");
//configure SETUPCON0 register
//set unipolar mode
dataRegister = 0B0001001100100000;
writeRegister16(SETUPCON0, dataRegister);
register16 = readRegister16(SETUPCON0);
checkRegisterData(register16, dataRegister, "SETUPCON0");
//configure FILTCON0 register
/*
FILTCON SYNC5 + SYNC 1 FILTER
*/
dataRegister = 0B0000010100000000;
//chose SPS
dataRegister |= SPS31250;
writeRegister16(FILTCON0, dataRegister);
register16 = readRegister16(FILTCON0);
checkRegisterData(register16, dataRegister, "FILTCON0");
//configure IFMODE register
//enable continious read by setting CONTREAD to 1
//ONCE CONTREAD is set any other command is ignored!!!
dataRegister = 0B0000100010000000;
writeRegister16(IFMODE, dataRegister);
//setup complete
if (ENABLE_VERBOSE_OUTPUT)
Serial.println("SETUP complete");
digitalWrite(CS, LOW);
digitalWrite(MOSI, LOW);
//attachInterrupt(digitalPinToInterrupt(12), readADC, FALLING);
}
void loop () {
digitalWrite(CS, LOW);
digitalWrite(MOSI, LOW);
//read analog input
if (Serial.available() > 0) {
byte pcFlag = Serial.read();
if (pcFlag == 115) {
ok = true;
delay(2000);
}
}
while (1 && ok) {
while (digitalRead(MISO)) {}
raw = SPI.transfer(0);
raw <<= 8;
raw |= SPI.transfer(0);
raw <<= 8;
raw |= SPI.transfer(0);
Serial.println(raw);
//adcData[0] = SPI.transfer(0);
//adcData[1] = SPI.transfer(0);
//adcData[2] = SPI.transfer(0);
//Serial.print(adcData[0], BIN);
//Serial.print(" ");
//Serial.print(adcData[1], BIN);
//Serial.print(" ");
//Serial.println(adcData[2], BIN);
//Serial.write(adcData, sizeof(adcData));
while (!digitalRead(MISO)) {}
}
}
uint16_t readID() {
uint16_t id;
//read JEDEC ID
digitalWrite(CS, LOW);
SPI.transfer(READ_REG | IDREG);
id = SPI.transfer(0);
id <<= 8;
id |= SPI.transfer(0);
digitalWrite(CS, HIGH);
return id;
}
void checkID(unsigned long id) {
if (ENABLE_VERBOSE_OUTPUT) {
if (id == 0x3CDE ) {
Serial.print("\nSuccesfully connected to ADC");
Serial.print("\nID=");
Serial.println(id, HEX);
}
else
Serial.println("ADC not responding");
}
}
void checkRegisterData(uint16_t received, uint16_t expected, char* registerName) {
if (ENABLE_VERBOSE_OUTPUT) {
if (received == expected) {
Serial.print("\n");
Serial.print(registerName);
Serial.print(" succesfully set to: ");
Serial.println(received, HEX);
}
else {
Serial.print("\n");
Serial.print(registerName);
Serial.println(" Register READ ERROR!");
Serial.print(registerName);
Serial.print(" = ");
Serial.println(received, HEX);
Serial.print("Expected ");
Serial.println(expected);
}
}
}
uint16_t readRegister16(byte regAddress) {
uint16_t register_value = 0;
digitalWrite(CS, LOW);
SPI.transfer(READ_REG | regAddress);
register_value = SPI.transfer16(0);
digitalWrite(CS, HIGH);
return register_value;
}
void writeRegister16(byte regAddress, uint16_t userData) {
digitalWrite(CS, LOW);
SPI.transfer(WRITE_REG | regAddress);
SPI.transfer16(userData);
digitalWrite(CS, HIGH);
}
void exitContinuous() {
while (digitalRead(MISO)) {};
digitalWrite(CS, LOW);
SPI.transfer16(0x44);
digitalWrite(CS, HIGH);
}
void opAmpSetup() {
//op-amp setup sequence
//Start----------------Op-Amp setup--------------------
// get Second Stage Gain code
Serial.println("Input Second Stage Gain code (0..7)");
// wait for user to enter value
while (!Serial.available());
// set Second Stage Gain
if (!opamp.setSecondStageGain(Serial.parseInt())) {
// opamp will return false if code is out of range
Serial.println("Invalid Second Stage Gain code. Valid range is 0..7");
return;
}
//get First Stage Gain code
Serial.println("Input First Stage Gain code (0..127)");
while (!Serial.available());
//set First Stage Gain
if (!opamp.setFirstStageGain(Serial.parseInt())) {
Serial.println("Invalid First Stage Gain code. Valid range is 0..127");
return;
}
// get offset code
Serial.println("Input Offset code (0..255)");
while (!Serial.available());
//set op-amp offset
if (!opamp.setOffset(Serial.parseInt())) {
Serial.println("Invalid Offset code. Valid range is 0..255");
return;
}
// Chose between programming/simulation mode
// !!! Once the op-amp gets programmed (programming has been chosen) you cannot revrse the settings! It's permanent!
Serial.println("Choose programming mode: Enter \"0\" for simulation, \"1\" for permanent programming");
while (!Serial.available());
int mode = Serial.parseInt();
if (mode == 0) {
// simulation mode
opamp.simulate();
Serial.println("Done!");
} else if (mode == 1) {
// permanent programming mode
Serial.println("Make sure to meet programming requirements described in AD8555 datasheet:");
Serial.println("- A 5.5 V supply is required");
Serial.println("- The power supply must be able to deliver 250 mA of current");
Serial.println("- At least 0.1 uF of decoupling capacitance is needed across the power pins of the device");
Serial.println("\nWARNING: This operation can not be undone, all programming values are permanent");
Serial.println("Continue? [y/N]");
while (!Serial.available());
if (Serial.read() == 'y') {
opamp.program();
Serial.println("Programming... done");
} else {
Serial.println("Operation canceled");
}
}
//opAmpData = opamp.readData(PAR_SSG_CODE);
//Serial.println("Op-Amp offset code= ");
//Serial.println(opAmpData, BIN);
//Finish----------------Op-Amp setup--------------------
}