Skip to content
Permalink
master
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
/***************************************************************************//**
* @file ad5761r.c
* @brief Implementation of AD5761R Driver.
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2015(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "ad5761r.h"
/******************************************************************************/
/************************ Functions Definitions *******************************/
/******************************************************************************/
/**
* SPI write to device.
* @param dev - The device structure.
* @param reg_addr_cmd - The input shift register command.
* Accepted values: CMD_NOP
* CMD_WR_TO_INPUT_REG
* CMD_UPDATE_DAC_REG_FROM_INPUT_REG
* CMD_WR_UPDATE_DAC_REG
* CMD_WR_CTRL_REG
* CMD_SW_DATA_RESET
* CMD_DIS_DAISY_CHAIN
* CMD_RD_INPUT_REG
* CMD_RD_DAC_REG
* CMD_RD_CTRL_REG
* CMD_SW_FULL_RESET
* @param reg_data - The transmitted data.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_write(struct ad5761r_dev *dev,
uint8_t reg_addr_cmd,
uint16_t reg_data)
{
uint8_t data[3];
int32_t ret;
data[0] = reg_addr_cmd;
data[1] = (reg_data & 0xFF00) >> 8;
data[2] = (reg_data & 0x00FF) >> 0;
ret = spi_write_and_read(dev->spi_desc, data, 3);
return ret;
}
/**
* SPI read from device.
* @param dev - The device structure.
* @param reg_addr_cmd - The input shift register command.
* Accepted values: CMD_NOP
* CMD_WR_TO_INPUT_REG
* CMD_UPDATE_DAC_REG_FROM_INPUT_REG
* CMD_WR_UPDATE_DAC_REG
* CMD_WR_CTRL_REG
* CMD_SW_DATA_RESET
* CMD_DIS_DAISY_CHAIN
* CMD_RD_INPUT_REG
* CMD_RD_DAC_REG
* CMD_RD_CTRL_REG
* CMD_SW_FULL_RESET
* @param reg_data - The received data.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_read(struct ad5761r_dev *dev,
uint8_t reg_addr_cmd,
uint16_t *reg_data)
{
uint8_t data[3];
int32_t ret;
data[0] = reg_addr_cmd;
data[1] = 0;
data[2] = 0;
ret = spi_write_and_read(dev->spi_desc, data, 3);
*reg_data = (data[1] << 8) | data[2];
return ret;
}
/**
* Readback the register data.
* Note: Readback operation is not enabled if daisy-chain mode is disabled.
* @param dev - The device structure.
* @param reg - The register to be read.
* Accepted values: AD5761R_REG_INPUT
* AD5761R_REG_DAC
* AD5761R_REG_CTRL
* @param reg_data - The register data.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_register_readback(struct ad5761r_dev *dev,
enum ad5761r_reg reg,
uint16_t *reg_data)
{
uint8_t reg_addr;
int32_t ret;
if (!dev->daisy_chain_en) {
printf("Readback operation is disabled.");
return -1;
}
switch (reg) {
case AD5761R_REG_INPUT:
reg_addr = CMD_RD_INPUT_REG;
break;
case AD5761R_REG_DAC:
reg_addr = CMD_RD_DAC_REG;
break;
case AD5761R_REG_CTRL:
reg_addr = CMD_RD_CTRL_REG;
break;
default:
return -1;
}
/* During the first command, the last 16 bits are don't care bits. */
ret = ad5761r_read(dev, reg_addr, reg_data);
/* During the next command, the register contents are shifted out of the
SDO pin with the MSB shifted out first. */
ret |= ad5761r_read(dev, reg_addr, reg_data);
return ret;
}
/**
* Configure the part based on the settings stored in the device structure.
* @param dev - The device structure.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_config(struct ad5761r_dev *dev)
{
uint16_t reg_data;
reg_data = AD5761R_CTRL_CV(dev->cv) |
(dev->ovr_en ? AD5761R_CTRL_OVR : 0) |
(dev->b2c_range_en? AD5761R_CTRL_B2C : 0) |
(dev->exc_temp_sd_en ? AD5761R_CTRL_ETS : 0) |
(dev->int_ref_en ? AD5761R_CTRL_IRO : 0) |
AD5761R_CTRL_PV(dev->pv) |
AD5761R_CTRL_RA(dev->ra);
return ad5761r_write(dev, CMD_WR_CTRL_REG, reg_data);
}
/**
* Enable/disable daisy-chain mode.
* @param dev - The device structure.
* @param en_dis - Set true in order to enable the daisy-chain mode.
* Accepted values: true
* false
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_set_daisy_chain_en_dis(struct ad5761r_dev *dev,
bool en_dis)
{
dev->daisy_chain_en = en_dis;
return ad5761r_write(dev, CMD_DIS_DAISY_CHAIN,
AD5761R_DIS_DAISY_CHAIN_DDC(!en_dis));
}
/**
* Get the status of the daisy-chain mode.
* @param dev - The device structure.
* @param en_dis - The status of the daisy-chain mode (enabled, disabled).
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_get_daisy_chain_en_dis(struct ad5761r_dev *dev,
bool *en_dis)
{
*en_dis = dev->daisy_chain_en;
return 0;
}
/**
* Set the output_range.
* @param dev - The device structure.
* @param out_range - The output range.
* Accepted values: AD5761R_RANGE_M_10V_TO_P_10V,
* AD5761R_RANGE_0_V_TO_P_10V
* AD5761R_RANGE_M_5V_TO_P_5V
* AD5761R_RANGE_0V_TO_P_5V
* AD5761R_RANGE_M_2V5_TO_P_7V5
* AD5761R_RANGE_M_3V_TO_P_3V
* AD5761R_RANGE_0V_TO_P_16V
* AD5761R_RANGE_0V_TO_P_20V
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_set_output_range(struct ad5761r_dev *dev,
enum ad5761r_range out_range)
{
dev->ra = out_range;
return ad5761r_config(dev);
}
/**
* Get the output_range.
* @param dev - The device structure.
* @param out_range - The output range values.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_get_output_range(struct ad5761r_dev *dev,
enum ad5761r_range *out_range)
{
*out_range = dev->ra;
return 0;
}
/**
* Set the power up voltage.
* @param dev - The device structure.
* @param pv - The power up voltage.
* Accepted values: AD5761R_SCALE_ZERO
* AD5761R_SCALE_HALF
* AD5761R_SCALE_FULL
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_set_power_up_voltage(struct ad5761r_dev *dev,
enum ad5761r_scale pv)
{
dev->pv = pv;
return ad5761r_config(dev);
}
/**
* Get the power up voltage.
* @param dev - The device structure.
* @param pv - The power up voltage.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_get_power_up_voltage(struct ad5761r_dev *dev,
enum ad5761r_scale *pv)
{
*pv = dev->pv;
return 0;
}
/**
* Set the clear voltage.
* @param dev - The device structure.
* @param cv - The clear voltage.
* Accepted values: AD5761R_SCALE_ZERO
* AD5761R_SCALE_HALF
* AD5761R_SCALE_FULL
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_set_clear_voltage(struct ad5761r_dev *dev,
enum ad5761r_scale cv)
{
dev->cv = cv;
return ad5761r_config(dev);
}
/**
* Get the clear voltage.
* @param dev - The device structure.
* @param cv - The clear voltage.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_get_clear_voltage(struct ad5761r_dev *dev,
enum ad5761r_scale *cv)
{
*cv = dev->cv;
return 0;
}
/**
* Enable/disable internal reference.
* @param dev - The device structure.
* @param en_dis - Set true in order to enable the internal reference.
* Accepted values: true
* false
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_set_internal_reference_en_dis(struct ad5761r_dev *dev,
bool en_dis)
{
dev->int_ref_en = en_dis;
return ad5761r_config(dev);
}
/**
* Get the status of the internal reference.
* @param dev - The device structure.
* @param en_dis - The status of the internal reference (enabled, disabled).
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_get_internal_reference_en_dis(struct ad5761r_dev *dev,
bool *en_dis)
{
*en_dis = dev->int_ref_en;
return 0;
}
/**
* Enable/disable ETS (exceed temperature shutdown) function.
* @param dev - The device structure.
* @param en_dis - Set true in order to enable the ETS function.
* Accepted values: true
* false
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_set_exceed_temp_shutdown_en_dis(struct ad5761r_dev *dev,
bool en_dis)
{
dev->exc_temp_sd_en = en_dis;
return ad5761r_config(dev);
}
/**
* Get the status of the ETS (exceed temperature shutdown) function.
* @param dev - The device structure.
* @param en_dis - The status of the ETS function (enabled, disabled).
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_get_exceed_temp_shutdown_en_dis(struct ad5761r_dev *dev,
bool *en_dis)
{
*en_dis = dev->exc_temp_sd_en;
return 0;
}
/**
* Enable/disable the twos complement bipolar output range.
* @param dev - The device structure.
* @param en_dis - Set true in order to enable the twos complement bipolar
* output range.
* Accepted values: true
* false
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_set_2c_bipolar_range_en_dis(struct ad5761r_dev *dev,
bool en_dis)
{
dev->b2c_range_en = en_dis;
return ad5761r_config(dev);
}
/**
* Get the status of the twos complement bipolar output range.
* @param dev - The device structure.
* @param en_dis - The status of the twos complement bipolar output range
* (enabled, disabled).
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_get_2c_bipolar_range_en_dis(struct ad5761r_dev *dev,
bool *en_dis)
{
*en_dis = dev->b2c_range_en;
return 0;
}
/**
* Enable/disable the 5% overrange.
* @param dev - The device structure.
* @param en_dis - Set true in order to enable the 5% overrange.
* Accepted values: true
* false
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_set_overrange_en_dis(struct ad5761r_dev *dev,
bool en_dis)
{
dev->ovr_en = en_dis;
return ad5761r_config(dev);
}
/**
* Get the status of the 5% overrange.
* @param dev - The device structure.
* @param en_dis - The status of the twos 5% overrange (enabled, disabled).
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_get_overrange_en_dis(struct ad5761r_dev *dev,
bool *en_dis)
{
*en_dis = dev->ovr_en;
return 0;
}
/**
* Get the short-circuit condition.
* Note: The condition is reset at every control register write.
* @param dev - The device structure.
* @param sc - The status of the short-circuit condition (detected,
* not detected).
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_get_short_circuit_condition(struct ad5761r_dev *dev,
bool *sc)
{
uint16_t reg_data;
int32_t ret;
ret = ad5761r_read(dev, CMD_RD_CTRL_REG, &reg_data);
*sc = ((reg_data & AD5761R_CTRL_SC) >> 12);
return ret;
}
/**
* Get the brownout condition.
* Note: The condition is reset at every control register write.
* @param dev - The device structure.
* @param bo - The status of the brownout condition (detected,
* not detected).
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_get_brownout_condition(struct ad5761r_dev *dev,
bool *bo)
{
uint16_t reg_data;
int32_t ret;
ret = ad5761r_read(dev, CMD_RD_CTRL_REG, &reg_data);
*bo = ((reg_data & AD5761R_CTRL_BO) >> 11);
return ret;
}
/**
* Set the reset pin value.
* @param dev - The device structure.
* @param value - The pin value.
* Accepted values: GPIO_LOW
* GPIO_HIGH
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_set_reset_pin(struct ad5761r_dev *dev,
uint8_t value)
{
if (dev->gpio_reset) {
dev->gpio_reset_value = value;
return gpio_set_value(dev->gpio_reset,
dev->gpio_reset_value);
} else
return -1;
}
/**
* Get the reset pin value.
* @param dev - The device structure.
* @param value - The pin value.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_get_reset_pin(struct ad5761r_dev *dev,
uint8_t *value)
{
if (dev->gpio_reset) {
*value = dev->gpio_reset_value;
return 0;
} else
return -1;
}
/**
* Set the clr pin value.
* @param dev - The device structure.
* @param value - The pin value.
* Accepted values: GPIO_LOW
* GPIO_HIGH
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_set_clr_pin(struct ad5761r_dev *dev,
uint8_t value)
{
if (dev->gpio_clr) {
dev->gpio_clr_value = value;
return gpio_set_value(dev->gpio_clr,
dev->gpio_clr_value);
} else
return -1;
}
/**
* Get the clr pin value.
* @param dev - The device structure.
* @param value - The pin value.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_get_clr_pin(struct ad5761r_dev *dev,
uint8_t *value)
{
if (dev->gpio_clr) {
*value = dev->gpio_clr_value;
return 0;
} else
return -1;
}
/**
* Set the ldac pin value.
* @param dev - The device structure.
* @param value - The pin value.
* Accepted values: GPIO_LOW
* GPIO_HIGH
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_set_ldac_pin(struct ad5761r_dev *dev,
uint8_t value)
{
if (dev->gpio_ldac) {
dev->gpio_ldac_value = value;
return gpio_set_value(dev->gpio_ldac,
dev->gpio_ldac_value);
} else
return -1;
}
/**
* Get the ldac pin value.
* @param dev - The device structure.
* @param value - The pin value.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_get_ldac_pin(struct ad5761r_dev *dev,
uint8_t *value)
{
if (dev->gpio_ldac) {
*value = dev->gpio_ldac_value;
return 0;
} else
return -1;
}
/**
* Write to input register.
* @param dev - The device structure.
* @param dac_data - The DAC data.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_write_input_register(struct ad5761r_dev *dev,
uint16_t dac_data)
{
uint16_t reg_data;
if (dev->type == AD5761R)
reg_data = AD5761R_DATA(dac_data);
else
reg_data = AD5721R_DATA(dac_data);
return ad5761r_write(dev, CMD_WR_TO_INPUT_REG, reg_data);
}
/**
* Update DAC register.
* @param dev - The device structure.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_update_dac_register(struct ad5761r_dev *dev)
{
return ad5761r_write(dev, CMD_UPDATE_DAC_REG, 0);
}
/**
* Write to input register and update DAC register.
* @param dev - The device structure.
* @param dac_data - The register data.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_write_update_dac_register(struct ad5761r_dev *dev,
uint16_t dac_data)
{
uint16_t reg_data;
if (dev->type == AD5761R)
reg_data = AD5761R_DATA(dac_data);
else
reg_data = AD5721R_DATA(dac_data);
return ad5761r_write(dev, CMD_WR_UPDATE_DAC_REG, reg_data);
}
/**
* Software data reset.
* @param dev - The device structure.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_software_data_reset(struct ad5761r_dev *dev)
{
return ad5761r_write(dev, CMD_SW_DATA_RESET, 0);
}
/**
* Software full reset.
* @param dev - The device structure.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_software_full_reset(struct ad5761r_dev *dev)
{
return ad5761r_write(dev, CMD_SW_FULL_RESET, 0);
}
/**
* Initialize the device.
* @param device - The device structure.
* @param init_param - The structure that contains the device initial
* parameters.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad5761r_init(struct ad5761r_dev **device,
struct ad5761r_init_param init_param)
{
struct ad5761r_dev *dev;
int32_t ret = 0;
dev = (struct ad5761r_dev *)malloc(sizeof(*dev));
if (!dev) {
return -1;
}
/* SPI */
ret = spi_init(&dev->spi_desc, &init_param.spi_init);
/* GPIO */
ret |= gpio_get(&dev->gpio_reset, &init_param.gpio_reset);
dev->gpio_reset_value = init_param.gpio_reset_value;
ret |= gpio_get(&dev->gpio_clr, &init_param.gpio_clr);
dev->gpio_clr_value = init_param.gpio_clr_value;
ret |= gpio_get(&dev->gpio_ldac, &init_param.gpio_ldac);
dev->gpio_ldac_value = init_param.gpio_ldac_value;
if (dev->gpio_reset)
ret |= gpio_direction_output(dev->gpio_reset,
dev->gpio_reset_value);
if (dev->gpio_clr)
ret |= gpio_direction_output(dev->gpio_clr,
dev->gpio_clr_value);
if (dev->gpio_ldac)
ret |= gpio_direction_output(dev->gpio_ldac,
dev->gpio_ldac_value);
/* Device Settings */
dev->type = init_param.type;
dev->ra = init_param.out_range;
dev->pv = init_param.pwr_voltage;
dev->cv = init_param.clr_voltage;
dev->int_ref_en = init_param.int_ref_en;
dev->exc_temp_sd_en = init_param.exc_temp_sd_en;
dev->b2c_range_en = init_param.b2c_range_en;
dev->ovr_en = init_param.ovr_en;
ret |= ad5761r_config(dev);
dev->daisy_chain_en = init_param.daisy_chain_en;
ret |= ad5761r_set_daisy_chain_en_dis(dev, dev->daisy_chain_en);
*device = dev;
return ret;
}
/***************************************************************************//**
* @brief Free the resources allocated by ad5761r_init().
* @param dev - The device structure.
* @return SUCCESS in case of success, negative error code otherwise.
*******************************************************************************/
int32_t ad5761r_remove(struct ad5761r_dev *dev)
{
int32_t ret;
ret = spi_remove(dev->spi_desc);
if (dev->gpio_reset)
ret |= gpio_remove(dev->gpio_reset);
if (dev->gpio_clr)
ret |= gpio_remove(dev->gpio_clr);
if (dev->gpio_ldac)
ret |= gpio_remove(dev->gpio_ldac);
free(dev);
return ret;
}