55 */
66
77#define ADC_CONTEXT_USES_KERNEL_TIMER
8+ #define ADC_DRIVER_USES_INTERNAL_TIMER
9+
810#include "adc_context.h"
911#include <nrfx_saadc.h>
1012#include <zephyr/dt-bindings/adc/nrf-saadc-v3.h>
@@ -104,15 +106,26 @@ struct driver_data {
104106 uint8_t active_channel_cnt ;
105107 void * mem_reg ;
106108 void * user_buffer ;
109+ #ifdef ADC_DRIVER_USES_INTERNAL_TIMER
110+ bool enable_internal_timer ;
111+ #endif
112+ bool internal_timer_enabled ;
107113};
108114
109115static struct driver_data m_data = {
110116 ADC_CONTEXT_INIT_TIMER (m_data , ctx ),
111117 ADC_CONTEXT_INIT_LOCK (m_data , ctx ),
112118 ADC_CONTEXT_INIT_SYNC (m_data , ctx ),
113119 .mem_reg = DMM_DEV_TO_REG (DT_NODELABEL (adc )),
120+ #ifdef ADC_DRIVER_USES_INTERNAL_TIMER
121+ .enable_internal_timer = DT_INST_PROP (0 , enable_internal_timer ),
122+ #endif
123+ .internal_timer_enabled = false,
114124};
115125
126+ /* Maximum value of the internal timer interval in microseconds. */
127+ #define ADC_INTERNAL_TIMER_INTERVAL_MAX_US 128U
128+
116129/* Forward declaration */
117130static void event_handler (const nrfx_saadc_evt_t * event );
118131
@@ -385,7 +398,7 @@ static void adc_context_start_sampling(struct adc_context *ctx)
385398
386399static void adc_context_update_buffer_pointer (struct adc_context * ctx , bool repeat )
387400{
388- if (!repeat ) {
401+ if (!repeat && ! m_data . internal_timer_enabled ) {
389402 void * samples_buffer ;
390403
391404 m_data .user_buffer = (uint16_t * )m_data .user_buffer + m_data .active_channel_cnt ;
@@ -399,11 +412,39 @@ static void adc_context_update_buffer_pointer(struct adc_context *ctx, bool repe
399412 adc_context_complete (ctx , - EIO );
400413 }
401414#if !defined(CONFIG_HAS_NORDIC_DMM )
402- nrfx_saadc_buffer_set (samples_buffer , m_data .active_channel_cnt );
415+ nrfx_err_t nrfx_err =
416+ nrfx_saadc_buffer_set (samples_buffer , m_data .active_channel_cnt );
417+ if (nrfx_err != NRFX_SUCCESS ) {
418+ LOG_ERR ("Failed to set buffer: %08x" , nrfx_err );
419+ adc_context_complete (ctx , - EIO );
420+ }
403421#endif
404422 }
405423}
406424
425+ #ifdef ADC_DRIVER_USES_INTERNAL_TIMER
426+ static inline void adc_context_enable_timer (struct adc_context * ctx )
427+ {
428+ if (!m_data .internal_timer_enabled ) {
429+ k_timer_start (& ctx -> timer , K_NO_WAIT , K_USEC (ctx -> options .interval_us ));
430+ } else {
431+ nrfx_err_t ret = nrfx_saadc_mode_trigger ();
432+
433+ if (ret != NRFX_SUCCESS ) {
434+ LOG_ERR ("Cannot start sampling: %d" , ret );
435+ adc_context_complete (& m_data .ctx , - EIO );
436+ }
437+ }
438+ }
439+
440+ static inline void adc_context_disable_timer (struct adc_context * ctx )
441+ {
442+ if (!m_data .internal_timer_enabled ) {
443+ k_timer_stop (& ctx -> timer );
444+ }
445+ }
446+ #endif /* ADC_DRIVER_USES_INTERNAL_TIMER */
447+
407448static int get_resolution (const struct adc_sequence * sequence , nrf_saadc_resolution_t * resolution )
408449{
409450 switch (sequence -> resolution ) {
@@ -491,29 +532,96 @@ static int check_buffer_size(const struct adc_sequence *sequence, uint8_t active
491532 return 0 ;
492533}
493534
535+ static inline void single_ended_channel_cut_negative_sample (uint16_t channel_bit ,
536+ uint8_t single_ended_channels ,
537+ int16_t * * sample )
538+ {
539+ if ((channel_bit & single_ended_channels ) && (* sample < 0 )) {
540+ * * sample = 0 ;
541+ }
542+
543+ (* sample )++ ;
544+ }
545+
494546static bool has_single_ended (const struct adc_sequence * sequence )
495547{
496548 return sequence -> channels & m_data .single_ended_channels ;
497549}
498550
499- static void correct_single_ended (const struct adc_sequence * sequence , nrf_saadc_value_t * buffer )
551+ static void correct_single_ended (const struct adc_sequence * sequence ,
552+ nrf_saadc_value_t * buffer ,
553+ uint16_t buffer_size )
500554{
501- uint16_t channel_bit = BIT (0 );
502555 uint8_t selected_channels = sequence -> channels ;
503556 uint8_t single_ended_channels = m_data .single_ended_channels ;
504557 int16_t * sample = (int16_t * )buffer ;
505558
506- while (channel_bit <= single_ended_channels ) {
507- if (channel_bit & selected_channels ) {
508- if ((channel_bit & single_ended_channels ) && (* sample < 0 )) {
509- * sample = 0 ;
559+ for (uint16_t channel_bit = BIT (0 ); channel_bit <= single_ended_channels ;
560+ channel_bit <<= 1 ) {
561+ if (!(channel_bit & selected_channels )) {
562+ continue ;
563+ }
564+
565+ #ifdef ADC_DRIVER_USES_INTERNAL_TIMER
566+ if (m_data .internal_timer_enabled ) {
567+ if (!(channel_bit & single_ended_channels )) {
568+ continue ;
510569 }
511570
512- sample ++ ;
571+ for (int i = 0 ; i < buffer_size ; i ++ ) {
572+ if (sample [i ] < 0 ) {
573+ sample [i ] = 0 ;
574+ }
575+ }
576+ } else {
577+ single_ended_channel_cut_negative_sample (channel_bit ,
578+ single_ended_channels ,
579+ & sample );
513580 }
581+ #else
582+ single_ended_channel_cut_negative_sample (channel_bit ,
583+ single_ended_channels ,
584+ & sample );
585+ #endif
586+ }
587+ }
514588
515- channel_bit <<= 1 ;
589+ /* The internal timer runs at 16 MHz, so to convert the interval in microseconds
590+ * to the internal timer CC value, we can use the formula:
591+ * interval_cc = interval_us * 16 MHz
592+ * where 16 MHz is the frequency of the internal timer.
593+ *
594+ * The maximum value for interval_cc is 2047, which corresponds to
595+ * approximately 7816 Hz ~ 128us.
596+ * The minimum value for interval_cc is depends on the SoC.
597+ */
598+ static inline uint16_t interval_to_cc (uint32_t interval_us )
599+ {
600+ uint16_t interval_cc = interval_us * 16 ;
601+
602+ if (interval_cc > NRF_SAADC_SAMPLERATE_CC_MAX ) {
603+ LOG_INF ("Interval %u us exceeds maximum CC value, setting to %lu" ,
604+ interval_us , NRF_SAADC_SAMPLERATE_CC_MAX );
605+ return NRF_SAADC_SAMPLERATE_CC_MAX ;
606+ } else if (interval_cc < NRF_SAADC_SAMPLERATE_CC_MIN ) {
607+ LOG_INF ("Interval %u us exceeds minimum CC value, setting to %lu" ,
608+ interval_us , NRF_SAADC_SAMPLERATE_CC_MIN );
609+ return NRF_SAADC_SAMPLERATE_CC_MIN ;
516610 }
611+
612+ return interval_cc ;
613+ }
614+
615+ static inline nrfx_err_t disable_internal_timer (uint32_t selected_channels ,
616+ nrf_saadc_resolution_t resolution ,
617+ nrf_saadc_oversample_t oversampling )
618+ {
619+ m_data .internal_timer_enabled = false;
620+
621+ return nrfx_saadc_simple_mode_set (selected_channels ,
622+ resolution ,
623+ oversampling ,
624+ event_handler );
517625}
518626
519627static int start_read (const struct device * dev ,
@@ -563,10 +671,36 @@ static int start_read(const struct device *dev,
563671 return error ;
564672 }
565673
566- nrfx_err = nrfx_saadc_simple_mode_set (selected_channels ,
567- resolution ,
568- oversampling ,
569- event_handler );
674+ #ifdef ADC_DRIVER_USES_INTERNAL_TIMER
675+ if (m_data .enable_internal_timer &&
676+ (active_channel_cnt == 1 ) &&
677+ (sequence -> options -> interval_us <= ADC_INTERNAL_TIMER_INTERVAL_MAX_US ) &&
678+ (sequence -> options -> interval_us > 0 )) {
679+
680+ nrfx_saadc_adv_config_t adv_config = {
681+ .oversampling = oversampling ,
682+ .burst = NRF_SAADC_BURST_DISABLED ,
683+ .internal_timer_cc = interval_to_cc (sequence -> options -> interval_us ),
684+ .start_on_end = true,
685+ };
686+
687+ m_data .internal_timer_enabled = true;
688+
689+ nrfx_err = nrfx_saadc_advanced_mode_set (selected_channels ,
690+ resolution ,
691+ & adv_config ,
692+ event_handler );
693+ } else {
694+ nrfx_err = disable_internal_timer (selected_channels ,
695+ resolution ,
696+ oversampling );
697+ }
698+ #else
699+ nrfx_err = disable_internal_timer (selected_channels ,
700+ resolution ,
701+ oversampling );
702+ #endif
703+
570704 if (nrfx_err != NRFX_SUCCESS ) {
571705 return - EINVAL ;
572706 }
@@ -579,9 +713,11 @@ static int start_read(const struct device *dev,
579713 m_data .active_channel_cnt = active_channel_cnt ;
580714 m_data .user_buffer = sequence -> buffer ;
581715
582- error = dmm_buffer_in_prepare (m_data .mem_reg ,
583- m_data .user_buffer ,
584- NRFX_SAADC_SAMPLES_TO_BYTES (active_channel_cnt ),
716+ error = dmm_buffer_in_prepare (m_data .mem_reg , m_data .user_buffer ,
717+ (m_data .internal_timer_enabled
718+ ? (NRFX_SAADC_SAMPLES_TO_BYTES (active_channel_cnt ) *
719+ (1 + sequence -> options -> extra_samplings ))
720+ : NRFX_SAADC_SAMPLES_TO_BYTES (active_channel_cnt )),
585721 & samples_buffer );
586722 if (error != 0 ) {
587723 LOG_ERR ("DMM buffer allocation failed err=%d" , error );
@@ -591,7 +727,15 @@ static int start_read(const struct device *dev,
591727 /* Buffer is filled in chunks, each chunk composed of number of samples equal to number
592728 * of active channels. Buffer pointer is advanced and reloaded after each chunk.
593729 */
594- nrfx_saadc_buffer_set (samples_buffer , active_channel_cnt );
730+ nrfx_err = nrfx_saadc_buffer_set (
731+ samples_buffer ,
732+ (m_data .internal_timer_enabled
733+ ? (active_channel_cnt * (1 + sequence -> options -> extra_samplings ))
734+ : active_channel_cnt ));
735+ if (nrfx_err != NRFX_SUCCESS ) {
736+ LOG_ERR ("Failed to set buffer: %08x" , nrfx_err );
737+ return - EINVAL ;
738+ }
595739
596740 adc_context_start_read (& m_data .ctx , sequence );
597741
@@ -634,11 +778,17 @@ static void event_handler(const nrfx_saadc_evt_t *event)
634778 if (event -> type == NRFX_SAADC_EVT_DONE ) {
635779 dmm_buffer_in_release (
636780 m_data .mem_reg , m_data .user_buffer ,
637- NRFX_SAADC_SAMPLES_TO_BYTES (m_data .active_channel_cnt ),
781+ (m_data .internal_timer_enabled
782+ ? (NRFX_SAADC_SAMPLES_TO_BYTES (
783+ m_data .active_channel_cnt ) *
784+ (1 + m_data .ctx .sequence .options -> extra_samplings ))
785+ : NRFX_SAADC_SAMPLES_TO_BYTES (
786+ m_data .active_channel_cnt )),
638787 event -> data .done .p_buffer );
639788
640789 if (has_single_ended (& m_data .ctx .sequence )) {
641- correct_single_ended (& m_data .ctx .sequence , m_data .user_buffer );
790+ correct_single_ended (& m_data .ctx .sequence , m_data .user_buffer ,
791+ event -> data .done .size );
642792 }
643793 adc_context_on_sampling_done (& m_data .ctx , DEVICE_DT_INST_GET (0 ));
644794 } else if (event -> type == NRFX_SAADC_EVT_CALIBRATEDONE ) {
@@ -647,6 +797,8 @@ static void event_handler(const nrfx_saadc_evt_t *event)
647797 LOG_ERR ("Cannot start sampling: 0x%08x" , err );
648798 adc_context_complete (& m_data .ctx , - EIO );
649799 }
800+ } else if (event -> type == NRFX_SAADC_EVT_FINISHED ) {
801+ adc_context_complete (& m_data .ctx , 0 );
650802 }
651803}
652804
0 commit comments