Merge pull request #410 from UncleRus/extras/ad770x
Driver for AD7705/AD7706 SPI ADC
This commit is contained in:
commit
e17b1a5db6
5 changed files with 363 additions and 0 deletions
4
examples/ad770x/Makefile
Normal file
4
examples/ad770x/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
PROGRAM = ad770x
|
||||||
|
EXTRA_COMPONENTS = extras/ad770x
|
||||||
|
#ESPBAUD = 460800
|
||||||
|
include ../../common.mk
|
50
examples/ad770x/main.c
Normal file
50
examples/ad770x/main.c
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Example of using AD7705/AD7706 driver
|
||||||
|
*
|
||||||
|
* Part of esp-open-rtos
|
||||||
|
* Copyright (C) 2017 Ruslan V. Uss <unclerus@gmail.com>
|
||||||
|
* BSD Licensed as described in the file LICENSE
|
||||||
|
*/
|
||||||
|
#include <esp/uart.h>
|
||||||
|
#include <espressif/esp_common.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <i2c/i2c.h>
|
||||||
|
#include <ad770x/ad770x.h>
|
||||||
|
#include <FreeRTOS.h>
|
||||||
|
#include <task.h>
|
||||||
|
|
||||||
|
#define CS_PIN 2
|
||||||
|
#define AIN_CHANNEL 0 // AIN1+,AIN1- for AD7705
|
||||||
|
|
||||||
|
static const ad770x_params_t dev = {
|
||||||
|
.cs_pin = CS_PIN,
|
||||||
|
.master_clock = AD770X_MCLK_4_9152MHz, // 4.9152 MHz
|
||||||
|
.bipolar = false, // Unipolar mode
|
||||||
|
.gain = AD770X_GAIN_1, // No gain
|
||||||
|
.update_rate = AD770X_RATE_50 // 50 Hz output update rate
|
||||||
|
};
|
||||||
|
|
||||||
|
void user_init(void)
|
||||||
|
{
|
||||||
|
uart_set_baud(0, 115200);
|
||||||
|
printf("SDK version:%s\n", sdk_system_get_sdk_version());
|
||||||
|
|
||||||
|
while (ad770x_init(&dev, AIN_CHANNEL) != 0)
|
||||||
|
{
|
||||||
|
printf("Cannot initialize AD7705\n");
|
||||||
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// wait for data
|
||||||
|
while (!ad770x_data_ready(&dev, AIN_CHANNEL)) {}
|
||||||
|
|
||||||
|
// Read result
|
||||||
|
uint16_t raw = ad770x_raw_adc_value(&dev, AIN_CHANNEL);
|
||||||
|
|
||||||
|
printf("Raw ADC value: %d\n", raw);
|
||||||
|
|
||||||
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
}
|
182
extras/ad770x/ad770x.c
Normal file
182
extras/ad770x/ad770x.c
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
/**
|
||||||
|
* Driver for AD7705/AD7706 SPI ADC
|
||||||
|
*
|
||||||
|
* Part of esp-open-rtos
|
||||||
|
* Copyright (C) 2017 Ruslan V. Uss <unclerus@gmail.com>
|
||||||
|
* BSD Licensed as described in the file LICENSE
|
||||||
|
*/
|
||||||
|
#include "ad770x.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <esp/gpio.h>
|
||||||
|
#include <esp/spi.h>
|
||||||
|
#include <espressif/esp_common.h>
|
||||||
|
|
||||||
|
#define AD770X_DEBUG
|
||||||
|
|
||||||
|
#define BUS 1
|
||||||
|
#define INIT_TIMEOUT 500000 // 500ms
|
||||||
|
|
||||||
|
#ifdef AD770X_DEBUG
|
||||||
|
#include <stdio.h>
|
||||||
|
#define debug(fmt, ...) printf("%s" fmt "\n", "AD770x: ", ## __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define debug(fmt, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define timeout_expired(start, len) ((uint32_t)(sdk_system_get_time() - (start)) >= (len))
|
||||||
|
|
||||||
|
#define _BV(x) (1 << (x))
|
||||||
|
|
||||||
|
#define REG_COMM 0x00 // 8 bits
|
||||||
|
#define REG_SETUP 0x01 // 8 bits
|
||||||
|
#define REG_CLOCK 0x02 // 8 bits
|
||||||
|
#define REG_DATA 0x03 // 16 bits
|
||||||
|
#define REG_TEST 0x04 // 8 bits
|
||||||
|
#define REG_OFFS 0x06 // 24 bits
|
||||||
|
#define REG_GAIN 0x07 // 24 bits
|
||||||
|
|
||||||
|
#define BIT_COMM_CH0 0
|
||||||
|
#define BIT_COMM_CH1 1
|
||||||
|
#define BIT_COMM_STBY 2
|
||||||
|
#define BIT_COMM_RW 3
|
||||||
|
#define BIT_COMM_RS0 4
|
||||||
|
#define BIT_COMM_RS1 5
|
||||||
|
#define BIT_COMM_RS2 6
|
||||||
|
#define BIT_COMM_DRDY 7
|
||||||
|
|
||||||
|
#define MASK_COMM_CH 0x03
|
||||||
|
#define MASK_COMM_RS 0x70
|
||||||
|
|
||||||
|
#define BIT_CLOCK_FS0 0
|
||||||
|
#define BIT_CLOCK_FS1 1
|
||||||
|
#define BIT_CLOCK_CLK 2
|
||||||
|
#define BIT_CLOCK_CLKDIV 3
|
||||||
|
#define BIT_CLOCK_CLKDIS 4
|
||||||
|
|
||||||
|
#define MASK_CLOCK_FS 0x03
|
||||||
|
#define MASK_CLOCK_CLK 0x0c
|
||||||
|
|
||||||
|
#define BIT_SETUP_FSYNC 0
|
||||||
|
#define BIT_SETUP_BUF 1
|
||||||
|
#define BIT_SETUP_BU 2
|
||||||
|
#define BIT_SETUP_G0 3
|
||||||
|
#define BIT_SETUP_G1 4
|
||||||
|
#define BIT_SETUP_G2 5
|
||||||
|
#define BIT_SETUP_MD0 6
|
||||||
|
#define BIT_SETUP_MD1 7
|
||||||
|
|
||||||
|
#define MASK_SETUP_GAIN 0x38
|
||||||
|
#define MASK_SETUP_MODE 0xc0
|
||||||
|
|
||||||
|
static const spi_settings_t config = {
|
||||||
|
.endianness = SPI_BIG_ENDIAN,
|
||||||
|
.msb = true,
|
||||||
|
.minimal_pins = true,
|
||||||
|
.mode = SPI_MODE3,
|
||||||
|
.freq_divider = SPI_FREQ_DIV_500K
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t write(uint8_t cs_pin, uint8_t value)
|
||||||
|
{
|
||||||
|
spi_settings_t old;
|
||||||
|
spi_get_settings(BUS, &old);
|
||||||
|
spi_set_settings(BUS, &config);
|
||||||
|
|
||||||
|
gpio_write(cs_pin, false);
|
||||||
|
uint8_t res = spi_transfer_8(BUS, value);
|
||||||
|
//debug("byte wr: 0x%02x", value);
|
||||||
|
gpio_write(cs_pin, true);
|
||||||
|
|
||||||
|
spi_set_settings(BUS, &old);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static uint8_t read_byte(uint8_t cs_pin)
|
||||||
|
{
|
||||||
|
return write(cs_pin, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t read_word(uint8_t cs_pin)
|
||||||
|
{
|
||||||
|
spi_settings_t old;
|
||||||
|
spi_get_settings(BUS, &old);
|
||||||
|
spi_set_settings(BUS, &config);
|
||||||
|
|
||||||
|
gpio_write(cs_pin, false);
|
||||||
|
uint16_t res = spi_transfer_16(BUS, 0);
|
||||||
|
gpio_write(cs_pin, true);
|
||||||
|
|
||||||
|
spi_set_settings(BUS, &old);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prepare(uint8_t channel, uint8_t reg, bool read, uint8_t cs_pin, bool standby)
|
||||||
|
{
|
||||||
|
write(cs_pin,
|
||||||
|
(channel & MASK_COMM_CH) |
|
||||||
|
(read ? _BV(BIT_COMM_RW) : 0) |
|
||||||
|
((reg << BIT_COMM_RS0) & MASK_COMM_RS) |
|
||||||
|
(standby ? _BV(BIT_COMM_STBY) : 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ad770x_init(const ad770x_params_t *params, uint8_t channel)
|
||||||
|
{
|
||||||
|
if (!spi_set_settings(BUS, &config))
|
||||||
|
{
|
||||||
|
debug("Cannot init SPI");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((params->master_clock >= AD770X_MCLK_2_4576MHz && params->update_rate < AD770X_RATE_50)
|
||||||
|
|| (params->master_clock < AD770X_MCLK_2_4576MHz && params->update_rate > AD770X_RATE_200))
|
||||||
|
{
|
||||||
|
debug("Invalid update rate / master clock combination");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_enable(params->cs_pin, GPIO_OUTPUT);
|
||||||
|
gpio_write(params->cs_pin, true);
|
||||||
|
|
||||||
|
prepare(channel, REG_CLOCK, false, params->cs_pin, false);
|
||||||
|
write(params->cs_pin,
|
||||||
|
((params->master_clock << BIT_CLOCK_CLK) & MASK_CLOCK_CLK) |
|
||||||
|
(params->update_rate & MASK_CLOCK_FS)
|
||||||
|
);
|
||||||
|
|
||||||
|
ad770x_set_mode(params, channel, AD770X_MODE_CALIBRATION);
|
||||||
|
|
||||||
|
uint32_t start = sdk_system_get_time();
|
||||||
|
while (!ad770x_data_ready(params, channel))
|
||||||
|
if (timeout_expired(start, INIT_TIMEOUT))
|
||||||
|
{
|
||||||
|
debug("Timeout while calibration");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ad770x_set_mode(const ad770x_params_t *params, uint8_t channel, ad770x_mode_t mode)
|
||||||
|
{
|
||||||
|
prepare(channel, REG_SETUP, false, params->cs_pin, false);
|
||||||
|
write(params->cs_pin,
|
||||||
|
((params->gain << BIT_SETUP_G0) & MASK_SETUP_GAIN) |
|
||||||
|
(params->bipolar ? 0 : _BV(BIT_SETUP_BU)) |
|
||||||
|
((mode << BIT_SETUP_MD0) & MASK_SETUP_MODE)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ad770x_data_ready(const ad770x_params_t *params, uint8_t channel)
|
||||||
|
{
|
||||||
|
prepare(channel, REG_COMM, true, params->cs_pin, false);
|
||||||
|
return !(read_byte(params->cs_pin) & _BV(BIT_COMM_DRDY));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t ad770x_raw_adc_value(const ad770x_params_t *params, uint8_t channel)
|
||||||
|
{
|
||||||
|
prepare(channel, REG_DATA, true, params->cs_pin, false);
|
||||||
|
return read_word(params->cs_pin);
|
||||||
|
}
|
||||||
|
|
118
extras/ad770x/ad770x.h
Normal file
118
extras/ad770x/ad770x.h
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/**
|
||||||
|
* Driver for AD7705/AD7706 SPI ADC
|
||||||
|
*
|
||||||
|
* Part of esp-open-rtos
|
||||||
|
* Copyright (C) 2017 Ruslan V. Uss <unclerus@gmail.com>
|
||||||
|
* BSD Licensed as described in the file LICENSE
|
||||||
|
*/
|
||||||
|
#ifndef _EXTRAS_AD770X_H_
|
||||||
|
#define _EXTRAS_AD770X_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Input gain
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
AD770X_GAIN_1 = 0,
|
||||||
|
AD770X_GAIN_2,
|
||||||
|
AD770X_GAIN_4,
|
||||||
|
AD770X_GAIN_8,
|
||||||
|
AD770X_GAIN_16,
|
||||||
|
AD770X_GAIN_32,
|
||||||
|
AD770X_GAIN_64,
|
||||||
|
AD770X_GAIN_128
|
||||||
|
} ad770x_gain_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Master clock frequency
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
AD770X_MCLK_1MHz = 0, //!< 1 MHz
|
||||||
|
AD770X_MCLK_2MHz, //!< 2 MHz
|
||||||
|
AD770X_MCLK_2_4576MHz, //!< 2.4576 MHz
|
||||||
|
AD770X_MCLK_4_9152MHz, //!< 4.9152 MHz
|
||||||
|
} ad770x_master_clock_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output update rate
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
AD770X_RATE_20 = 0, //!< Output update rate is 20 Hz, -3 dB filter cutoff = 5.24 Hz, works with 1 or 2 MHz master clock
|
||||||
|
AD770X_RATE_25, //!< Output update rate is 25 Hz, -3 dB filter cutoff = 6.55 Hz, works with 1 or 2 MHz master clock
|
||||||
|
AD770X_RATE_100, //!< Output update rate is 100 Hz, -3 dB filter cutoff = 26.2 Hz, works with 1 or 2 MHz master clock
|
||||||
|
AD770X_RATE_200, //!< Output update rate is 200 Hz, -3 dB filter cutoff = 52.4 Hz, works with 1 or 2 MHz master clock
|
||||||
|
AD770X_RATE_50, //!< Output update rate is 50 Hz, -3 dB filter cutoff = 13.1 Hz, works with 2.4576 or 4.9152 MHz master clock
|
||||||
|
AD770X_RATE_60, //!< Output update rate is 60 Hz, -3 dB filter cutoff = 15.7 Hz, works with 2.4576 or 4.9152 MHz master clock
|
||||||
|
AD770X_RATE_250, //!< Output update rate is 250 Hz, -3 dB filter cutoff = 65.5 Hz, works with 2.4576 or 4.9152 MHz master clock
|
||||||
|
AD770X_RATE_500, //!< Output update rate is 500 Hz, -3 dB filter cutoff = 131 Hz, works with 2.4576 or 4.9152 MHz master clock
|
||||||
|
} ad770x_update_rate_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Device mode
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
AD770X_MODE_NORMAL = 0,
|
||||||
|
AD770X_MODE_CALIBRATION,
|
||||||
|
AD770X_MODE_ZERO_CALIBRATION,
|
||||||
|
AD770X_MODE_FULL_CALIBRATION
|
||||||
|
} ad770x_mode_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Device descriptor
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t cs_pin; //!< GPIO pin for chip select
|
||||||
|
ad770x_master_clock_t master_clock; //!< Master clock frequency
|
||||||
|
bool bipolar; //!< Bipolar/Unipolar mode
|
||||||
|
ad770x_gain_t gain; //!< Input gain
|
||||||
|
ad770x_update_rate_t update_rate; //!< Output update rate
|
||||||
|
} ad770x_params_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init device and setup channel params
|
||||||
|
* @param params Device descriptor pointer
|
||||||
|
* @param channel Input channel
|
||||||
|
* @return Non-zero when error occured
|
||||||
|
*/
|
||||||
|
int ad770x_init(const ad770x_params_t *params, uint8_t channel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set device mode (see datasheet)
|
||||||
|
* @param params Device descriptor pointer
|
||||||
|
* @param channel Input channel
|
||||||
|
* @param mode Device mode
|
||||||
|
*/
|
||||||
|
void ad770x_set_mode(const ad770x_params_t *params, uint8_t channel, ad770x_mode_t mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get conversion status
|
||||||
|
* @param params Device descriptor pointer
|
||||||
|
* @param channel Input channel
|
||||||
|
* @return true when data is ready
|
||||||
|
*/
|
||||||
|
bool ad770x_data_ready(const ad770x_params_t *params, uint8_t channel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get converted ADC value
|
||||||
|
* @param params Device descriptor pointer
|
||||||
|
* @param channel Input channel
|
||||||
|
* @return Raw ADC value
|
||||||
|
*/
|
||||||
|
uint16_t ad770x_raw_adc_value(const ad770x_params_t *params, uint8_t channel);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _EXTRAS_AD770X_H_ */
|
9
extras/ad770x/component.mk
Normal file
9
extras/ad770x/component.mk
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# Component makefile for extras/ad770x (AD7705/AD7706 driver)
|
||||||
|
|
||||||
|
# expected anyone using ADC driver includes it as 'ad770x/ad770x.h'
|
||||||
|
INC_DIRS += $(ad770x_ROOT)..
|
||||||
|
|
||||||
|
# args for passing into compile rule generation
|
||||||
|
ad770x_SRC_DIR = $(ad770x_ROOT)
|
||||||
|
|
||||||
|
$(eval $(call component_compile_rules,ad770x))
|
Loading…
Reference in a new issue