diff --git a/drivers/adc/Kconfig.nrfx b/drivers/adc/Kconfig.nrfx index d411d5c99e1..0a602f5b97b 100644 --- a/drivers/adc/Kconfig.nrfx +++ b/drivers/adc/Kconfig.nrfx @@ -27,5 +27,6 @@ config ADC_NRFX_SAADC default y depends on DT_HAS_NORDIC_NRF_SAADC_ENABLED select ADC_CONFIGURABLE_INPUTS + select NRFX_SAADC help Enable support for nrfx SAADC driver. diff --git a/drivers/adc/adc_nrfx_saadc.c b/drivers/adc/adc_nrfx_saadc.c index 986cca49af8..f9f136f2509 100644 --- a/drivers/adc/adc_nrfx_saadc.c +++ b/drivers/adc/adc_nrfx_saadc.c @@ -6,18 +6,15 @@ #define ADC_CONTEXT_USES_KERNEL_TIMER #include "adc_context.h" -#include +#include #include #include #include #include -#include -#include - -#define LOG_LEVEL CONFIG_ADC_LOG_LEVEL #include #include -LOG_MODULE_REGISTER(adc_nrfx_saadc); + +LOG_MODULE_REGISTER(adc_nrfx_saadc, CONFIG_ADC_LOG_LEVEL); #define DT_DRV_COMPAT nordic_nrf_saadc @@ -103,16 +100,9 @@ BUILD_ASSERT((NRF_SAADC_AIN0 == NRF_SAADC_INPUT_AIN0) && #endif #if defined(CONFIG_NRF_PLATFORM_HALTIUM) - +#include /* Haltium devices always use bounce buffers in RAM */ - -#define SAADC_MEMORY_SECTION \ - COND_CODE_1(DT_NODE_HAS_PROP(DT_NODELABEL(adc), memory_regions), \ - (__attribute__((__section__(LINKER_DT_NODE_REGION_NAME( \ - DT_PHANDLE(DT_NODELABEL(adc), memory_regions)))))), \ - ()) - -static uint16_t adc_samples_buffer[SAADC_CH_NUM] SAADC_MEMORY_SECTION; +static uint16_t adc_samples_buffer[SAADC_CH_NUM] DMM_MEMORY_SECTION(DT_NODELABEL(adc)); #define ADC_BUFFER_IN_RAM @@ -120,14 +110,13 @@ static uint16_t adc_samples_buffer[SAADC_CH_NUM] SAADC_MEMORY_SECTION; struct driver_data { struct adc_context ctx; - - uint8_t positive_inputs[SAADC_CH_NUM]; uint8_t single_ended_channels; + nrf_saadc_value_t *buffer; /* Pointer to the buffer with converted samples. */ + uint8_t active_channel_cnt; #if defined(ADC_BUFFER_IN_RAM) void *samples_buffer; void *user_buffer; - uint8_t active_channels; #endif }; @@ -140,45 +129,37 @@ static struct driver_data m_data = { #endif }; -/* Helper function to convert number of samples to the byte representation. */ -static uint32_t samples_to_bytes(const struct adc_sequence *sequence, uint16_t number_of_samples) -{ - if (NRF_SAADC_8BIT_SAMPLE_WIDTH == 8 && sequence->resolution == 8) { - return number_of_samples; - } - - return number_of_samples * 2; -} +/* Forward declaration */ +static void event_handler(const nrfx_saadc_evt_t *event); /* Helper function to convert acquisition time to register TACQ value. */ -static int adc_convert_acq_time(uint16_t acquisition_time, nrf_saadc_acqtime_t *p_tacq_val) +static int acq_time_set(nrf_saadc_channel_config_t *ch_cfg, uint16_t acquisition_time) { - int result = 0; - #if NRF_SAADC_HAS_ACQTIME_ENUM switch (acquisition_time) { case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 3): - *p_tacq_val = NRF_SAADC_ACQTIME_3US; + ch_cfg->acq_time = NRF_SAADC_ACQTIME_3US; break; case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 5): - *p_tacq_val = NRF_SAADC_ACQTIME_5US; + ch_cfg->acq_time = NRF_SAADC_ACQTIME_5US; break; case ADC_ACQ_TIME_DEFAULT: case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 10): - *p_tacq_val = NRF_SAADC_ACQTIME_10US; + ch_cfg->acq_time = NRF_SAADC_ACQTIME_10US; break; case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 15): - *p_tacq_val = NRF_SAADC_ACQTIME_15US; + ch_cfg->acq_time = NRF_SAADC_ACQTIME_15US; break; case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 20): - *p_tacq_val = NRF_SAADC_ACQTIME_20US; + ch_cfg->acq_time = NRF_SAADC_ACQTIME_20US; break; case ADC_ACQ_TIME_MAX: case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 40): - *p_tacq_val = NRF_SAADC_ACQTIME_40US; + ch_cfg->acq_time = NRF_SAADC_ACQTIME_40US; break; default: - result = -EINVAL; + LOG_ERR("Selected ADC acquisition time is not valid"); + return -EINVAL; } #else #define MINIMUM_ACQ_TIME_IN_NS 125 @@ -195,130 +176,138 @@ static int adc_convert_acq_time(uint16_t acquisition_time, nrf_saadc_acqtime_t * tacq = (nrf_saadc_acqtime_t)(acq_time / MINIMUM_ACQ_TIME_IN_NS) - 1; if ((tacq > NRF_SAADC_ACQTIME_MAX) || (acq_time < MINIMUM_ACQ_TIME_IN_NS)) { - result = -EINVAL; + LOG_ERR("Selected ADC acquisition time is not valid"); + return -EINVAL; } else { - *p_tacq_val = tacq; + ch_cfg->acq_time = tacq; } #endif - return result; + LOG_DBG("ADC acquisition_time: %d", acquisition_time); + + return 0; } -static int saadc_pm_hook(const struct device *dev, enum pm_device_action action) +static int input_assign(nrf_saadc_input_t *pin_p, + nrf_saadc_input_t *pin_n, + const struct adc_channel_cfg *channel_cfg) { - ARG_UNUSED(dev); - - switch (action) { - case PM_DEVICE_ACTION_SUSPEND: - nrf_saadc_disable(NRF_SAADC); - return 0; +#if (NRF_SAADC_HAS_AIN_AS_PIN) + if (channel_cfg->input_positive > ARRAY_SIZE(saadc_psels) || + channel_cfg->input_positive < NRF_SAADC_AIN0) { + LOG_ERR("Invalid analog positive input number: %d", channel_cfg->input_positive); + return -EINVAL; + } - case PM_DEVICE_ACTION_RESUME: - nrf_saadc_enable(NRF_SAADC); - return 0; + *pin_p = saadc_psels[channel_cfg->input_positive]; - default: - break; + if (channel_cfg->differential) { + if (channel_cfg->input_negative > ARRAY_SIZE(saadc_psels) || + channel_cfg->input_negative < NRF_SAADC_AIN0 || + (IS_ENABLED(CONFIG_NRF_PLATFORM_HALTIUM) && + (channel_cfg->input_positive > NRF_SAADC_AIN7) != + (channel_cfg->input_negative > NRF_SAADC_AIN7))) { + LOG_ERR("Invalid analog negative input number: %d", + channel_cfg->input_negative); + return -EINVAL; + } + *pin_n = saadc_psels[channel_cfg->input_negative]; + } else { + *pin_n = NRF_SAADC_INPUT_DISABLED; } +#else + *pin_p = channel_cfg->input_positive; + *pin_n = channel_cfg->differential ? channel_cfg->input_negative + : NRF_SAADC_INPUT_DISABLED; +#endif + LOG_DBG("ADC positive input: %d", *pin_p); + LOG_DBG("ADC negative input: %d", *pin_n); - return -ENOTSUP; + return 0; } -/* Implementation of the ADC driver API function: adc_channel_setup. */ -static int adc_nrfx_channel_setup(const struct device *dev, - const struct adc_channel_cfg *channel_cfg) +static int gain_set(nrf_saadc_channel_config_t *ch_cfg, enum adc_gain gain) { - nrf_saadc_channel_config_t config = { -#if NRF_SAADC_HAS_CH_CONFIG_RES - .resistor_p = NRF_SAADC_RESISTOR_DISABLED, - .resistor_n = NRF_SAADC_RESISTOR_DISABLED, -#endif -#if NRF_SAADC_HAS_CH_BURST - .burst = NRF_SAADC_BURST_DISABLED, -#endif - }; - uint8_t channel_id = channel_cfg->channel_id; - uint32_t input_negative = channel_cfg->input_negative; - - if (channel_id >= SAADC_CH_NUM) { - return -EINVAL; - } - #if NRF_SAADC_HAS_CH_GAIN - switch (channel_cfg->gain) { + switch (gain) { #if defined(SAADC_CH_CONFIG_GAIN_Gain1_6) case ADC_GAIN_1_6: - config.gain = NRF_SAADC_GAIN1_6; + ch_cfg->gain = NRF_SAADC_GAIN1_6; break; #endif #if defined(SAADC_CH_CONFIG_GAIN_Gain1_5) case ADC_GAIN_1_5: - config.gain = NRF_SAADC_GAIN1_5; + ch_cfg->gain = NRF_SAADC_GAIN1_5; break; #endif #if defined(SAADC_CH_CONFIG_GAIN_Gain1_4) || defined(SAADC_CH_CONFIG_GAIN_Gain2_8) case ADC_GAIN_1_4: - config.gain = NRF_SAADC_GAIN1_4; + ch_cfg->gain = NRF_SAADC_GAIN1_4; break; #endif #if defined(SAADC_CH_CONFIG_GAIN_Gain2_7) case ADC_GAIN_2_7: - config.gain = NRF_SAADC_GAIN2_7; + ch_cfg->gain = NRF_SAADC_GAIN2_7; break; #endif #if defined(SAADC_CH_CONFIG_GAIN_Gain1_3) || defined(SAADC_CH_CONFIG_GAIN_Gain2_6) case ADC_GAIN_1_3: - config.gain = NRF_SAADC_GAIN1_3; + ch_cfg->gain = NRF_SAADC_GAIN1_3; break; #endif #if defined(SAADC_CH_CONFIG_GAIN_Gain2_5) case ADC_GAIN_2_5: - config.gain = NRF_SAADC_GAIN2_5; + ch_cfg->gain = NRF_SAADC_GAIN2_5; break; #endif #if defined(SAADC_CH_CONFIG_GAIN_Gain1_2) || defined(SAADC_CH_CONFIG_GAIN_Gain2_4) case ADC_GAIN_1_2: - config.gain = NRF_SAADC_GAIN1_2; + ch_cfg->gain = NRF_SAADC_GAIN1_2; break; #endif #if defined(SAADC_CH_CONFIG_GAIN_Gain2_3) case ADC_GAIN_2_3: - config.gain = NRF_SAADC_GAIN2_3; + ch_cfg->gain = NRF_SAADC_GAIN2_3; break; #endif case ADC_GAIN_1: - config.gain = NRF_SAADC_GAIN1; + ch_cfg->gain = NRF_SAADC_GAIN1; break; case ADC_GAIN_2: - config.gain = NRF_SAADC_GAIN2; + ch_cfg->gain = NRF_SAADC_GAIN2; break; #if defined(SAADC_CH_CONFIG_GAIN_Gain4) case ADC_GAIN_4: - config.gain = NRF_SAADC_GAIN4; + ch_cfg->gain = NRF_SAADC_GAIN4; break; #endif default: #else - if (channel_cfg->gain != ADC_GAIN_1) { + if (ch_cfg->gain != ADC_GAIN_1) { #endif /* defined(NRF_SAADC_HAS_CH_GAIN) */ LOG_ERR("Selected ADC gain is not valid"); return -EINVAL; } - switch (channel_cfg->reference) { + return 0; +} + +static int reference_set(nrf_saadc_channel_config_t *ch_cfg, enum adc_reference reference) +{ + switch (reference) { #if defined(SAADC_CH_CONFIG_REFSEL_Internal) case ADC_REF_INTERNAL: - config.reference = NRF_SAADC_REFERENCE_INTERNAL; + ch_cfg->reference = NRF_SAADC_REFERENCE_INTERNAL; break; #endif #if defined(SAADC_CH_CONFIG_REFSEL_VDD1_4) case ADC_REF_VDD_1_4: - config.reference = NRF_SAADC_REFERENCE_VDD4; + ch_cfg->reference = NRF_SAADC_REFERENCE_VDD4; break; #endif #if defined(SAADC_CH_CONFIG_REFSEL_External) case ADC_REF_EXTERNAL0: - config.reference = NRF_SAADC_REFERENCE_EXTERNAL; + ch_cfg->reference = NRF_SAADC_REFERENCE_EXTERNAL; break; #endif default: @@ -326,133 +315,130 @@ static int adc_nrfx_channel_setup(const struct device *dev, return -EINVAL; } - int ret = adc_convert_acq_time(channel_cfg->acquisition_time, &config.acq_time); + return 0; +} - if (ret) { - LOG_ERR("Selected ADC acquisition time is not valid"); +/* Implementation of the ADC driver API function: adc_channel_setup. */ +static int adc_nrfx_channel_setup(const struct device *dev, + const struct adc_channel_cfg *channel_cfg) +{ + int err; + nrf_saadc_channel_config_t *ch_cfg; + nrfx_saadc_channel_t cfg = { + .channel_config = { +#if NRF_SAADC_HAS_CH_CONFIG_RES + .resistor_p = NRF_SAADC_RESISTOR_DISABLED, + .resistor_n = NRF_SAADC_RESISTOR_DISABLED, +#endif +#if NRF_SAADC_HAS_CH_BURST + .burst = NRF_SAADC_BURST_DISABLED, +#endif + }, + .channel_index = channel_cfg->channel_id, + }; + + if (channel_cfg->channel_id >= SAADC_CH_NUM) { + LOG_ERR("Invalid channel ID: %d", channel_cfg->channel_id); return -EINVAL; } + ch_cfg = &cfg.channel_config; + + err = input_assign(&cfg.pin_p, &cfg.pin_n, channel_cfg); + if (err != 0) { + return err; + } + + err = gain_set(ch_cfg, channel_cfg->gain); + if (err != 0) { + return err; + } + + err = reference_set(ch_cfg, channel_cfg->reference); + if (err != 0) { + return err; + } + + err = acq_time_set(ch_cfg, channel_cfg->acquisition_time); + if (err != 0) { + return err; + } + /* Store channel mode to allow correcting negative readings in single-ended mode * after ADC sequence ends. */ if (channel_cfg->differential) { - config.mode = NRF_SAADC_MODE_DIFFERENTIAL; + ch_cfg->mode = NRF_SAADC_MODE_DIFFERENTIAL; m_data.single_ended_channels &= ~BIT(channel_cfg->channel_id); } else { - config.mode = NRF_SAADC_MODE_SINGLE_ENDED; + ch_cfg->mode = NRF_SAADC_MODE_SINGLE_ENDED; m_data.single_ended_channels |= BIT(channel_cfg->channel_id); } -#if (NRF_SAADC_HAS_AIN_AS_PIN) - if ((channel_cfg->input_positive >= ARRAY_SIZE(saadc_psels)) || - (channel_cfg->input_positive < NRF_SAADC_AIN0)) { - return -EINVAL; - } - - if (config.mode == NRF_SAADC_MODE_DIFFERENTIAL) { -#if defined(CONFIG_NRF_PLATFORM_HALTIUM) - if ((input_negative > NRF_SAADC_AIN7) != - (channel_cfg->input_positive > NRF_SAADC_AIN7)) { -#else - if (input_negative > NRF_SAADC_AIN7 || - input_negative < NRF_SAADC_AIN0) { -#endif - return -EINVAL; - } + nrfx_err_t ret = nrfx_saadc_channel_config(&cfg); - input_negative = saadc_psels[input_negative]; - } else { - input_negative = NRF_SAADC_INPUT_DISABLED; + if (ret != NRFX_SUCCESS) { + LOG_ERR("Cannot configure channel %d: %d", channel_cfg->channel_id, ret); + return -EINVAL; } -#endif - /* Store the positive input selection in a dedicated array, - * to get it later when the channel is selected for a sampling - * and to mark the channel as configured (ready to be selected). - */ - m_data.positive_inputs[channel_id] = channel_cfg->input_positive; - - nrf_saadc_channel_init(NRF_SAADC, channel_id, &config); - /* Keep the channel disabled in hardware (set positive input to - * NRF_SAADC_INPUT_DISABLED) until it is selected to be included - * in a sampling sequence. - */ - nrf_saadc_channel_input_set(NRF_SAADC, - channel_id, - NRF_SAADC_INPUT_DISABLED, - input_negative); return 0; } static void adc_context_start_sampling(struct adc_context *ctx) { -#if defined(CONFIG_PM_DEVICE_RUNTIME) - pm_device_runtime_get(DEVICE_DT_INST_GET(0)); -#else - nrf_saadc_enable(NRF_SAADC); -#endif - if (ctx->sequence.calibrate) { - nrf_saadc_task_trigger(NRF_SAADC, - NRF_SAADC_TASK_CALIBRATEOFFSET); + nrfx_saadc_offset_calibrate(event_handler); } else { - nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_START); - nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_SAMPLE); + nrfx_err_t ret = nrfx_saadc_mode_trigger(); + + if (ret != NRFX_SUCCESS) { + LOG_ERR("Cannot start sampling: 0x%08x", ret); + adc_context_complete(&m_data.ctx, -EIO); + } } } -static void adc_context_update_buffer_pointer(struct adc_context *ctx, - bool repeat) +static void adc_context_update_buffer_pointer(struct adc_context *ctx, bool repeat) { - ARG_UNUSED(ctx); - if (!repeat) { #if defined(ADC_BUFFER_IN_RAM) - m_data.user_buffer = (uint8_t *)m_data.user_buffer + - samples_to_bytes(&ctx->sequence, nrfy_saadc_amount_get(NRF_SAADC)); + m_data.user_buffer = (uint16_t *)m_data.user_buffer + m_data.active_channel_cnt; #else - nrf_saadc_value_t *buffer = - (uint8_t *)nrf_saadc_buffer_pointer_get(NRF_SAADC) + - samples_to_bytes(&ctx->sequence, nrfy_saadc_amount_get(NRF_SAADC)); - nrfy_saadc_buffer_pointer_set(NRF_SAADC, buffer); + nrf_saadc_value_t *buffer = (uint16_t *)m_data.buffer + m_data.active_channel_cnt; + + nrfx_saadc_buffer_set(buffer, m_data.active_channel_cnt); #endif } } -static int set_resolution(const struct adc_sequence *sequence) +static int get_resolution(const struct adc_sequence *sequence, nrf_saadc_resolution_t *resolution) { - nrf_saadc_resolution_t nrf_resolution; - switch (sequence->resolution) { - case 8: - nrf_resolution = NRF_SAADC_RESOLUTION_8BIT; + case 8: + *resolution = NRF_SAADC_RESOLUTION_8BIT; break; case 10: - nrf_resolution = NRF_SAADC_RESOLUTION_10BIT; + *resolution = NRF_SAADC_RESOLUTION_10BIT; break; case 12: - nrf_resolution = NRF_SAADC_RESOLUTION_12BIT; + *resolution = NRF_SAADC_RESOLUTION_12BIT; break; case 14: - nrf_resolution = NRF_SAADC_RESOLUTION_14BIT; + *resolution = NRF_SAADC_RESOLUTION_14BIT; break; default: - LOG_ERR("ADC resolution value %d is not valid", - sequence->resolution); + LOG_ERR("ADC resolution value %d is not valid", sequence->resolution); return -EINVAL; } - nrf_saadc_resolution_set(NRF_SAADC, nrf_resolution); return 0; } -static int set_oversampling(const struct adc_sequence *sequence, - uint8_t active_channels) +static int get_oversampling(const struct adc_sequence *sequence, uint8_t active_channel_cnt, + nrf_saadc_oversample_t *oversampling) { - nrf_saadc_oversample_t nrf_oversampling; - - if ((active_channels > 1) && (sequence->oversampling > 0)) { + if ((active_channel_cnt > 1) && (sequence->oversampling > 0)) { LOG_ERR( "Oversampling is supported for single channel only"); return -EINVAL; @@ -460,48 +446,45 @@ static int set_oversampling(const struct adc_sequence *sequence, switch (sequence->oversampling) { case 0: - nrf_oversampling = NRF_SAADC_OVERSAMPLE_DISABLED; + *oversampling = NRF_SAADC_OVERSAMPLE_DISABLED; break; case 1: - nrf_oversampling = NRF_SAADC_OVERSAMPLE_2X; + *oversampling = NRF_SAADC_OVERSAMPLE_2X; break; case 2: - nrf_oversampling = NRF_SAADC_OVERSAMPLE_4X; + *oversampling = NRF_SAADC_OVERSAMPLE_4X; break; case 3: - nrf_oversampling = NRF_SAADC_OVERSAMPLE_8X; + *oversampling = NRF_SAADC_OVERSAMPLE_8X; break; case 4: - nrf_oversampling = NRF_SAADC_OVERSAMPLE_16X; + *oversampling = NRF_SAADC_OVERSAMPLE_16X; break; case 5: - nrf_oversampling = NRF_SAADC_OVERSAMPLE_32X; + *oversampling = NRF_SAADC_OVERSAMPLE_32X; break; case 6: - nrf_oversampling = NRF_SAADC_OVERSAMPLE_64X; + *oversampling = NRF_SAADC_OVERSAMPLE_64X; break; case 7: - nrf_oversampling = NRF_SAADC_OVERSAMPLE_128X; + *oversampling = NRF_SAADC_OVERSAMPLE_128X; break; case 8: - nrf_oversampling = NRF_SAADC_OVERSAMPLE_256X; + *oversampling = NRF_SAADC_OVERSAMPLE_256X; break; default: - LOG_ERR("Oversampling value %d is not valid", - sequence->oversampling); + LOG_ERR("Oversampling value %d is not valid", sequence->oversampling); return -EINVAL; } - nrf_saadc_oversample_set(NRF_SAADC, nrf_oversampling); return 0; } -static int check_buffer_size(const struct adc_sequence *sequence, - uint8_t active_channels) +static int check_buffer_size(const struct adc_sequence *sequence, uint8_t active_channel_cnt) { size_t needed_buffer_size; - needed_buffer_size = samples_to_bytes(sequence, active_channels); + needed_buffer_size = NRFX_SAADC_SAMPLES_TO_BYTES(active_channel_cnt); if (sequence->options) { needed_buffer_size *= (1 + sequence->options->extra_samplings); @@ -509,7 +492,7 @@ static int check_buffer_size(const struct adc_sequence *sequence, if (sequence->buffer_size < needed_buffer_size) { LOG_ERR("Provided buffer is too small (%u/%u)", - sequence->buffer_size, needed_buffer_size); + sequence->buffer_size, needed_buffer_size); return -ENOMEM; } @@ -526,7 +509,7 @@ static void correct_single_ended(const struct adc_sequence *sequence) uint16_t channel_bit = BIT(0); uint8_t selected_channels = sequence->channels; uint8_t single_ended_channels = m_data.single_ended_channels; - int16_t *sample = nrf_saadc_buffer_pointer_get(NRF_SAADC); + int16_t *sample = (int16_t *)m_data.buffer; while (channel_bit <= single_ended_channels) { if (channel_bit & selected_channels) { @@ -544,12 +527,13 @@ static void correct_single_ended(const struct adc_sequence *sequence) static int start_read(const struct device *dev, const struct adc_sequence *sequence) { + nrfx_err_t nrfx_err; int error; uint32_t selected_channels = sequence->channels; - uint8_t resolution = sequence->resolution; - uint8_t active_channels; - uint8_t channel_id; - nrf_saadc_burst_t burst; + nrf_saadc_resolution_t resolution; + nrf_saadc_oversample_t oversampling; + uint8_t active_channel_cnt = 0U; + uint8_t channel_id = 0U; /* Signal an error if channel selection is invalid (no channels or * a non-existing one is selected). @@ -560,104 +544,55 @@ static int start_read(const struct device *dev, return -EINVAL; } - active_channels = 0U; - - /* Enable only the channels selected for the pointed sequence. - * Disable all the rest. - */ - channel_id = 0U; do { if (selected_channels & BIT(channel_id)) { - /* Signal an error if a selected channel has not been - * configured yet. - */ - if (m_data.positive_inputs[channel_id] == 0U) { - LOG_ERR("Channel %u not configured", - channel_id); - return -EINVAL; - } - /* Signal an error if the channel is configured as - * single ended with a resolution which is identical - * to the sample bit size. The SAADC's "single ended" - * mode is really differential mode with the - * negative input tied to ground. We can therefore - * observe negative values if the positive input falls - * below ground. If the sample bitsize is larger than - * the resolution, we can detect negative values and - * correct them to 0 after the sequencen has ended. - */ - if ((m_data.single_ended_channels & BIT(channel_id)) && - (NRF_SAADC_8BIT_SAMPLE_WIDTH == 8 && resolution == 8)) { - LOG_ERR("Channel %u invalid single ended resolution", - channel_id); + /* Signal an error if a selected channel has not been configured yet. */ + if (0 == (nrfx_saadc_channels_configured_get() & BIT(channel_id))) { + LOG_ERR("Channel %u not configured", channel_id); return -EINVAL; } - /* When oversampling is used, the burst mode needs to - * be activated. Unfortunately, this mode cannot be - * activated permanently in the channel setup, because - * then the multiple channel sampling fails (the END - * event is not generated) after switching to a single - * channel sampling and back. Thus, when oversampling - * is not used (hence, the multiple channel sampling is - * possible), the burst mode have to be deactivated. - */ - burst = (sequence->oversampling != 0U ? - NRF_SAADC_BURST_ENABLED : NRF_SAADC_BURST_DISABLED); -#if NRF_SAADC_HAS_CH_BURST - nrf_saadc_channel_burst_set(NRF_SAADC, channel_id, burst); -#else - nrf_saadc_burst_set(NRF_SAADC, burst); -#endif - nrf_saadc_channel_pos_input_set( - NRF_SAADC, - channel_id, -#if NRF_SAADC_HAS_AIN_AS_PIN - saadc_psels[m_data.positive_inputs[channel_id]] -#else - m_data.positive_inputs[channel_id] -#endif - ); - ++active_channels; - } else { - burst = NRF_SAADC_BURST_DISABLED; -#if NRF_SAADC_HAS_CH_BURST - nrf_saadc_channel_burst_set(NRF_SAADC, channel_id, burst); -#else - nrf_saadc_burst_set(NRF_SAADC, burst); -#endif - nrf_saadc_channel_pos_input_set( - NRF_SAADC, - channel_id, - NRF_SAADC_INPUT_DISABLED); + ++active_channel_cnt; } } while (++channel_id < SAADC_CH_NUM); - error = set_resolution(sequence); + if (active_channel_cnt == 0) { + LOG_ERR("No channel configured"); + return -EINVAL; + } + + error = get_resolution(sequence, &resolution); if (error) { return error; } - error = set_oversampling(sequence, active_channels); + error = get_oversampling(sequence, active_channel_cnt, &oversampling); if (error) { return error; } - error = check_buffer_size(sequence, active_channels); + nrfx_err = nrfx_saadc_simple_mode_set(selected_channels, + resolution, + oversampling, + event_handler); + if (nrfx_err != NRFX_SUCCESS) { + return -EINVAL; + } + + error = check_buffer_size(sequence, active_channel_cnt); if (error) { return error; } + m_data.active_channel_cnt = active_channel_cnt; #if defined(ADC_BUFFER_IN_RAM) m_data.user_buffer = sequence->buffer; - m_data.active_channels = active_channels; - nrf_saadc_buffer_init(NRF_SAADC, - (nrf_saadc_value_t *)m_data.samples_buffer, - active_channels); + nrfx_saadc_buffer_set(m_data.samples_buffer, active_channel_cnt); #else - nrf_saadc_buffer_init(NRF_SAADC, - (nrf_saadc_value_t *)sequence->buffer, - active_channels); + /* Buffer is filled in chunks, each chunk composed of number of samples equal to number + * of active channels. Buffer pointer is advanced and reloaded after each chunk. + */ + nrfx_saadc_buffer_set(sequence->buffer, active_channel_cnt); #endif adc_context_start_read(&m_data.ctx, sequence); @@ -694,18 +629,12 @@ static int adc_nrfx_read_async(const struct device *dev, } #endif /* CONFIG_ADC_ASYNC */ -static void saadc_irq_handler(const struct device *dev) +static void event_handler(const nrfx_saadc_evt_t *event) { - if (nrf_saadc_event_check(NRF_SAADC, NRF_SAADC_EVENT_END)) { - nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_END); - - nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_STOP); + nrfx_err_t err; -#if defined(CONFIG_PM_DEVICE_RUNTIME) - pm_device_runtime_put(DEVICE_DT_INST_GET(0)); -#else - nrf_saadc_disable(NRF_SAADC); -#endif + if (event->type == NRFX_SAADC_EVT_DONE) { + m_data.buffer = event->data.done.p_buffer; if (has_single_ended(&m_data.ctx.sequence)) { correct_single_ended(&m_data.ctx.sequence); @@ -713,39 +642,35 @@ static void saadc_irq_handler(const struct device *dev) #if defined(ADC_BUFFER_IN_RAM) memcpy(m_data.user_buffer, m_data.samples_buffer, - samples_to_bytes(&m_data.ctx.sequence, m_data.active_channels)); + NRFX_SAADC_SAMPLES_TO_BYTES(m_data.active_channel_cnt)); #endif - adc_context_on_sampling_done(&m_data.ctx, dev); - } else if (nrf_saadc_event_check(NRF_SAADC, - NRF_SAADC_EVENT_CALIBRATEDONE)) { - nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_CALIBRATEDONE); - - /* - * The workaround for Nordic nRF52832 anomalies 86 and - * 178 is an explicit STOP after CALIBRATEOFFSET - * before issuing START. - */ - nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_STOP); - nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_START); - nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_SAMPLE); + adc_context_on_sampling_done(&m_data.ctx, DEVICE_DT_INST_GET(0)); + } else if (event->type == NRFX_SAADC_EVT_CALIBRATEDONE) { + err = nrfx_saadc_mode_trigger(); + if (err != NRFX_SUCCESS) { + LOG_ERR("Cannot start sampling: 0x%08x", err); + adc_context_complete(&m_data.ctx, -EIO); + } } } static int init_saadc(const struct device *dev) { - nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_END); - nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_CALIBRATEDONE); - nrf_saadc_int_enable(NRF_SAADC, - NRF_SAADC_INT_END | NRF_SAADC_INT_CALIBRATEDONE); - NRFX_IRQ_ENABLE(DT_INST_IRQN(0)); + nrfx_err_t err; + + /* The priority value passed here is ignored (see nrfx_glue.h). */ + err = nrfx_saadc_init(0); + if (err != NRFX_SUCCESS) { + LOG_ERR("Failed to initialize device: %s", dev->name); + return -EIO; + } - IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), - saadc_irq_handler, DEVICE_DT_INST_GET(0), 0); + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), nrfx_isr, nrfx_saadc_irq_handler, 0); adc_context_unlock_unconditionally(&m_data.ctx); - return pm_device_driver_init(dev, saadc_pm_hook); + return 0; } static DEVICE_API(adc, adc_nrfx_driver_api) = { @@ -784,29 +709,7 @@ static DEVICE_API(adc, adc_nrfx_driver_api) = { "1v8 inputs cannot be mixed with 3v3 inputs"); /* Validate configuration of all channels. */ -#define VALIDATE_CHANNELS_CONFIG(inst) DT_FOREACH_CHILD(DT_DRV_INST(inst), VALIDATE_CHANNEL_CONFIG) +DT_FOREACH_CHILD(DT_DRV_INST(0), VALIDATE_CHANNEL_CONFIG) -/* - * There is only one instance on supported SoCs, so inst is guaranteed - * to be 0 if any instance is okay. (We use adc_0 above, so the driver - * is relying on the numeric instance value in a way that happens to - * be safe.) - * - * Just in case that assumption becomes invalid in the future, we use - * a BUILD_ASSERT(). - */ -#define SAADC_INIT(inst) \ - BUILD_ASSERT((inst) == 0, \ - "multiple instances not supported"); \ - VALIDATE_CHANNELS_CONFIG(inst) \ - PM_DEVICE_DT_INST_DEFINE(0, saadc_pm_hook, 1); \ - DEVICE_DT_INST_DEFINE(0, \ - init_saadc, \ - PM_DEVICE_DT_INST_GET(0), \ - NULL, \ - NULL, \ - POST_KERNEL, \ - CONFIG_ADC_INIT_PRIORITY, \ - &adc_nrfx_driver_api); - -DT_INST_FOREACH_STATUS_OKAY(SAADC_INIT) +DEVICE_DT_INST_DEFINE(0, init_saadc, NULL, NULL, NULL, POST_KERNEL, + CONFIG_ADC_INIT_PRIORITY, &adc_nrfx_driver_api); diff --git a/modules/hal_nordic/nrfx/nrfx_config.h b/modules/hal_nordic/nrfx/nrfx_config.h index 4a2d5af18b6..fac2341c1c5 100644 --- a/modules/hal_nordic/nrfx/nrfx_config.h +++ b/modules/hal_nordic/nrfx/nrfx_config.h @@ -9,7 +9,7 @@ /* Define nrfx API version used in Zephyr. */ #define NRFX_CONFIG_API_VER_MAJOR 3 -#define NRFX_CONFIG_API_VER_MINOR 8 +#define NRFX_CONFIG_API_VER_MINOR 12 #define NRFX_CONFIG_API_VER_MICRO 0 /* Macros used in zephyr-specific config files. */ diff --git a/samples/drivers/adc/adc_sequence/sample.yaml b/samples/drivers/adc/adc_sequence/sample.yaml index 9a824045d13..09edd4cc03c 100644 --- a/samples/drivers/adc/adc_sequence/sample.yaml +++ b/samples/drivers/adc/adc_sequence/sample.yaml @@ -1,10 +1,19 @@ sample: name: ADC driver sequence sample +common: + tags: + - adc + depends_on: adc + harness: console + timeout: 10 + harness_config: + type: multi_line + regex: + - "ADC sequence reading \\[\\d+\\]:" + - "- .+, channel \\d+, \\d+ sequence samples:" + - "- - \\d+ (= \\d+mV)|(\\(value in mV not available\\))" tests: sample.drivers.adc.adc_sequence: - tags: - - adc - depends_on: adc platform_allow: - cy8cproto_063_ble - cy8cproto_062_4343w @@ -18,11 +27,11 @@ tests: - stm32f3_disco integration_platforms: - nrf52840dk/nrf52840 - harness: console - timeout: 10 - harness_config: - type: multi_line - regex: - - "ADC sequence reading \\[\\d+\\]:" - - "- .+, channel \\d+, \\d+ sequence samples:" - - "- - \\d+ (= \\d+mV)|(\\(value in mV not available\\))" + sample.drivers.adc.adc_sequence.8bit: + platform_allow: + - nrf54l15dk/nrf54l15/cpuapp + - nrf54h20dk/nrf54h20/cpuapp + integration_platforms: + - nrf54l15dk/nrf54l15/cpuapp + extra_configs: + - CONFIG_SEQUENCE_RESOLUTION=8 diff --git a/west.yml b/west.yml index 76ca9284ec8..9fdf19767b5 100644 --- a/west.yml +++ b/west.yml @@ -200,7 +200,7 @@ manifest: groups: - hal - name: hal_nordic - revision: 71308dc6d8c021887ce5d98a36cafe9517375a91 + revision: pull/304/head path: modules/hal/nordic groups: - hal