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