diff --git a/drivers/adc/adc_nrfx_saadc.c b/drivers/adc/adc_nrfx_saadc.c index 499d7c4b110..61497326174 100644 --- a/drivers/adc/adc_nrfx_saadc.c +++ b/drivers/adc/adc_nrfx_saadc.c @@ -100,6 +100,7 @@ BUILD_ASSERT((NRF_SAADC_AIN0 == NRF_SAADC_INPUT_AIN0) && struct driver_data { struct adc_context ctx; uint8_t single_ended_channels; + uint8_t divide_single_ended_value; uint8_t active_channel_cnt; void *mem_reg; void *user_buffer; @@ -360,8 +361,8 @@ static int adc_nrfx_channel_setup(const struct device *dev, if (channel_cfg->differential) { if (channel_cfg->input_negative == NRF_SAADC_GND) { ch_cfg->mode = NRF_SAADC_MODE_SINGLE_ENDED; - /* Do not mark as single-ended to not correct negative values. */ - m_data.single_ended_channels &= ~BIT(channel_cfg->channel_id); + m_data.single_ended_channels |= BIT(channel_cfg->channel_id); + m_data.divide_single_ended_value |= BIT(channel_cfg->channel_id); } else { ch_cfg->mode = NRF_SAADC_MODE_DIFFERENTIAL; m_data.single_ended_channels &= ~BIT(channel_cfg->channel_id); @@ -369,12 +370,13 @@ static int adc_nrfx_channel_setup(const struct device *dev, } else { ch_cfg->mode = NRF_SAADC_MODE_SINGLE_ENDED; m_data.single_ended_channels |= BIT(channel_cfg->channel_id); + m_data.divide_single_ended_value &= ~BIT(channel_cfg->channel_id); } nrfx_err_t ret = nrfx_saadc_channel_config(&cfg); if (ret != NRFX_SUCCESS) { - LOG_ERR("Cannot configure channel %d: %d", channel_cfg->channel_id, ret); + LOG_ERR("Cannot configure channel %d: 0x%08x", channel_cfg->channel_id, ret); return -EINVAL; } @@ -411,12 +413,13 @@ static void adc_context_update_buffer_pointer(struct adc_context *ctx, bool repe if (error != 0) { LOG_ERR("DMM buffer allocation failed err=%d", error); adc_context_complete(ctx, -EIO); + return; } nrfx_err_t nrfx_err = nrfx_saadc_buffer_set(samples_buffer, m_data.active_channel_cnt); if (nrfx_err != NRFX_SUCCESS) { - LOG_ERR("Failed to set buffer: %08x", nrfx_err); + LOG_ERR("Failed to set buffer: 0x%08x", nrfx_err); adc_context_complete(ctx, -EIO); } } @@ -430,7 +433,7 @@ static inline void adc_context_enable_timer(struct adc_context *ctx) nrfx_err_t ret = nrfx_saadc_mode_trigger(); if (ret != NRFX_SUCCESS) { - LOG_ERR("Cannot start sampling: %d", ret); + LOG_ERR("Cannot start sampling: 0x%08x", ret); adc_context_complete(&m_data.ctx, -EIO); } } @@ -443,7 +446,7 @@ static inline void adc_context_disable_timer(struct adc_context *ctx) } } -static void adc_context_on_timer_expired(struct k_timer *timer_id) +static void external_timer_expired_handler(struct k_timer *timer_id) { ARG_UNUSED(timer_id); @@ -537,49 +540,47 @@ static int check_buffer_size(const struct adc_sequence *sequence, uint8_t active return 0; } -static inline void single_ended_channel_cut_negative_sample(uint16_t channel_bit, - uint8_t single_ended_channels, - int16_t **sample) -{ - if ((channel_bit & single_ended_channels) && (**sample < 0)) { - **sample = 0; - } - - (*sample)++; -} - static bool has_single_ended(const struct adc_sequence *sequence) { return sequence->channels & m_data.single_ended_channels; } static void correct_single_ended(const struct adc_sequence *sequence, nrf_saadc_value_t *buffer, - uint16_t buffer_size) + uint16_t num_samples) { - uint8_t selected_channels = sequence->channels; - uint8_t single_ended_channels = m_data.single_ended_channels; int16_t *sample = (int16_t *)buffer; + uint8_t selected_channels = sequence->channels; + uint8_t divide_mask = m_data.divide_single_ended_value; + uint8_t single_ended_mask = m_data.single_ended_channels; - for (uint16_t channel_bit = BIT(0); channel_bit <= single_ended_channels; - channel_bit <<= 1) { - if (!(channel_bit & selected_channels)) { - continue; - } - - if (m_data.internal_timer_enabled) { - if (!(channel_bit & single_ended_channels)) { - continue; + if (m_data.internal_timer_enabled) { + if (selected_channels & divide_mask) { + for (int i = 0; i < num_samples; i++) { + sample[i] /= 2; } - - for (int i = 0; i < buffer_size; i++) { + } else { + for (int i = 0; i < num_samples; i++) { if (sample[i] < 0) { sample[i] = 0; } } - } else { - single_ended_channel_cut_negative_sample(channel_bit, single_ended_channels, - &sample); } + return; + } + + for (uint16_t channel_bit = BIT(0); channel_bit <= single_ended_mask; channel_bit <<= 1) { + if (!(channel_bit & selected_channels)) { + continue; + } + + if (channel_bit & single_ended_mask) { + if (channel_bit & divide_mask) { + *sample /= 2; + } else if (*sample < 0) { + *sample = 0; + } + } + sample++; } } @@ -647,6 +648,7 @@ static int start_read(const struct device *dev, } if ((active_channel_cnt == 1) && (sequence->options != NULL) && + (sequence->options->callback == NULL) && (sequence->options->interval_us <= ADC_INTERNAL_TIMER_INTERVAL_MAX_US) && (sequence->options->interval_us > 0)) { @@ -680,12 +682,12 @@ static int start_read(const struct device *dev, m_data.active_channel_cnt = active_channel_cnt; m_data.user_buffer = sequence->buffer; - error = dmm_buffer_in_prepare(m_data.mem_reg, m_data.user_buffer, - (m_data.internal_timer_enabled - ? (NRFX_SAADC_SAMPLES_TO_BYTES(active_channel_cnt) * - (1 + sequence->options->extra_samplings)) - : NRFX_SAADC_SAMPLES_TO_BYTES(active_channel_cnt)), - &samples_buffer); + error = dmm_buffer_in_prepare( + m_data.mem_reg, m_data.user_buffer, + (m_data.internal_timer_enabled + ? NRFX_SAADC_SAMPLES_TO_BYTES(1 + sequence->options->extra_samplings) + : NRFX_SAADC_SAMPLES_TO_BYTES(active_channel_cnt)), + &samples_buffer); if (error != 0) { LOG_ERR("DMM buffer allocation failed err=%d", error); return error; @@ -697,10 +699,10 @@ static int start_read(const struct device *dev, nrfx_err = nrfx_saadc_buffer_set( samples_buffer, (m_data.internal_timer_enabled - ? (active_channel_cnt * (1 + sequence->options->extra_samplings)) + ? (1 + sequence->options->extra_samplings) : active_channel_cnt)); if (nrfx_err != NRFX_SUCCESS) { - LOG_ERR("Failed to set buffer: %08x", nrfx_err); + LOG_ERR("Failed to set buffer: 0x%08x", nrfx_err); return -EINVAL; } @@ -746,8 +748,8 @@ static void event_handler(const nrfx_saadc_evt_t *event) dmm_buffer_in_release( m_data.mem_reg, m_data.user_buffer, (m_data.internal_timer_enabled - ? (NRFX_SAADC_SAMPLES_TO_BYTES(m_data.active_channel_cnt) * - (1 + m_data.ctx.sequence.options->extra_samplings)) + ? NRFX_SAADC_SAMPLES_TO_BYTES( + 1 + m_data.ctx.sequence.options->extra_samplings) : NRFX_SAADC_SAMPLES_TO_BYTES(m_data.active_channel_cnt)), event->data.done.p_buffer); @@ -772,7 +774,7 @@ static int init_saadc(const struct device *dev) { nrfx_err_t err; - k_timer_init(&m_data.timer, adc_context_on_timer_expired, NULL); + k_timer_init(&m_data.timer, external_timer_expired_handler, NULL); /* The priority value passed here is ignored (see nrfx_glue.h). */ err = nrfx_saadc_init(0);