Commit 8756dffa authored by Anders Blomdell's avatar Anders Blomdell
Browse files

Move ADS869X code to it's own file. Add detection of I/O chips.

parent bdabdf28
......@@ -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
......
#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
......@@ -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");
}
......
......@@ -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();
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment