353 lines
9.6 KiB
C
353 lines
9.6 KiB
C
#include "ads8691.h"
|
|
#include "edc20_pin_ctrl.h"
|
|
|
|
#include "nrf_log.h"
|
|
#include "nrf_spim.h"
|
|
|
|
#include "FreeRTOS.h"
|
|
#include "task.h"
|
|
|
|
#include <string.h>
|
|
|
|
/*
|
|
* ADS8691
|
|
* Features:
|
|
* -18-Bit ADC With Integrated Analog Front-End
|
|
* -High Speed: 1 MSPS
|
|
*
|
|
* Spi data:
|
|
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Input | 9-bit address | 16-bit data |
|
|
* | Commands | | |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
*
|
|
* -CMD [7bits]
|
|
* 0b11000xx CLEAR_HWORD
|
|
* 0b11001xx READ_HWORD
|
|
* 0b01001xx READ
|
|
* 0b1101000 WRITE (We used this CMD)
|
|
* 0b1101001 WRITE
|
|
* 0b1101010 WRITE
|
|
* 0b11011xx SET_HWORD
|
|
*
|
|
* -Address [9bits]
|
|
* 00h DEVICE_ID_REG
|
|
* 04h RST_PWRCTL_REG
|
|
* 08h SDI_CTL_REG
|
|
* 0Ch SDO_CTL_REG
|
|
* 10h DATAOUT_CTL_REG
|
|
* 14h RANGE_SEL_REG
|
|
* 20h ALARM_REG
|
|
* 24h ALARM_H_TH_REG
|
|
* 28h ALARM_L_TH_REG
|
|
*
|
|
*/
|
|
|
|
#define ADS8691_CMD_NOP 0b0000000 // 7 bits
|
|
#define ADS8691_CMD_CLR_HWORD 0b1100000
|
|
#define ADS8691_CMD_READ_HWORD 0b1100100
|
|
#define ADS8691_CMD_READ 0b0100100
|
|
#define ADS8691_CMD_WRITE 0b1101000
|
|
#define ADS8691_CMD_WRITE_MSB 0b1101001
|
|
#define ADS8691_CMD_WRITE_LSB 0b1101010
|
|
#define ADS8691_CMD_SET_HWORD 0b1101100
|
|
|
|
#define DEVICE_ID_REG 0x0000
|
|
#define RST_PWRCTL_REG 0x0004
|
|
#define SDI_CTL_REG 0x0008
|
|
#define DATAOUT_CTL_REG 0x0010
|
|
#define RANGE_SEL_REG 0x0014
|
|
#define ALARM_H_TH_REG 0x0024
|
|
#define ALARM_L_TH_REG 0x0028
|
|
|
|
#define ADS8691_SPI_MODE0 0b00
|
|
#define ADS8691_SPI_MODE1 0b01
|
|
#define ADS8691_SPI_MODE2 0b10
|
|
#define ADS8691_SPI_MODE3 0b11
|
|
|
|
#define INT_VREF_ENABLE 0 // Internal reference is enabled
|
|
#define INT_VREF_DISABLE 1 // Internal reference is disabled
|
|
#define VREF_NP_3P000 0b0000 // +/- 3.000 x Vref
|
|
#define VREF_NP_2P500 0b0001 // +/- 2.500 x Vref
|
|
#define VREF_NP_1P500 0b0010 // +/- 1.500 x Vref
|
|
#define VREF_NP_1P250 0b0011 // +/- 1.250 x Vref
|
|
#define VREF_NP_0P625 0b0100 // +/- 0.625 x Vref
|
|
#define VREF_P_3P000 0b1000 // 3.000 x Vref
|
|
#define VREF_P_2P500 0b1001 // 2.500 x Vref
|
|
#define VREF_P_1P500 0b1010 // 1.500 x Vref
|
|
#define VREF_P_1P250 0b1011 // 1.250 x Vref
|
|
|
|
typedef union
|
|
{
|
|
struct
|
|
{
|
|
uint16_t data;
|
|
uint16_t addr : 9;
|
|
uint16_t cmd : 7;
|
|
};
|
|
uint32_t val;
|
|
} opcode_t;
|
|
|
|
typedef union
|
|
{
|
|
struct
|
|
{
|
|
uint16_t data_val : 3;
|
|
uint16_t par_en : 1;
|
|
uint16_t : 4;
|
|
uint16_t range_incl : 1;
|
|
uint16_t : 1;
|
|
uint16_t in_active_alarm_incl : 2;
|
|
uint16_t vdd_active_alarm_incl : 2;
|
|
uint16_t device_addr_incl : 1;
|
|
uint16_t : 1;
|
|
};
|
|
uint16_t val;
|
|
} dataout_ctl_t;
|
|
|
|
typedef union
|
|
{
|
|
struct
|
|
{
|
|
uint16_t range_sel : 4;
|
|
uint16_t : 2;
|
|
uint16_t intref_dis : 1;
|
|
uint16_t : 1;
|
|
uint16_t : 8;
|
|
};
|
|
uint16_t val;
|
|
} range_sel_t;
|
|
static dataout_ctl_t m_dataout_ctl;
|
|
static range_sel_t m_range_sel;
|
|
static uint32_t m_channel = 0;
|
|
static uint32_t m_flush = 0;
|
|
static void write_cmd(uint32_t cmd, uint32_t addr, uint16_t data)
|
|
{
|
|
opcode_t opcode = {
|
|
.cmd = cmd,
|
|
.addr = addr,
|
|
.data = data,
|
|
};
|
|
uint32_t tx = __REV(opcode.val);
|
|
spi2_write(CS_ADC_PIN, (uint8_t *)&tx, sizeof(tx), NULL, 0);
|
|
}
|
|
|
|
static uint16_t read_hword(void)
|
|
{
|
|
uint32_t tx = 0x00000000;
|
|
uint32_t rx = 0x00000000;
|
|
spi2_write(CS_ADC_PIN, (uint8_t *)&tx, sizeof(tx), (uint8_t *)&rx, sizeof(rx));
|
|
rx = __REV(rx);
|
|
return rx >> 16;
|
|
}
|
|
|
|
static uint32_t read_word(void)
|
|
{
|
|
uint32_t tx = 0x00000000;
|
|
uint32_t rx = 0x00000000;
|
|
spi2_write(CS_ADC_PIN, (uint8_t *)&tx, sizeof(tx), (uint8_t *)&rx, sizeof(rx));
|
|
rx = __REV(rx);
|
|
return rx;
|
|
}
|
|
|
|
int write_dev_id(uint32_t new_id)
|
|
{
|
|
write_cmd(ADS8691_CMD_WRITE, DEVICE_ID_REG + 2, new_id & 0b1111);
|
|
write_cmd(ADS8691_CMD_READ_HWORD, DEVICE_ID_REG + 2, 0x0000);
|
|
return read_hword() == (new_id & 0b1111) ? 0 : -1;
|
|
}
|
|
|
|
uint32_t read_dev_id(void)
|
|
{
|
|
write_cmd(ADS8691_CMD_READ_HWORD, DEVICE_ID_REG + 2, 0x0000);
|
|
return read_hword();
|
|
}
|
|
|
|
int write_dataout_ctrl(dataout_ctl_t *dataout_ctl)
|
|
{
|
|
m_flush = 1;
|
|
write_cmd(ADS8691_CMD_WRITE, DATAOUT_CTL_REG, dataout_ctl->val);
|
|
return 0;
|
|
}
|
|
|
|
int read_dataout_ctrl(dataout_ctl_t *dataout_ctl)
|
|
{
|
|
write_cmd(ADS8691_CMD_READ_HWORD, DATAOUT_CTL_REG, 0x0000);
|
|
dataout_ctl->val = read_hword();
|
|
return 0;
|
|
}
|
|
|
|
int write_range_sel(range_sel_t *range_sel)
|
|
{
|
|
m_flush = 1;
|
|
write_cmd(ADS8691_CMD_WRITE, RANGE_SEL_REG, range_sel->val);
|
|
return 0;
|
|
}
|
|
|
|
int read_range_sel(range_sel_t *range_sel)
|
|
{
|
|
write_cmd(ADS8691_CMD_READ_HWORD, DATAOUT_CTL_REG, 0x0000);
|
|
range_sel->val = read_hword();
|
|
return 0;
|
|
}
|
|
|
|
double adc_convert_volt(uint16_t range_sel, int32_t val_18bit)
|
|
{
|
|
// LSB[uV]
|
|
#define LSB_VREF_NP_3P000 93.75
|
|
#define LSB_VREF_NP_2P500 78.125
|
|
#define LSB_VREF_NP_1P500 48.875
|
|
#define LSB_VREF_NP_1P250 39.06
|
|
#define LSB_VREF_NP_0P625 19.53
|
|
#define LSB_VREF_P_3P000 46.875
|
|
#define LSB_VREF_P_2P500 39.06
|
|
#define LSB_VREF_P_1P500 23.43
|
|
#define LSB_VREF_P_1P250 19.53
|
|
|
|
// FULL-SCALE RANGE[V]
|
|
#define FSR_VREF_NP_3P000 24.576
|
|
#define FSR_VREF_NP_2P500 20.48
|
|
#define FSR_VREF_NP_1P500 12.288
|
|
#define FSR_VREF_NP_1P250 10.24
|
|
#define FSR_VREF_NP_0P625 5.12
|
|
#define FSR_VREF_P_3P000 12.288
|
|
#define FSR_VREF_P_2P500 10.24
|
|
#define FSR_VREF_P_1P500 6.144
|
|
#define FSR_VREF_P_1P250 5.12
|
|
|
|
double volt;
|
|
|
|
if (range_sel == VREF_NP_3P000)
|
|
volt = (double)val_18bit * LSB_VREF_NP_3P000 / 1000000 - FSR_VREF_NP_3P000 / 2;
|
|
else if (range_sel == VREF_NP_2P500)
|
|
volt = (double)val_18bit * LSB_VREF_NP_2P500 / 1000000 - FSR_VREF_NP_2P500 / 2;
|
|
else if (range_sel == VREF_NP_1P500)
|
|
volt = (double)val_18bit * LSB_VREF_NP_1P500 / 1000000 - FSR_VREF_NP_1P500 / 2;
|
|
else if (range_sel == VREF_NP_1P250)
|
|
volt = (double)val_18bit * LSB_VREF_NP_1P250 / 1000000 - FSR_VREF_NP_1P250 / 2;
|
|
else if (range_sel == VREF_NP_0P625)
|
|
volt = (double)val_18bit * LSB_VREF_NP_0P625 / 1000000 - FSR_VREF_NP_0P625 / 2;
|
|
else if (range_sel == VREF_P_3P000)
|
|
volt = (double)val_18bit * LSB_VREF_P_3P000 / 1000000 - FSR_VREF_P_3P000 / 2;
|
|
else if (range_sel == VREF_P_2P500)
|
|
volt = (double)val_18bit * LSB_VREF_P_2P500 / 1000000 - FSR_VREF_P_2P500 / 2;
|
|
else if (range_sel == VREF_P_3P000)
|
|
volt = (double)val_18bit * LSB_VREF_P_1P500 / 1000000 - FSR_VREF_P_1P500 / 2;
|
|
else if (range_sel == VREF_P_3P000)
|
|
volt = (double)val_18bit * LSB_VREF_P_1P250 / 1000000 - FSR_VREF_P_1P250 / 2;
|
|
|
|
NRF_LOG_INFO("adc_convert_volt(input_range_idx:%d, val_18bit:%d)", range_sel, val_18bit);
|
|
{
|
|
char str[32];
|
|
snprintf(str, sizeof(str), "%.16lf", volt);
|
|
NRF_LOG_INFO("adc_convert_result: %sV", str);
|
|
}
|
|
|
|
return volt;
|
|
}
|
|
|
|
int ads8691_read(uint32_t channel, int32_t *adc_val)
|
|
{
|
|
if (m_channel != channel)
|
|
{
|
|
m_channel = channel;
|
|
m_flush = 1;
|
|
nrf_gpio_pin_write(ADCA0_PIN, m_channel & (0x01 << 0));
|
|
nrf_gpio_pin_write(ADCA1_PIN, m_channel & (0x01 << 1));
|
|
nrf_gpio_pin_write(ADCA2_PIN, m_channel & (0x01 << 2));
|
|
NRF_LOG_INFO("channel:%d, [A2,A1,A0]=[%d %d %d]", channel, m_channel & (0x01 << 2), m_channel & (0x01 << 1), m_channel & (0x01 << 0));
|
|
}
|
|
|
|
if (m_flush)
|
|
{
|
|
m_flush = 0;
|
|
read_word();
|
|
}
|
|
|
|
uint32_t val = read_word();
|
|
*adc_val = val >> 14;
|
|
adc_convert_volt(m_range_sel.range_sel, *adc_val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ads8691_gain(adc_gain_t gain)
|
|
{
|
|
switch (gain)
|
|
{
|
|
case NP_GAIN_3P000:
|
|
m_range_sel.range_sel = VREF_NP_3P000;
|
|
break;
|
|
case NP_GAIN_2P500:
|
|
m_range_sel.range_sel = VREF_NP_2P500;
|
|
break;
|
|
case NP_GAIN_1P500:
|
|
m_range_sel.range_sel = VREF_NP_1P500;
|
|
break;
|
|
case NP_GAIN_1P250:
|
|
m_range_sel.range_sel = VREF_NP_1P250;
|
|
break;
|
|
case NP_GAIN_0P625:
|
|
m_range_sel.range_sel = VREF_NP_0P625;
|
|
break;
|
|
case P_GAIN_3P000:
|
|
m_range_sel.range_sel = VREF_P_3P000;
|
|
break;
|
|
case P_GAIN_2P500:
|
|
m_range_sel.range_sel = VREF_P_2P500;
|
|
break;
|
|
case P_GAIN_1P500:
|
|
m_range_sel.range_sel = VREF_P_1P500;
|
|
break;
|
|
case P_GAIN_1P250:
|
|
m_range_sel.range_sel = VREF_P_1P250;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
write_range_sel(&m_range_sel);
|
|
return 0;
|
|
}
|
|
|
|
int ads8691_reset(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int ads8691_init(void)
|
|
{
|
|
int ret = -1;
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
if (read_dev_id() == 0b0101)
|
|
{
|
|
ret = 0;
|
|
break;
|
|
}
|
|
if (write_dev_id(0b0101) == 0)
|
|
{
|
|
ret = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ret == 0)
|
|
{
|
|
read_dataout_ctrl(&m_dataout_ctl);
|
|
read_range_sel(&m_range_sel);
|
|
nrf_gpio_pin_write(ADCA0_PIN, m_channel & (0x01 << 0));
|
|
nrf_gpio_pin_write(ADCA1_PIN, m_channel & (0x01 << 1));
|
|
nrf_gpio_pin_write(ADCA2_PIN, m_channel & (0x01 << 2));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
adc_drv_if_t ads8691 = {
|
|
.init = ads8691_init,
|
|
.reset = ads8691_reset,
|
|
.read = ads8691_read,
|
|
.gain = ads8691_gain,
|
|
};
|