importing repo
Revision 18:5ae03a197e59, committed 2021-08-02
- Comitter:
- mahphalke
- Date:
- Mon Aug 02 16:03:08 2021 +0530
- Parent:
- 17:af1f2416dd26
- Commit message:
- Modified the ADC data capture module to remove dependancy on type of ADC and it's specific operations
Changed in this revision
adc_data_capture.c | Show annotated file Show diff for this revision Revisions of this file |
adc_data_capture.h | Show annotated file Show diff for this revision Revisions of this file |
--- a/adc_data_capture.c Tue Jul 13 13:58:07 2021 +0530 +++ b/adc_data_capture.c Mon Aug 02 16:03:08 2021 +0530 @@ -26,24 +26,28 @@ /********************** Macros and Constants Definition ***********************/ /******************************************************************************/ -/* IIO buffer request size in bytes */ -#define IIO_BUF_READ_REQUEST_SIZE (256) +/* Max available channels for continuous data capture. Actual number of channels + * to be captured are supplied from an application */ +#define MAX_AVAILABLE_CHANNELS (16) -/* Max size of the acquisition buffer (in terms of samples) */ -#define DATA_BUFFER_SIZE (8192) +/* Max size of the acquisition buffer (in terms of bytes) */ +#define DATA_BUFFER_SIZE (32768) // 32Kbytes /* Timeout count to avoid stuck into potential infinite loop while checking * for new data into an acquisition buffer. The actual timeout factor is determined - * through 'sampling_frequency' attribute, but this period here makes sure - * we are not stuck into a loop forever in case data capture interrupted - * or failed in between */ + * through 'sampling_frequency' attribute of IIO app, but this period here makes sure + * we are not stuck into a forever loop in case data capture is interrupted + * or failed in between. + * Note: This timeout factor is dependent upon the MCU clock frequency. Below timeout + * is tested for SDP-K1 platform @180Mhz default core clock */ #define BUF_READ_TIMEOUT (100000000) /******************************************************************************/ /********************** Variables and User Defined Data Types *****************/ /******************************************************************************/ -/* Extern declaration for data capture operations structure variable */ +/* Extern declaration for device specific data capture operations structure + * (actual definition should be present in an application) */ extern struct data_capture_ops data_capture_ops; /* @@ -61,11 +65,15 @@ *@details Structure holding the data acquisition buffer parameters **/ typedef struct { - acq_buffer_state_e state; // buffer state - uint32_t rd_indx; // buffer read index - uint32_t wr_indx; // buffer write index - uint32_t sample_cnt; // buffer data/sample counter - uint32_t data[DATA_BUFFER_SIZE]; // buffer data (adc raw values) + acq_buffer_state_e state; // Buffer state + bool refill_buffer; // Flag to start refilling acquisition buffer + uint32_t rd_indx; // Buffer read index (incremented per sample transmit) + uint32_t wr_indx; // Buffer write index (incremented per sample read) + uint8_t sample_size; // ADC sample/raw data size received from application + uint8_t chn_indx; // ADC channel index into acquisition buffer + uint8_t active_chn[MAX_AVAILABLE_CHANNELS]; // Active channel number sequence + uint8_t data[DATA_BUFFER_SIZE]; // buffer data (adc raw values) + uint8_t *pdata; // Pointer to data buffer } acq_buf_t; /* ADC data acquisition buffers */ @@ -77,13 +85,12 @@ /* Number of active channels in any data buffer read request */ static volatile uint8_t num_of_active_channels = 0; -/* Channel data alignment variables */ -static volatile uint8_t buff_chn_indx = 0; -static volatile bool do_chn_alignment = false; - /* Count to track number of actual samples requested by IIO client */ static volatile uint16_t num_of_requested_samples = 0; +/* Channel alignment offset */ +static volatile uint8_t chn_alignment_offset = 0; + /* Actual or max available size of acquisition buffer */ static volatile uint16_t max_available_buffer_size = 0; @@ -96,65 +103,38 @@ /******************************************************************************/ /*! - * @brief Function to read the ADC raw data for single channel + * @brief Function to read the single ADC sample (raw data) for input channel * @param input_chn[in] - Input channel to sample and read data for * @param raw_data[in, out]- ADC raw data * @return SUCCESS in case of success, FAILURE otherwise */ -int32_t single_data_read(uint8_t input_chn, uint32_t *raw_data) +int32_t read_single_sample(uint8_t input_chn, uint32_t *raw_data) { uint32_t read_adc_data = 0; int32_t status = SUCCESS; do { - if (data_capture_ops.save_prev_active_chns) { - /* Save previously active channels */ - if (data_capture_ops.save_prev_active_chns() != SUCCESS) { + /* Perform operations required before single sample conversion read */ + if (data_capture_ops.single_sample_read_start_ops) { + if (data_capture_ops.single_sample_read_start_ops(input_chn) != SUCCESS) { status = FAILURE; break; } } - if (data_capture_ops.disable_all_chns) { - /* Disable all channels */ - if (data_capture_ops.disable_all_chns() != SUCCESS) { - status = FAILURE; - break; - } - } - - if (data_capture_ops.enable_curr_chn) { - /* Enable user input channel */ - if (data_capture_ops.enable_curr_chn(input_chn) != SUCCESS) { - status = FAILURE; - break; - } - } - - if (data_capture_ops.enable_single_read_conversion) { - /* Enable single data read conversion */ - if (data_capture_ops.enable_single_read_conversion() != SUCCESS) { - status = FAILURE; - break; - } - } - - /* Read the data */ - if (data_capture_ops.wait_for_conv_and_read_data(&read_adc_data, input_chn) != + /* Perform ADC conversion and read the converted sample after EOC */ + if (data_capture_ops.perform_conv_and_read_sample(&read_adc_data, input_chn) != SUCCESS) { status = FAILURE; break; } } while (0); - if (data_capture_ops.restore_prev_active_chns) { - /* Enable back channels which were disabled prior to single data read */ - data_capture_ops.restore_prev_active_chns(); - } - - if (data_capture_ops.disable_conversion) { - /* Exit from conversion mode */ - data_capture_ops.disable_conversion(); + /* Perform operations required post single sample conversion read */ + if (data_capture_ops.single_sample_read_stop_ops) { + if (data_capture_ops.single_sample_read_stop_ops(input_chn) != SUCCESS) { + status = FAILURE; + } } *raw_data = read_adc_data; @@ -163,41 +143,46 @@ /*! - * @brief Function to store the number of actul requested samples from IIO client + * @brief Function to store the number of actul requested ADC samples from IIO client * @param bytes[in] - Number of bytes corresponding to requested samples * @param sample_size_in_bytes[in] - Size of each sample in bytes (eqv to ADC resolution) * @return none + * @note The information about sample and buffer size is required for continuous + * data acquisition */ void store_requested_samples_count(size_t bytes, uint8_t sample_size_in_bytes) { /* This gets the number of samples requested by IIO client for all active channels */ num_of_requested_samples = bytes / sample_size_in_bytes; + /* Store the ADC sample size */ + acq_buffer.sample_size = sample_size_in_bytes; + /* Get the actual available size of buffer by aligning with number of requested samples. - * e.g. if requested samples are 400, the max available size of buffer is: - * available size = (2048 / 400) * 400 = 5 * 400 = 2000. + * e.g. if requested samples are 400 and sample size is 2 bytes, the max available + * size of buffer is: available size = ((32768 / 2) / 400) * 400 = 40 * 400 = 16000. * The max samples to be requested should always be less than half the max size of buffer - * (in this case: 2048 / 2 = 1024). + * (in this case: (32768/2) / 2 = 8192). * */ - max_available_buffer_size = ((DATA_BUFFER_SIZE / num_of_requested_samples) * - num_of_requested_samples); + max_available_buffer_size = ((DATA_BUFFER_SIZE / sample_size_in_bytes) / + num_of_requested_samples) * num_of_requested_samples; } /*! - * @brief Function to read new samples into buffer without IIO request timeout + * @brief Function to read acquired samples into buffer without IIO request timeout * @param input_buffer[in] - Input data acquisition buffer * @param output_buffer[in, out] - Output data buffer * @param samples_to_read[in] - Number of samples to read * @param sample_size_in_bytes[in] - Size of each sample in bytes (eqv to ADC resolution) * @return none */ -static void wait_and_read_new_samples(char *output_buffer, - size_t samples_to_read, - uint8_t sample_size_in_bytes) +static void read_acquired_samples(char *output_buffer, + size_t samples_to_read, + uint8_t sample_size_in_bytes) { - int32_t buff_rd_wr_indx_offset; // Offset b/w buffer read and write indexes - uint32_t timeout = BUF_READ_TIMEOUT; // Buffer new data read timeout count + int32_t buff_rd_wr_indx_offset; // Offset b/w buffer read and write indexes + uint32_t timeout = BUF_READ_TIMEOUT; // Buffer new data read timeout count size_t bytes = samples_to_read * sample_size_in_bytes; /* Copy the bytes into buffer provided there is enough offset b/w read and write counts. @@ -216,7 +201,7 @@ } memcpy(output_buffer, - (void const *)&acq_buffer.data[acq_buffer.rd_indx], + (void const *)&acq_buffer.data[acq_buffer.rd_indx * sample_size_in_bytes], bytes); acq_buffer.rd_indx += samples_to_read; } @@ -230,27 +215,36 @@ * @param active_chns_mask[in] - Active channels mask * @return Number of bytes read */ -size_t buffered_data_read(char *pbuf, size_t bytes, - size_t offset, uint32_t active_chns_mask, uint8_t sample_size_in_bytes) +size_t read_buffered_data(char *pbuf, + size_t bytes, + size_t offset, + uint32_t active_chns_mask, + uint8_t sample_size_in_bytes) { size_t samples_to_read = bytes / - sample_size_in_bytes; // Bytes to sample conversion + sample_size_in_bytes; // Bytes to sample conversion /* Make sure requested samples size is less than ADC buffer size. Return constant * value to avoid IIO client getting timed-out */ - if (num_of_requested_samples >= max_available_buffer_size) { + if(num_of_requested_samples >= max_available_buffer_size) { memset(pbuf, 1, bytes); return bytes; } - wait_and_read_new_samples(pbuf, samples_to_read, sample_size_in_bytes); + /* Increment read counter to point to next acquired data of 1st active channel */ + if ((offset == 0) && (acq_buffer.rd_indx > 0)) { + acq_buffer.rd_indx += chn_alignment_offset; + } - /* Make buffer available again once read completely */ + read_acquired_samples(pbuf, samples_to_read, sample_size_in_bytes); + + /* Make buffer available again once it is read/transmited completely */ if (acq_buffer.rd_indx >= max_available_buffer_size) { acq_buffer.rd_indx = 0; acq_buffer.wr_indx = 0; - acq_buffer.sample_cnt = 0; + acq_buffer.pdata = acq_buffer.data; acq_buffer.state = BUF_AVAILABLE; + acq_buffer.refill_buffer = true; } return bytes; @@ -267,77 +261,54 @@ * manner depending upon the application implementation. The conversion results * are read into acquisition buffer and control continue to sample next channel. * This continues until conversion is stopped (through IIO client command) - * @note This function also handles the logic to align the zeroth channel data after + * @note This function also handles the logic to align the first channel data after * every 'n' sample transmission. This is required to visualize data properly - * on IIO client application (more details listed below). + * on IIO client application. */ void data_capture_callback(void *ctx, uint32_t event, void *extra) { uint32_t adc_sample; if (start_adc_data_capture == true) { - do { - /* Read the data for channel which has been sampled recently */ - if (data_capture_ops.read_sampled_data(&adc_sample, buff_chn_indx) != SUCCESS) { - break; - } - - /* If next sample/data in acquisition buffer is required to be of the zeroth - * channel from a list of enabled channels (i.e. chn data alignment needed), then - * wait until a conversion end event is triggered for that zeroth enabled channel */ - /* Note: As shown below, after nth sample read, next sample must be for the zeroth - * channel present in the list of enabled channels */ - /*+-----------------------+-------------------------+---------------------------+ - *| 0 | 1 | 2 | ------| n | 0 | 1 | 2 | --------| n | 0 | 1 | 2 |-----------| n | - *+-^-------------------^-+-^---------------------^-+-^-----------------------^-+ - * | | | | | | - * 0th chn data last data 0th chn data last data 0th chn data last data - * n = number of requested samples - **/ - /* Wait until conversion event for the zeroth channel is triggered */ - if ((do_chn_alignment == true) && (buff_chn_indx != 0)) { - /* Track the count for recently sampled channel */ - buff_chn_indx++; - if (buff_chn_indx >= num_of_active_channels) { - buff_chn_indx = 0; - } + /* Read the sample(s) for channel(s) which has/have been sampled recently and + * get the number of samples read count */ + if (data_capture_ops.read_converted_sample(&adc_sample, + acq_buffer.active_chn[acq_buffer.chn_indx]) != FAILURE) { + do { + if (acq_buffer.state == BUF_AVAILABLE) { + if (acq_buffer.refill_buffer) { + /* Buffer refilling must start with first active channel data + * for IIO client to synchronize the buffered data */ + if (acq_buffer.chn_indx != 0) { + break; + } + acq_buffer.refill_buffer = false; + } - /* If recent sampled channel is not a zeroth enabled channel - * in the channels list, return without storing data into buffer */ - break; - } - - /* Track the count for recently sampled channel */ - buff_chn_indx++; - if (buff_chn_indx >= num_of_active_channels) { - buff_chn_indx = 0; - } - - if (acq_buffer.state == BUF_AVAILABLE) { - /* Reset channel data alignment flag if control reach here */ - do_chn_alignment = false; + /* Copy adc samples into acquisition buffer to transport over + * communication link */ + memcpy(acq_buffer.pdata, &adc_sample, acq_buffer.sample_size); + acq_buffer.pdata += acq_buffer.sample_size; - acq_buffer.data[acq_buffer.wr_indx++] = adc_sample; - acq_buffer.sample_cnt++; - - /* Check if current buffer is full */ - if (acq_buffer.wr_indx >= max_available_buffer_size) { - acq_buffer.state = BUF_FULL; + /* Check for acquisition buffer full condition */ + acq_buffer.wr_indx++; + if (acq_buffer.wr_indx >= max_available_buffer_size) { + acq_buffer.state = BUF_FULL; + } } + } while (0); - /* Once all requested number of samples are transmitted, make sure - * next data to be loaded into acquisition buffer is for zeroth channel - * present in the channels list */ - if (acq_buffer.sample_cnt >= num_of_requested_samples) { - acq_buffer.sample_cnt = 0; - do_chn_alignment = true; - } + /* Keep tracking channel index as it is needed to refill the buffer + * starting with first channel data */ + acq_buffer.chn_indx++; + if (acq_buffer.chn_indx >= num_of_active_channels) { + acq_buffer.chn_indx = 0; } - } while (0); + } /* Trigger next continuous conversion (optional or device dependent) */ - if (data_capture_ops.trigger_next_cont_conversion) { - data_capture_ops.trigger_next_cont_conversion(); + if (data_capture_ops.trigger_next_conversion) { + data_capture_ops.trigger_next_conversion(); } } } @@ -358,10 +329,9 @@ acq_buffer.wr_indx = 0; acq_buffer.rd_indx = 0; - acq_buffer.sample_cnt = 0; - - buff_chn_indx = 0; - do_chn_alignment = true; + acq_buffer.chn_indx = 0; + acq_buffer.refill_buffer = false; + acq_buffer.pdata = acq_buffer.data; } @@ -375,58 +345,53 @@ void start_data_capture(uint32_t ch_mask, uint8_t num_of_chns) { uint32_t mask = 0x1; + uint8_t index = 0; - /* Make sure requested samples size is less than ADC buffer size */ + /* Make sure requested samples size is less than max available buffer size */ if (num_of_requested_samples >= max_available_buffer_size) { return; } - if (data_capture_ops.disable_conversion) { - /* Stop any previous conversion by putting ADC into standby mode */ - if (data_capture_ops.disable_conversion() != SUCCESS) { - return; - } - } - - /* Reset data capture related flags and variables */ + /* Reset data capture module specific flags and variables */ reset_data_capture(); - if (data_capture_ops.save_prev_active_chns) { - /* Store the previous active channels */ - if (data_capture_ops.save_prev_active_chns() != SUCCESS) { - return; - } - } - - /* Enable/Disable channels based on channel mask set in the IIO client */ + /* Count active channels based on channel mask set in the IIO client */ for (uint8_t chn = 0; chn < num_of_chns; chn++) { if (ch_mask & mask) { - if (data_capture_ops.enable_curr_chn) { - /* Enable the selected channel */ - if (data_capture_ops.enable_curr_chn(chn) != SUCCESS) { - return; - } - } - + acq_buffer.active_chn[index++] = chn; num_of_active_channels++; - } else { - if (data_capture_ops.disable_curr_chn) { - /* Disable the selected channel */ - if (data_capture_ops.disable_curr_chn(chn) != SUCCESS) { - return; - } - } } mask <<= 1; } - /* Make primary acquisition buffer available and start continuous conversion */ + /* Note: As shown below, after nth sample read, next sample must be for the first + * channel present in the list of enabled channels */ + /*+-----------------------+-------------------------+---------------------------+ + *| 0 | 1 | 2 | ------| n | 0 | 1 | 2 | --------| n | 0 | 1 | 2 |-----------| l | + *+-^-------------------^-+-^---------------------^-+-^-----------------------^-+ + * | | | | | | + * 1st chn data nth data 1st chn data nth data 1st chn data last data + * n = number of requested samples. l = last data (channel unknown) + * To achieve this, offset value is determined based on the requested samples count + * and number of active channels. The read index is then incremented by offset value + * to read the data for first enabled channel by mapping into acquisition buffer. + **/ + if (num_of_requested_samples % num_of_active_channels) { + chn_alignment_offset = (num_of_requested_samples - ((num_of_requested_samples / + num_of_active_channels) * num_of_active_channels)) + 1; + } else { + chn_alignment_offset = 0; + } + + /* Make acquisition buffer available and start continuous conversion */ acq_buffer.state = BUF_AVAILABLE; - if (data_capture_ops.enable_continuous_read_conversion(ch_mask) == SUCCESS) { + if (data_capture_ops.continuous_sample_read_start_ops) { + if (data_capture_ops.continuous_sample_read_start_ops(ch_mask) != FAILURE) { + start_adc_data_capture = true; + } + } else { start_adc_data_capture = true; - } else { - start_adc_data_capture = false; } } @@ -439,15 +404,11 @@ { start_adc_data_capture = false; - if (data_capture_ops.disable_conversion) { - /* Stop conversion */ - data_capture_ops.disable_conversion(); + /* Enable operations required post continuous sample read */ + if (data_capture_ops.continuous_sample_read_stop_ops) { + data_capture_ops.continuous_sample_read_stop_ops(); } - if (data_capture_ops.restore_prev_active_chns) { - /* Enabled all previously active channels (active during conversion start) */ - data_capture_ops.restore_prev_active_chns(); - } - + /* Reset data capture module specific flags and variables */ reset_data_capture(); }
--- a/adc_data_capture.h Tue Jul 13 13:58:07 2021 +0530 +++ b/adc_data_capture.h Mon Aug 02 16:03:08 2021 +0530 @@ -35,41 +35,41 @@ * data capture functions */ struct data_capture_ops { - /* Save the previous active channels value */ - int32_t (*save_prev_active_chns)(void); - /* Restore (enable) the previous active channels */ - int32_t (*restore_prev_active_chns)(void); - /* Enable ADC current (user input) channel */ - int32_t (*enable_curr_chn)(uint32_t chn); - /* Disable ADC current (user input) channel */ - int32_t (*disable_curr_chn)(uint32_t chn); - /* Disable all ADC channels */ - int32_t(*disable_all_chns)(void); - /* Enable conversion for single sample read */ - int32_t (*enable_single_read_conversion)(void); - /* Enable conversion for continuous sample read */ - int32_t (*enable_continuous_read_conversion)(uint32_t chn_mask); - /* Disable conversion */ - int32_t (*disable_conversion)(void); + /* Perform operations required before single sample read */ + int32_t(*single_sample_read_start_ops)(uint8_t input_chn); + /* Wait for conversion to finish on enabled channels and read conversion data */ - int32_t (*wait_for_conv_and_read_data)(uint32_t *read_data, uint8_t chn); + int32_t(*perform_conv_and_read_sample)(uint32_t *read_data, uint8_t chn); + + /* Enable operations required post single sample read */ + int32_t(*single_sample_read_stop_ops)(uint8_t input_chn); + + /* Perform operations required before continuous sample read */ + int32_t(*continuous_sample_read_start_ops)(uint32_t chn_mask); + /* Read ADC raw sample/data */ - int32_t (*read_sampled_data)(uint32_t *read_data, uint8_t buff_chn_indx); - /* Trigger next continuous conversion sample read */ - int32_t (*trigger_next_cont_conversion)(void); + int32_t(*read_converted_sample)(uint32_t *read_data, uint8_t input_chn); + + /* Perform operations required post continuous sample read */ + int32_t(*continuous_sample_read_stop_ops)(void); + + /* Trigger next data conversion */ + int32_t(*trigger_next_conversion)(void); }; /******************************************************************************/ /************************ Public Declarations *********************************/ /******************************************************************************/ -void save_data_capture_ops_instance(struct data_capture_ops *ops); +int32_t read_single_sample(uint8_t input_chn, uint32_t *raw_data); +size_t read_buffered_data(char *pbuf, + size_t bytes, + size_t offset, + uint32_t active_chns_mask, + uint8_t sample_size_in_bytes); +void store_requested_samples_count(size_t bytes, uint8_t sample_size_in_bytes); void start_data_capture(uint32_t ch_mask, uint8_t num_of_chns); -void data_capture_callback(void *ctx, uint32_t event, void *extra); void stop_data_capture(void); -size_t buffered_data_read(char *pbuf, size_t bytes, - size_t offset, uint32_t active_chns_mask, uint8_t sample_size_in_bytes); -void store_requested_samples_count(size_t bytes, uint8_t sample_size_in_bytes); -int32_t single_data_read(uint8_t input_chn, uint32_t *raw_data); +void data_capture_callback(void *ctx, uint32_t event, void *extra); #endif /* _ADC_DATA_CAPTURE_H_ */