Skip to content

Commit 376b34c

Browse files
jaz1-nordickartben
authored andcommitted
drivers: adc: nrfx_saadc: Add support for SAADC internal sampling timer
The SAMPLERATE register can be used as a local timer instead of triggering individual SAMPLE tasks. When SAMPLERATE.MODE is set to Timers, it is sufficient to trigger SAMPLE task only once in order to start the SAADC and triggering the STOP task will stop sampling. The SAMPLERATE.CC field controls the sample rate. The SAMPLERATE timer should not be combined with SCAN mode and only one channel should be enabled when using the internal timer. Signed-off-by: Jakub Zymelka <[email protected]>
1 parent 44929f7 commit 376b34c

File tree

1 file changed

+134
-35
lines changed

1 file changed

+134
-35
lines changed

drivers/adc/adc_nrfx_saadc.c

Lines changed: 134 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

7-
#define ADC_CONTEXT_USES_KERNEL_TIMER
87
#include "adc_context.h"
98
#include <nrfx_saadc.h>
109
#include <zephyr/dt-bindings/adc/nrf-saadc-v3.h>
@@ -104,15 +103,20 @@ struct driver_data {
104103
uint8_t active_channel_cnt;
105104
void *mem_reg;
106105
void *user_buffer;
106+
struct k_timer timer;
107+
bool internal_timer_enabled;
107108
};
108109

109110
static struct driver_data m_data = {
110-
ADC_CONTEXT_INIT_TIMER(m_data, ctx),
111111
ADC_CONTEXT_INIT_LOCK(m_data, ctx),
112112
ADC_CONTEXT_INIT_SYNC(m_data, ctx),
113113
.mem_reg = DMM_DEV_TO_REG(DT_NODELABEL(adc)),
114+
.internal_timer_enabled = false,
114115
};
115116

117+
/* Maximum value of the internal timer interval in microseconds. */
118+
#define ADC_INTERNAL_TIMER_INTERVAL_MAX_US 128U
119+
116120
/* Forward declaration */
117121
static void event_handler(const nrfx_saadc_evt_t *event);
118122

@@ -362,7 +366,7 @@ static int adc_nrfx_channel_setup(const struct device *dev,
362366
nrfx_err_t ret = nrfx_saadc_channel_config(&cfg);
363367

364368
if (ret != NRFX_SUCCESS) {
365-
LOG_ERR("Cannot configure channel %d: %d", channel_cfg->channel_id, ret);
369+
LOG_ERR("Cannot configure channel %d: 0x%08x", channel_cfg->channel_id, ret);
366370
return -EINVAL;
367371
}
368372

@@ -385,22 +389,58 @@ static void adc_context_start_sampling(struct adc_context *ctx)
385389

386390
static void adc_context_update_buffer_pointer(struct adc_context *ctx, bool repeat)
387391
{
388-
void *samples_buffer;
392+
if (!m_data.internal_timer_enabled) {
393+
void *samples_buffer;
394+
395+
if (!repeat) {
396+
m_data.user_buffer =
397+
(uint16_t *)m_data.user_buffer + m_data.active_channel_cnt;
398+
}
399+
400+
int error = dmm_buffer_in_prepare(
401+
m_data.mem_reg, m_data.user_buffer,
402+
NRFX_SAADC_SAMPLES_TO_BYTES(m_data.active_channel_cnt), &samples_buffer);
403+
if (error != 0) {
404+
LOG_ERR("DMM buffer allocation failed err=%d", error);
405+
adc_context_complete(ctx, -EIO);
406+
return;
407+
}
389408

390-
if (!repeat) {
391-
m_data.user_buffer = (uint16_t *)m_data.user_buffer + m_data.active_channel_cnt;
409+
nrfx_err_t nrfx_err =
410+
nrfx_saadc_buffer_set(samples_buffer, m_data.active_channel_cnt);
411+
if (nrfx_err != NRFX_SUCCESS) {
412+
LOG_ERR("Failed to set buffer: 0x%08x", nrfx_err);
413+
adc_context_complete(ctx, -EIO);
414+
}
392415
}
416+
}
393417

394-
int error = dmm_buffer_in_prepare(
395-
m_data.mem_reg, m_data.user_buffer,
396-
NRFX_SAADC_SAMPLES_TO_BYTES(m_data.active_channel_cnt),
397-
&samples_buffer);
398-
if (error != 0) {
399-
LOG_ERR("DMM buffer allocation failed err=%d", error);
400-
adc_context_complete(ctx, -EIO);
418+
static inline void adc_context_enable_timer(struct adc_context *ctx)
419+
{
420+
if (!m_data.internal_timer_enabled) {
421+
k_timer_start(&m_data.timer, K_NO_WAIT, K_USEC(ctx->options.interval_us));
422+
} else {
423+
nrfx_err_t ret = nrfx_saadc_mode_trigger();
424+
425+
if (ret != NRFX_SUCCESS) {
426+
LOG_ERR("Cannot start sampling: 0x%08x", ret);
427+
adc_context_complete(&m_data.ctx, -EIO);
428+
}
401429
}
430+
}
431+
432+
static inline void adc_context_disable_timer(struct adc_context *ctx)
433+
{
434+
if (!m_data.internal_timer_enabled) {
435+
k_timer_stop(&m_data.timer);
436+
}
437+
}
402438

403-
nrfx_saadc_buffer_set(samples_buffer, m_data.active_channel_cnt);
439+
static void external_timer_expired_handler(struct k_timer *timer_id)
440+
{
441+
ARG_UNUSED(timer_id);
442+
443+
adc_context_request_next_sampling(&m_data.ctx);
404444
}
405445

406446
static int get_resolution(const struct adc_sequence *sequence, nrf_saadc_resolution_t *resolution)
@@ -495,26 +535,48 @@ static bool has_single_ended(const struct adc_sequence *sequence)
495535
return sequence->channels & m_data.single_ended_channels;
496536
}
497537

498-
static void correct_single_ended(const struct adc_sequence *sequence, nrf_saadc_value_t *buffer)
538+
static void correct_single_ended(const struct adc_sequence *sequence, nrf_saadc_value_t *buffer,
539+
uint16_t num_samples)
499540
{
500-
uint16_t channel_bit = BIT(0);
501-
uint8_t selected_channels = sequence->channels;
502-
uint8_t single_ended_channels = m_data.single_ended_channels;
503541
int16_t *sample = (int16_t *)buffer;
504542

505-
while (channel_bit <= single_ended_channels) {
506-
if (channel_bit & selected_channels) {
507-
if ((channel_bit & single_ended_channels) && (*sample < 0)) {
508-
*sample = 0;
543+
if (m_data.internal_timer_enabled) {
544+
for (int i = 0; i < num_samples; i++) {
545+
if (sample[i] < 0) {
546+
sample[i] = 0;
509547
}
548+
}
549+
} else {
550+
uint8_t selected_channels = sequence->channels;
551+
uint8_t single_ended_channels = m_data.single_ended_channels;
510552

553+
for (uint16_t channel_bit = BIT(0); channel_bit <= single_ended_channels;
554+
channel_bit <<= 1) {
555+
if ((channel_bit & selected_channels & single_ended_channels) &&
556+
(*sample < 0)) {
557+
*sample = 0;
558+
}
511559
sample++;
512560
}
513-
514-
channel_bit <<= 1;
515561
}
516562
}
517563

564+
/* The internal timer runs at 16 MHz, so to convert the interval in microseconds
565+
* to the internal timer CC value, we can use the formula:
566+
* interval_cc = interval_us * 16 MHz
567+
* where 16 MHz is the frequency of the internal timer.
568+
*
569+
* The maximum value for interval_cc is 2047, which corresponds to
570+
* approximately 7816 Hz ~ 128us.
571+
* The minimum value for interval_cc is depends on the SoC.
572+
*/
573+
static inline uint16_t interval_to_cc(uint16_t interval_us)
574+
{
575+
NRFX_ASSERT((interval_us <= ADC_INTERNAL_TIMER_INTERVAL_MAX_US) && (interval_us > 0));
576+
577+
return (interval_us * 16) - 1;
578+
}
579+
518580
static int start_read(const struct device *dev,
519581
const struct adc_sequence *sequence)
520582
{
@@ -562,10 +624,29 @@ static int start_read(const struct device *dev,
562624
return error;
563625
}
564626

565-
nrfx_err = nrfx_saadc_simple_mode_set(selected_channels,
566-
resolution,
567-
oversampling,
568-
event_handler);
627+
if ((active_channel_cnt == 1) && (sequence->options != NULL) &&
628+
(sequence->options->callback == NULL) &&
629+
(sequence->options->interval_us <= ADC_INTERNAL_TIMER_INTERVAL_MAX_US) &&
630+
(sequence->options->interval_us > 0)) {
631+
632+
nrfx_saadc_adv_config_t adv_config = {
633+
.oversampling = oversampling,
634+
.burst = NRF_SAADC_BURST_DISABLED,
635+
.internal_timer_cc = interval_to_cc(sequence->options->interval_us),
636+
.start_on_end = true,
637+
};
638+
639+
m_data.internal_timer_enabled = true;
640+
641+
nrfx_err = nrfx_saadc_advanced_mode_set(selected_channels, resolution, &adv_config,
642+
event_handler);
643+
} else {
644+
m_data.internal_timer_enabled = false;
645+
646+
nrfx_err = nrfx_saadc_simple_mode_set(selected_channels, resolution, oversampling,
647+
event_handler);
648+
}
649+
569650
if (nrfx_err != NRFX_SUCCESS) {
570651
return -EINVAL;
571652
}
@@ -578,10 +659,12 @@ static int start_read(const struct device *dev,
578659
m_data.active_channel_cnt = active_channel_cnt;
579660
m_data.user_buffer = sequence->buffer;
580661

581-
error = dmm_buffer_in_prepare(m_data.mem_reg,
582-
m_data.user_buffer,
583-
NRFX_SAADC_SAMPLES_TO_BYTES(active_channel_cnt),
584-
&samples_buffer);
662+
error = dmm_buffer_in_prepare(
663+
m_data.mem_reg, m_data.user_buffer,
664+
(m_data.internal_timer_enabled
665+
? NRFX_SAADC_SAMPLES_TO_BYTES(1 + sequence->options->extra_samplings)
666+
: NRFX_SAADC_SAMPLES_TO_BYTES(active_channel_cnt)),
667+
&samples_buffer);
585668
if (error != 0) {
586669
LOG_ERR("DMM buffer allocation failed err=%d", error);
587670
return error;
@@ -590,7 +673,15 @@ static int start_read(const struct device *dev,
590673
/* Buffer is filled in chunks, each chunk composed of number of samples equal to number
591674
* of active channels. Buffer pointer is advanced and reloaded after each chunk.
592675
*/
593-
nrfx_saadc_buffer_set(samples_buffer, active_channel_cnt);
676+
nrfx_err = nrfx_saadc_buffer_set(
677+
samples_buffer,
678+
(m_data.internal_timer_enabled
679+
? (1 + sequence->options->extra_samplings)
680+
: active_channel_cnt));
681+
if (nrfx_err != NRFX_SUCCESS) {
682+
LOG_ERR("Failed to set buffer: 0x%08x", nrfx_err);
683+
return -EINVAL;
684+
}
594685

595686
adc_context_start_read(&m_data.ctx, sequence);
596687

@@ -633,11 +724,15 @@ static void event_handler(const nrfx_saadc_evt_t *event)
633724
if (event->type == NRFX_SAADC_EVT_DONE) {
634725
dmm_buffer_in_release(
635726
m_data.mem_reg, m_data.user_buffer,
636-
NRFX_SAADC_SAMPLES_TO_BYTES(m_data.active_channel_cnt),
727+
(m_data.internal_timer_enabled
728+
? NRFX_SAADC_SAMPLES_TO_BYTES(
729+
1 + m_data.ctx.sequence.options->extra_samplings)
730+
: NRFX_SAADC_SAMPLES_TO_BYTES(m_data.active_channel_cnt)),
637731
event->data.done.p_buffer);
638732

639733
if (has_single_ended(&m_data.ctx.sequence)) {
640-
correct_single_ended(&m_data.ctx.sequence, m_data.user_buffer);
734+
correct_single_ended(&m_data.ctx.sequence, m_data.user_buffer,
735+
event->data.done.size);
641736
}
642737
nrfy_saadc_disable(NRF_SAADC);
643738
adc_context_on_sampling_done(&m_data.ctx, DEVICE_DT_INST_GET(0));
@@ -647,13 +742,17 @@ static void event_handler(const nrfx_saadc_evt_t *event)
647742
LOG_ERR("Cannot start sampling: 0x%08x", err);
648743
adc_context_complete(&m_data.ctx, -EIO);
649744
}
745+
} else if (event->type == NRFX_SAADC_EVT_FINISHED) {
746+
adc_context_complete(&m_data.ctx, 0);
650747
}
651748
}
652749

653750
static int init_saadc(const struct device *dev)
654751
{
655752
nrfx_err_t err;
656753

754+
k_timer_init(&m_data.timer, external_timer_expired_handler, NULL);
755+
657756
/* The priority value passed here is ignored (see nrfx_glue.h). */
658757
err = nrfx_saadc_init(0);
659758
if (err != NRFX_SUCCESS) {

0 commit comments

Comments
 (0)