Platform drivers for Mbed.
Dependents: EVAL-CN0535-FMCZ EVAL-CN0535-FMCZ EVAL-AD568x-AD569x EVAL-AD7606 ... more
adc_data_capture.c
00001 /***************************************************************************//** 00002 * @file adc_data_capture.c 00003 * @brief ADC common data capture interface for IIO based applications 00004 * @details This module handles the ADC data capturing for IIO client 00005 ******************************************************************************** 00006 * Copyright (c) 2021 Analog Devices, Inc. 00007 * All rights reserved. 00008 * 00009 * This software is proprietary to Analog Devices, Inc. and its licensors. 00010 * By using this software you agree to the terms of the associated 00011 * Analog Devices Software License Agreement. 00012 *******************************************************************************/ 00013 00014 /******************************************************************************/ 00015 /***************************** Include Files **********************************/ 00016 /******************************************************************************/ 00017 00018 #include <stdint.h> 00019 #include <stdbool.h> 00020 #include <string.h> 00021 00022 #include "adc_data_capture.h" 00023 #include "error.h" 00024 00025 /******************************************************************************/ 00026 /********************** Macros and Constants Definition ***********************/ 00027 /******************************************************************************/ 00028 00029 /* Max available channels for continuous data capture. Actual number of channels 00030 * to be captured are supplied from an application */ 00031 #define MAX_AVAILABLE_CHANNELS (16) 00032 00033 /* Max size of the acquisition buffer (in terms of bytes) */ 00034 #define DATA_BUFFER_SIZE (32768) // 32Kbytes 00035 00036 /* Timeout count to avoid stuck into potential infinite loop while checking 00037 * for new data into an acquisition buffer. The actual timeout factor is determined 00038 * through 'sampling_frequency' attribute of IIO app, but this period here makes sure 00039 * we are not stuck into a forever loop in case data capture is interrupted 00040 * or failed in between. 00041 * Note: This timeout factor is dependent upon the MCU clock frequency. Below timeout 00042 * is tested for SDP-K1 platform @180Mhz default core clock */ 00043 #define BUF_READ_TIMEOUT (100000000) 00044 00045 /******************************************************************************/ 00046 /********************** Variables and User Defined Data Types *****************/ 00047 /******************************************************************************/ 00048 00049 /* Extern declaration for device specific data capture operations structure 00050 * (actual definition should be present in an application) */ 00051 extern struct data_capture_ops data_capture_ops; 00052 00053 /* 00054 *@enum acq_buffer_state_e 00055 *@details Enum holding the data acquisition buffer states 00056 **/ 00057 typedef enum { 00058 BUF_AVAILABLE, 00059 BUF_EMPTY, 00060 BUF_FULL 00061 } acq_buffer_state_e; 00062 00063 /* 00064 *@struct acq_buf_t 00065 *@details Structure holding the data acquisition buffer parameters 00066 **/ 00067 typedef struct { 00068 acq_buffer_state_e state; // Buffer state 00069 bool refill_buffer; // Flag to start refilling acquisition buffer 00070 uint32_t rd_indx; // Buffer read index (incremented per sample transmit) 00071 uint32_t wr_indx; // Buffer write index (incremented per sample read) 00072 uint8_t sample_size; // ADC sample/raw data size received from application 00073 uint8_t chn_indx; // ADC channel index into acquisition buffer 00074 uint8_t active_chn[MAX_AVAILABLE_CHANNELS]; // Active channel number sequence 00075 uint8_t data[DATA_BUFFER_SIZE]; // buffer data (adc raw values) 00076 uint8_t *pdata; // Pointer to data buffer 00077 } acq_buf_t; 00078 00079 /* ADC data acquisition buffers */ 00080 static volatile acq_buf_t acq_buffer; 00081 00082 /* Flag to indicate data capture status */ 00083 static volatile bool start_adc_data_capture = false; 00084 00085 /* Number of active channels in any data buffer read request */ 00086 static volatile uint8_t num_of_active_channels = 0; 00087 00088 /* Count to track number of actual samples requested by IIO client */ 00089 static volatile uint16_t num_of_requested_samples = 0; 00090 00091 /* Channel alignment offset */ 00092 static volatile uint8_t chn_alignment_offset = 0; 00093 00094 /* Actual or max available size of acquisition buffer */ 00095 static volatile uint16_t max_available_buffer_size = 0; 00096 00097 /******************************************************************************/ 00098 /************************ Functions Declarations ******************************/ 00099 /******************************************************************************/ 00100 00101 /******************************************************************************/ 00102 /************************ Functions Definitions *******************************/ 00103 /******************************************************************************/ 00104 00105 /*! 00106 * @brief Function to read the single ADC sample (raw data) for input channel 00107 * @param input_chn[in] - Input channel to sample and read data for 00108 * @param raw_data[in, out]- ADC raw data 00109 * @return SUCCESS in case of success, FAILURE otherwise 00110 */ 00111 int32_t read_single_sample(uint8_t input_chn, uint32_t *raw_data) 00112 { 00113 uint32_t read_adc_data = 0; 00114 int32_t status = SUCCESS; 00115 00116 do { 00117 /* Perform operations required before single sample conversion read */ 00118 if (data_capture_ops.single_sample_read_start_ops) { 00119 if (data_capture_ops.single_sample_read_start_ops(input_chn) != SUCCESS) { 00120 status = FAILURE; 00121 break; 00122 } 00123 } 00124 00125 /* Perform ADC conversion and read the converted sample after EOC */ 00126 if (data_capture_ops.perform_conv_and_read_sample(&read_adc_data, input_chn) != 00127 SUCCESS) { 00128 status = FAILURE; 00129 break; 00130 } 00131 } while (0); 00132 00133 /* Perform operations required post single sample conversion read */ 00134 if (data_capture_ops.single_sample_read_stop_ops) { 00135 if (data_capture_ops.single_sample_read_stop_ops(input_chn) != SUCCESS) { 00136 status = FAILURE; 00137 } 00138 } 00139 00140 *raw_data = read_adc_data; 00141 return status; 00142 } 00143 00144 00145 /*! 00146 * @brief Function to store the number of actul requested ADC samples from IIO client 00147 * @param bytes[in] - Number of bytes corresponding to requested samples 00148 * @param sample_size_in_bytes[in] - Size of each sample in bytes (eqv to ADC resolution) 00149 * @return none 00150 * @note The information about sample and buffer size is required for continuous 00151 * data acquisition 00152 */ 00153 void store_requested_samples_count(size_t bytes, uint8_t sample_size_in_bytes) 00154 { 00155 /* This gets the number of samples requested by IIO client for all active channels */ 00156 num_of_requested_samples = bytes / sample_size_in_bytes; 00157 00158 /* Store the ADC sample size */ 00159 acq_buffer.sample_size = sample_size_in_bytes; 00160 00161 /* Get the actual available size of buffer by aligning with number of requested samples. 00162 * e.g. if requested samples are 400 and sample size is 2 bytes, the max available 00163 * size of buffer is: available size = ((32768 / 2) / 400) * 400 = 40 * 400 = 16000. 00164 * The max samples to be requested should always be less than half the max size of buffer 00165 * (in this case: (32768/2) / 2 = 8192). 00166 * */ 00167 max_available_buffer_size = ((DATA_BUFFER_SIZE / sample_size_in_bytes) / 00168 num_of_requested_samples) * num_of_requested_samples; 00169 } 00170 00171 00172 /*! 00173 * @brief Function to read acquired samples into buffer without IIO request timeout 00174 * @param input_buffer[in] - Input data acquisition buffer 00175 * @param output_buffer[in, out] - Output data buffer 00176 * @param samples_to_read[in] - Number of samples to read 00177 * @param sample_size_in_bytes[in] - Size of each sample in bytes (eqv to ADC resolution) 00178 * @return none 00179 */ 00180 static void read_acquired_samples(char *output_buffer, 00181 size_t samples_to_read, 00182 uint8_t sample_size_in_bytes) 00183 { 00184 int32_t buff_rd_wr_indx_offset; // Offset b/w buffer read and write indexes 00185 uint32_t timeout = BUF_READ_TIMEOUT; // Buffer new data read timeout count 00186 size_t bytes = samples_to_read * sample_size_in_bytes; 00187 00188 /* Copy the bytes into buffer provided there is enough offset b/w read and write counts. 00189 * If there is overlap b/w read and write indexes (read is faster than write), empty buffer 00190 * should be returned to IIO client to avoid IIO request timeout */ 00191 do { 00192 buff_rd_wr_indx_offset = (acq_buffer.wr_indx - acq_buffer.rd_indx); 00193 timeout--; 00194 } while (((buff_rd_wr_indx_offset < (int32_t)(samples_to_read)) 00195 || (acq_buffer.wr_indx < acq_buffer.rd_indx)) && (timeout > 0) 00196 && start_adc_data_capture); 00197 00198 if ((timeout == 0) || (acq_buffer.wr_indx <= 0)) { 00199 /* This returns the empty buffer */ 00200 return; 00201 } 00202 00203 memcpy(output_buffer, 00204 (void const *)&acq_buffer.data[acq_buffer.rd_indx * sample_size_in_bytes], 00205 bytes); 00206 acq_buffer.rd_indx += samples_to_read; 00207 } 00208 00209 00210 /*! 00211 * @brief Function to read and align the ADC buffered raw data 00212 * @param device[in]- Device instance 00213 * @param pbuf[out] - Buffer to load ADC raw data 00214 * @param bytes[in] - Number of bytes to be read 00215 * @param active_chns_mask[in] - Active channels mask 00216 * @return Number of bytes read 00217 */ 00218 size_t read_buffered_data(char *pbuf, 00219 size_t bytes, 00220 size_t offset, 00221 uint32_t active_chns_mask, 00222 uint8_t sample_size_in_bytes) 00223 { 00224 size_t samples_to_read = bytes / 00225 sample_size_in_bytes; // Bytes to sample conversion 00226 00227 /* Make sure requested samples size is less than ADC buffer size. Return constant 00228 * value to avoid IIO client getting timed-out */ 00229 if(num_of_requested_samples >= max_available_buffer_size) { 00230 memset(pbuf, 1, bytes); 00231 return bytes; 00232 } 00233 00234 /* Increment read counter to point to next acquired data of 1st active channel */ 00235 if ((offset == 0) && (acq_buffer.rd_indx > 0)) { 00236 acq_buffer.rd_indx += chn_alignment_offset; 00237 } 00238 00239 read_acquired_samples(pbuf, samples_to_read, sample_size_in_bytes); 00240 00241 /* Make buffer available again once it is read/transmited completely */ 00242 if (acq_buffer.rd_indx >= max_available_buffer_size) { 00243 acq_buffer.rd_indx = 0; 00244 acq_buffer.wr_indx = 0; 00245 acq_buffer.pdata = acq_buffer.data; 00246 acq_buffer.state = BUF_AVAILABLE; 00247 acq_buffer.refill_buffer = true; 00248 } 00249 00250 return bytes; 00251 } 00252 00253 00254 /*! 00255 * @brief This is an ISR (Interrupt Service Routine) to monitor end of conversion event. 00256 * @param *ctx[in] - Callback context (unused) 00257 * @param event[in] - Callback event (unused) 00258 * @param extra[in] - Callback extra (unused) 00259 * @return none 00260 * @details This is an Interrupt callback function/ISR invoked in synchronous/asynchronous 00261 * manner depending upon the application implementation. The conversion results 00262 * are read into acquisition buffer and control continue to sample next channel. 00263 * This continues until conversion is stopped (through IIO client command) 00264 * @note This function also handles the logic to align the first channel data after 00265 * every 'n' sample transmission. This is required to visualize data properly 00266 * on IIO client application. 00267 */ 00268 void data_capture_callback(void *ctx, uint32_t event, void *extra) 00269 { 00270 uint32_t adc_sample; 00271 00272 if (start_adc_data_capture == true) { 00273 /* Read the sample(s) for channel(s) which has/have been sampled recently and 00274 * get the number of samples read count */ 00275 if (data_capture_ops.read_converted_sample(&adc_sample, 00276 acq_buffer.active_chn[acq_buffer.chn_indx]) != FAILURE) { 00277 do { 00278 if (acq_buffer.state == BUF_AVAILABLE) { 00279 if (acq_buffer.refill_buffer) { 00280 /* Buffer refilling must start with first active channel data 00281 * for IIO client to synchronize the buffered data */ 00282 if (acq_buffer.chn_indx != 0) { 00283 break; 00284 } 00285 acq_buffer.refill_buffer = false; 00286 } 00287 00288 /* Copy adc samples into acquisition buffer to transport over 00289 * communication link */ 00290 memcpy(acq_buffer.pdata, &adc_sample, acq_buffer.sample_size); 00291 acq_buffer.pdata += acq_buffer.sample_size; 00292 00293 /* Check for acquisition buffer full condition */ 00294 acq_buffer.wr_indx++; 00295 if (acq_buffer.wr_indx >= max_available_buffer_size) { 00296 acq_buffer.state = BUF_FULL; 00297 } 00298 } 00299 } while (0); 00300 00301 /* Keep tracking channel index as it is needed to refill the buffer 00302 * starting with first channel data */ 00303 acq_buffer.chn_indx++; 00304 if (acq_buffer.chn_indx >= num_of_active_channels) { 00305 acq_buffer.chn_indx = 0; 00306 } 00307 } 00308 00309 /* Trigger next continuous conversion (optional or device dependent) */ 00310 if (data_capture_ops.trigger_next_conversion) { 00311 data_capture_ops.trigger_next_conversion(); 00312 } 00313 } 00314 } 00315 00316 00317 /*! 00318 * @brief Reset the data capture specific variables 00319 * @return none 00320 */ 00321 static void reset_data_capture(void) 00322 { 00323 /* Reset data capture flags */ 00324 start_adc_data_capture = false; 00325 num_of_active_channels = 0; 00326 00327 /* Reset acquisition buffer states and clear old data */ 00328 acq_buffer.state = BUF_EMPTY; 00329 00330 acq_buffer.wr_indx = 0; 00331 acq_buffer.rd_indx = 0; 00332 acq_buffer.chn_indx = 0; 00333 acq_buffer.refill_buffer = false; 00334 acq_buffer.pdata = acq_buffer.data; 00335 } 00336 00337 00338 /*! 00339 * @brief Function to trigger ADC conversion for new READBUFF 00340 * request from IIO client (for active channels) 00341 * @param ch_mask[in] - Channels to enable for data capturing 00342 * @param num_of_chns[in] - ADC channel count 00343 * @return none 00344 */ 00345 void start_data_capture(uint32_t ch_mask, uint8_t num_of_chns) 00346 { 00347 uint32_t mask = 0x1; 00348 uint8_t index = 0; 00349 00350 /* Make sure requested samples size is less than max available buffer size */ 00351 if (num_of_requested_samples >= max_available_buffer_size) { 00352 return; 00353 } 00354 00355 /* Reset data capture module specific flags and variables */ 00356 reset_data_capture(); 00357 00358 /* Count active channels based on channel mask set in the IIO client */ 00359 for (uint8_t chn = 0; chn < num_of_chns; chn++) { 00360 if (ch_mask & mask) { 00361 acq_buffer.active_chn[index++] = chn; 00362 num_of_active_channels++; 00363 } 00364 00365 mask <<= 1; 00366 } 00367 00368 /* Note: As shown below, after nth sample read, next sample must be for the first 00369 * channel present in the list of enabled channels */ 00370 /*+-----------------------+-------------------------+---------------------------+ 00371 *| 0 | 1 | 2 | ------| n | 0 | 1 | 2 | --------| n | 0 | 1 | 2 |-----------| l | 00372 *+-^-------------------^-+-^---------------------^-+-^-----------------------^-+ 00373 * | | | | | | 00374 * 1st chn data nth data 1st chn data nth data 1st chn data last data 00375 * n = number of requested samples. l = last data (channel unknown) 00376 * To achieve this, offset value is determined based on the requested samples count 00377 * and number of active channels. The read index is then incremented by offset value 00378 * to read the data for first enabled channel by mapping into acquisition buffer. 00379 **/ 00380 if (num_of_requested_samples % num_of_active_channels) { 00381 chn_alignment_offset = (num_of_requested_samples - ((num_of_requested_samples / 00382 num_of_active_channels) * num_of_active_channels)) + 1; 00383 } else { 00384 chn_alignment_offset = 0; 00385 } 00386 00387 /* Make acquisition buffer available and start continuous conversion */ 00388 acq_buffer.state = BUF_AVAILABLE; 00389 if (data_capture_ops.continuous_sample_read_start_ops) { 00390 if (data_capture_ops.continuous_sample_read_start_ops(ch_mask) != FAILURE) { 00391 start_adc_data_capture = true; 00392 } 00393 } else { 00394 start_adc_data_capture = true; 00395 } 00396 } 00397 00398 00399 /*! 00400 * @brief Function to stop ADC data capture 00401 * @return none 00402 */ 00403 void stop_data_capture(void) 00404 { 00405 start_adc_data_capture = false; 00406 00407 /* Enable operations required post continuous sample read */ 00408 if (data_capture_ops.continuous_sample_read_stop_ops) { 00409 data_capture_ops.continuous_sample_read_stop_ops(); 00410 } 00411 00412 /* Reset data capture module specific flags and variables */ 00413 reset_data_capture(); 00414 }
Generated on Wed Jul 13 2022 14:37:51 by 1.7.2