Files
microchip-application-bmd38…/ads8691.c
T
2024-06-27 21:30:37 +08:00

337 lines
9.1 KiB
C

#include "ads8691.h"
#include "elite_board.h"
#include "nrf_delay.h"
#include "FreeRTOS.h"
#include "task.h"
#include <string.h>
#if (DEF_ADS8691_ENABLED)
/*
* 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 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);
spim_xfer(CS_ADC_PIN, NRF_SPIM_MODE_0, (uint8_t *)&tx, sizeof(tx), NULL, 0);
}
static uint16_t read_hword(void)
{
uint32_t tx = 0x00000000;
uint32_t rx = 0x00000000;
spim_xfer(CS_ADC_PIN, NRF_SPIM_MODE_0, (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;
spim_xfer(CS_ADC_PIN, NRF_SPIM_MODE_0, (uint8_t *)&tx, sizeof(tx), (uint8_t *)&rx, sizeof(rx));
rx = __REV(rx);
return rx;
}
static 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();
}
static int write_dataout_ctrl(dataout_ctl_t *dataout_ctl)
{
write_cmd(ADS8691_CMD_WRITE, DATAOUT_CTL_REG, dataout_ctl->val);
return 0;
}
static 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;
}
static int write_range_sel(range_sel_t *range_sel)
{
write_cmd(ADS8691_CMD_WRITE, RANGE_SEL_REG, range_sel->val);
return 0;
}
static 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;
}
static 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_1P500)
volt = (double)val_18bit * LSB_VREF_P_1P500 / 1000000 - FSR_VREF_P_1P500 / 2;
else if (range_sel == VREF_P_1P250)
volt = (double)val_18bit * LSB_VREF_P_1P250 / 1000000 - FSR_VREF_P_1P250 / 2;
return volt;
}
static int ads8691_read(uint32_t channel, int32_t *adc_val)
{
if (m_channel != channel)
{
m_channel = channel;
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_delay_us(100);
}
read_word();
uint32_t val = read_word();
*adc_val = val >> 14;
return 0;
}
static int ads8691_read_milivolt(uint32_t channel, float *mv)
{
int32_t val = 0;
ads8691_read(channel, &val);
*mv = adc_convert_volt(m_range_sel.range_sel, val) * 1000.0;
return 0;
}
static int ads8691_gain(adc_gain_t gain)
{
switch (gain)
{
case GAIN_3P000:
m_range_sel.range_sel = VREF_NP_3P000;
break;
case GAIN_2P500:
m_range_sel.range_sel = VREF_NP_2P500;
break;
case GAIN_1P500:
m_range_sel.range_sel = VREF_NP_1P500;
break;
case GAIN_1P250:
m_range_sel.range_sel = VREF_NP_1P250;
break;
case GAIN_0P625:
m_range_sel.range_sel = VREF_NP_0P625;
break;
default:
break;
}
write_range_sel(&m_range_sel);
return 0;
}
static int ads8691_reset(void)
{
return 0;
}
static 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;
}
const adc_drv_if_t ads8691 = {
.init = ads8691_init,
.reset = ads8691_reset,
.read = ads8691_read,
.gain = ads8691_gain,
.read_milivolt = ads8691_read_milivolt,
};
#endif /* ! DEF_ADS8691_ENABLED */