Other Parts Discussed in Thread: ADS8688, MSP430F2274, AM3359, DAC8760, ADS8588S
Dear All
Is there any C code sample to use ADS8688 with AVR MCU?
Thanks
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Other Parts Discussed in Thread: ADS8688, MSP430F2274, AM3359, DAC8760, ADS8588S
Dear All
Is there any C code sample to use ADS8688 with AVR MCU?
Thanks
Dear Mr Li
Thank you very much for your help. C code is fine I will be able to port for AVR.
My e-mail is reyah@medcotas.com, or reyahabd@aol.com .
Sorry about the delay in my answer.
Best Regards
Reyah
/********************** ads8688.c *************************/
#include <stdio.h>
#include <stdlib.h>
#include "ads8688.h"
/*
* 可测试范围:
* Vref = 4.096V
* +-10V 1LSB = 312.50uV
* +-5V 1LSB = 156.25uV
* +-2.5V 1LSB = 78.125uV
* 0-10V 1LSB = 156.25uV
* 0-5V 1LSB = 78.125uV
* 0-20mA
* 4-20mA
* +-20mA
*/
// power_up -> idle
// command transfer
//
/* ADC 各个通道的配置 */
// 通道,输入范围,电压/电流
CHANNEL_CFG_t g_ch_range_cfg[8] = {
{ch:CH0, range : BIPOLAR_VREF_2P5, type:VOLTAGE},
{ch:CH1, range : BIPOLAR_VREF_2P5, type:VOLTAGE},
{ch:CH2, range : BIPOLAR_VREF_2P5, type:VOLTAGE},
{ch:CH3, range : BIPOLAR_VREF_2P5, type:VOLTAGE},
{ch:CH4, range : UNIPOLAR_VREF_2P5, type:VOLTAGE},
{ch:CH5, range : UNIPOLAR_VREF_2P5, type:VOLTAGE},
{ch:CH6, range : UNIPOLAR_VREF_2P5, type:VOLTAGE},
{ch:CH7, range : UNIPOLAR_VREF_2P5, type:VOLTAGE},
};
/*
* 5个范围
*/
SCALE_RANGE_t g_scale_range[7] = {
{range:BIPOLAR_VREF_2P5, positive_full_scale: 10.24, negative_full_scale : -10.24, lsb_cnt1 : 312.50},
{range:BIPOLAR_VREF_1P25, positive_full_scale: 5.12, negative_full_scale : -5.12, lsb_cnt1 : 156.25},
{range:BIPOLAR_VREF_0P625, positive_full_scale: 2.56, negative_full_scale : -2.56, lsb_cnt1 : 78.125},
{},//reserved
{},//reserved
{range:UNIPOLAR_VREF_2P5, positive_full_scale: 10.24, negative_full_scale : 0, lsb_cnt1 : 156.25},
{range:UNIPOLAR_VREF_1P25, positive_full_scale: 5.12, negative_full_scale : 0, lsb_cnt1 : 78.125},
};
/*
* 根据寄存器的值转换为当前的电压
*/
float ads8688_reg_to_vtg_cur(uint16_t reg, RANGE_SELC_t range, ADC_SAMPLE_t type)
{
float tmp;
/* register_value * (V/div) / 1000000 (uV/V) */
tmp = reg * g_scale_range[range].lsb_cnt1 / (1000 * 1000) + g_scale_range[range].negative_full_scale;
if (type == CURRENT) {
/* mA = mV / R */
tmp = tmp * 1000 / 200;
}
return tmp;
}
/* set RST/PD pin LOW 40-100nS */
void ads8688_reset(ADS8688_HANDLE_t handle)
{
;
}
/*
* function: put the device into <power down> mode;
* set RST/PD pin LOW > 400nS to put the device power down-
* or send POWER_DOWN command
* param:
* return:
*/
uint16_t ads8688_power_down(ADS8688_HANDLE_t handle)
{
uint16_t half_word;
// 发送数据准备,接收数据缓冲
handle->buf[tx][0] = CMD_PWR_DN;
// cs low
handle->gpioHandle (handle->gpio_group, 0);
// 发送命令
handle->spiHandle (SPI1, (uint16_t)handle->buf[tx][0]);
// 接收数据
half_word = handle->spiHandle (SPI1, (uint16_t)handle->buf[tx][1]);
// cs high
handle->gpioHandle (handle->gpio_group, 1);
return half_word;
}
void ads8688_idle(ADS8688_HANDLE_t handle)
{
;
}
/*
* function: put the device into <standby> mode
* param:
* return:
*/
uint16_t ads8688_standby (ADS8688_HANDLE_t handle)
{
uint16_t half_word;
// 发送数据准备,接收数据缓冲
handle->buf[tx][0] = CMD_STDBY;
// cs low
handle->gpioHandle (handle->gpio_group, 0);
// 发送命令
handle->spiHandle (SPI1, (uint16_t )handle->buf[tx][0]);
// 接收数据
half_word = handle->spiHandle (SPI1, (uint16_t )handle->buf[tx][1]);
// cs high
handle->gpioHandle (handle->gpio_group, 1);
return half_word;
}
/*
* function:
* param:
* return:
*/
uint16_t ads8688_manual_mode (ADS8688_HANDLE_t handle, CMD_REG_t cmd)
{
uint16_t i;
uint16_t half_word = 0;
// 发送数据准备,接收数据缓冲
handle->buf[tx][0] = cmd;
handle->buf[tx][2] = CMD_NO_OP;
// 数据长度
handle->size_half_word = 2;
// cs low
handle->gpioHandle (handle->gpio_group, 0);
#if 1
for(i = 0; i < handle->size_half_word; i++) {
half_word = handle->spiHandle (SPI1, (uint16_t)handle->buf[tx][i]);
}
#else
// 发送命令
handle->spiHandle (SPI1, (uint16_t *)handle->buf[tx][0]);
// 接收数据
half_word = handle->spiHandle (SPI1, (uint16_t *)handle->buf[tx][1]);
#endif
// cs high
handle->gpioHandle (handle->gpio_group, 1);
return half_word;
}
/*
* function: read 1 channel value from ads8688, no care of manual or auto select mode;
* param:
* ads8688_handle:spi and gpio handle;
* adc_val: current channel register value from adc;
*/
uint16_t ads8688_read_1ch (ADS8688_HANDLE_t handle)
{
// todo
// cs from H -> L;
// first 16 sclk transfer to SDI pin for the next conversion;
// next 16 sclk transfer read out the SDO pin;
handle->buf[tx][0] = CMD_NO_OP;
handle->buf[tx][1] = CMD_BIT_FILL;
uint16_t half_word;
// cs low
handle->gpioHandle (handle->gpio_group, 0);
// 发送命令
handle->spiHandle (SPI1, (uint16_t) handle->buf[tx][0]);
// 接收数据
half_word = handle->spiHandle (SPI1, (uint16_t) handle->buf[tx][1]);
// cs high
handle->gpioHandle (handle->gpio_group, 1);
return half_word;
}
/*
* function:
* param:
* return:
*/
uint16_t ads8688_auto_seq_rst_mode (ADS8688_HANDLE_t handle)
{
uint16_t half_word;
// 发送数据准备,接收数据缓冲
handle->buf[tx][0] = CMD_AUTO_RST;
// cs low
handle->gpioHandle (handle->gpio_group, 0);
// 发送命令
handle->spiHandle (SPI1, (uint16_t)handle->buf[tx][0]);
// 接收数据
half_word = handle->spiHandle (SPI1, (uint16_t)handle->buf[tx][1]);
// cs high
handle->gpioHandle (handle->gpio_group, 1);
return half_word;
}
/*
* function:
* param:
* return:
*/
void ads8688_auto_ch_scan (ADS8688_HANDLE_t handle)
{
}
/* pull high the CS pin and put the device into idle mode */
void ads8688_frame_abort (ADS8688_HANDLE_t handle)
{
handle->gpioHandle(handle->gpio_group, 1);
}
/*
* function: reset program register, follow a auto/manual select;
* param:
* return:
*/
uint16_t ads8688_rst_prgm_reg (ADS8688_HANDLE_t handle)
{
uint16_t half_word;
// 发送数据准备,接收数据缓冲
handle->buf[tx][0] = CMD_RST;
handle->buf[tx][1] = CMD_BIT_FILL;
// cs low
handle->gpioHandle (handle->gpio_group, 0);
// 发送命令
handle->spiHandle (SPI1, (uint16_t)handle->buf[tx][0]);
// 接收数据
half_word = handle->spiHandle (SPI1, (uint16_t)handle->buf[tx][1]);
// cs high
handle->gpioHandle (handle->gpio_group, 1);
return half_word;
}
/*
* function:
* param:
* return:
*/
uint16_t ads8688_auto_scan_seq_ctrl (ADS8688_HANDLE_t handle,CHANNEL_SELC_t ch, bool stat)
{
uint16_t prgm_reg = 0;
uint16_t half_word;
prgm_reg = (uint16_t) PGRM_AUTO_SEQ_EN; //address
prgm_reg |= (PRGM_WR << 8); //read or write
prgm_reg |= (stat << ch); //register value
// cs low
handle->gpioHandle (handle->gpio_group, 0);
// 发送
half_word = handle->spiHandle (SPI1, (uint16_t) prgm_reg);
// 保持最少24个clk,这里使用16+16个clk
half_word = handle->spiHandle (SPI1, (uint16_t) 0);
// cs high
handle->gpioHandle (handle->gpio_group, 1);
half_word >>= 8;
half_word &= 0xff;
return half_word;
}
/*
* function:
* param:
* return:
*/
uint16_t ads8688_ch_power_down (ADS8688_HANDLE_t handle,CHANNEL_SELC_t ch, bool stat)
{
uint16_t prgm_reg = 0;
uint16_t half_word;
prgm_reg = (uint16_t) PGRM_CH_POW_DOWN; //address
prgm_reg |= (PRGM_WR << 8); //read or write
prgm_reg |= (stat << ch); //register value
// cs low
handle->gpioHandle (handle->gpio_group, 0);
// 发送
half_word = handle->spiHandle (SPI1, (uint16_t) prgm_reg);
// 保持最少24个clk,这里使用16+16个clk
half_word = handle->spiHandle (SPI1, (uint16_t) 0);
// cs high
handle->gpioHandle (handle->gpio_group, 1);
half_word >>= 8;
half_word &= 0xff;
return half_word;
}
/*
* function:
* param:
* return:
*/
uint16_t ads8688_dev_feature_ctrl (ADS8688_HANDLE_t handle, DEV_ID_t dev, SDO_FORMAT_t sdo)
{
uint16_t prgm_reg = 0;
uint16_t half_word;
prgm_reg = (uint16_t) PGRM_FEATURE_SELC; //address
prgm_reg |= (PRGM_WR << 8); //read or write
prgm_reg |= ( (dev << 5) | sdo ); //dev and sdo
// cs low
handle->gpioHandle (handle->gpio_group, 0);
// 发送
half_word = handle->spiHandle (SPI1, (uint16_t) prgm_reg);
// 保持最少24个clk,这里使用16+16个clk
half_word = handle->spiHandle (SPI1, (uint16_t) 0);
// cs high
handle->gpioHandle (handle->gpio_group, 1);
half_word >>= 8;
half_word &= 0xff;
return half_word;
}
/*
* function:
* param:
* return:
*/
int8_t ads8688_range_selc (ADS8688_HANDLE_t handle, CHANNEL_SELC_t ch, RANGE_SELC_t range)
{
uint16_t prgm_reg = 0;
uint16_t half_word;
int8_t rlt = 0;
//address + (read or write) + range
prgm_reg = ((uint16_t)PGRM_CH_IN_RANGE_0 + ch) << 9;
prgm_reg |= (PRGM_WR << 8);
prgm_reg |= (uint8_t) range;
// cs low
handle->gpioHandle (handle->gpio_group, 0);
// 发送
half_word = handle->spiHandle (SPI1, (uint16_t) prgm_reg);
// 保持最少24个clk,这里使用16+16个clk
half_word = handle->spiHandle (SPI1, (uint16_t) PRGM__BIT_FILL);
// cs high
handle->gpioHandle (handle->gpio_group, 1);
if( ((half_word >> 8) & 0xff) != (uint8_t)range) {
rlt = ERR_COMM;
trace_printf ("Error:prgm_reg=0x%04x,readback=0x%04x, in %s:%d\n",prgm_reg,half_word,__FILE__, __LINE__);
}
return rlt;
}
/*
* function:
* param:
* return:
*/
uint16_t ads8688_cmd_readback(ADS8688_HANDLE_t handle)
{
uint16_t prgm_reg = 0;
uint16_t half_word;
prgm_reg = (uint16_t) PGRM_CMD_RD_BACK; // address
prgm_reg |= (PRGM_RD << 8); // read or write
// cs low
handle->gpioHandle (handle->gpio_group, 0);
// 发送
half_word = handle->spiHandle (SPI1, (uint16_t) prgm_reg);
// 保持最少24个clk,这里使用 (16+16) 个clk
half_word = handle->spiHandle (SPI1, (uint16_t) 0);
// cs high
handle->gpioHandle (handle->gpio_group, 1);
half_word >>= 8;
half_word &= 0xff;
return half_word;
}
/*
* function: set gpio callback function
* param:
* return:
*/
void ads8688_set_gpio_handle (ADS8688_HANDLE_t handle, GPIO_Handle gpio_handle)
{
ADS8688_OBJ_t *obj = (ADS8688_OBJ_t *) handle;
obj->gpioHandle = gpio_handle;
}
/*
* function: set spi callback funcation
* param:
* return:
*/
void ads8688_set_spi_handle (ADS8688_HANDLE_t handle, SPI_Handle spi_handle)
{
ADS8688_OBJ_t *obj = (ADS8688_OBJ_t *) handle;
obj->spiHandle = spi_handle;
}
/********************** ads8688.h *************************/
#ifndef _ADS8688_H_
#define _ADS8688_H_
//#pragma pack(1)
// **************************************************************************
// the includes
#include <stdbool.h>
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_spi.h"
/* 4字节对齐 */
#pragma pack(4)
#define NR_CH_ADS8688 8
#define NR_CH_ADS8644 4
#define ADS8688_REG_RANGE 65536
#define ADS8688_REF_VTG 4.096
/* SPI1 最大读写字节数 */
#define MAX_HALF_WORD_SPI1 16
#define NUM_CH NR_CH_ADS8688
/* command register map */
typedef enum {
CMD_NO_OP = 0x0000,
CMD_STDBY = 0x8200,
CMD_PWR_DN = 0x8300,
CMD_RST = 0x8500,
CMD_AUTO_RST = 0xA000,
CMD_MAN_CH_0 = 0xC000,
CMD_MAN_CH_1 = 0xC400,
CMD_MAN_CH_2 = 0xC800,
CMD_MAN_CH_3 = 0xCC00,
CMD_MAN_CH_4 = 0xD000,
CMD_MAN_CH_5 = 0xD400,
CMD_MAN_CH_6 = 0xD800,
CMD_MAN_CH_7 = 0xDC00,
CMD_MAN_AUX = 0xE000,
CMD_BIT_FILL = 0xFFFF,
} CMD_REG_t;
/* program register map */
typedef enum {
PGRM_AUTO_SEQ_EN = 0x01,
PGRM_CH_POW_DOWN = 0x02,
PGRM_FEATURE_SELC = 0x03,
PGRM_CH_IN_RANGE_0 = 0x05,
PGRM_CH_IN_RANGE_1 = 0x06,
PGRM_CH_IN_RANGE_2 = 0x07,
PGRM_CH_IN_RANGE_3 = 0x08,
PGRM_CH_IN_RANGE_4 = 0x09,
PGRM_CH_IN_RANGE_5 = 0x0A,
PGRM_CH_IN_RANGE_6 = 0x0B,
PGRM_CH_IN_RANGE_7 = 0x0C,
// PGRM_CH_0_HYST = (0x15 << 8),
// PGRM_CH_0_HT_MSB = (0x16 << 8),
// PGRM_CH_0_HT_LSB = (0x17 << 8),
// PGRM_CH_0_LT_MSB = (0x18 << 8),
// PGRM_CH_0_LT_LSB = (0x19 << 8),
// PGRM_CH_7_HYST = (0x38 << 8),
// PGRM_CH_7_HT_MSB = (0x39 << 8),
// PGRM_CH_7_HT_LSB = (0x3A << 8),
// PGRM_CH_7_LT_MSB = (0x3B << 8),
// PGRM_CH_7_LT_LSB = (0x3C << 8),
PGRM_CMD_RD_BACK = 0x3F,
PRGM__BIT_FILL = 0x00,
} PRGM_REG_ADDRESS_t;
/* number of channels in current IC */
typedef enum {
CH0 = 0,
CH1,
CH2,
CH3,
CH4,
CH5,
CH6,
CH7,
AUX,
TOTAL_CH,
}CHANNEL_SELC_t;
typedef enum {
id_0,
id_1,
id_2,
id_3,
} DEV_ID_t;
/* Program Register Bits for SDO Data Format */
typedef enum {
format_0,
format_1,
format_2,
format_4,
} SDO_FORMAT_t;
/* 各个通道的输入范围选择 */
typedef enum {
BIPOLAR_VREF_2P5 = 0,
BIPOLAR_VREF_1P25,
BIPOLAR_VREF_0P625,
UNIPOLAR_VREF_2P5 = 5,
UNIPOLAR_VREF_1P25,
} RANGE_SELC_t;
typedef struct {
RANGE_SELC_t range;
float positive_full_scale;
float negative_full_scale;
float lsb_cnt1;
} SCALE_RANGE_t;
/* program register map */
/* Auto-Scan Sequence Enable Register (address = 01h) */
typedef struct {
PRGM_REG_ADDRESS_t ADDRESS;
bool RW;
bool CH7_EN;
bool CH6_EN;
bool CH5_EN;
bool CH4_EN;
bool CH3_EN;
bool CH2_EN;
bool CH1_EN;
bool CH0_EN;
} PRGM_REG_AUTO_SEQ_t;
/* 电流,电压采样 */
typedef enum {
VOLTAGE = 0, // 电压
CURRENT, // 电流
}ADC_SAMPLE_t;
typedef struct {
CHANNEL_SELC_t ch;
RANGE_SELC_t range;
ADC_SAMPLE_t type;
} CHANNEL_CFG_t;
/* Channel Power Down Register (address = 02h) */
typedef struct {
PRGM_REG_ADDRESS_t ADDRESS;
bool RW;
bool CH7_PD;
bool CH6_PD;
bool CH5_PD;
bool CH4_PD;
bool CH3_PD;
bool CH2_PD;
bool CH1_PD;
bool CH0_PD;
} PRGM_REG_CH_POWER_DOWN_t;
/* Device Features Selection Control Register (address = 03h) */
typedef struct {
PRGM_REG_ADDRESS_t ADDRESS;
bool RW;
DEV_ID_t DEV;
bool BIT5;
bool BIT4;
bool BIT3;
SDO_FORMAT_t SDO;
}PRGM_REG_FEATURE_SELECT_t;
/* Range Select Registers (addresses 05h-0Ch) */
typedef struct {
PRGM_REG_ADDRESS_t ADDRESS;
bool RW;
RANGE_SELC_t RANGE_SELC_CH;
}PRGM_REG_CH_SELECT_t;
/* ch0 -ch7 hysteresis */
typedef struct {
PRGM_REG_ADDRESS_t ADDRESS;
bool RW;
uint16_t CH_HYSTERESIS;
uint16_t CH_HT_MSB;
uint16_t CH_HT_LSB;
uint16_t CH_LT_MSB;
uint16_t CH_LT_LSB;
} PRGM_REG_CH_HYSTERESIS_t;
/* Command Read-Back Register (address = 3Fh) */
typedef struct {
PRGM_REG_ADDRESS_t ADDRESS;
bool RW;
uint8_t CMD_WORD;
} PRGM_REG_CMD_READ_BACK_t;
typedef struct {
GPIO_TypeDef* port_gpio_x; // gpio port number
uint16_t gpioNumber; //!< the gpio number that is connected to the drv8305 enable pin
} GPIO_GROUP_t;
enum {
tx,
rx,
buf_total,
};
enum {
PRGM_RD,
PRGM_WR,
};
/* 定义错误类型 */
enum {
ERR_COMM = -1,
ERR_TIMEOUT = -2,
}DEF_ERROR_t;
typedef uint16_t (*SPI_Handle) (SPI_TypeDef* SPIx, uint16_t half_word);
typedef uint16_t (*GPIO_Handle) (GPIO_GROUP_t gpio, bool BitVal);
typedef struct {
SPI_Handle spiHandle; //!< the handle for the serial peripheral interface >
GPIO_Handle gpioHandle; //!< the gpio handle that is connected to the drv8305 enable pin >
GPIO_GROUP_t gpio_group; //!< GPIO port and pin >
bool RxTimeOut; //!< the timeout flag for the RX fifo >
bool enableTimeOut; //!< the timeout flag for drv8305 enable >
uint16_t buf[buf_total][MAX_HALF_WORD_SPI1]; // dma的收发缓冲区
uint16_t size_half_word; // 一次收发spi的数据量大小
} ADS8688_OBJ_t;
typedef ADS8688_OBJ_t *ADS8688_HANDLE_t;
/* read/write command register */
void ads8688_reset(ADS8688_HANDLE_t handle);
void ads8688_idle(ADS8688_HANDLE_t handle);
void ads8688_audo_seq_rst(ADS8688_HANDLE_t handle);
void ads8688_audo_ch_scan(ADS8688_HANDLE_t handle);
void ads8688_frame_abort (ADS8688_HANDLE_t handle);
void ads8688_set_gpio_handle (ADS8688_HANDLE_t handle, GPIO_Handle gpio_handle);
void ads8688_set_spi_handle (ADS8688_HANDLE_t handle, SPI_Handle spi_handle);
uint16_t ads8688_manual_mode (ADS8688_HANDLE_t handle, CMD_REG_t cmd);
uint16_t ads8688_power_down(ADS8688_HANDLE_t handle);
uint16_t ads8688_standby(ADS8688_HANDLE_t handle);
uint16_t ads8688_rst_prgm_reg(ADS8688_HANDLE_t handle);
/* read/write program register */
uint16_t ads8688_auto_scan_seq_ctrl (ADS8688_HANDLE_t handle,CHANNEL_SELC_t ch, bool stat);
uint16_t ads8688_ch_power_down (ADS8688_HANDLE_t handle,CHANNEL_SELC_t ch, bool stat);
uint16_t ads8688_dev_feature_ctrl (ADS8688_HANDLE_t handle, DEV_ID_t dev, SDO_FORMAT_t sdo);
int8_t ads8688_range_selc (ADS8688_HANDLE_t handle, CHANNEL_SELC_t ch, RANGE_SELC_t range);
uint16_t ads8688_cmd_readback(ADS8688_HANDLE_t handle);
uint16_t ads8688_read_1ch (ADS8688_HANDLE_t handle);
uint16_t ads8688_auto_seq_rst_mode (ADS8688_HANDLE_t handle);
/* 电压电流转换 */
float ads8688_reg_to_vtg_cur(uint16_t reg, RANGE_SELC_t range, ADC_SAMPLE_t type);
#endif