Lines Matching +full:sample +full:- +full:point +full:- +full:data
4 * SPDX-License-Identifier: Apache-2.0
9 * - sampling: a single analog-to-digital conversion performed by the ADC
10 * - sequence: one or more sampling(s) performed one after the other by the
13 * - round: all ADC operations needed to read all channels in the adc_sequence passed
20 * - idle mode: clock & ADC configuration that minimizes power consumption
21 * - Only the ADC digital domain clock is turned on:
22 * - ADC is powered off (CTRL.ADC_CTRL_ADC_ON_OFF = 0)
23 * - ADC analog domain clock is turned off
24 * - If applicable:
25 * - ADC LDO is disabled
26 * - ADC I/O Booster clock is turned off
27 * - ADC I/O Booster is disabled
28 * - ADC-SMPS clock synchronization is disabled
78 #define NUM_CALIBRATION_POINTS 4 /* 4 calibration point registers (COMP_[0-3]) */
86 /* The STM32WB0 has a 12-bit ADC, but the resolution can be
87 * enhanced to 16-bit by oversampling (using the downsampler)
93 * it uses per-type functions instead. Bring our own.
95 #define ADC_CHANNEL_TYPE_SINGLE_NEG (0x00U) /* Single-ended, positive */
96 #define ADC_CHANNEL_TYPE_SINGLE_POS (0x01U) /* Single-ended, negative */
118 * Pointer in output buffer where the first data sample of the round
125 * Pointer in output buffer where the next data sample from ADC should
194 * 12 -> 0 (LL_ADC_DS_DATA_WIDTH_12_BIT) in ds_width_from_adc_res()
195 * 13 -> 1 (LL_ADC_DS_DATA_WIDTH_13_BIT) in ds_width_from_adc_res()
196 * 14 -> 2 (LL_ADC_DS_DATA_WIDTH_14_BIT) in ds_width_from_adc_res()
197 * 15 -> 3 (LL_ADC_DS_DATA_WIDTH_15_BIT) in ds_width_from_adc_res()
198 * 16 -> 4 (LL_ADC_DS_DATA_WIDTH_16_BIT) in ds_width_from_adc_res()
200 return resolution - 12; in ds_width_from_adc_res()
238 const size_t round_size = sizeof(uint16_t) * POPCOUNT(sequence->channels); in validate_adc_sequence()
241 if (sequence->channels == 0 || in validate_adc_sequence()
242 (sequence->channels & ~BIT_MASK(LL_ADC_CHANNEL_MAX)) != 0) { in validate_adc_sequence()
244 return -EINVAL; in validate_adc_sequence()
247 CHECKIF(!sequence->buffer) { in validate_adc_sequence()
249 return -EINVAL; in validate_adc_sequence()
252 if (!IN_RANGE(sequence->resolution, ADC_MIN_RESOLUTION, ADC_MAX_RESOLUTION)) { in validate_adc_sequence()
254 sequence->resolution, ADC_MIN_RESOLUTION, ADC_MAX_RESOLUTION); in validate_adc_sequence()
255 return -EINVAL; in validate_adc_sequence()
259 if (sequence->oversampling > LL_ADC_DS_RATIO_128) { in validate_adc_sequence()
261 return -ENOTSUP; in validate_adc_sequence()
264 if (sequence->options) { in validate_adc_sequence()
265 const size_t samplings = (size_t)sequence->options->extra_samplings + 1; in validate_adc_sequence()
268 return -ENOMEM; in validate_adc_sequence()
274 if (needed_buf_size > sequence->buffer_size) { in validate_adc_sequence()
275 return -ENOMEM; in validate_adc_sequence()
286 * @param Channel Channel to sample during specified conversion
295 * - SEQ_1 holds channel selection for conversions 0~7 in ll_adc_set_conversion_channel()
296 * - SEQ_2 holds channel selection for conversions 8~15 in ll_adc_set_conversion_channel()
307 MODIFY_REG((&ADCx->SEQ_1)[reg], ADC_SEQ_1_SEQ0 << shift, Channel << shift); in ll_adc_set_conversion_channel()
311 * @brief Set the calibration point to use for a chosen channel type and Vinput range.
316 * @param Point Calibration point to use
321 uint32_t Range, uint32_t Point) in ll_adc_set_calib_point_for_any() argument
331 __ASSERT(Point == LL_ADC_CALIB_POINT_1 in ll_adc_set_calib_point_for_any()
332 || Point == LL_ADC_CALIB_POINT_2 in ll_adc_set_calib_point_for_any()
333 || Point == LL_ADC_CALIB_POINT_3 in ll_adc_set_calib_point_for_any()
334 || Point == LL_ADC_CALIB_POINT_4, "Point is not valid"); in ll_adc_set_calib_point_for_any()
338 * - Group for 1.2V Vinput range in ll_adc_set_calib_point_for_any()
339 * - Group for 2.4V Vinput range in ll_adc_set_calib_point_for_any()
340 * - Group for 3.6V Vinput range in ll_adc_set_calib_point_for_any()
343 * - Select for Single Negative mode in ll_adc_set_calib_point_for_any()
344 * - Select for Single Positive mode in ll_adc_set_calib_point_for_any()
345 * - Select for Differential mode in ll_adc_set_calib_point_for_any()
382 MODIFY_REG(ADCx->COMP_SEL, (ADC_COMP_SEL_OFFSET_GAIN0 << shift), (Point << shift)); in ll_adc_set_calib_point_for_any()
420 * @brief Obtain calibration data for specified channel type and Vinput range
421 * from engineering flash, and write it to specified calibration point
424 * @param Point Calibration point to configure
428 static void configure_calib_point_from_flash(ADC_TypeDef *ADCx, uint32_t Point, in configure_calib_point_from_flash() argument
485 LL_ADC_ConfigureCalibPoint(ADCx, Point, gain, offset); in configure_calib_point_from_flash()
584 static void schedule_and_start_adc_sequence(ADC_TypeDef *adc, struct adc_stm32wb0_data *data) in schedule_and_start_adc_sequence() argument
586 uint32_t remaining_unsampled = data->unsampled_channels; in schedule_and_start_adc_sequence()
593 * point registers are used for what type of acquisition, in in schedule_and_start_adc_sequence()
594 * order to share the same calibration point for different in schedule_and_start_adc_sequence()
619 const uint8_t ch_vin_range = data->channel_config[channel].vinput_range; in schedule_and_start_adc_sequence()
621 /* Attempt to find a compatible calibration point */ in schedule_and_start_adc_sequence()
632 /* No compatible calibration point found. in schedule_and_start_adc_sequence()
633 * If an unallocated calibration point remains, use it. in schedule_and_start_adc_sequence()
651 * with any other 1.2V Vinput range, single-ended positive channel. in schedule_and_start_adc_sequence()
667 /* Ensure calibration point tables are updated. in schedule_and_start_adc_sequence()
681 /* Select the calibration point to use for channel */ in schedule_and_start_adc_sequence()
710 /* Configure special calibration point for temperature sensor */ in schedule_and_start_adc_sequence()
723 data->unsampled_channels = remaining_unsampled; in schedule_and_start_adc_sequence()
726 const struct adc_stm32wb0_config *config = data->dev->config; in schedule_and_start_adc_sequence()
729 /* Save sequence length in driver data for later usage */ in schedule_and_start_adc_sequence()
730 data->sequence_length = sequence_length; in schedule_and_start_adc_sequence()
732 /* Prepare the DMA controller for ADC->memory transfers */ in schedule_and_start_adc_sequence()
733 data->dma_block_config.source_address = (uint32_t)&adc->DS_DATAOUT; in schedule_and_start_adc_sequence()
734 data->dma_block_config.dest_address = (uint32_t)data->next_sample_ptr; in schedule_and_start_adc_sequence()
735 data->dma_block_config.block_size = data->sequence_length * sizeof(uint16_t); in schedule_and_start_adc_sequence()
737 err = dma_config(config->dmac, config->dma_channel, &data->dmac_config); in schedule_and_start_adc_sequence()
739 LOG_ERR("%s: FAIL - dma_config returns %d", __func__, err); in schedule_and_start_adc_sequence()
740 adc_context_complete(&data->ctx, err); in schedule_and_start_adc_sequence()
744 err = dma_start(config->dmac, config->dma_channel); in schedule_and_start_adc_sequence()
746 LOG_ERR("%s: FAIL - dma_start returns %d", __func__, err); in schedule_and_start_adc_sequence()
747 adc_context_complete(&data->ctx, err); in schedule_and_start_adc_sequence()
756 static inline void handle_end_of_sequence(ADC_TypeDef *adc, struct adc_stm32wb0_data *data) in handle_end_of_sequence() argument
758 if (data->unsampled_channels != 0) { in handle_end_of_sequence()
763 schedule_and_start_adc_sequence(adc, data); in handle_end_of_sequence()
766 adc_context_on_sampling_done(&data->ctx, data->dev); in handle_end_of_sequence()
773 const struct adc_stm32wb0_config *config = dev->config; in initiate_read_operation()
774 struct adc_stm32wb0_data *data = dev->data; in initiate_read_operation() local
775 ADC_TypeDef *adc = (ADC_TypeDef *)config->reg; in initiate_read_operation()
784 err = adc_exit_idle_mode(adc, &config->ana_clk); in initiate_read_operation()
790 data->next_sample_ptr = data->round_buf_pointer = sequence->buffer; in initiate_read_operation()
793 LL_ADC_SetDSDataOutputWidth(adc, ds_width_from_adc_res(sequence->resolution)); in initiate_read_operation()
796 LL_ADC_SetDSDataOutputRatio(adc, sequence->oversampling); in initiate_read_operation()
799 adc_context_start_read(&data->ctx, sequence); in initiate_read_operation()
807 const struct adc_stm32wb0_config *config = dev->config; in adc_stm32wb0_isr()
808 struct adc_stm32wb0_data *data = dev->data; in adc_stm32wb0_isr() local
809 ADC_TypeDef *adc = config->reg; in adc_stm32wb0_isr()
811 /* Down sampler output data available */ in adc_stm32wb0_isr()
816 /* Write ADC data to output buffer and update pointer */ in adc_stm32wb0_isr()
817 *data->next_sample_ptr++ = LL_ADC_DSGetOutputData(adc); in adc_stm32wb0_isr()
820 /* Down sampler overflow detected - return error */ in adc_stm32wb0_isr()
826 adc_context_complete(&data->ctx, -EIO); in adc_stm32wb0_isr()
838 /* Execute end-of-sequence logic */ in adc_stm32wb0_isr()
839 handle_end_of_sequence(adc, data); in adc_stm32wb0_isr()
845 struct adc_stm32wb0_data *data = user_data; in adc_stm32wb0_dma_callback() local
846 const struct device *dev = data->dev; in adc_stm32wb0_dma_callback()
847 const struct adc_stm32wb0_config *config = dev->config; in adc_stm32wb0_dma_callback()
848 ADC_TypeDef *adc = config->reg; in adc_stm32wb0_dma_callback()
854 if (dma_channel == config->dma_channel) { in adc_stm32wb0_dma_callback()
856 /* Sequence finished - update driver data accordingly */ in adc_stm32wb0_dma_callback()
857 data->next_sample_ptr += data->sequence_length; in adc_stm32wb0_dma_callback()
860 err = dma_stop(config->dmac, config->dma_channel); in adc_stm32wb0_dma_callback()
865 /* Execute the common end-of-sequence logic */ in adc_stm32wb0_dma_callback()
866 handle_end_of_sequence(adc, data); in adc_stm32wb0_dma_callback()
871 err = dma_stop(config->dmac, config->dma_channel); in adc_stm32wb0_dma_callback()
875 adc_context_complete(&data->ctx, dma_status); in adc_stm32wb0_dma_callback()
878 LOG_DBG("dma_channel 0x%08X != config->dma_channel 0x%08X", in adc_stm32wb0_dma_callback()
879 dma_channel, config->dma_channel); in adc_stm32wb0_dma_callback()
889 struct adc_stm32wb0_data *data = drv_data_from_adc_ctx(ctx); in adc_context_start_sampling() local
890 const struct adc_stm32wb0_config *config = data->dev->config; in adc_context_start_sampling()
893 data->unsampled_channels = data->ctx.sequence.channels; in adc_context_start_sampling()
896 schedule_and_start_adc_sequence(config->reg, data); in adc_context_start_sampling()
902 struct adc_stm32wb0_data *data = drv_data_from_adc_ctx(ctx); in adc_context_update_buffer_pointer() local
905 /* Roll back output pointer to address of first sample in round */ in adc_context_update_buffer_pointer()
906 data->next_sample_ptr = data->round_buf_pointer; in adc_context_update_buffer_pointer()
908 /* Save address of first sample in round in case we have to repeat it */ in adc_context_update_buffer_pointer()
909 data->round_buf_pointer = data->next_sample_ptr; in adc_context_update_buffer_pointer()
915 struct adc_stm32wb0_data *data = drv_data_from_adc_ctx(ctx); in adc_context_on_complete() local
916 const struct adc_stm32wb0_config *config = data->dev->config; in adc_context_on_complete()
924 adc_enter_idle_mode(config->reg, &config->ana_clk); in adc_context_on_complete()
926 /* Prevent data corruption if something goes wrong. */ in adc_context_on_complete()
927 data->next_sample_ptr = NULL; in adc_context_on_complete()
936 CHECKIF(dev == NULL) { return -ENODEV; } in adc_stm32wb0_channel_setup()
937 CHECKIF(channel_cfg == NULL) { return -EINVAL; } in adc_stm32wb0_channel_setup()
939 (channel_cfg->channel_id == LL_ADC_CHANNEL_VINP0_VINM0 in adc_stm32wb0_channel_setup()
940 || channel_cfg->channel_id == LL_ADC_CHANNEL_VINP1_VINM1 in adc_stm32wb0_channel_setup()
941 || channel_cfg->channel_id == LL_ADC_CHANNEL_VINP2_VINM2 in adc_stm32wb0_channel_setup()
942 || channel_cfg->channel_id == LL_ADC_CHANNEL_VINP3_VINM3); in adc_stm32wb0_channel_setup()
943 const uint8_t vin_range = vinput_range_from_adc_ref(channel_cfg->reference); in adc_stm32wb0_channel_setup()
944 const uint32_t channel_id = channel_cfg->channel_id; in adc_stm32wb0_channel_setup()
945 struct adc_stm32wb0_data *data = dev->data; in adc_stm32wb0_channel_setup() local
949 res = k_sem_take(&data->ctx.lock, K_NO_WAIT); in adc_stm32wb0_channel_setup()
955 if (channel_cfg->gain != ADC_GAIN_1) { in adc_stm32wb0_channel_setup()
957 res = -ENOTSUP; in adc_stm32wb0_channel_setup()
963 res = -EINVAL; in adc_stm32wb0_channel_setup()
968 LOG_ERR("invalid channel id %d", channel_cfg->channel_id); in adc_stm32wb0_channel_setup()
969 res = -EINVAL; in adc_stm32wb0_channel_setup()
971 } else if (is_diff_channel != channel_cfg->differential) { in adc_stm32wb0_channel_setup()
972 /* channel_cfg->differential flag does not match in adc_stm32wb0_channel_setup()
976 res = -EINVAL; in adc_stm32wb0_channel_setup()
980 if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) { in adc_stm32wb0_channel_setup()
982 res = -ENOTSUP; in adc_stm32wb0_channel_setup()
989 res = -EINVAL; in adc_stm32wb0_channel_setup()
993 res = -EINVAL; in adc_stm32wb0_channel_setup()
997 /* Save the channel configuration in driver data. in adc_stm32wb0_channel_setup()
1001 data->channel_config[channel_id].vinput_range = vin_range; in adc_stm32wb0_channel_setup()
1005 k_sem_give(&data->ctx.lock); in adc_stm32wb0_channel_setup()
1013 CHECKIF(dev == NULL) { return -ENODEV; } in adc_stm32wb0_read()
1014 struct adc_stm32wb0_data *data = dev->data; in adc_stm32wb0_read() local
1017 adc_context_lock(&data->ctx, false, NULL); in adc_stm32wb0_read()
1025 err = adc_context_wait_for_completion(&data->ctx); in adc_stm32wb0_read()
1030 adc_context_release(&data->ctx, err); in adc_stm32wb0_read()
1039 CHECKIF(dev == NULL) { return -ENODEV; } in adc_stm32wb0_read_async()
1040 struct adc_stm32wb0_data *data = dev->data; in adc_stm32wb0_read_async() local
1043 adc_context_lock(&data->ctx, true, async); in adc_stm32wb0_read_async()
1053 adc_context_release(&data->ctx, err); in adc_stm32wb0_read_async()
1071 const struct adc_stm32wb0_config *config = dev->config; in adc_stm32wb0_init()
1072 struct adc_stm32wb0_data *data = dev->data; in adc_stm32wb0_init() local
1073 ADC_TypeDef *adc = config->reg; in adc_stm32wb0_init()
1078 return -ENODEV; in adc_stm32wb0_init()
1083 (clock_control_subsys_t)&config->dig_clk); in adc_stm32wb0_init()
1089 /* Configure DT-provided signals when available */ in adc_stm32wb0_init()
1090 err = pinctrl_apply_state(config->pinctrl_cfg, PINCTRL_STATE_DEFAULT); in adc_stm32wb0_init()
1091 if (err < 0 && err != -ENOENT) { in adc_stm32wb0_init()
1092 /* ENOENT indicates no entry - should not be treated as failure */ in adc_stm32wb0_init()
1103 /* Enable on-die temperature sensor */ in adc_stm32wb0_init()
1107 /* Set ADC sample rate to 1 Msps (maximum speed) */ in adc_stm32wb0_init()
1110 /* Keep new data on overrun, if it ever happens */ in adc_stm32wb0_init()
1127 if (!config->dmac) { in adc_stm32wb0_init()
1129 return -ENODEV; in adc_stm32wb0_init()
1132 if (!device_is_ready(config->dmac)) { in adc_stm32wb0_init()
1133 LOG_ERR("DMA controller '%s' for ADC not ready", config->dmac->name); in adc_stm32wb0_init()
1134 return -ENODEV; in adc_stm32wb0_init()
1137 /* Finalize DMA configuration structure in driver data */ in adc_stm32wb0_init()
1138 data->dmac_config.head_block = &data->dma_block_config; in adc_stm32wb0_init()
1139 data->dmac_config.user_data = data; in adc_stm32wb0_init()
1146 adc_context_unlock_unconditionally(&data->ctx); in adc_stm32wb0_init()
1149 * It will be awakened on-demand when a call to the ADC API in adc_stm32wb0_init()
1162 const struct adc_stm32wb0_config *config = dev->config; in adc_stm32wb0_pm_action()
1163 ADC_TypeDef *adc = config->reg; in adc_stm32wb0_pm_action()
1170 adc_enter_idle_mode(adc, &config->ana_clk); in adc_stm32wb0_pm_action()
1173 res = pinctrl_apply_state(config->pinctrl_cfg, PINCTRL_STATE_SLEEP); in adc_stm32wb0_pm_action()
1176 * -ENOENT is returned if there are no pins defined in DTS for sleep mode. in adc_stm32wb0_pm_action()
1180 if (res >= 0 || res == -ENOENT) { in adc_stm32wb0_pm_action()
1186 return -ENOTSUP; in adc_stm32wb0_pm_action()