Program files for Example program for EVAL-AD7768-1
Dependencies: platform_drivers
app/ad77681_iio.c
- Committer:
- Kjansen
- Date:
- 2021-09-24
- Revision:
- 1:260e834a8dc1
File content as of revision 1:260e834a8dc1:
/***************************************************************************//** * @file ad77681_iio.c * @brief Implementation of AD7768-1 IIO application interfaces * @details This module acts as an interface for AD7768-1 IIO application ******************************************************************************** * Copyright (c) 2021 Analog Devices, Inc. * All rights reserved. * * This software is proprietary to Analog Devices, Inc. and its licensors. * By using this software you agree to the terms of the associated * Analog Devices Software License Agreement. *******************************************************************************/ /******************************************************************************/ /***************************** Include Files **********************************/ /******************************************************************************/ #include <stdint.h> #include <string.h> #include <stdio.h> #include <errno.h> #include "app_config.h" #include "tinyiiod.h" #include "ad77681_iio.h" #include "ad77681_user_config.h" #include "ad77681_regs.h" #include "ad77681_data_capture.h" #include "adc_data_capture.h" #include "error.h" /******************************************************************************/ /************************ Macros/Constants ************************************/ /******************************************************************************/ /* AD77681 Channel Number */ #define AD77681_NUM_CHANNELS 1 /* Bytes per sample (for ADC resolution of 24-bits) */ #define AD77681_BYTES_PER_SAMPLE sizeof(uint32_t) /* Number of data storage bits (needed for IIO client) */ #define AD77681_CHN_STORAGE_BITS (AD77681_BYTES_PER_SAMPLE * 8) /* AD77681 24 bits scale factor */ #define AD77681_SCALE_FACTOR (1 << ADC_RESOLUTION) /* AD77681 ADC data to Voltage conversion default scale factor for IIO client */ #define AD77681_DEFAULT_SCALE ((((float)(AD77681_VOLTAGE_REF / 1000.00) * 2) / AD77681_SCALE_FACTOR) * 1000) /* Register Max Address */ #define AD77681_REG_MAX_ADDR AD77681_REG_MCLK_COUNTER + 1 /* Conv Mode Value after setting a single conversion mode */ #define SINGLE_MODE_CONV_STANDBY 6 /* Conv Mode Value after setting a periodic conversion mode */ #define PERIODIC_MODE_CONV_STANDBY 7 /******************************************************************************/ /*************************** Types Declarations *******************************/ /******************************************************************************/ /* IIO interface descriptor */ static struct iio_desc *p_ad77681_iio_desc; /* Device name */ static const char dev_name[] = ACTIVE_DEVICE_NAME; /* Pointer to the struct representing the AD77681 IIO device */ struct ad77681_dev *p_ad77681_dev_inst = NULL; /* Pointer to the struct AD77681 status register */ struct ad77681_status_registers *p_ad77681_stat_reg = NULL; /* Flag to trigger new data capture */ static bool adc_data_capture_started = false; /* Scale value per channel */ static float attr_scale_val[AD77681_NUM_CHANNELS] = { AD77681_DEFAULT_SCALE }; /* Power mode values string representation */ static const char* power_mode_str[] = { "Eco-Mode", "Value-Not-Assigned", "Median-Mode", "Fast-Mode" }; /* Conversion mode values string representation */ static const char* conv_mode_str[] = { "Continuous-Mode", "Continious-One-Shot-Mode", "Single-Mode", "Periodic-Mode", "Standby-Mode" }; /* MCLK division values string representation */ static const char* mclk_division_str[] = { "AD77681_MCLK_DIV_16", "AD77681_MCLK_DIV_8", "AD77681_MCLK_DIV_4", "AD77681_MCLK_DIV_2" }; /******************************************************************************/ /************************ Functions Prototypes ********************************/ /******************************************************************************/ /******************************************************************************/ /************************ Functions Definitions *******************************/ /******************************************************************************/ /*! * @brief Getter/Setter for the sampling frequency attribute value * @param device- pointer to IIO device structure * @param buf- pointer to buffer holding attribute value * @param len- length of buffer string data * @param channel- pointer to IIO channel structure * @param id- Attribute ID (optional) * @return Number of characters read/written * @Note This attribute is used to define the timeout period in IIO * client during data capture. * Timeout = (number of requested samples * (1/sampling frequency)) + 1sec * e.g. if sampling frequency = 64KSPS and requested samples = 400 * Timeout = (400 * (1/64000)) + 1 = 1.00625sec = ~1sec */ static ssize_t get_sampling_frequency(void *device, char *buf, size_t len, const struct iio_ch_info *channel, intptr_t id) { return (ssize_t) sprintf(buf, "%d", (int32_t)AD77681_DEFAULT_SAMPLING_FREQ); } static ssize_t set_sampling_frequency(void *device, char *buf, size_t len, const struct iio_ch_info *channel, intptr_t id) { /* NA- Can't set sampling frequency value */ return len; } /*! * @brief Getter/Setter for the raw attribute value * @param device- pointer to IIO device structure * @param buf- pointer to buffer holding attribute value * @param len- length of buffer string data * @param channel- pointer to IIO channel structure * @return Number of characters read/written */ ssize_t get_raw(void *device, char *buf, size_t len, const struct iio_ch_info *channel, intptr_t id) { uint32_t adc_data_raw = 0; /* Capture the raw adc data */ if (read_single_sample((uint32_t)channel->ch_num, &adc_data_raw) != FAILURE) { return (ssize_t) sprintf(buf, "%d", (int32_t)adc_data_raw); } return - EINVAL; } ssize_t set_raw(void *device, char *buf, size_t len, const struct iio_ch_info *channel, intptr_t id) { /* NA- Can't set raw value */ return len; } /*! * @brief Getter/Setter for the scale attribute value * @param device- pointer to IIO device structure * @param buf- pointer to buffer holding attribute value * @param len- length of buffer string data * @param channel- pointer to IIO channel structure * @return Number of characters read/written */ ssize_t get_scale(void* device, char* buf, size_t len, const struct iio_ch_info* channel, intptr_t id) { return (ssize_t)sprintf(buf, "%f", attr_scale_val[channel->ch_num]); } ssize_t set_scale(void* device, char* buf, size_t len, const struct iio_ch_info* channel, intptr_t id) { float scale; (void)sscanf(buf, "%f", &scale); if (scale > 0.0) { attr_scale_val[channel->ch_num] = scale; return len; } return -EINVAL; } /*! * @brief Getter for the power mode available values * @param device- pointer to IIO device structure * @param buf- pointer to buffer holding attribute value * @param len- length of buffer string data * @param channel- pointer to IIO channel structure * @param id- Attribute ID (optional) * @return Number of characters read/written */ static ssize_t get_power_mode_available(void *device, char *buf, size_t len, const struct iio_ch_info *channel, intptr_t id) { return sprintf(buf, "%s", "Eco-Mode Value-Not-Assigned Median-Mode Fast-Mode"); } /*! * @brief Setter for the power mode available values * @param device- pointer to IIO device structure * @param buf- pointer to buffer holding attribute value * @param len- length of buffer string data * @param channel- pointer to IIO channel structure * @param id- Attribute ID (optional) * @return Number of characters read/written */ static ssize_t set_power_mode_available(void *device, char *buf, size_t len, const struct iio_ch_info *channel, intptr_t id) { /* NA- Can't set error value */ return len; } /*! * @brief Getter/Setter for the power mode attribute value * @param device- pointer to IIO device structure * @param buf- pointer to buffer holding attribute value * @param len- length of buffer string data * @param channel- pointer to IIO channel structure * @return Number of characters read/written */ ssize_t get_power_mode(void *device, char *buf, size_t len, const struct iio_ch_info *channel, intptr_t id) { uint8_t power_mode_value = 0; if (ad77681_spi_read_mask(device, AD77681_REG_POWER_CLOCK, AD77681_POWER_CLK_PWRMODE_MSK, &power_mode_value) == SUCCESS) { return (ssize_t)sprintf(buf, "%s", power_mode_str[power_mode_value]); } return -EINVAL; } ssize_t set_power_mode(void *device, char *buf, size_t len, const struct iio_ch_info *channel, intptr_t id) { uint8_t power_mode_value; for (power_mode_value = 0; power_mode_value < (uint8_t)ARRAY_SIZE(power_mode_str); power_mode_value++) { if (!strncmp(buf, power_mode_str[power_mode_value], strlen(power_mode_str[power_mode_value]))) { break; } } if (power_mode_value < (uint8_t)ARRAY_SIZE(power_mode_str)) { if (ad77681_set_power_mode(device, power_mode_value) == SUCCESS) { return len; } } return -EINVAL; } /*! * @brief Getter for the conv mode available values * @param device- pointer to IIO device structure * @param buf- pointer to buffer holding attribute value * @param len- length of buffer string data * @param channel- pointer to IIO channel structure * @param id- Attribute ID (optional) * @return Number of characters read/written */ static ssize_t get_conv_mode_available(void *device, char *buf, size_t len, const struct iio_ch_info *channel, intptr_t id) { return sprintf(buf, "%s", "Continuous-Mode Continious-One-Shot-Mode Single-Mode Periodic-Mode Standby-Mode"); } /*! * @brief Setter for the conv mode available values * @param device- pointer to IIO device structure * @param buf- pointer to buffer holding attribute value * @param len- length of buffer string data * @param channel- pointer to IIO channel structure * @param id- Attribute ID (optional) * @return Number of characters read/written */ static ssize_t set_conv_mode_available(void *device, char *buf, size_t len, const struct iio_ch_info *channel, intptr_t id) { /* NA- Can't set error value */ return len; } /*! * @brief Getter/Setter for the conversion mode attribute value * @param device- pointer to IIO device structure * @param buf- pointer to buffer holding attribute value * @param len- length of buffer string data * @param channel- pointer to IIO channel structure * @return Number of characters read/written */ ssize_t get_conv_mode(void* device, char* buf, size_t len, const struct iio_ch_info* channel, intptr_t id) { uint8_t conv_mode_value = 0; if (ad77681_spi_read_mask(device, AD77681_REG_CONVERSION, AD77681_CONVERSION_MODE_MSK, &conv_mode_value) == SUCCESS) { if (conv_mode_value <= (uint8_t)ARRAY_SIZE(conv_mode_str)) { return (ssize_t)sprintf(buf, "%s", conv_mode_str[conv_mode_value]); } else if (conv_mode_value == SINGLE_MODE_CONV_STANDBY) { return (ssize_t)sprintf(buf, "%s", conv_mode_str[2]); } else if (conv_mode_value == PERIODIC_MODE_CONV_STANDBY) { return (ssize_t)sprintf(buf, "%s", conv_mode_str[3]); } } return -EINVAL; } ssize_t set_conv_mode(void* device, char* buf, size_t len, const struct iio_ch_info* channel, intptr_t id) { uint8_t conv_mode_value; for (conv_mode_value = 0; conv_mode_value < (uint8_t)ARRAY_SIZE(conv_mode_str); conv_mode_value++) { if (!strncmp(buf, conv_mode_str[conv_mode_value], strlen(conv_mode_str[conv_mode_value]))) { break; } } if (conv_mode_value < (uint8_t)ARRAY_SIZE(conv_mode_str)) { if (ad77681_set_conv_mode(device, conv_mode_value, AD77681_AIN_SHORT, false) == SUCCESS) { return len; } } return -EINVAL; } /*! * @brief Getter for the mclk division available values * @param device- pointer to IIO device structure * @param buf- pointer to buffer holding attribute value * @param len- length of buffer string data * @param channel- pointer to IIO channel structure * @param id- Attribute ID (optional) * @return Number of characters read/written */ static ssize_t get_mclk_division_available(void *device, char *buf, size_t len, const struct iio_ch_info *channel, intptr_t id) { return sprintf(buf, "%s", "AD77681_MCLK_DIV_16 AD77681_MCLK_DIV_8 AD77681_MCLK_DIV_4 AD77681_MCLK_DIV_2"); } /*! * @brief Setter for the mclk division available values * @param device- pointer to IIO device structure * @param buf- pointer to buffer holding attribute value * @param len- length of buffer string data * @param channel- pointer to IIO channel structure * @param id- Attribute ID (optional) * @return Number of characters read/written */ static ssize_t set_mclk_division_available(void *device, char *buf, size_t len, const struct iio_ch_info *channel, intptr_t id) { /* NA- Can't set error value */ return len; } /*! * @brief Getter/Setter for the MCLK division attribute value * @param device- pointer to IIO device structure * @param buf- pointer to buffer holding attribute value * @param len- length of buffer string data * @param channel- pointer to IIO channel structure * @param channel- pointer to IIO channel structure * @return Number of characters read/written */ ssize_t get_mclk_division(void* device, char* buf, size_t len, const struct iio_ch_info* channel, intptr_t id) { uint8_t mclk_division_value = 0; if (ad77681_spi_read_mask(device, AD77681_REG_POWER_CLOCK, AD77681_POWER_CLK_MCLK_DIV_MSK, &mclk_division_value) == SUCCESS) { return (ssize_t)sprintf(buf, "%s", mclk_division_str[mclk_division_value >> 4]); } return -EINVAL; } ssize_t set_mclk_division(void* device, char* buf, size_t len, const struct iio_ch_info* channel, intptr_t id) { uint8_t mclk_division_value = 0; uint8_t mclk_division_str_len = 0; mclk_division_str_len = (uint8_t)ARRAY_SIZE(mclk_division_str); for (uint8_t mclk_division_cntr = 0; mclk_division_cntr < mclk_division_str_len; mclk_division_cntr++) { if (!strncmp(buf, mclk_division_str[mclk_division_cntr], strlen(mclk_division_str[mclk_division_cntr]))) { mclk_division_value = mclk_division_cntr; break; } } if (mclk_division_value < mclk_division_str_len) { if (ad77681_set_mclk_div(device, mclk_division_value) == SUCCESS) { return len; } } return -EINVAL; } /*! * @brief Get the actual register address value from the list * @param reg- Register address to read from * @param Reg_add - actual value of Register address * @return true in case of success, false value otherwise */ bool debug_get_reg_value(uint8_t reg, uint8_t* Reg_add) { bool ad77681_regs_debug_flg = false; uint8_t ad77681_regs_arr_cntr; for (ad77681_regs_arr_cntr = 0; ad77681_regs_arr_cntr < (uint8_t)AD77681_REG_MAX_ADDR; ad77681_regs_arr_cntr++) { if (reg == ad77681_regs[ad77681_regs_arr_cntr]) { ad77681_regs_debug_flg = true; *Reg_add = reg; break; } } return ad77681_regs_debug_flg; } /*! * @brief Read the debug register value * @param dev- Pointer to IIO device instance * @param reg- Register address to read from * @param readval- Pointer to variable to read data into * @return SUCCESS in case of success, negative value otherwise */ int32_t debug_reg_read(void *dev, uint32_t reg, uint32_t *readval) { bool ad77681_dev_debug_read_flg = false; uint8_t ad77681_dev_actual_reg_add = 0; ad77681_dev_debug_read_flg = debug_get_reg_value((uint8_t)reg, &ad77681_dev_actual_reg_add); /* Read the data from device */ if (ad77681_dev_debug_read_flg == true) { if ((ad77681_spi_reg_read(dev, (uint8_t)ad77681_dev_actual_reg_add, (uint8_t *)readval) == SUCCESS)) { // Shift 8 bits to get the uint8 value from uint32 *readval = *readval >> 8; return SUCCESS; } } return FAILURE; } /*! * @brief Write into the debug register * @param dev- Pointer to IIO device instance * @param reg- Register address to write into * @param writeval- Register value to write * @return SUCCESS in case of success, negative value otherwise */ int32_t debug_reg_write(void *dev, uint32_t reg, uint32_t writeval) { bool ad77681_dev_debug_write_flg = false; uint8_t ad77681_dev_actual_reg_add = 0; ad77681_dev_debug_write_flg = debug_get_reg_value((uint8_t)reg, &ad77681_dev_actual_reg_add); if (ad77681_dev_debug_write_flg == true) { if (ad77681_spi_reg_write(dev, ad77681_dev_actual_reg_add, (uint8_t) writeval) == SUCCESS) { return SUCCESS; } } return FAILURE; } /** * @brief Read buffer data corresponding to AD4170 IIO device * @param dev_instance[in] - IIO device instance * @param pbuf[out] - Pointer to output data buffer * @param offset[in] - Data buffer offset * @param bytes_count[in] - Number of bytes to read * @param ch_mask[in] - Channels select mask * @return SUCCESS in case of success or negative value otherwise */ static ssize_t iio_ad77681_read_data(void *dev_instance, char *pbuf, size_t offset, size_t bytes_count, uint32_t ch_mask) { if (adc_data_capture_started == false) { start_data_capture(ch_mask, AD77681_NUM_CHANNELS); adc_data_capture_started = true; } /* Read the data stored into acquisition buffers */ return (ssize_t)read_buffered_data(pbuf, bytes_count, offset, ch_mask, AD77681_BYTES_PER_SAMPLE); } /** * @brief Transfer the device data into memory (optional) * @param dev_instance[in] - IIO device instance * @param bytes_count[in] - Number of bytes to read * @param ch_mask[in] - Channels select mask * @return SUCCESS in case of success or negative value otherwise */ static ssize_t iio_ad77681_transfer_dev_data(void *dev_instance, size_t bytes_count, uint32_t ch_mask) { /* The function insures that data is first read into memory from the device. * This function doesn't do any sort of data transfer but it make sure data * read and it's transfer to memory from device is happening in application through * iio_ad4130_read_data() function */ /* Store the requested samples count value for data capture */ store_requested_samples_count(bytes_count, AD77681_BYTES_PER_SAMPLE); return SUCCESS; } /** * @brief Perform tasks before new data transfer * @param dev_instance[in] - IIO device instance * @param ch_mask[in] - Channels select mask * @return SUCCESS in case of success or negative value otherwise */ static int32_t iio_ad77681_start_transfer(void *dev_instance, uint32_t ch_mask) { return SUCCESS; } /** * @brief Perform tasks before end of current data transfer * @param dev_instance[in] - IIO device instance * @return SUCCESS in case of success or negative value otherwise */ static int32_t iio_ad77681_stop_transfer(void *dev) { adc_data_capture_started = false; stop_data_capture(); return SUCCESS; } /********************************************************* * IIO Attributes and Structures ********************************************************/ /* IIOD channels attributes list */ struct iio_attribute channel_input_attributes[] = { { .name = "raw", .show = get_raw, .store = set_raw, }, { .name = "scale", .show = get_scale, .store = set_scale, }, END_ATTRIBUTES_ARRAY }; /* IIOD device (global) attributes list */ static struct iio_attribute global_attributes[] = { { .name = "sampling_frequency", .show = get_sampling_frequency, .store = set_sampling_frequency, }, { .name = "conv_mode_available", .show = get_conv_mode_available, .store = set_conv_mode_available, }, { .name = "conv_mode", .show = get_conv_mode, .store = set_conv_mode, }, { .name = "power_mode_available", .show = get_power_mode_available, .store = set_power_mode_available, }, { .name = "power_mode", .show = get_power_mode, .store = set_power_mode, }, { .name = "mclk_division_available", .show = get_mclk_division_available, .store = set_mclk_division_available, }, { .name = "mclk_division", .show = get_mclk_division, .store = set_mclk_division, }, END_ATTRIBUTES_ARRAY }; /* IIOD debug attributes list */ static struct iio_attribute debug_attributes[] = { { .name = "direct_reg_access", .show = NULL, .store = NULL, }, END_ATTRIBUTES_ARRAY }; /* IIOD channels configurations */ struct scan_type chn_scan = { .sign = 's', .realbits = AD77681_CHN_STORAGE_BITS, .storagebits = AD77681_CHN_STORAGE_BITS, .shift = 0, .is_big_endian = false }; /* IIOD Channel list */ static struct iio_channel iio_ad77681_channels[] = { { .name = "voltage0", .ch_type = IIO_VOLTAGE, .channel = 0, .scan_index = 0, .scan_type = &chn_scan, .attributes = channel_input_attributes, .ch_out = false, .indexed = true, }, }; /** * @brief Init for reading/writing and parameterization of a * ad77681 IIO device * @param desc[in,out] - IIO device descriptor * @return SUCCESS in case of success, FAILURE otherwise */ static int32_t iio_ad77681_init(struct iio_device **desc) { struct iio_device *iio_ad77861_inst; iio_ad77861_inst = calloc(1, sizeof(struct iio_device)); if (!iio_ad77861_inst) { return FAILURE; } iio_ad77861_inst->num_ch = sizeof(iio_ad77681_channels) / sizeof( iio_ad77681_channels[0]); iio_ad77861_inst->channels = iio_ad77681_channels; iio_ad77861_inst->attributes = global_attributes; iio_ad77861_inst->debug_attributes = debug_attributes; iio_ad77861_inst->transfer_dev_to_mem = iio_ad77681_transfer_dev_data; iio_ad77861_inst->transfer_mem_to_dev = NULL; iio_ad77861_inst->read_data = iio_ad77681_read_data; iio_ad77861_inst->write_data = NULL; iio_ad77861_inst->prepare_transfer = iio_ad77681_start_transfer; iio_ad77861_inst->end_transfer = iio_ad77681_stop_transfer; iio_ad77861_inst->debug_reg_read = debug_reg_read; iio_ad77861_inst->debug_reg_write = debug_reg_write; *desc = iio_ad77861_inst; return SUCCESS; } /** * @brief Release resources allocated for AD77681 IIO device * @param desc[in] - IIO device descriptor * @return SUCCESS in case of success, FAILURE otherwise */ static int32_t iio_ad77681_remove(struct iio_desc *desc) { int32_t status; if (!desc) { return FAILURE; } status = iio_unregister(desc, (char *)dev_name); if (status != SUCCESS) { return FAILURE; } return SUCCESS; } /** * @brief Initialize the IIO interface for AD77681 IIO device * @return none * @return SUCCESS in case of success, FAILURE otherwise */ int32_t ad77681_iio_initialize(void) { int32_t init_status = FAILURE; /* IIO device descriptor */ struct iio_device *p_iio_ad77681_dev; /** * IIO interface init parameters */ struct iio_init_param iio_init_params = { .phy_type = USE_UART, { &uart_init_params } }; /* Initialize AD77681 device and peripheral interface */ init_status = ad77681_setup(&p_ad77681_dev_inst, sad77681_init, &p_ad77681_stat_reg); if (init_status != SUCCESS) { return init_status; } /* Initialize the IIO interface */ init_status = iio_init(&p_ad77681_iio_desc, &iio_init_params); if (init_status != SUCCESS) { return init_status; } /* Initialize the AD77681 IIO application interface */ init_status = iio_ad77681_init(&p_iio_ad77681_dev); if (init_status != SUCCESS) { return init_status; } /* Register AD77681 IIO interface */ init_status = iio_register(p_ad77681_iio_desc, p_iio_ad77681_dev, (char *)dev_name, p_ad77681_dev_inst, NULL, NULL); if (init_status != SUCCESS) { return init_status; } /* Init the system peripherals */ init_status = init_system(); if (init_status != SUCCESS) { return init_status; } return init_status; } /** * @brief Run the AD77681 IIO event handler * @return none * @details This function monitors the new IIO client event */ void ad77681_iio_event_handler(void) { while (1) { (void)iio_step(p_ad77681_iio_desc); } }