Skip to content

Commit 0769170

Browse files
committed
[nrf fromtree] drivers: adc: nrfx: enable negative values for single-ended ADC readings
The ADC driver API already supports ADC readings which can return signed values, these are differential readings. In Nordic's datasheet, we have a mode called "single ended", but its just a name. "Single ended" is a differential reading, with the negative channel tied to GND. This is not compatible with zephyrs definition of a single ended reading. To support Nordic's "single ended" mode, the user must configure a differential reading, with the negative input tied to ground, which the saadc driver can then use to configure the reading as Nordic SAADC "single ended", and return negative values as expected. (cherry picked from commit 138f977) Signed-off-by: Jakub Zymelka <[email protected]>
1 parent b5bbe12 commit 0769170

File tree

2 files changed

+57
-13
lines changed

2 files changed

+57
-13
lines changed

drivers/adc/adc_nrfx_saadc.c

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ BUILD_ASSERT((NRF_SAADC_AIN0 == NRF_SAADC_INPUT_AIN0) &&
100100
struct driver_data {
101101
struct adc_context ctx;
102102
uint8_t single_ended_channels;
103+
uint8_t divide_single_ended_value;
103104
uint8_t active_channel_cnt;
104105
void *mem_reg;
105106
void *user_buffer;
@@ -191,22 +192,24 @@ static int input_assign(nrf_saadc_input_t *pin_p,
191192

192193
if (channel_cfg->differential) {
193194
if (channel_cfg->input_negative > ARRAY_SIZE(saadc_psels) ||
194-
channel_cfg->input_negative < NRF_SAADC_AIN0 ||
195195
(IS_ENABLED(CONFIG_NRF_PLATFORM_HALTIUM) &&
196196
(channel_cfg->input_positive > NRF_SAADC_AIN7) !=
197197
(channel_cfg->input_negative > NRF_SAADC_AIN7))) {
198198
LOG_ERR("Invalid analog negative input number: %d",
199199
channel_cfg->input_negative);
200200
return -EINVAL;
201201
}
202-
*pin_n = saadc_psels[channel_cfg->input_negative];
202+
*pin_n = channel_cfg->input_negative == NRF_SAADC_GND ?
203+
NRF_SAADC_INPUT_DISABLED :
204+
saadc_psels[channel_cfg->input_negative];
203205
} else {
204206
*pin_n = NRF_SAADC_INPUT_DISABLED;
205207
}
206208
#else
207209
*pin_p = channel_cfg->input_positive;
208-
*pin_n = channel_cfg->differential ? channel_cfg->input_negative
209-
: NRF_SAADC_INPUT_DISABLED;
210+
*pin_n = (channel_cfg->differential && (channel_cfg->input_negative != NRF_SAADC_GND))
211+
? channel_cfg->input_negative
212+
: NRF_SAADC_INPUT_DISABLED;
210213
#endif
211214
LOG_DBG("ADC positive input: %d", *pin_p);
212215
LOG_DBG("ADC negative input: %d", *pin_n);
@@ -356,11 +359,18 @@ static int adc_nrfx_channel_setup(const struct device *dev,
356359
* after ADC sequence ends.
357360
*/
358361
if (channel_cfg->differential) {
359-
ch_cfg->mode = NRF_SAADC_MODE_DIFFERENTIAL;
360-
m_data.single_ended_channels &= ~BIT(channel_cfg->channel_id);
362+
if (channel_cfg->input_negative == NRF_SAADC_GND) {
363+
ch_cfg->mode = NRF_SAADC_MODE_SINGLE_ENDED;
364+
m_data.single_ended_channels |= BIT(channel_cfg->channel_id);
365+
m_data.divide_single_ended_value |= BIT(channel_cfg->channel_id);
366+
} else {
367+
ch_cfg->mode = NRF_SAADC_MODE_DIFFERENTIAL;
368+
m_data.single_ended_channels &= ~BIT(channel_cfg->channel_id);
369+
}
361370
} else {
362371
ch_cfg->mode = NRF_SAADC_MODE_SINGLE_ENDED;
363372
m_data.single_ended_channels |= BIT(channel_cfg->channel_id);
373+
m_data.divide_single_ended_value &= ~BIT(channel_cfg->channel_id);
364374
}
365375

366376
nrfx_err_t ret = nrfx_saadc_channel_config(&cfg);
@@ -539,22 +549,32 @@ static void correct_single_ended(const struct adc_sequence *sequence, nrf_saadc_
539549
uint16_t num_samples)
540550
{
541551
int16_t *sample = (int16_t *)buffer;
552+
uint8_t selected_channels = sequence->channels;
553+
uint8_t divide_single_ended_value = m_data.divide_single_ended_value;
542554

543555
if (m_data.internal_timer_enabled) {
544-
for (int i = 0; i < num_samples; i++) {
545-
if (sample[i] < 0) {
546-
sample[i] = 0;
556+
if (selected_channels & divide_single_ended_value) {
557+
for (int i = 0; i < num_samples; i++) {
558+
sample[i] /= 2;
559+
}
560+
} else {
561+
for (int i = 0; i < num_samples; i++) {
562+
if (sample[i] < 0) {
563+
sample[i] = 0;
564+
}
547565
}
548566
}
549567
} else {
550-
uint8_t selected_channels = sequence->channels;
551568
uint8_t single_ended_channels = m_data.single_ended_channels;
552569

553570
for (uint16_t channel_bit = BIT(0); channel_bit <= single_ended_channels;
554571
channel_bit <<= 1) {
555-
if ((channel_bit & selected_channels & single_ended_channels) &&
556-
(*sample < 0)) {
557-
*sample = 0;
572+
if (channel_bit & selected_channels & single_ended_channels) {
573+
if (channel_bit & divide_single_ended_value) {
574+
*sample /= 2;
575+
} else if (*sample < 0) {
576+
*sample = 0;
577+
}
558578
}
559579
sample++;
560580
}

include/zephyr/dt-bindings/adc/nrf-saadc.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,30 @@
77
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ADC_NRF_SAADC_H_
88
#define ZEPHYR_INCLUDE_DT_BINDINGS_ADC_NRF_SAADC_H_
99

10+
/**
11+
* @brief Short ADC negative input to ground
12+
*
13+
* @details The nRF SAADC hardware only supports differential readings.
14+
* The nRF SAADC SE (single ended) mode is differential with the negative
15+
* input shorted to GND (ground). To use the nRF SAADC SE mode, set the
16+
* negative input to NRF_SAADC_GND:
17+
*
18+
* @code{.dts}
19+
* zephyr,input-positive = <NRF_SAADC_AIN3>;
20+
* zephyr,input-negative = <NRF_SAADC_GND>;
21+
* @endcode
22+
*
23+
* The nRF SAADC driver also supports using the nRF SAADC SE mode in
24+
* emulated "single-ended" mode, as defined by zephyr. In this mode,
25+
* negative readings will be clamped to 0 by software to emulate the
26+
* behavior of an ADC in "single-ended" mode, as defined by zephyr. To
27+
* do this, only define the positive input:
28+
*
29+
* @code{.dts}
30+
* zephyr,input-positive = <NRF_SAADC_AIN3>;
31+
* @endcode
32+
*/
33+
#define NRF_SAADC_GND 0
1034
#define NRF_SAADC_AIN0 1
1135
#define NRF_SAADC_AIN1 2
1236
#define NRF_SAADC_AIN2 3

0 commit comments

Comments
 (0)