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.
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_ */