Pratyush Mallick
/
testing
this is testing
app/src/ad7606_data_capture.c
- Committer:
- pmallick
- Date:
- 2021-01-14
- Revision:
- 0:3afcd581558d
File content as of revision 0:3afcd581558d:
/***************************************************************************//** * @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; }