diff --git a/china_io-2019/avr/Makefile b/china_io-2019/avr/Makefile
index 2e6b2c84a3343360588bd7f6531e53583c49a6de..f435c2d6ffdee0e37f4b91bad77c5b797c68f20d 100644
--- a/china_io-2019/avr/Makefile
+++ b/china_io-2019/avr/Makefile
@@ -7,7 +7,7 @@ china-io.FUSE=--wr_fuse_l=0x1f --wr_fuse_h=0xd9 --wr_fuse_e=0xff
 china-io.FUSE_L=0x1f
 china-io.FUSE_H=0xd9
 china-io.C=china-io
-china-io.H=../../lib/avr/serialio i2c_master
+china-io.H=../../lib/avr/serialio i2c_master ads869x
 
 china-io-test.ARCH=avr
 china-io-test.CHIP=atmega32
diff --git a/china_io-2019/avr/ads869x.h b/china_io-2019/avr/ads869x.h
new file mode 100644
index 0000000000000000000000000000000000000000..1ff1a0e17d0db2561bf566d36f12b46070ffc6f2
--- /dev/null
+++ b/china_io-2019/avr/ads869x.h
@@ -0,0 +1,48 @@
+#ifndef __ADS869X_H__
+#define __ADS869X_H__
+
+#define ADS869X_AUTO_SEQ_EN		0x01
+#define ADS869X_FeatureSelect 		0x03
+
+
+#define ADS869X_REG_W(REG_ADDR, VALUE) ((REG_ADDR<<1)|0x01),(VALUE)
+#define ADS869X_REG_R(REG_ADDR, VALUE) ((REG_ADDR<<1)),(VALUE)
+
+#define ADS869X_W(W_DATA) DO_ADS869X_W_R(sizeof(W_DATA), W_DATA,        \
+                                         0, NULL)
+#define ADS869X_R(R_DATA) DO_ADS869X_W_R(0, NULL,                       \
+                                         sizeof(R_DATA), R_DATA)
+#define ADS869X_W_R(W_DATA, R_DATA) DO_ADS869X_W_R(sizeof(W_DATA), W_DATA, \
+                                                   sizeof(R_DATA), R_DATA)
+
+static uint8_t DO_ADS869X_W_R(
+  uint8_t w_length,
+  const __flash uint8_t *w_data,
+  uint8_t r_length,
+  uint8_t *r_data)
+{
+  uint8_t last_byte;
+
+  /* Always setup SPI in case others use SPI */
+  DDR_SPI |= (1<<DD_MOSI) | (1<<DD_SCK) | (1<<DD_SS);
+  PORT_SPI |= (1<<DD_MISO); // Pull up
+  SPCR = (SPCR & (1<<SPIE)) | (1<<SPE) | (1<<MSTR) | (1<<CPHA);
+  SPSR = (1<<SPI2X);
+  
+  PORT_SPI &= ~(1<<DD_SS); // Chip select
+  for (uint8_t i = 0 ; i < w_length ; i++) {
+    SPDR = w_data[i];
+    while ((SPSR & (1<<SPIF)) == 0) {}
+    last_byte = SPDR; // Clear SPIF flag
+  }
+  for (uint8_t i = 0 ; i < r_length ; i++) {
+    SPDR = 0;
+    while ((SPSR & (1<<SPIF)) == 0) {}
+    last_byte = SPDR; // Clear SPIF flag
+    r_data[i] = last_byte;
+  }
+  PORT_SPI |= (1<<DD_SS); // Chip deselect
+  return last_byte;
+}
+
+#endif
diff --git a/china_io-2019/avr/china-io-test.c b/china_io-2019/avr/china-io-test.c
index 3373cdc89165b7f61003153f903a86eeb9309399..6c90da78a6c04131c60d05e50bdc8865a60819a2 100644
--- a/china_io-2019/avr/china-io-test.c
+++ b/china_io-2019/avr/china-io-test.c
@@ -110,6 +110,35 @@ static const __flash struct i2c_transcation write_all[] = {
   I2C_END()
 };
 
+
+static volatile struct dac8574_check {
+  struct dac8574_check_chan {
+    uint8_t no_pdo[2];
+    uint8_t pdo[3];
+  } chan[4];
+} dac8574_check;
+
+static const __flash struct i2c_transcation read_all[] = {
+  I2C_WRITE_1(DAC8574ADDR, 0x10),
+  I2C_READ(DAC8574ADDR, 2, dac8574_check.chan[0].no_pdo),
+  I2C_WRITE_1(DAC8574ADDR, 0x11),
+  I2C_READ(DAC8574ADDR, 3, dac8574_check.chan[0].pdo),
+  I2C_WRITE_1(DAC8574ADDR, 0x12),
+  I2C_READ(DAC8574ADDR, 2, dac8574_check.chan[1].no_pdo),
+  I2C_WRITE_1(DAC8574ADDR, 0x13),
+  I2C_READ(DAC8574ADDR, 3, dac8574_check.chan[1].pdo),
+  I2C_WRITE_1(DAC8574ADDR, 0x14),
+  I2C_READ(DAC8574ADDR, 2, dac8574_check.chan[2].no_pdo),
+  I2C_WRITE_1(DAC8574ADDR, 0x15),
+  I2C_READ(DAC8574ADDR, 3, dac8574_check.chan[2].pdo),
+  I2C_WRITE_1(DAC8574ADDR, 0x16),
+  I2C_READ(DAC8574ADDR, 2, dac8574_check.chan[3].no_pdo),
+  I2C_WRITE_1(DAC8574ADDR, 0x17),
+  I2C_READ(DAC8574ADDR, 3, dac8574_check.chan[3].pdo),
+  I2C_CHAIN(write_all),
+  I2C_END()
+};
+
 static volatile int32_t ADS8694_value[4] = { 0, 0, 0, 0};
 
 SIGNAL(TIMER1_COMPA_vect)
@@ -210,12 +239,23 @@ int main()
     }
     putstr("\r");
     if (i2c_idle()) {
+      putstr("\r\n");
+      for (uint8_t i = 0 ; i < 4 ; i++) {
+        for (int j = 0 ; j < 2 ; j++) {
+          puthex(dac8574_check.chan[i].no_pdo[j]);
+        }
+        putch(' ');
+        for (int j = 0 ; j < 3 ; j++) {
+          puthex(dac8574_check.chan[i].pdo[j]);
+        }
+        putch(',');
+      }
       cli();
       *dac8574.a.reg.data = *tmp.a.reg.data;
       *dac8574.b.reg.data = *tmp.b.reg.data;
       *dac8574.c.reg.data = *tmp.c.reg.data;
       *dac8574.d.reg.data = *tmp.d.reg.data;
-      i2c_start(write_all);
+      i2c_start(read_all);
       sei();
       putstr("\r\n");
     }
diff --git a/china_io-2019/avr/china-io.c b/china_io-2019/avr/china-io.c
index ac414e6bf68e27cbae7185e47d7856f694d44df5..2e90011f2dbd5b68f9886e3b2173d45448c29873 100644
--- a/china_io-2019/avr/china-io.c
+++ b/china_io-2019/avr/china-io.c
@@ -5,26 +5,13 @@
 #include "i2c_master.h"
 #include "serialio.h"
 
-/*
- * Serial I/O assignments:
- *   
- *   AI 0 -- Analog In 0
- *   AI 1 -- Analog In 1
- *   AI 2 -- Analog In 2
- *   AI 3 -- Analog In 3
- *
- *   AO 0 -- Analog Out 0
- *   AO 1 -- Analog Out 1
- *
- */
-
 /*
  * Used I/O pins
  *
- * PB4  SPI SS           / ADS8694 SPI CS
- * PB5  Programming MOSI / ADS8694 SPI SDI
- * PB6  Programming MISO / ADS8694 SPI SDO
- * PB7  Programming SCK  / ADS8694 SPI SCLK
+ * PB4  SPI SS           / ADS869X SPI CS
+ * PB5  Programming MOSI / ADS869X SPI SDI
+ * PB6  Programming MISO / ADS869X SPI SDO
+ * PB7  Programming SCK  / ADS869X SPI SCLK
  *
  * PC0  I2C SCL
  * PC1  I2C SDA
@@ -34,6 +21,7 @@
  *
  */
 
+/* Needed for ads869x.h definitions */
 #define DDR_SPI DDRB
 #define DD_MISO PB6
 #define DD_MOSI PB5
@@ -41,6 +29,22 @@
 #define DD_SS PB4
 #define PORT_SPI PORTB
 
+#include "ads869x.h"
+
+/*
+ * Serial I/O assignments:
+ *
+ *   AI 0 -- Analog In 0
+ *   AI 1 -- Analog In 1
+ *   AI 2 -- Analog In 2
+ *   AI 3 -- Analog In 3
+ *
+ *   AO 0 -- Analog Out 0
+ *   AO 1 -- Analog Out 1
+ *
+ */
+
+
 static volatile uint8_t serial_readchannels;
 static volatile uint8_t serial_writechannels;
 static volatile uint8_t serial_readconfig;
@@ -62,26 +66,6 @@ static volatile struct calibration {
   } channel[2];
 } calibration;
   
-static uint8_t ADS8694_W(
-  uint8_t length,
-  const __flash uint8_t *data)
-{
-  DDR_SPI |= (1<<DD_MOSI) | (1<<DD_SCK) | (1<<DD_SS);
-  SPCR &= (1<<SPIE);
-  SPCR = (1<<SPE) | (1<<MSTR) | (1<<CPHA);
-  SPSR = (1<<SPI2X);
-  PORT_SPI |= (1<<DD_MISO); // Pull up
-  
-  PORT_SPI &= ~(1<<DD_SS);
-  for (uint8_t i = 0 ; i < length ; i++) {
-    SPDR = data[i];
-    while ((SPSR & (1<<SPIF)) == 0) {}
-  }
-  uint8_t dummy = SPDR; // Clear SPIF flag
-  PORT_SPI |= (1<<DD_SS);
-  return dummy;
-}
-
 /*
  * DAC8574 4-channel D/A convert
  */
@@ -174,33 +158,28 @@ SIGNAL(USART_RXC_vect)
   }
 }
 
+static volatile int16_t timeout_timer = 0;
+
 SIGNAL(TIMER1_COMPA_vect)
 {
-  unsigned char data[5];
-
-  SPCR = (1<<SPE) | (1<<MSTR) | (1<< CPHA);
-  PORT_SPI &= ~(1<<DD_SS); // Chip select
-  SPDR = 0x00; // NOP
-  for (int i = 0 ; i < 5 ; i++) {
-    while ((SPSR & 0x80) == 0) { }
-    data[i] = SPDR;
-    if (i < 4) {
-      // More to read
-      SPDR = 0;
-    }
-  }
-  PORT_SPI |= (1<<DD_SS); // Chip deselect
+  timeout_timer++;
+
+  static const __flash uint8_t NOP[] = { 0x00, 0x00 };
+  uint8_t data[] = { 0x00, 0x00, 0x00 };
+
+  // Write NOP and read back 3 bytes (18 bits + channel #)
+  ADS869X_W_R(NOP, data);
 
   union {
     uint32_t i;
-    unsigned char b[4];
+    uint8_t b[4];
   } v;
   uint8_t chan;
   v.i = 0;
-  v.b[2] = data[2];
-  v.b[1] = data[3];
-  v.b[0] = data[4];
-  chan = (v.i>>2) & 0xf;
+  v.b[2] = data[0];
+  v.b[1] = data[1];
+  v.b[0] = data[2];
+  chan = (v.i>>2) & 0x03;
   adc.value[chan] = (v.i>>6);
 }
 
@@ -213,8 +192,60 @@ static uint32_t conf_millivolt(int32_t value)
   }
 }
 
+static uint8_t dac8574_check()
+{
+  static struct dac8574_check {
+    struct {
+      uint8_t no_pdo[2];
+      uint8_t pdo[3];
+    } chan[4];
+  } check;
+
+  static const __flash struct i2c_transcation read_all[] = {
+    I2C_WRITE_1(DAC8574ADDR, 0x10),
+    I2C_READ(DAC8574ADDR, 2, check.chan[0].no_pdo),
+    I2C_WRITE_1(DAC8574ADDR, 0x11),
+    I2C_READ(DAC8574ADDR, 3, check.chan[0].pdo),
+    I2C_WRITE_1(DAC8574ADDR, 0x12),
+    I2C_READ(DAC8574ADDR, 2, check.chan[1].no_pdo),
+    I2C_WRITE_1(DAC8574ADDR, 0x13),
+    I2C_READ(DAC8574ADDR, 3, check.chan[1].pdo),
+    I2C_WRITE_1(DAC8574ADDR, 0x14),
+    I2C_READ(DAC8574ADDR, 2, check.chan[2].no_pdo),
+    I2C_WRITE_1(DAC8574ADDR, 0x15),
+    I2C_READ(DAC8574ADDR, 3, check.chan[2].pdo),
+    I2C_WRITE_1(DAC8574ADDR, 0x16),
+    I2C_READ(DAC8574ADDR, 2, check.chan[3].no_pdo),
+    I2C_WRITE_1(DAC8574ADDR, 0x17),
+    I2C_READ(DAC8574ADDR, 3, check.chan[3].pdo),
+    I2C_CHAIN(write_all),
+    I2C_END()
+  };
+
+  // Read back channel data
+  timeout_timer = 0;
+  while (!i2c_idle() && timeout_timer < 14000) { }
+  if (!i2c_idle()) { return 0; }
+  i2c_start(read_all);
+
+  // Check that channel data with and without power down are equal
+  timeout_timer = 0;
+  while (!i2c_idle() && timeout_timer < 14000) { }
+  if (!i2c_idle()) { return 0; }
+
+  for (int i = 0 ; i < 4 ; i++) {
+    if ((check.chan[i].pdo[0] & 0x3f) != 0x3f) { return 0; }
+    if (check.chan[i].pdo[1] != check.chan[i].no_pdo[0]) { return 0; }
+    if (check.chan[i].pdo[2] != check.chan[i].no_pdo[1]) { return 0; }
+  }
+  return 1;
+}
+
 int main() 
 {
+  static uint8_t in_channel_count = 0;
+  static uint8_t out_channel_count = 0;
+
   eeprom_read_block((void*)&calibration, 0, sizeof(calibration));
   if (calibration.not_valid) {
     calibration.not_valid = 0;
@@ -243,15 +274,41 @@ int main()
   TWBR = 0x0a;      // Max allowed master speed 
   TWSR = 0x00;
 
-  /* Setup DAC8574 (SPI setup is done in ADS8694_W) */
-  static const __flash uint8_t RST[] = { 0x85, 0x00, 0x00 };
-  static const __flash uint8_t SEQUENCE[] = { (0x01<<1)|0x01, 0x0f, 0x00 };
-  static const __flash uint8_t FEATURES[] = { (0x03<<1)|0x01, 0x03, 0x00 };
-  static const __flash uint8_t AUTO_RST[] = { 0xa0, 0x00, 0x00, 0x00, 0x00 };
-  ADS8694_W(3, RST);
-  ADS8694_W(3, SEQUENCE);
-  ADS8694_W(3, FEATURES);
-  ADS8694_W(5, AUTO_RST);
+  /* Check and setup ADS869X (SPI setup is done in ADS869X_W) */
+  static const __flash uint8_t RST[] =
+    { 0x85, 0x00, 0x00 };
+  static const __flash uint8_t SEQUENCE_READ[] =
+    { ADS869X_REG_R(ADS869X_AUTO_SEQ_EN, 0x01), 0x00 };
+  static const __flash uint8_t SEQUENCE_0[] =
+    { ADS869X_REG_W(ADS869X_AUTO_SEQ_EN, 0x00), 0x00 };
+  static const __flash uint8_t SEQUENCE_4[] =
+    { ADS869X_REG_W(ADS869X_AUTO_SEQ_EN, 0x0f), 0x00 };
+  static const __flash uint8_t FEATURES[] =
+    { ADS869X_REG_W(ADS869X_FeatureSelect, 0x03), 0x00 };
+  static const __flash uint8_t AUTO_RST[] =
+    { 0xa0, 0x00, 0x00, 0x00, 0x00 };
+  uint8_t seq_bits;
+  ADS869X_W(RST);
+  seq_bits = ADS869X_W(SEQUENCE_READ);
+  if (seq_bits != 0xff) {
+    in_channel_count = 0;
+  } else {
+    ADS869X_W(SEQUENCE_0);
+    seq_bits = ADS869X_W(SEQUENCE_READ);
+    if (seq_bits == 0xf0 || seq_bits == 0x00) {
+      // ADS8694 or ADS8698
+      ADS869X_W(SEQUENCE_4);
+      in_channel_count = 4;
+    } else {
+      in_channel_count = 0;
+    }
+    seq_bits = ADS869X_W(SEQUENCE_READ);
+    if (seq_bits != 0x0f) {
+      in_channel_count = 0;
+    }
+  }
+  ADS869X_W(FEATURES);
+  ADS869X_W(AUTO_RST);
 
   /* Setup serialio communication */
   serialio_init();
@@ -262,7 +319,11 @@ int main()
   dac.value[0] = 0x8000;
   dac.value[1] = 0x8000;
   
-  sei(); // Global interrupt enable 
+  sei(); // Global interrupt enable
+
+  if (dac8574_check()) {
+    out_channel_count = 2;
+  }
 
   unsigned char readchannels = 0;
   while (1) {
@@ -303,26 +364,18 @@ int main()
     }
    
     if (config) {
-      CONF_ANALOG_IN(0, CONF_RESOLUTION(18));	// Analog In 0
-      CONF_ANALOG_IN(0, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(10000)));
-      CONF_ANALOG_IN(0, CONF_MAX(CONF_POSITIVE_MILLIVOLT(10000)));
-      CONF_ANALOG_IN(1, CONF_RESOLUTION(18));	// Analog In 1
-      CONF_ANALOG_IN(1, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(10000)));
-      CONF_ANALOG_IN(1, CONF_MAX(CONF_POSITIVE_MILLIVOLT(10000)));
-      CONF_ANALOG_IN(2, CONF_RESOLUTION(18));	// Analog In 2
-      CONF_ANALOG_IN(2, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(10000)));
-      CONF_ANALOG_IN(2, CONF_MAX(CONF_POSITIVE_MILLIVOLT(10000)));
-      CONF_ANALOG_IN(3, CONF_RESOLUTION(18));	// Analog In 3
-      CONF_ANALOG_IN(3, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(10000)));
-      CONF_ANALOG_IN(3, CONF_MAX(CONF_POSITIVE_MILLIVOLT(10000)));
-
-      CONF_ANALOG_OUT(0, CONF_RESOLUTION(16));	// Analog Out 0
-      CONF_ANALOG_OUT(0, CONF_MIN(conf_millivolt(calibration.channel[0].min)));
-      CONF_ANALOG_OUT(0, CONF_MAX(conf_millivolt(calibration.channel[0].max)));
-      CONF_ANALOG_OUT(1, CONF_RESOLUTION(16));	// Analog Out 1
-      CONF_ANALOG_OUT(1, CONF_MIN(conf_millivolt(calibration.channel[1].min)));
-      CONF_ANALOG_OUT(1, CONF_MAX(conf_millivolt(calibration.channel[1].max)));
-
+      for (int i = 0 ; i < in_channel_count ; i++) {
+        CONF_ANALOG_IN(i, CONF_RESOLUTION(18));	// Analog In 0
+        CONF_ANALOG_IN(i, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(10000)));
+        CONF_ANALOG_IN(i, CONF_MAX(CONF_POSITIVE_MILLIVOLT(10000)));
+      }
+      for (int i = 0 ; i < out_channel_count ; i++) {
+        CONF_ANALOG_OUT(i, CONF_RESOLUTION(16));
+        CONF_ANALOG_OUT(i, CONF_MIN(conf_millivolt(
+                                      calibration.channel[i].min)));
+        CONF_ANALOG_OUT(i, CONF_MAX(conf_millivolt(
+                                      calibration.channel[i].max)));
+      }
       CONF_END();
     }
   }