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,20 @@ struct driver_data {
104106 uint8_t active_channel_cnt ;
105107 void * mem_reg ;
106108 void * user_buffer ;
109+ bool internal_timer_enabled ;
107110};
108111
109112static struct driver_data m_data = {
110113 ADC_CONTEXT_INIT_TIMER (m_data , ctx ),
111114 ADC_CONTEXT_INIT_LOCK (m_data , ctx ),
112115 ADC_CONTEXT_INIT_SYNC (m_data , ctx ),
113116 .mem_reg = DMM_DEV_TO_REG (DT_NODELABEL (adc )),
117+ .internal_timer_enabled = false,
114118};
115119
120+ /* Maximum value of the internal timer interval in microseconds. */
121+ #define ADC_INTERNAL_TIMER_INTERVAL_MAX_US 128U
122+
116123/* Forward declaration */
117124static void event_handler (const nrfx_saadc_evt_t * event );
118125
@@ -385,22 +392,50 @@ static void adc_context_start_sampling(struct adc_context *ctx)
385392
386393static void adc_context_update_buffer_pointer (struct adc_context * ctx , bool repeat )
387394{
388- void * samples_buffer ;
395+ if (!m_data .internal_timer_enabled ) {
396+ void * samples_buffer ;
397+
398+ if (!repeat ) {
399+ m_data .user_buffer =
400+ (uint16_t * )m_data .user_buffer + m_data .active_channel_cnt ;
401+ }
402+
403+ int error = dmm_buffer_in_prepare (
404+ m_data .mem_reg , m_data .user_buffer ,
405+ NRFX_SAADC_SAMPLES_TO_BYTES (m_data .active_channel_cnt ), & samples_buffer );
406+ if (error != 0 ) {
407+ LOG_ERR ("DMM buffer allocation failed err=%d" , error );
408+ adc_context_complete (ctx , - EIO );
409+ }
389410
390- if (!repeat ) {
391- m_data .user_buffer = (uint16_t * )m_data .user_buffer + m_data .active_channel_cnt ;
411+ nrfx_err_t nrfx_err =
412+ nrfx_saadc_buffer_set (samples_buffer , m_data .active_channel_cnt );
413+ if (nrfx_err != NRFX_SUCCESS ) {
414+ LOG_ERR ("Failed to set buffer: %08x" , nrfx_err );
415+ adc_context_complete (ctx , - EIO );
416+ }
392417 }
418+ }
393419
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 );
420+ static inline void adc_context_enable_timer (struct adc_context * ctx )
421+ {
422+ if (!m_data .internal_timer_enabled ) {
423+ k_timer_start (& ctx -> timer , K_NO_WAIT , K_USEC (ctx -> options .interval_us ));
424+ } else {
425+ nrfx_err_t ret = nrfx_saadc_mode_trigger ();
426+
427+ if (ret != NRFX_SUCCESS ) {
428+ LOG_ERR ("Cannot start sampling: %d" , ret );
429+ adc_context_complete (& m_data .ctx , - EIO );
430+ }
401431 }
432+ }
402433
403- nrfx_saadc_buffer_set (samples_buffer , m_data .active_channel_cnt );
434+ static inline void adc_context_disable_timer (struct adc_context * ctx )
435+ {
436+ if (!m_data .internal_timer_enabled ) {
437+ k_timer_stop (& ctx -> timer );
438+ }
404439}
405440
406441static int get_resolution (const struct adc_sequence * sequence , nrf_saadc_resolution_t * resolution )
@@ -490,29 +525,78 @@ static int check_buffer_size(const struct adc_sequence *sequence, uint8_t active
490525 return 0 ;
491526}
492527
528+ static inline void single_ended_channel_cut_negative_sample (uint16_t channel_bit ,
529+ uint8_t single_ended_channels ,
530+ int16_t * * sample )
531+ {
532+ if ((channel_bit & single_ended_channels ) && (* sample < 0 )) {
533+ * * sample = 0 ;
534+ }
535+
536+ (* sample )++ ;
537+ }
538+
493539static bool has_single_ended (const struct adc_sequence * sequence )
494540{
495541 return sequence -> channels & m_data .single_ended_channels ;
496542}
497543
498- static void correct_single_ended (const struct adc_sequence * sequence , nrf_saadc_value_t * buffer )
544+ static void correct_single_ended (const struct adc_sequence * sequence ,
545+ nrf_saadc_value_t * buffer ,
546+ uint16_t buffer_size )
499547{
500- uint16_t channel_bit = BIT (0 );
501548 uint8_t selected_channels = sequence -> channels ;
502549 uint8_t single_ended_channels = m_data .single_ended_channels ;
503550 int16_t * sample = (int16_t * )buffer ;
504551
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 ;
552+ for (uint16_t channel_bit = BIT (0 ); channel_bit <= single_ended_channels ;
553+ channel_bit <<= 1 ) {
554+ if (!(channel_bit & selected_channels )) {
555+ continue ;
556+ }
557+
558+ if (m_data .internal_timer_enabled ) {
559+ if (!(channel_bit & single_ended_channels )) {
560+ continue ;
509561 }
510562
511- sample ++ ;
563+ for (int i = 0 ; i < buffer_size ; i ++ ) {
564+ if (sample [i ] < 0 ) {
565+ sample [i ] = 0 ;
566+ }
567+ }
568+ } else {
569+ single_ended_channel_cut_negative_sample (channel_bit ,
570+ single_ended_channels ,
571+ & sample );
512572 }
573+ }
574+ }
513575
514- channel_bit <<= 1 ;
576+ /* The internal timer runs at 16 MHz, so to convert the interval in microseconds
577+ * to the internal timer CC value, we can use the formula:
578+ * interval_cc = interval_us * 16 MHz
579+ * where 16 MHz is the frequency of the internal timer.
580+ *
581+ * The maximum value for interval_cc is 2047, which corresponds to
582+ * approximately 7816 Hz ~ 128us.
583+ * The minimum value for interval_cc is depends on the SoC.
584+ */
585+ static inline uint16_t interval_to_cc (uint32_t interval_us )
586+ {
587+ uint16_t interval_cc = interval_us * 16 ;
588+
589+ if (interval_cc > NRF_SAADC_SAMPLERATE_CC_MAX ) {
590+ LOG_INF ("Interval %u us exceeds maximum CC value, setting to %lu" ,
591+ interval_us , NRF_SAADC_SAMPLERATE_CC_MAX );
592+ return NRF_SAADC_SAMPLERATE_CC_MAX ;
593+ } else if (interval_cc < NRF_SAADC_SAMPLERATE_CC_MIN ) {
594+ LOG_INF ("Interval %u us exceeds minimum CC value, setting to %lu" ,
595+ interval_us , NRF_SAADC_SAMPLERATE_CC_MIN );
596+ return NRF_SAADC_SAMPLERATE_CC_MIN ;
515597 }
598+
599+ return interval_cc ;
516600}
517601
518602static int start_read (const struct device * dev ,
@@ -562,10 +646,32 @@ static int start_read(const struct device *dev,
562646 return error ;
563647 }
564648
565- nrfx_err = nrfx_saadc_simple_mode_set (selected_channels ,
566- resolution ,
567- oversampling ,
568- event_handler );
649+ if ((active_channel_cnt == 1 ) &&
650+ (sequence -> options -> interval_us <= ADC_INTERNAL_TIMER_INTERVAL_MAX_US ) &&
651+ (sequence -> options -> interval_us > 0 )) {
652+
653+ nrfx_saadc_adv_config_t adv_config = {
654+ .oversampling = oversampling ,
655+ .burst = NRF_SAADC_BURST_DISABLED ,
656+ .internal_timer_cc = interval_to_cc (sequence -> options -> interval_us ),
657+ .start_on_end = true,
658+ };
659+
660+ m_data .internal_timer_enabled = true;
661+
662+ nrfx_err = nrfx_saadc_advanced_mode_set (selected_channels ,
663+ resolution ,
664+ & adv_config ,
665+ event_handler );
666+ } else {
667+ m_data .internal_timer_enabled = false;
668+
669+ nrfx_err = nrfx_saadc_simple_mode_set (selected_channels ,
670+ resolution ,
671+ oversampling ,
672+ event_handler );
673+ }
674+
569675 if (nrfx_err != NRFX_SUCCESS ) {
570676 return - EINVAL ;
571677 }
@@ -578,9 +684,11 @@ static int start_read(const struct device *dev,
578684 m_data .active_channel_cnt = active_channel_cnt ;
579685 m_data .user_buffer = sequence -> buffer ;
580686
581- error = dmm_buffer_in_prepare (m_data .mem_reg ,
582- m_data .user_buffer ,
583- NRFX_SAADC_SAMPLES_TO_BYTES (active_channel_cnt ),
687+ error = dmm_buffer_in_prepare (m_data .mem_reg , m_data .user_buffer ,
688+ (m_data .internal_timer_enabled
689+ ? (NRFX_SAADC_SAMPLES_TO_BYTES (active_channel_cnt ) *
690+ (1 + sequence -> options -> extra_samplings ))
691+ : NRFX_SAADC_SAMPLES_TO_BYTES (active_channel_cnt )),
584692 & samples_buffer );
585693 if (error != 0 ) {
586694 LOG_ERR ("DMM buffer allocation failed err=%d" , error );
@@ -590,7 +698,15 @@ static int start_read(const struct device *dev,
590698 /* Buffer is filled in chunks, each chunk composed of number of samples equal to number
591699 * of active channels. Buffer pointer is advanced and reloaded after each chunk.
592700 */
593- nrfx_saadc_buffer_set (samples_buffer , active_channel_cnt );
701+ nrfx_err = nrfx_saadc_buffer_set (
702+ samples_buffer ,
703+ (m_data .internal_timer_enabled
704+ ? (active_channel_cnt * (1 + sequence -> options -> extra_samplings ))
705+ : active_channel_cnt ));
706+ if (nrfx_err != NRFX_SUCCESS ) {
707+ LOG_ERR ("Failed to set buffer: %08x" , nrfx_err );
708+ return - EINVAL ;
709+ }
594710
595711 adc_context_start_read (& m_data .ctx , sequence );
596712
@@ -633,11 +749,17 @@ static void event_handler(const nrfx_saadc_evt_t *event)
633749 if (event -> type == NRFX_SAADC_EVT_DONE ) {
634750 dmm_buffer_in_release (
635751 m_data .mem_reg , m_data .user_buffer ,
636- NRFX_SAADC_SAMPLES_TO_BYTES (m_data .active_channel_cnt ),
752+ (m_data .internal_timer_enabled
753+ ? (NRFX_SAADC_SAMPLES_TO_BYTES (
754+ m_data .active_channel_cnt ) *
755+ (1 + m_data .ctx .sequence .options -> extra_samplings ))
756+ : NRFX_SAADC_SAMPLES_TO_BYTES (
757+ m_data .active_channel_cnt )),
637758 event -> data .done .p_buffer );
638759
639760 if (has_single_ended (& m_data .ctx .sequence )) {
640- correct_single_ended (& m_data .ctx .sequence , m_data .user_buffer );
761+ correct_single_ended (& m_data .ctx .sequence , m_data .user_buffer ,
762+ event -> data .done .size );
641763 }
642764 adc_context_on_sampling_done (& m_data .ctx , DEVICE_DT_INST_GET (0 ));
643765 } else if (event -> type == NRFX_SAADC_EVT_CALIBRATEDONE ) {
@@ -646,6 +768,8 @@ static void event_handler(const nrfx_saadc_evt_t *event)
646768 LOG_ERR ("Cannot start sampling: 0x%08x" , err );
647769 adc_context_complete (& m_data .ctx , - EIO );
648770 }
771+ } else if (event -> type == NRFX_SAADC_EVT_FINISHED ) {
772+ adc_context_complete (& m_data .ctx , 0 );
649773 }
650774}
651775
0 commit comments