Pratyush Mallick
/
testing
this is testing
Diff: app/src/ad7606_data_capture.c
- Revision:
- 0:3afcd581558d
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/src/ad7606_data_capture.c Thu Jan 14 18:54:16 2021 +0530 @@ -0,0 +1,311 @@ +/***************************************************************************//** + * @file ad7606_data_capture.c + * @brief Data capture interface for AD7606 IIO application + * @details This module handles the AD7606 data capturing +******************************************************************************** + * Copyright (c) 2020 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 <string.h> +#include <stdlib.h> + +#include "app_config.h" +#include "ad7606_data_capture.h" +#include "ad7606_support.h" +#include "gpio_extra.h" + +/******************************************************************************/ +/********************** Macros and Constants Definition ***********************/ +/******************************************************************************/ + +/******************************************************************************/ +/********************** Variables and User Defined Data Types *****************/ +/******************************************************************************/ + +/* Device instance for background adc conversion callback */ +static volatile struct ad7606_dev *dev = NULL; + +/* + *@enum acq_buffer_state_e + *@details Enum holding the data acquisition buffer states + **/ +typedef enum { + BUF_AVAILABLE, + BUF_FULL +} acq_buffer_state_e; + +/* + *@struct acq_buf_t + *@details Structure holding the data acquisition buffer parameters + **/ +typedef struct { + acq_buffer_state_e state; +#if (ADC_RESOLUTION > 16) + uint32_t data[NO_OF_SAMPLES]; +#else + uint16_t data[NO_OF_SAMPLES]; +#endif +} acq_buf_t; + +/* ADC data acquisition buffers */ +static volatile acq_buf_t acq_buffer[2]; + +/* Flag to indicate background data conversion status */ +static volatile bool start_background_conversion = false; + +/* Active channels to be captured */ +static volatile uint32_t active_channels = 0; + +/* Minimum number of bytes to be read from device */ +static volatile uint8_t min_bytes_to_read = 0; + +/* Minimum number of samples to be stored into acquisition buffer */ +static volatile uint8_t min_samples_to_store = 0; + +/******************************************************************************/ +/************************ Functions Definitions *******************************/ +/******************************************************************************/ + +/*! + * @brief Function to init the data capture for AD7606 device + * @param device[in]- Device instance + * @return none + */ +int32_t iio_data_capture_init(struct ad7606_dev *device) +{ + /* Save the device structure for background conversion */ + dev = malloc(sizeof(struct ad7606_dev *)); + if (!dev) { + return FAILURE; + } + + memcpy(&dev, &device, sizeof(dev)); + + return SUCCESS; +} + + +/*! + * @brief Function to read the ADC raw data for single channel + * @param device[in]- Device instance + * @param chn[in] - Input channel + * @return adc raw data/sample + */ +int32_t single_data_read(void *device, uint8_t chn, polarity_e polarity) +{ + int32_t adc_data = 0; + uint32_t adc_raw[ADC_RESOLUTION] = { 0 }; + + if (ad7606_read(device, adc_raw) != SUCCESS) { + adc_raw[chn] = 0; + } + + if (polarity == BIPOLAR) { + /* Check for negative adc value for bipolar inputs */ + if (adc_raw[chn] >= ADC_MAX_COUNT_BIPOLAR) { + /* Take the 2s complement for the negative counts (>full scale value) */ + adc_data = ADC_MAX_COUNT_UNIPOLAR - adc_raw[chn]; + adc_data = 0 - adc_data; + } else { + adc_data = adc_raw[chn]; + } + } else { + adc_data = adc_raw[chn]; + } + + return adc_data; +} + + +/*! + * @brief Function to read the ADC buffered raw data + * @param device[in]- Device instance + * @param pbuf[out] - Buffer to load ADC raw data + * @param bytes[in] - Number of bytes to be read + * @param chn_mask[in] - Active channels mask + * @return none + * @details This function reads the data from any available acquisition + * buffer (the buffer which is full). The intention here is to + * have most recent data fetched from the device. + */ +void buffered_data_read(char *pbuf, size_t bytes, size_t offset, + uint32_t chn_mask) +{ + uint8_t mask = 0x1; + + if (acq_buffer[0].state == BUF_FULL) { + /* Copy the acquisition buffer 0 into output data buffer */ + memcpy(pbuf, acq_buffer[0].data, bytes); + } else if(acq_buffer[1].state == BUF_FULL) { + /* Copy the acquisition buffer 1 into output data buffer */ + memcpy(pbuf, acq_buffer[1].data, bytes); + } else { + /* This case should never reach. At any instance, at least one + * of the buffer should be full */ + } + + /* Find the minimum number of bytes to be read from device during + * background conversion (Reading all channels adds extra overhead, + * so restrict the minimum reads to whatever is possible) */ + if (offset == 0) { + active_channels = chn_mask; + for (uint8_t chn = 1; chn <= NO_OF_CHANNELS; chn++) { + if (active_channels & mask) { +#if (ADC_RESOLUTION == 18) + /* 1 sample = 3 bytes (max 18 bytes) */ + min_bytes_to_read = chn * 3; + if (min_bytes_to_read > ADC_RESOLUTION) { + min_bytes_to_read = ADC_RESOLUTION; + } +#else + /* 1 sample = 2 bytes */ + min_bytes_to_read = chn * 2; +#endif + min_samples_to_store = chn; + } + + mask <<= 1; + } + } +} + + +/*! + * @brief Function to perform background ADC conversion + * @return none + * @details This is an External Interrupt callback function/ISR, which is tied up to + * falling edge trigger of BUSY pin. It is trigered when previous data + * conversion is over and BUSY line goes low. Upon trigger, conversion + * results are read into acquisition buffer and next conversion is triggered. + * This continues until background conversion is stopped. + */ +void do_conversion_callback(void) +{ + static uint16_t sample_cnt = 0; +#if (ADC_RESOLUTION == 18) + uint8_t arr_indx = 0; + uint8_t offset_end = 2; + uint8_t mask = 0xff; +#else + uint8_t mask = 0x01; +#endif + + if (start_background_conversion == true) { + + /* Read the conversion result for required number of bytes */ + (void)ad7606_read_conversion_data(dev, min_bytes_to_read); + + /* Extract the channels data based on the active channels + * Note: The extraction of data based on active channel needs + * to be done since its not possible to capture individual + * channel in AD7606 devices */ + for (uint8_t cnt = 0; cnt < min_samples_to_store; cnt++) { + if (active_channels & mask) { + /* Fill the buffer based on the availability */ + if (acq_buffer[0].state == BUF_AVAILABLE) { +#if (ADC_RESOLUTION == 18) + acq_buffer[0].data[sample_cnt] = + (((uint32_t)(dev->data[arr_indx] & mask) << 16) | // MSB + ((uint32_t)dev->data[arr_indx+1] << 8) | + ((uint32_t)(dev->data[arr_indx+2] >> (8-offset_end)))); // LSB +#else + acq_buffer[0].data[sample_cnt] = + (uint16_t)(((uint16_t)dev->data[cnt << 1] << 8) | // MSB + dev->data[(cnt << 1) + 1]); // LSB +#endif + } else if (acq_buffer[1].state == BUF_AVAILABLE) { +#if (ADC_RESOLUTION == 18) + acq_buffer[1].data[sample_cnt] = + (((uint32_t)(dev->data[arr_indx] & mask) << 16) | // MSB + ((uint32_t)dev->data[arr_indx + 1] << 8) | + ((uint32_t)(dev->data[arr_indx + 2] >> (8 - offset_end))));// LSB +#else + acq_buffer[1].data[sample_cnt] = + (uint16_t)(((uint16_t)dev->data[cnt << 1] << 8) | // MSB + dev->data[(cnt << 1) + 1]); // LSB +#endif + } else { + /* This case should never reach */ + } + + sample_cnt++; + } + +#if (ADC_RESOLUTION == 18) + arr_indx += 2; + + /* Track array to reach at the middle (9 bytes apart) to change the offsets */ + if (arr_indx == ((ADC_RESOLUTION / 2) -1)) { + arr_indx++; + offset_end = 2; + mask = 0xff; + } else { + mask = (0xff >> offset_end); + offset_end += 2; + } +#endif + + if (sample_cnt >= NO_OF_SAMPLES) { + break; + } + + mask <<= 1; + } + + /* Monitor buffer full status based on active buffer state */ + if (sample_cnt >= NO_OF_SAMPLES) { + if (acq_buffer[0].state == BUF_AVAILABLE) { + /* Buffer 0 is set FULL */ + acq_buffer[0].state = BUF_FULL; + + /* Buffer 1 is set available to store next data samples */ + acq_buffer[1].state = BUF_AVAILABLE; + } else if (acq_buffer[1].state == BUF_AVAILABLE) { + /* Buffer 1 is set FULL */ + acq_buffer[1].state = BUF_FULL; + + /* Buffer 0 is set available to store next data samples */ + acq_buffer[0].state = BUF_AVAILABLE; + } else { + /* This case should never reach */ + } + + sample_cnt = 0; + } + + /* Trigger next conversion */ + (void)ad7606_convst(dev); + } +} + + +/*! + * @brief Function to start bakground ADC conversion + * @return none + */ +void start_background_data_conversion(void) +{ + /* Start conversion */ + (void)ad7606_convst(dev); + start_background_conversion = true; +} + + +/*! + * @brief Function to stop bakground ADC conversion + * @return none + */ +void stop_background_data_conversion(void) +{ + start_background_conversion = false; +}