Ever had a week where nothing works? Mine has to do with the ADC MCP3564 chip

KrisKasprzak

Well-known member
I'm having issues getting a reading from my MCP3564 chip. I have tried 2 chips no luck. Anyone have this working and have wiring and some code?



I'm using the library https://github.com/nerdyscout/Arduino_MCP3x6x_Library

One person has chimed in but still nothing is working.

If I run the example analogRead_Scan.ino (and comment out the _status.dr at line 325), I get an output but fixed to some value.

Serial.print("voltage0: "); returns 2.3999998569. In fact all voltages return this value--sure looks like the internal reference

My Chip
MCP3564RT-E/ST
https://www.digikey.com/en/products/detail/microchip-technology/MCP3564RT-E-ST/12807301
chip soldered to a test PCB board with no other chips/components

My hardware
MCU Teensy 3.2
IDE Arduino 2.1.0
Windows 10 OS

Chip wiring
mcp.png
chip Teensy
AVdd 3v3
Agnd gnd
REFIN(-) N/C but no change if connected to Teensy GND
REF(+) N/C but no change if connected to Teensy GND
CHO (connected to a pot between Teensy GND and 3v3)
CH1 N/C
CH2 N/C
CH3 N/C
CH4 N/C
CH5 N/C
DVdd 3v3
Dgnd gnd
MCLK N/C
IRQ 100K pullup
SDO pin 11
SDI pin 12
SCK Pin 13
cs Pin 10
CH7 N/C
CH6 N/C

If I run the test program analogRead_Scan I never get anything printed to the serial monitor

mcp.begin() does returns 1 and if I add code
Serial.print("getReference ");
Serial.println(mcp.getReference(), 7);

Serial shows
getReference = 2.4000001

in the method analogRead(mux_t ch), _status.dr after _status = read(&adcdata);

always returns 0

If I comment out while (!_status.dr) {... around line 325

the code continues and Serial.print("voltage0: "); returns 2.3999998569 (looks like the internal reference voltage.

I have added
mcp.setReference(0); to force internal clock, still nothing...



questions

  1. is my wiring correct.
  2. thoughts on what the problem could be?
 
yea, tried that, and the series resistors, nothing helps.

I looked at the low level spi call in the library where spi transfers are done and _spi->transfer returns 255

I really have no idea how to proceed.

Code:
MCP3x6x::status_t MCP3x6x::_transfer(uint8_t *data, uint8_t addr, size_t size) {
  _spi->beginTransaction(SPISettings(MCP3x6x_SPI_SPEED, MCP3x6x_SPI_ORDER, MCP3x6x_SPI_MODE));
  noInterrupts();
  digitalWrite(_pinCS, LOW);
  _status.raw = _spi->transfer(addr);
 
 // _status.raw returns 255
 // _pinCS is correct (pin 10 in my case)
 
  _spi->transfer(data, size);
  digitalWrite(_pinCS, HIGH);
  interrupts();
  _spi->endTransaction();
  return _status;
}
 
Disconnect the MISO signal from the ADC and short it to GND. Does the SPI test return 0s instead of 0xFF?
It will tell if the issue is with :
- ADC chip, it's config, wiring etc if the SPI reads 0s.
- Teensy SPI side or the library if the value is still 0xFF

Might give a hint where to look next.
 
Can you post an _accurate_ schematic - the one you've provided shows no ground connection the Teensy, the photoresistor is an antenna hanging off one wire, its either incorrect and thus we can't figure out what your circuit is, or its correct and you've forgotten vital parts of circuitry!!
 
All,

Thanks for helping out, a better schematic is.

The author of the library has indicated the current code and apparently there are some issues with the library. It's been suggested I try a different lib. I considered writing my own but after looking at the data sheets programming section, the doc is not written in a way I can understand.

I'm trying a different lib, fingers crossed...

schematic.png
attached
 
OK this will be my last attempt at trying to get the MCP3564 working before I claim Microchip got the best of me :(

It was suggested trying this lib (its the 4 channel version of the 8-channel MCP3564). This person built a dev board with a Teensy 4.1 so I think I'm close to getting this working.

https://github.com/edmundsj/MCP3561DevBoard



Using the wiring above the printRegisters() displays all 0's. One time i did get some values, but never again.

This persons library did not have SPI.beginTransaction or SPI.endTransaction(); so I added those lines around any SPI.transfer. Original code that I modified
https://github.com/edmundsj/MCP3561DevBoard/blob/master/mcp3561_arduino/mcp3561.h

I surely don't expect anyone to debug the library or verify the #define, but after a quick scan, does anything jump out as being wrong (wiring, INO, .h)?

Here's the output (first is all 0,s second attempt (just plugging in the MCU)

Code:
Here's what's odd 2 tries

I just Plugged my chip in and I get some data--not sure if its correct or not

Starting..........................................................................................
DEVICE_ADDRESS 1 // note I have tried 0b00, 0b01,0b10, 0b11
writeRegisterDefaults...
registers read...
SOME REGISTER NOT OK. REGISTER TABLE:
CONFIG0: BAD
CONFIG1: OK
CONFIG2: OK
CONFIG3: BAD
IRQ: BAD
registers verifyRegisters...
ADCDATA Register: 000
CONFIG0: 11000000
CONFIG1: 1100
CONFIG2: 10001011
CONFIG3: 0
IRQ: 1100011
MUX: 1
SCAN: 0
TIMER: 0
OFFSETCAL: 0
GAINCAL: 0
RESERVED1: 0
RESERVED2: 0
LOCK: 0
RESERVED3: 0
CRCCFG: 0
registers should have been printed...
kris.data_counter 0
kris.data_points_to_sample 1
Data Read Interrupt Activated. data_counter: 0/1
reading adc:
ADC raw data: 12582912
do we have some data?...

UNplugging and plugging back in....

Starting..........................................................................................
DEVICE_ADDRESS 1 // note I have tried 0b00, 0b01,0b10, 0b11
writeRegisterDefaults...
registers read...
SOME REGISTER NOT OK. REGISTER TABLE:
CONFIG0: BAD
CONFIG1: BAD
CONFIG2: BAD
CONFIG3: BAD
IRQ: BAD
registers verifyRegisters...
ADCDATA Register: 000
CONFIG0: 0
CONFIG1: 0
CONFIG2: 0
CONFIG3: 0
IRQ: 0
MUX: 0
SCAN: 0
TIMER: 0
OFFSETCAL: 0
GAINCAL: 0
RESERVED1: 0
RESERVED2: 0
LOCK: 0
RESERVED3: 0
CRCCFG: 0
registers should have been printed...
kris.data_counter 0
kris.data_points_to_sample 1
Data Read Interrupt Activated. data_counter: 0/1
reading adc:
ADC raw data: 0
do we have some data?...

Here's the code to the library (all code in a .h)

Code:
/*
 * NOTES -
 * The MCP3561 uses SPI mode 0,0.
 * This should be turned into a class so that it's simpler to use.
 */
 
 #include "SPI.h"
 
 
#define DEVICE_ADDRESS 0b01 // data sheet says 1 unless special ordered
#define SPEED_WRITE 1000000 // data sheet says 20 MHZ is max
#define CS_PIN 10



#define DEVICE_ADDRESS_MASK (DEVICE_ADDRESS << 6)
#define COMMAND_ADDR_POS 2

// USEFUL MASKS FOR ADC COMMUNICATION
#define DATA_READY_MASK 0b00000100 // Tells us whether data is ready from an SPI transaction
#define ADDRESS_MASK 0b00111000
#define WRITE_COMMAND_MASK 0b00000010
#define WRITE_COMMAND WRITE_COMMAND_MASK | DEVICE_ADDRESS_MASK
#define IREAD_COMMAND_MASK 0b00000011 // Incremental read command
#define IREAD_COMMAND IREAD_COMMAND_MASK | DEVICE_ADDRESS_MASK
#define SREAD_COMMAND_MASK 0b1 // Static read command
#define SREAD_DATA_COMMAND SREAD_COMMAND_MASK | DEVICE_ADDRESS_MASK

#define CONFIG0_ADDR 0x01
#define CONFIG0_WRITE (CONFIG0_ADDR << COMMAND_ADDR_POS) | WRITE_COMMAND
#define CONFIG0_CLK_SEL_MASK 0b00110000
#define CONFIG0_CLK_SEL_POS 4
#define CONFIG0_CLK_SEL_INT 0b11 << CONFIG0_CLK_SEL_POS
#define CONFIG0_CLK_SEL_EXT 0b00 << CONFIG0_CLK_SEL_POS
#define CONFIG0_ADC_MODE_POS 0
#define CONFIG0_ADC_MODE_CONV 0b11 << CONFIG0_ADC_MODE_POS

#define CONFIG1_ADDR 0x02
#define CONFIG1_WRITE (CONFIG1_ADDR << COMMAND_ADDR_POS) | WRITE_COMMAND
#define CONFIG1_OSR_POS 2
#define CONFIG1_OSR_32 0b0000 << CONFIG1_OSR_POS
#define CONFIG1_OSR_256 0b0011 << CONFIG1_OSR_POS

#define CONFIG3_ADDR 0x04
#define CONFIG3_WRITE (CONFIG3_ADDR << COMMAND_ADDR_POS) | WRITE_COMMAND
#define CONFIG3_CONV_MODE_POS 6
#define CONFIG3_CONV_MODE_CONTINUOUS 0b11 << CONFIG3_CONV_MODE_POS

#define IRQ_ADDR 0x05
#define IRQ_WRITE (IRQ_ADDR << COMMAND_ADDR_POS) | WRITE_COMMAND
#define IRQ_MODE_POS 2
#define IRQ_MODE_HIGH 0b01110111


#define IRQ_PIN 2 // data ready interrupt pin. HIGH = data ready. LOW = data not ready.
#define EXTERNAL_SYNC_PIN 5
#define MAX_SYNCHRONIZATION_POINTS 5000

// USEFUL FAST COMMANDS AND OTHER COMMANDS
// Resets the device registers to their default  values
#define DEVICE_RESET_COMMAND DEVICE_ADDRESS_BYTE | 0b111000

class MCP3564 {
  public:
    // Class methods
    void readRegisters(void);
    void verifyRegisters(void);
    void writeRegisterDefaults(void);
    void printRegisters(void);
    void Reset(void);
    static void readADCData(void);
    static void recordSync(void);

    // Static class variables used in interrupts
    static uint32_t data_counter;
    static uint32_t data_points_to_sample;
    static byte adc_data[3];
    static uint32_t adc_sample;
    static uint32_t synchronization_data[MAX_SYNCHRONIZATION_POINTS];
    static uint32_t synchronization_counter;

    // Class variables
    byte config0_data;
    byte config1_data;
    byte config2_data;
    byte config3_data;
    byte irq_data;
    byte mux_data;
    uint32_t scan_data; // A 24-bit register
    uint32_t timer_data; // A 24-bit register
    uint32_t offsetcal_data; // A 24-bit register
    uint32_t gaincal_data; // A 24-bit register
    uint32_t reserved_1_data;
    byte reserved_2_data;
    byte lock_data;
    uint16_t reserved_3_data;
    uint16_t crccfg_data;
    
    bool config0_ok = false;
    bool config1_ok = false;
    bool config2_ok = false;
    bool config3_ok = false;
    bool irq_ok = false;
    bool mux_ok = false;
    bool scan_ok = false;
    bool timer_ok = false;
    bool offsetcal_ok = false;
    bool gaincal_ok = false;
    bool reserved1_ok = false;
    bool reserved2_ok = false;
    bool lock_ok = false;
    bool reserved3_ok = false;
    bool crccfg_ok = false;
};

uint32_t MCP3564::data_counter;
uint32_t MCP3564::data_points_to_sample = 1;
byte MCP3564::adc_data[3];
uint32_t MCP3564::adc_sample = 0;
uint32_t MCP3564::synchronization_data[MAX_SYNCHRONIZATION_POINTS];
uint32_t MCP3564::synchronization_counter = 0;

void MCP3564::writeRegisterDefaults(void) {
  byte command_byte = 0;
  byte data_byte = 0;
 
  // First write to CONFIG0 register
  command_byte = CONFIG0_WRITE;
  // Configure the ADC to read use its own internal clock and output it to the MCLK pin
  data_byte = CONFIG0_CLK_SEL_EXT;
  // Ronfigure the ADC to be in conversion mode rather than shutdown mode
 
 
 
 SPI.beginTransaction(SPISettings(SPEED_WRITE, MSBFIRST, SPI_MODE0));
 
  data_byte |= CONFIG0_ADC_MODE_CONV;
  digitalWrite(CS_PIN, LOW);
  SPI.transfer(command_byte);
  SPI.transfer(data_byte);
  digitalWrite(CS_PIN, HIGH);
  // TODO
SPI.endTransaction();
delay(100);
SPI.beginTransaction(SPISettings(SPEED_WRITE, MSBFIRST, SPI_MODE0));

  // Next write to CONFIG1 register.
  command_byte = CONFIG1_WRITE;
  // This gives a oversampling ratio of 32 with sampling at MCLK
  data_byte = CONFIG1_OSR_256;
 
  digitalWrite(CS_PIN, LOW);
  SPI.transfer(command_byte);
  SPI.transfer(data_byte);
  digitalWrite(CS_PIN, HIGH);
  // TODO
SPI.endTransaction();
delay(100);
SPI.beginTransaction(SPISettings(SPEED_WRITE, MSBFIRST, SPI_MODE0));
  // Next, write to CONFIG2 register. No need to change anything, defaults OK.

  // Next, write to CONFIG3 register.
  command_byte = CONFIG3_WRITE;
  // Change ADC mode to continuous conversion
  data_byte = CONFIG3_CONV_MODE_CONTINUOUS;
  digitalWrite(CS_PIN, LOW);
  SPI.transfer(command_byte);
  SPI.transfer(data_byte);
  digitalWrite(CS_PIN, HIGH);
SPI.endTransaction();
delay(100);
SPI.beginTransaction(SPISettings(SPEED_WRITE, MSBFIRST, SPI_MODE0));
  // Next, write to the IRQ register to enable a conversion to trigger an interrupt.
  command_byte = IRQ_WRITE;
  data_byte = IRQ_MODE_HIGH;
  digitalWrite(CS_PIN, LOW);
  SPI.transfer(command_byte);
  SPI.transfer(data_byte);
  digitalWrite(CS_PIN, HIGH);
  SPI.endTransaction();
delay(100);
}

void MCP3564::Reset(void) {
  MCP3564::synchronization_counter = 0;
  writeRegisterDefaults();
  MCP3564::data_counter = 0;
  MCP3564::data_points_to_sample = 10;
}
void MCP3564::readRegisters(void) {
    
    SPI.beginTransaction(SPISettings(SPEED_WRITE, MSBFIRST, SPI_MODE0));
    
  digitalWrite(CS_PIN, LOW);
  SPI.transfer(IREAD_COMMAND);
  // First, read the ADCDATA register
  adc_data[2] = SPI.transfer(0);
  adc_data[1] = SPI.transfer(0);
  adc_data[0] = SPI.transfer(0);
  adc_sample = (adc_data[2] << 16) | (adc_data[1] << 8) | (adc_data[0]);

  config0_data = SPI.transfer(0);
  config1_data = SPI.transfer(0);
  config2_data = SPI.transfer(0);
  config3_data = SPI.transfer(0);
  irq_data = SPI.transfer(0);
  mux_data = SPI.transfer(0);
  byte temp0 = SPI.transfer(0);
  byte temp1 = SPI.transfer(0);
  byte temp2 = SPI.transfer(0);
  scan_data = (temp2 << 16) | (temp1 << 8) | temp0;
  temp0 = SPI.transfer(0);
  temp1 = SPI.transfer(0);
  temp2 = SPI.transfer(0);
  timer_data = (temp2 << 16) | (temp1 << 8) | temp0;
  temp0 = SPI.transfer(0);
  temp1 = SPI.transfer(0);
  temp2 = SPI.transfer(0);
  offsetcal_data =  (temp2 << 16) | (temp1 << 8) | temp0;
  temp0 = SPI.transfer(0);
  temp1 = SPI.transfer(0);
  temp2 = SPI.transfer(0);
  gaincal_data = (temp2 << 16) | (temp1 << 8) | temp0;
  temp0 = SPI.transfer(0);
  temp1 = SPI.transfer(0);
  temp2 = SPI.transfer(0);
  reserved_1_data = (temp2 << 16) | (temp1 << 8) | temp0;
  reserved_2_data = SPI.transfer(0);
  lock_data = SPI.transfer(0);
  temp0 = SPI.transfer(0);
  temp1 = SPI.transfer(0);
  reserved_3_data = (temp1 << 8) | temp0;
  temp0 = SPI.transfer(0);
  temp1 = SPI.transfer(0);
  crccfg_data = (temp1 << 8) | temp0;
  digitalWrite(CS_PIN, HIGH);
  SPI.endTransaction();
delay(100);
}

// PARTIALLY COMPLETE. DOES NOT VERIFY ALL REGISTERS.
void MCP3564::verifyRegisters(void) {
  if(config0_data == 0b00000011) config0_ok = true;
  if(config1_data == 0b00001100) config1_ok = true;
  if(config2_data == 0b10001011) config2_ok = true;
  if(config3_data == 0b11000000) config3_ok = true;
  if(irq_data == 0b00110111) irq_ok = true;

  bool all_ok = config0_ok && config1_ok && config2_ok && config3_ok && irq_ok;

  if(all_ok == true) {
    Serial.println("ALL REGISTERS OK.");
  }
  else
  {
    Serial.println("SOME REGISTER NOT OK. REGISTER TABLE:");
    Serial.print("CONFIG0: ");
    Serial.println(config0_ok ? "OK" : "BAD");
    Serial.print("CONFIG1: ");
    Serial.println(config1_ok ? "OK" : "BAD");
    Serial.print("CONFIG2: ");
    Serial.println(config2_ok ? "OK" : "BAD");
    Serial.print("CONFIG3: ");
    Serial.println(config3_ok ? "OK" : "BAD");
    Serial.print("IRQ: ");
    Serial.println(irq_ok ? "OK" : "BAD");
  }
 
}

void MCP3564::printRegisters(void) {
  Serial.print("ADCDATA Register: ");
  Serial.print(adc_data[2], BIN);
  Serial.print(adc_data[1], BIN);
  Serial.println(adc_data[0], BIN);
  Serial.print("CONFIG0: ");
  Serial.println(config0_data, BIN);
  Serial.print("CONFIG1: ");
  Serial.println(config1_data, BIN);
  Serial.print("CONFIG2: ");
  Serial.println(config2_data, BIN);
  Serial.print("CONFIG3: ");
  Serial.println(config3_data, BIN);
  Serial.print("IRQ: ");
  Serial.println(irq_data, BIN);
  Serial.print("MUX: ");
  Serial.println(mux_data, BIN);
  Serial.print("SCAN: ");
  Serial.println(scan_data, BIN);
  Serial.print("TIMER: ");
  Serial.println(scan_data, BIN);
  Serial.print("OFFSETCAL: ");
  Serial.println(scan_data, BIN);
  Serial.print("GAINCAL: ");
  Serial.println(scan_data, BIN);
  Serial.print("RESERVED1: ");
  Serial.println(scan_data, HEX);
  Serial.print("RESERVED2: ");
  Serial.println(scan_data, HEX);
  Serial.print("LOCK: ");
  Serial.println(scan_data, BIN);
  Serial.print("RESERVED3: ");
  Serial.println(scan_data, HEX);
  Serial.print("CRCCFG: ");
  Serial.println(scan_data, BIN);
  Serial.println("-----------------------------");
}

void MCP3564::readADCData(void) {
  Serial.print("Data Read Interrupt Activated. data_counter: ");
  Serial.print(MCP3564::data_counter);
  Serial.print("/");
  Serial.println(MCP3564::data_points_to_sample);
 
  if(MCP3564::data_counter < MCP3564::data_points_to_sample) {
    Serial.println("reading adc: ");
    digitalWrite(CS_PIN, LOW);
    SPI.transfer(SREAD_DATA_COMMAND);
    MCP3564::adc_data[0] = SPI.transfer(0);
    MCP3564::adc_data[1] = SPI.transfer(0);
    MCP3564::adc_data[2] = SPI.transfer(0);
    MCP3564::adc_sample = (adc_data[2] << 16) | (adc_data[1] << 8) | (adc_data[0]);
    digitalWrite(CS_PIN, HIGH);
    //Serial.print("Results: ");
    //Serial.print(adc_sample);
    //Serial.print(" = ");
    //Serial.print(adc_data[2]);
    //Serial.print(adc_data[1]);
    //Serial.println(adc_data[0]);
    //Serial.write(MCP3564::adc_data, 3);
    MCP3564::data_counter += 1;
  }
  else {
    Serial.println("Read Complete. Detatching Interrupts.");
    detachInterrupt(digitalPinToInterrupt(IRQ_PIN));
    detachInterrupt(digitalPinToInterrupt(EXTERNAL_SYNC_PIN));
    MCP3564::data_counter = 0;
  }
}

void MCP3564::recordSync() {
  MCP3564::synchronization_data[MCP3564::synchronization_counter] = MCP3564::data_counter;
  MCP3564::synchronization_counter += 1;
}
 
Maybe try knocking the clock rate down even further? If it worked 1 time, then nothing, perhaps that is indicating it is close to working with the clock currently set to 10MHz? Oh, you can also try putting 100Ohm resistors in series with MISO and MOSI...
 
Thanks, I tried many clock times all the way down to 100 kHz, I'll try a 100 ohm. Data sheet said 10 ohm, but I'll try anything at this point.
 
I remember some devices sampling MOSI pin at falling edge of clock signal. Maybe the other edge, but not the standard way of SPI communication.
It was on the 68HC11 era, and in the SPI setup, you could choose various clock phase and idle levels.
 
Hi,

Do you have an oscilloscope? Or, can you get access to use one for a day or two? At least 50MHz, preferably 100MHz. 4 channels would be good.

Why did you choose this chip? What are you hoping to measure? Did you look at the TI chips? They have much better SNR.

Also, using the T3.2's 3.3V for Vref is probably not a great idea. It has 72uV of noise. Here is something about vref noise and ADCs:

Really getting 24 bits (or close to it) is hard. It takes a lot of attention to detail. (Not to discourage you, we can look at it after the (or a) chip is working, if you want.)
 
it occurred to me. Are you using the regular SPI transfer function?

As I recall (someone will correct me in the details) the spi library might implement a 24 bit transfer as three 8 bit transfers. (or perhaps 16 + 8).

It may very well toggle the MOSI line between those transfers. Looking at the lines with an oscilloscope will make this clear.

If so, it may be necessary to write a 24 bit transfer function. I dont know the details for the T3.2, but in general it is straightforward. There should be a transfer size field in some register, and then you write the transmit register and then you read the receive register.

Aside, you also need to put resistors in series at the source side of each of the logic lines. 50 to 100 ohms is typical
 
DrM, thanks wiring up the 100 ohm resistor.

answering your previous question

key objectives are

1. add ADC to get more pins. I need 4-8 more and my have to move to a 4.1 but I'm trying to keep the PCB as small as possible.
2. SPI communication preferred.
3. Current Teensy analogRead with 12 bit resolution is acceptable but could be better--noise too high at higher bit depth
4. ADC Chip really needs to be standalone--no external clocks, reference volt generators, level shifters, etc. PCB space is at a premium and I really don't have time finding and debugging components that will work
5. Cost is a bit of an issue, I'll eventually need 10 of these
6. read speed: if one read is reliable, fine, otherwise approx. 100-200 times per second will probably provide enough averaging. Currently i'm averaging ~200 every 500 ms using analogRead

This chip looked promising due to high bit resolution, cost, and what I thought were public libraries. Selecting some discrete components such as the is a bit past my expertise so I grabbed what I thought would be fine.

Currently I'm looking at the TI ADS8344NB/1K. No public libs but communication looks straightforward and I think I can follow the data sheet. Other parameters that I know how to decipher look acceptable--'aint crazy about the cost, but not sure I have a choice.

Thanks everyone for helping, but I'll give the above a try.
 
DrM, thanks wiring up the 100 ohm resistor.

answering your previous question

key objectives are

1. add ADC to get more pins. I need 4-8 more and my have to move to a 4.1 but I'm trying to keep the PCB as small as possible.
2. SPI communication preferred.
3. Current Teensy analogRead with 12 bit resolution is acceptable but could be better--noise too high at higher bit depth
4. ADC Chip really needs to be standalone--no external clocks, reference volt generators, level shifters, etc. PCB space is at a premium and I really don't have time finding and debugging components that will work
5. Cost is a bit of an issue, I'll eventually need 10 of these
6. read speed: if one read is reliable, fine, otherwise approx. 100-200 times per second will probably provide enough averaging. Currently i'm averaging ~200 every 500 ms using analogRead

This chip looked promising due to high bit resolution, cost, and what I thought were public libraries. Selecting some discrete components such as the is a bit past my expertise so I grabbed what I thought would be fine.

Currently I'm looking at the TI ADS8344NB/1K. No public libs but communication looks straightforward and I think I can follow the data sheet. Other parameters that I know how to decipher look acceptable--'aint crazy about the cost, but not sure I have a choice.

Thanks everyone for helping, but I'll give the above a try.
Very good. Can you say anything about the source of the signal that you want to digitize. In particular the source impedance can be important.

The ADS8166/7/8 is a multiplexed single ended chip with an internal voltage reference, SNR 92dB, but it is single ended.

(For reference, 15 bits with 1LSB noise is 90dB, 16 bits is 96dB)

The ADS168M is a new chip, dual multiplexers and SARs, differential, 2.5v internal vref or external, SNR 93dB.

The ADS1174/8 is a 16 bit quad/orctal with SNR 97dB, but needs an external vref and the interface is more complicated.

The ADS8344 has SNR a little under 90dB up to 3kHz. It is still good since 15 bits was okay. It needs an external vref

The libraries should not be an issue. The chips are generally easy to use and writing a library does not take very long. And if you filter based on "has a library", you are likely to miss out on some of the newer and better chips, including one that might suit your purpose extremely well.

Re the ADS8344:

Make sure the voltage reference that you choose is suitable for 16 bit precision, and check whether it needs buffering.

Follow layout instructions to the letter. We usually put power bypass caps as close to their pins as physically feasible.

The conversion engine can run on from an internal clock or it share the SPI clock. I would choose the internal option absent a strong reason otherwise.

The SPI protocol is 24 bit, but it seems they designed it to be able to work with three 8 bit transfers. That is important. Many arduino SPI libraries implement large transfers as 8 bit transfers and, there is a 1usec or so delay for setup for each 8 bit transfer. I would look at the timing specs in the datasheet for the ADS8344 and make sure that is okay. (The fallback would be to custom code a 24 bit transfer. That is easy to do for the Teensy 4.x)
 
Take a look at this, LTC2374, https://www.analog.com/en/products/ltc2374-16.html

It seems fantastic.

It is like the ADS816x, in terms of the opamp option, but it is much better. It is single ended, pseudo differential or fully differential, has an internal reference voltge, SNR is 96dB, it seems to have a very simple SPI interface, and it is much more effiicient in how it uses the transfer protocol..

In addition to all that, the application information in the datasheet is pretty thorough. It has what we need to use the chip properly.

This is a pretty fantastic chip, I would be willing to design something to use it, if someone wants to sponsor the effort.


(P/S You mentioned needing ten boards. I assumed you meant they would be running on ten different systems, rather all on one system. Is that cotrect?
 
On why T4 SPI may not work as intended with the MCP3564: with the default Teensy SPI library implementation, in this SPI MODE, the MOSI level for the first bit is either 1 or 0, depending on what the the last bit in the last byte of a previous SPI transaction was. This behavior is specific to the T4 iMRXT1062 chip, other processors (i think T3 and other Arduinos) behave different.
Other SPI libraries for T4 may fix this issue. Doing a dummy SPI transaction with value 0, before asserting CS for the MCP3564, may also be a workaround.
 
Back
Top