Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: tempsensors sdp_k1_sdram
ad4110_data_capture.c
00001 /***************************************************************************//** 00002 * @file ad4110_data_capture.c 00003 * @brief Source file for AD4110 Data capture 00004 ******************************************************************************** 00005 * Copyright (c) 2022 Analog Devices, Inc. 00006 * All rights reserved. 00007 * 00008 * This software is proprietary to Analog Devices, Inc. and its licensors. 00009 * By using this software you agree to the terms of the associated 00010 * Analog Devices Software License Agreement. 00011 *******************************************************************************/ 00012 00013 /******************************************************************************/ 00014 /***************************** Include Files **********************************/ 00015 /******************************************************************************/ 00016 00017 #include <string.h> 00018 #include "ad4110_data_capture.h" 00019 #include "ad4110_iio.h" 00020 #include "ad4110.h" 00021 #include "no_os_error.h" 00022 #include "app_config.h" 00023 00024 /******************************************************************************/ 00025 /********************* Macros and Constants Definition ************************/ 00026 /******************************************************************************/ 00027 00028 /* Timeout count to avoid stuck into potential infinite loop while checking 00029 * for new data into an acquisition buffer. The actual timeout factor is determined 00030 * through 'sampling_frequency' attribute of IIO app, but this period here makes sure 00031 * we are not stuck into a forever loop in case data capture is interrupted 00032 * or failed in between. 00033 * Note: This timeout factor is dependent upon the MCU clock frequency. Below timeout 00034 * is tested for SDP-K1 platform @180Mhz default core clock */ 00035 #define BUF_READ_TIMEOUT 0xffffffff 00036 00037 /******************************************************************************/ 00038 /******************** Variables and User Defined Data Types *******************/ 00039 /******************************************************************************/ 00040 00041 /* 00042 *@enum acq_buffer_state_e 00043 *@details Data acquisition buffer states 00044 **/ 00045 typedef enum { 00046 BUF_AVAILABLE, 00047 BUF_EMPTY, 00048 BUF_FULL 00049 } acq_buffer_state_e; 00050 00051 /* 00052 *@struct acq_buf_t 00053 *@details Data acquisition buffer parameters 00054 **/ 00055 typedef struct { 00056 acq_buffer_state_e state; // Buffer state 00057 uint32_t wr_indx; // Buffer write index (incremented per sample read) 00058 uint32_t rd_indx; // Buffer read index (incremented per sample read) 00059 int8_t *wr_pdata; // Data buffer write pointer 00060 int8_t *rd_pdata; // Data buffer read pointer 00061 bool reindex_buffer; // Reindex buffer to 0th channel 00062 } acq_buf_t; 00063 00064 /* ADC data acquisition buffers */ 00065 static volatile acq_buf_t acq_buffer; 00066 00067 /* Number of samples requested by IIO client */ 00068 static volatile uint32_t num_of_requested_samples = 0; 00069 00070 /* Number of active channels */ 00071 static volatile uint8_t num_of_active_channels; 00072 00073 /* ADC sample/raw data size in bytes */ 00074 static volatile uint8_t sample_size_in_bytes; 00075 00076 /* ADC data buffer */ 00077 #if !defined(USE_SDRAM_CAPTURE_BUFFER) 00078 int8_t adc_data_buffer[DATA_BUFFER_SIZE] = { 0 }; 00079 #endif 00080 00081 /* List of input channels to be captured */ 00082 static volatile uint8_t input_channels[AD4110_NUM_CHANNELS]; 00083 00084 /* Flag to indicate data capture status */ 00085 static volatile bool start_cont_data_capture = false; 00086 00087 /* Max available buffer size (after considering the data alignment with IIO buffer) */ 00088 static volatile uint32_t max_buffer_sz; 00089 00090 /* Current active channel index */ 00091 static volatile uint8_t chn_indx; 00092 00093 /******************************************************************************/ 00094 /************************** Functions Declaration *****************************/ 00095 /******************************************************************************/ 00096 00097 /******************************************************************************/ 00098 /************************** Functions Definition ******************************/ 00099 /******************************************************************************/ 00100 00101 /*! 00102 * @brief Reset the data capture specific variables 00103 * @return none 00104 */ 00105 static void reset_data_capture(void) 00106 { 00107 /* Reset data capture flags */ 00108 num_of_active_channels = 0; 00109 start_cont_data_capture = false; 00110 00111 /* Reset acquisition buffer states and clear old data */ 00112 acq_buffer.state = BUF_EMPTY; 00113 acq_buffer.wr_indx = 0; 00114 acq_buffer.rd_indx = 0; 00115 acq_buffer.reindex_buffer = false; 00116 00117 acq_buffer.wr_pdata = adc_data_buffer; 00118 acq_buffer.rd_pdata = adc_data_buffer; 00119 max_buffer_sz = DATA_BUFFER_SIZE; 00120 } 00121 00122 00123 /*! 00124 * @brief Trigger a data capture in continuous/burst mode 00125 * @return 0 in case of success, negative error code otherwise 00126 */ 00127 static int32_t adc_start_data_capture(void) 00128 { 00129 return ad4110_set_adc_mode(ad4110_dev_inst, AD4110_CONTINOUS_CONV_MODE); 00130 } 00131 00132 00133 /*! 00134 * @brief Stop a data capture operation 00135 * @return 0 in case of success, negative error code otherwise 00136 */ 00137 static int32_t adc_stop_data_capture(void) 00138 { 00139 return ad4110_set_adc_mode(ad4110_dev_inst, AD4110_STANDBY_MODE); 00140 } 00141 00142 00143 /*! 00144 * @brief Function to prepare the data ADC capture for new READBUFF 00145 * request from IIO client (for active channels) 00146 * @param chn_mask[in] - Channels to enable for data capturing 00147 * @param num_of_chns[in] - ADC channel count 00148 * @param sample_size[in] - Sample size in bytes 00149 * @return 0 in case of success, negative error code otherwise 00150 */ 00151 int32_t prepare_data_transfer(uint32_t ch_mask, uint8_t num_of_chns, 00152 uint8_t sample_size) 00153 { 00154 int32_t ret; 00155 uint8_t ch_id; 00156 uint8_t mask = 0x1; 00157 00158 /* Reset the data capture module */ 00159 reset_data_capture(); 00160 00161 sample_size_in_bytes = sample_size; 00162 00163 /* Enable Active channels requested and Disable the remaining */ 00164 for (ch_id = 0; 00165 ch_id < num_of_chns; ch_id++) { 00166 if (ch_mask & mask) { 00167 ret = ad4110_set_channel_status(ad4110_dev_inst, ch_id, true); 00168 if (ret) { 00169 return ret; 00170 } 00171 num_of_requested_samples++; 00172 } else { 00173 ret = ad4110_set_channel_status(ad4110_dev_inst, ch_id, false); 00174 if (ret) { 00175 return ret; 00176 } 00177 } 00178 mask <<= 1; 00179 } 00180 00181 /* Trigger continuous data capture */ 00182 #if (DATA_CAPTURE_MODE == CONTINUOUS_DATA_CAPTURE) 00183 ret = adc_start_data_capture(); 00184 if (ret) { 00185 return ret; 00186 } 00187 00188 acq_buffer.state = BUF_AVAILABLE; 00189 start_cont_data_capture = true; 00190 00191 /* Pull the cs line low to detect the EOC bit during data capture */ 00192 ret = no_os_gpio_set_value(csb_gpio, NO_OS_GPIO_LOW); 00193 if (ret) { 00194 return ret; 00195 } 00196 00197 ret = no_os_irq_enable(external_int_desc, IRQ_INT_ID); 00198 if(ret) { 00199 return ret; 00200 } 00201 #endif 00202 00203 return 0; 00204 } 00205 00206 00207 /*! 00208 * @brief Function to end data capture 00209 * @return 0 in case of success, negative error code otherwise 00210 */ 00211 int32_t end_data_transfer(void) 00212 { 00213 start_cont_data_capture = false; 00214 00215 /* Reset data capture module specific flags and variables */ 00216 reset_data_capture(); 00217 00218 /* Stop ADC data capture */ 00219 return adc_stop_data_capture(); 00220 } 00221 00222 00223 /*! 00224 * @brief Capture requested number of ADC samples in burst mode 00225 * @param pbuf[out] - Pointer to ADC data buffer 00226 * @param nb_of_samples[in] - Number of samples to be read 00227 * @return 0 in case of success, negative error code otherwise 00228 */ 00229 static int32_t read_burst_data(int8_t *pbuf, uint32_t nb_of_samples) 00230 { 00231 uint32_t sample_index = 0; 00232 uint32_t adc_raw_data = 0; 00233 int32_t ret; 00234 00235 if (adc_start_data_capture()) { 00236 return -EIO; 00237 } 00238 00239 while (sample_index < nb_of_samples) { 00240 /* Wait for the RDY Bit to go low to notify end of conversion */ 00241 ret = ad4110_wait_for_rdy_low(ad4110_dev_inst, AD4110_ADC_CONV_TIMEOUT); 00242 if (ret) { 00243 return ret; 00244 } 00245 00246 /* Read the converted data from the Data register */ 00247 ret = ad4110_spi_int_data_reg_read(ad4110_dev_inst, &adc_raw_data); 00248 if (ret) { 00249 return ret; 00250 } 00251 00252 /* Copy raw data to the buffer */ 00253 memcpy((uint8_t*)pbuf, &adc_raw_data, sample_size_in_bytes); 00254 sample_index++; 00255 pbuf += sample_size_in_bytes; 00256 } 00257 00258 /* Stop any active conversion */ 00259 ret = adc_stop_data_capture(); 00260 if (ret) { 00261 return ret; 00262 } 00263 00264 return 0; 00265 } 00266 00267 00268 /*! 00269 * @brief Perform buffer read operations to read requested samples 00270 * @param nb_of_samples[in] - Requested number of samples to read 00271 * @return 0 in case of success, negative error code otherwise 00272 */ 00273 static int32_t buffer_read_operations(uint32_t nb_of_samples) 00274 { 00275 uint32_t timeout = BUF_READ_TIMEOUT; 00276 int32_t offset; 00277 00278 /* Wait until requested samples are available in the buffer to read */ 00279 do { 00280 if (acq_buffer.wr_indx >= acq_buffer.rd_indx) { 00281 offset = acq_buffer.wr_indx - acq_buffer.rd_indx; 00282 } else { 00283 offset = max_buffer_sz + (acq_buffer.wr_indx - acq_buffer.rd_indx); 00284 } 00285 00286 timeout--; 00287 } while ((offset < (int32_t)(nb_of_samples)) && (timeout > 0)); 00288 00289 if (timeout == 0) { 00290 /* This returns the empty buffer */ 00291 return -EIO; 00292 } 00293 00294 if (acq_buffer.rd_indx >= max_buffer_sz) { 00295 acq_buffer.rd_indx = 0; 00296 } 00297 00298 return 0; 00299 } 00300 00301 00302 /*! 00303 * @brief Perform buffer write operations such as buffer full or empty 00304 * check, resetting buffer index and pointers, etc 00305 * @return none 00306 */ 00307 static void buffer_write_operations(void) 00308 { 00309 acq_buffer.wr_indx++; 00310 00311 /* Perform buffer full check and operations */ 00312 if (acq_buffer.wr_indx >= max_buffer_sz) { 00313 if ((acq_buffer.rd_indx >= num_of_requested_samples) 00314 && (acq_buffer.rd_indx != 0)) { 00315 /* Reset buffer write index and write pointer when enough 00316 * space available in the buffer to wrap to start */ 00317 acq_buffer.wr_indx = 0; 00318 00319 acq_buffer.wr_pdata = adc_data_buffer; 00320 if (acq_buffer.rd_indx >= max_buffer_sz) { 00321 /* Wrap the read index and read pointer to start of buffer 00322 * if buffer is completely read/emptied */ 00323 acq_buffer.rd_indx = 0; 00324 acq_buffer.rd_pdata = adc_data_buffer; 00325 } 00326 00327 acq_buffer.state = BUF_AVAILABLE; 00328 } else { 00329 /* Wait until enough space available to wrap buffer write index 00330 * at the start of buffer */ 00331 acq_buffer.wr_indx = max_buffer_sz; 00332 acq_buffer.state = BUF_FULL; 00333 acq_buffer.reindex_buffer = true; 00334 } 00335 } 00336 } 00337 00338 00339 /*! 00340 * @brief Read requested number of ADC samples in continuous mode 00341 * @param pbuf[in] - Pointer to data buffer 00342 * @param nb_of_samples[in] - Number of samples to read 00343 * @return 0 in case of success, negative error code otherwise 00344 * @note The actual sample capturing happens through interrupt. This 00345 * function tracks the buffer read pointer to read block of data 00346 */ 00347 static int32_t read_continuous_conv_data(int8_t **pbuf, uint32_t nb_of_samples) 00348 { 00349 volatile int8_t *rd_addr; 00350 int32_t ret; 00351 00352 /* Determine the max available buffer size based on the requested 00353 * samples count and actual avilable buffer size. Buffer should be 00354 * capable of holding all requested 'n' samples from previous write 00355 * index upto to the end of buffer, as data is read linearly 00356 * from adc buffer in IIO library. 00357 * E.g. If actual buffer size is 2048 samples and requested samples 00358 * are 1600, max available buffer size is actually 1600. So in given 00359 * iteration, only 1600 samples will be stored into buffer and after 00360 * that buffer indexes will be wrapped to a start of buffer. If index 00361 * is not wrapped, the next 1600 requested samples won't accomodate into 00362 * remaining 448 samples space. As buffer is read in linear fashion, the 00363 * read index can't be wrapped to start of buffer to read remaining samples. 00364 * So max available space in this case is 2048 but only utilized space 00365 * will be 1600 in single read buffer request from IIO client. 00366 **/ 00367 max_buffer_sz = ((DATA_BUFFER_SIZE / sample_size_in_bytes) / 00368 nb_of_samples) * nb_of_samples; 00369 00370 ret = buffer_read_operations(nb_of_samples); 00371 if (ret) { 00372 return ret; 00373 } 00374 00375 /* Get the next read address */ 00376 rd_addr = (volatile int8_t *)(acq_buffer.rd_pdata + (acq_buffer.rd_indx * 00377 sample_size_in_bytes)); 00378 acq_buffer.rd_indx += nb_of_samples; 00379 00380 /* Update the IIO buffer pointer to point to next read start location */ 00381 *pbuf = rd_addr; 00382 00383 return 0; 00384 } 00385 00386 00387 /*! 00388 * @brief Read ADC raw data for recently sampled channel 00389 * @param adc_data[out] - Pointer to adc data read variable 00390 * @param input_chn[in] - Input channel 00391 * @return 0 in case of success, negative error code otherwise 00392 * @note This function is intended to call from the conversion end trigger 00393 * event. Therefore, this function should just read raw ADC data 00394 * without further monitoring conversion end event 00395 */ 00396 static int32_t adc_read_converted_sample(uint32_t *adc_data, uint8_t input_chn) 00397 { 00398 int32_t ret; 00399 00400 if (!adc_data) { 00401 return -EIO; 00402 } 00403 00404 ret = ad4110_spi_int_data_reg_read(ad4110_dev_inst, adc_data); 00405 if (ret) { 00406 return ret; 00407 } 00408 00409 /* Pull the cs line low to detect the EOC bit during data capture */ 00410 ret = no_os_gpio_set_value(csb_gpio, NO_OS_GPIO_LOW); 00411 if (ret) { 00412 return ret; 00413 } 00414 00415 ret = no_os_irq_enable(external_int_desc, IRQ_INT_ID); 00416 if (ret) { 00417 return ret; 00418 } 00419 00420 return 0; 00421 } 00422 00423 00424 /*! 00425 * @brief This is an ISR (Interrupt Service Routine) to monitor end of conversion event. 00426 * @param ctx[in] - Callback context (unused) 00427 * @return none 00428 * @details This is an Interrupt callback function/ISR invoked in synchronous/asynchronous 00429 * manner depending upon the application implementation. The conversion results 00430 * are read into acquisition buffer and control continue to sample next channel. 00431 * This continues until conversion is stopped (through IIO client command) 00432 */ 00433 void data_capture_callback(void *ctx) 00434 { 00435 uint32_t adc_sample; 00436 volatile uint8_t *wr_addr; 00437 00438 /* The callback function is triggered when the first falling edge is detected 00439 * on the MISO pin, indicating End of Conversion. Interrupt is disabled 00440 because any data transaction on the SPI line could be interpreted 00441 by the MCU as a falling edge. 00442 */ 00443 00444 no_os_irq_disable(external_int_desc, IRQ_INT_ID); 00445 00446 if (start_cont_data_capture == true) { 00447 /* Read the sample for channel which has been sampled recently */ 00448 if (adc_read_converted_sample(&adc_sample, 00449 input_channels[chn_indx]) == 0) { 00450 do { 00451 if (acq_buffer.state == BUF_AVAILABLE) { 00452 if (acq_buffer.reindex_buffer) { 00453 /* Buffer refilling must start with first active channel data 00454 * for IIO client to synchronize the buffered data */ 00455 if (chn_indx != 0) { 00456 break; 00457 } 00458 acq_buffer.reindex_buffer = false; 00459 } 00460 00461 /* Copy adc samples into acquisition buffer to transport over 00462 * communication link */ 00463 wr_addr = (volatile uint8_t *)(acq_buffer.wr_pdata + (acq_buffer.wr_indx * 00464 sample_size_in_bytes)); 00465 memcpy((uint8_t *)wr_addr, &adc_sample, sample_size_in_bytes); 00466 } 00467 00468 /* Perform buffer write operations */ 00469 buffer_write_operations(); 00470 } while (0); 00471 00472 /* Track the count for recently sampled channel */ 00473 chn_indx++; 00474 if (chn_indx >= num_of_active_channels) { 00475 chn_indx = 0; 00476 } 00477 } 00478 } 00479 } 00480 00481 00482 /*! 00483 * @brief Function to read the ADC buffered raw data requested by IIO client 00484 * @param pbuf[in] - Pointer to data buffer 00485 * @param nb_of_bytes[in] - Number of bytes to read 00486 * @return 0 in case of success, negative error code otherwise 00487 */ 00488 int32_t read_buffered_data(int8_t **pbuf, uint32_t nb_of_bytes) 00489 { 00490 int32_t ret; 00491 num_of_requested_samples = nb_of_bytes / sample_size_in_bytes; 00492 00493 #if (DATA_CAPTURE_MODE == BURST_DATA_CAPTURE) 00494 ret = read_burst_data(*pbuf, num_of_requested_samples); 00495 #else 00496 ret = read_continuous_conv_data(pbuf, num_of_requested_samples); 00497 #endif 00498 if (ret) { 00499 return ret; 00500 } 00501 00502 return 0; 00503 }
Generated on Mon Aug 1 2022 05:40:39 by
1.7.2