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
109110static 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 */
117121static void event_handler (const nrfx_saadc_evt_t * event );
118122
@@ -385,22 +389,57 @@ static void adc_context_start_sampling(struct adc_context *ctx)
385389
386390static 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+ }
389407
390- if (!repeat ) {
391- m_data .user_buffer = (uint16_t * )m_data .user_buffer + m_data .active_channel_cnt ;
408+ nrfx_err_t nrfx_err =
409+ nrfx_saadc_buffer_set (samples_buffer , m_data .active_channel_cnt );
410+ if (nrfx_err != NRFX_SUCCESS ) {
411+ LOG_ERR ("Failed to set buffer: %08x" , nrfx_err );
412+ adc_context_complete (ctx , - EIO );
413+ }
392414 }
415+ }
393416
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 );
417+ static inline void adc_context_enable_timer (struct adc_context * ctx )
418+ {
419+ if (!m_data .internal_timer_enabled ) {
420+ k_timer_start (& m_data .timer , K_NO_WAIT , K_USEC (ctx -> options .interval_us ));
421+ } else {
422+ nrfx_err_t ret = nrfx_saadc_mode_trigger ();
423+
424+ if (ret != NRFX_SUCCESS ) {
425+ LOG_ERR ("Cannot start sampling: %d" , ret );
426+ adc_context_complete (& m_data .ctx , - EIO );
427+ }
401428 }
429+ }
430+
431+ static inline void adc_context_disable_timer (struct adc_context * ctx )
432+ {
433+ if (!m_data .internal_timer_enabled ) {
434+ k_timer_stop (& m_data .timer );
435+ }
436+ }
437+
438+ static void adc_context_on_timer_expired (struct k_timer * timer_id )
439+ {
440+ ARG_UNUSED (timer_id );
402441
403- nrfx_saadc_buffer_set ( samples_buffer , m_data .active_channel_cnt );
442+ adc_context_request_next_sampling ( & m_data .ctx );
404443}
405444
406445static int get_resolution (const struct adc_sequence * sequence , nrf_saadc_resolution_t * resolution )
@@ -490,31 +529,70 @@ static int check_buffer_size(const struct adc_sequence *sequence, uint8_t active
490529 return 0 ;
491530}
492531
532+ static inline void single_ended_channel_cut_negative_sample (uint16_t channel_bit ,
533+ uint8_t single_ended_channels ,
534+ int16_t * * sample )
535+ {
536+ if ((channel_bit & single_ended_channels ) && (* sample < 0 )) {
537+ * * sample = 0 ;
538+ }
539+
540+ (* sample )++ ;
541+ }
542+
493543static bool has_single_ended (const struct adc_sequence * sequence )
494544{
495545 return sequence -> channels & m_data .single_ended_channels ;
496546}
497547
498- static void correct_single_ended (const struct adc_sequence * sequence , nrf_saadc_value_t * buffer )
548+ static void correct_single_ended (const struct adc_sequence * sequence ,
549+ nrf_saadc_value_t * buffer ,
550+ uint16_t buffer_size )
499551{
500- uint16_t channel_bit = BIT (0 );
501552 uint8_t selected_channels = sequence -> channels ;
502553 uint8_t single_ended_channels = m_data .single_ended_channels ;
503554 int16_t * sample = (int16_t * )buffer ;
504555
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 ;
556+ for (uint16_t channel_bit = BIT (0 ); channel_bit <= single_ended_channels ;
557+ channel_bit <<= 1 ) {
558+ if (!(channel_bit & selected_channels )) {
559+ continue ;
560+ }
561+
562+ if (m_data .internal_timer_enabled ) {
563+ if (!(channel_bit & single_ended_channels )) {
564+ continue ;
509565 }
510566
511- sample ++ ;
567+ for (int i = 0 ; i < buffer_size ; i ++ ) {
568+ if (sample [i ] < 0 ) {
569+ sample [i ] = 0 ;
570+ }
571+ }
572+ } else {
573+ single_ended_channel_cut_negative_sample (channel_bit ,
574+ single_ended_channels ,
575+ & sample );
512576 }
513-
514- channel_bit <<= 1 ;
515577 }
516578}
517579
580+ /* The internal timer runs at 16 MHz, so to convert the interval in microseconds
581+ * to the internal timer CC value, we can use the formula:
582+ * interval_cc = interval_us * 16 MHz
583+ * where 16 MHz is the frequency of the internal timer.
584+ *
585+ * The maximum value for interval_cc is 2047, which corresponds to
586+ * approximately 7816 Hz ~ 128us.
587+ * The minimum value for interval_cc is depends on the SoC.
588+ */
589+ static inline uint16_t interval_to_cc (uint16_t interval_us )
590+ {
591+ NRFX_ASSERT ((interval_us <= ADC_INTERNAL_TIMER_INTERVAL_MAX_US ) && (interval_us > 0 ));
592+
593+ return (interval_us * 16 ) - 1 ;
594+ }
595+
518596static int start_read (const struct device * dev ,
519597 const struct adc_sequence * sequence )
520598{
@@ -562,10 +640,32 @@ static int start_read(const struct device *dev,
562640 return error ;
563641 }
564642
565- nrfx_err = nrfx_saadc_simple_mode_set (selected_channels ,
566- resolution ,
567- oversampling ,
568- event_handler );
643+ if ((active_channel_cnt == 1 ) &&
644+ (sequence -> options -> interval_us <= ADC_INTERNAL_TIMER_INTERVAL_MAX_US ) &&
645+ (sequence -> options -> interval_us > 0 )) {
646+
647+ nrfx_saadc_adv_config_t adv_config = {
648+ .oversampling = oversampling ,
649+ .burst = NRF_SAADC_BURST_DISABLED ,
650+ .internal_timer_cc = interval_to_cc (sequence -> options -> interval_us ),
651+ .start_on_end = true,
652+ };
653+
654+ m_data .internal_timer_enabled = true;
655+
656+ nrfx_err = nrfx_saadc_advanced_mode_set (selected_channels ,
657+ resolution ,
658+ & adv_config ,
659+ event_handler );
660+ } else {
661+ m_data .internal_timer_enabled = false;
662+
663+ nrfx_err = nrfx_saadc_simple_mode_set (selected_channels ,
664+ resolution ,
665+ oversampling ,
666+ event_handler );
667+ }
668+
569669 if (nrfx_err != NRFX_SUCCESS ) {
570670 return - EINVAL ;
571671 }
@@ -578,9 +678,11 @@ static int start_read(const struct device *dev,
578678 m_data .active_channel_cnt = active_channel_cnt ;
579679 m_data .user_buffer = sequence -> buffer ;
580680
581- error = dmm_buffer_in_prepare (m_data .mem_reg ,
582- m_data .user_buffer ,
583- NRFX_SAADC_SAMPLES_TO_BYTES (active_channel_cnt ),
681+ error = dmm_buffer_in_prepare (m_data .mem_reg , m_data .user_buffer ,
682+ (m_data .internal_timer_enabled
683+ ? (NRFX_SAADC_SAMPLES_TO_BYTES (active_channel_cnt ) *
684+ (1 + sequence -> options -> extra_samplings ))
685+ : NRFX_SAADC_SAMPLES_TO_BYTES (active_channel_cnt )),
584686 & samples_buffer );
585687 if (error != 0 ) {
586688 LOG_ERR ("DMM buffer allocation failed err=%d" , error );
@@ -590,7 +692,15 @@ static int start_read(const struct device *dev,
590692 /* Buffer is filled in chunks, each chunk composed of number of samples equal to number
591693 * of active channels. Buffer pointer is advanced and reloaded after each chunk.
592694 */
593- nrfx_saadc_buffer_set (samples_buffer , active_channel_cnt );
695+ nrfx_err = nrfx_saadc_buffer_set (
696+ samples_buffer ,
697+ (m_data .internal_timer_enabled
698+ ? (active_channel_cnt * (1 + sequence -> options -> extra_samplings ))
699+ : active_channel_cnt ));
700+ if (nrfx_err != NRFX_SUCCESS ) {
701+ LOG_ERR ("Failed to set buffer: %08x" , nrfx_err );
702+ return - EINVAL ;
703+ }
594704
595705 adc_context_start_read (& m_data .ctx , sequence );
596706
@@ -633,11 +743,17 @@ static void event_handler(const nrfx_saadc_evt_t *event)
633743 if (event -> type == NRFX_SAADC_EVT_DONE ) {
634744 dmm_buffer_in_release (
635745 m_data .mem_reg , m_data .user_buffer ,
636- NRFX_SAADC_SAMPLES_TO_BYTES (m_data .active_channel_cnt ),
746+ (m_data .internal_timer_enabled
747+ ? (NRFX_SAADC_SAMPLES_TO_BYTES (
748+ m_data .active_channel_cnt ) *
749+ (1 + m_data .ctx .sequence .options -> extra_samplings ))
750+ : NRFX_SAADC_SAMPLES_TO_BYTES (
751+ m_data .active_channel_cnt )),
637752 event -> data .done .p_buffer );
638753
639754 if (has_single_ended (& m_data .ctx .sequence )) {
640- correct_single_ended (& m_data .ctx .sequence , m_data .user_buffer );
755+ correct_single_ended (& m_data .ctx .sequence , m_data .user_buffer ,
756+ event -> data .done .size );
641757 }
642758 adc_context_on_sampling_done (& m_data .ctx , DEVICE_DT_INST_GET (0 ));
643759 } else if (event -> type == NRFX_SAADC_EVT_CALIBRATEDONE ) {
@@ -646,13 +762,17 @@ static void event_handler(const nrfx_saadc_evt_t *event)
646762 LOG_ERR ("Cannot start sampling: 0x%08x" , err );
647763 adc_context_complete (& m_data .ctx , - EIO );
648764 }
765+ } else if (event -> type == NRFX_SAADC_EVT_FINISHED ) {
766+ adc_context_complete (& m_data .ctx , 0 );
649767 }
650768}
651769
652770static int init_saadc (const struct device * dev )
653771{
654772 nrfx_err_t err ;
655773
774+ k_timer_init (& m_data .timer , adc_context_on_timer_expired , NULL );
775+
656776 /* The priority value passed here is ignored (see nrfx_glue.h). */
657777 err = nrfx_saadc_init (0 );
658778 if (err != NRFX_SUCCESS ) {
0 commit comments