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,68 @@ 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 , nrf_saadc_value_t * buffer ,
549+ uint16_t buffer_size )
499550{
500- uint16_t channel_bit = BIT (0 );
501551 uint8_t selected_channels = sequence -> channels ;
502552 uint8_t single_ended_channels = m_data .single_ended_channels ;
503553 int16_t * sample = (int16_t * )buffer ;
504554
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 ;
555+ for (uint16_t channel_bit = BIT (0 ); channel_bit <= single_ended_channels ;
556+ channel_bit <<= 1 ) {
557+ if (!(channel_bit & selected_channels )) {
558+ continue ;
559+ }
560+
561+ if (m_data .internal_timer_enabled ) {
562+ if (!(channel_bit & single_ended_channels )) {
563+ continue ;
509564 }
510565
511- sample ++ ;
566+ for (int i = 0 ; i < buffer_size ; i ++ ) {
567+ if (sample [i ] < 0 ) {
568+ sample [i ] = 0 ;
569+ }
570+ }
571+ } else {
572+ single_ended_channel_cut_negative_sample (channel_bit , single_ended_channels ,
573+ & sample );
512574 }
513-
514- channel_bit <<= 1 ;
515575 }
516576}
517577
578+ /* The internal timer runs at 16 MHz, so to convert the interval in microseconds
579+ * to the internal timer CC value, we can use the formula:
580+ * interval_cc = interval_us * 16 MHz
581+ * where 16 MHz is the frequency of the internal timer.
582+ *
583+ * The maximum value for interval_cc is 2047, which corresponds to
584+ * approximately 7816 Hz ~ 128us.
585+ * The minimum value for interval_cc is depends on the SoC.
586+ */
587+ static inline uint16_t interval_to_cc (uint16_t interval_us )
588+ {
589+ NRFX_ASSERT ((interval_us <= ADC_INTERNAL_TIMER_INTERVAL_MAX_US ) && (interval_us > 0 ));
590+
591+ return (interval_us * 16 ) - 1 ;
592+ }
593+
518594static int start_read (const struct device * dev ,
519595 const struct adc_sequence * sequence )
520596{
@@ -562,10 +638,28 @@ static int start_read(const struct device *dev,
562638 return error ;
563639 }
564640
565- nrfx_err = nrfx_saadc_simple_mode_set (selected_channels ,
566- resolution ,
567- oversampling ,
568- event_handler );
641+ if ((active_channel_cnt == 1 ) && (sequence -> options != NULL ) &&
642+ (sequence -> options -> interval_us <= ADC_INTERNAL_TIMER_INTERVAL_MAX_US ) &&
643+ (sequence -> options -> interval_us > 0 )) {
644+
645+ nrfx_saadc_adv_config_t adv_config = {
646+ .oversampling = oversampling ,
647+ .burst = NRF_SAADC_BURST_DISABLED ,
648+ .internal_timer_cc = interval_to_cc (sequence -> options -> interval_us ),
649+ .start_on_end = true,
650+ };
651+
652+ m_data .internal_timer_enabled = true;
653+
654+ nrfx_err = nrfx_saadc_advanced_mode_set (selected_channels , resolution , & adv_config ,
655+ event_handler );
656+ } else {
657+ m_data .internal_timer_enabled = false;
658+
659+ nrfx_err = nrfx_saadc_simple_mode_set (selected_channels , resolution , oversampling ,
660+ event_handler );
661+ }
662+
569663 if (nrfx_err != NRFX_SUCCESS ) {
570664 return - EINVAL ;
571665 }
@@ -578,9 +672,11 @@ static int start_read(const struct device *dev,
578672 m_data .active_channel_cnt = active_channel_cnt ;
579673 m_data .user_buffer = sequence -> buffer ;
580674
581- error = dmm_buffer_in_prepare (m_data .mem_reg ,
582- m_data .user_buffer ,
583- NRFX_SAADC_SAMPLES_TO_BYTES (active_channel_cnt ),
675+ error = dmm_buffer_in_prepare (m_data .mem_reg , m_data .user_buffer ,
676+ (m_data .internal_timer_enabled
677+ ? (NRFX_SAADC_SAMPLES_TO_BYTES (active_channel_cnt ) *
678+ (1 + sequence -> options -> extra_samplings ))
679+ : NRFX_SAADC_SAMPLES_TO_BYTES (active_channel_cnt )),
584680 & samples_buffer );
585681 if (error != 0 ) {
586682 LOG_ERR ("DMM buffer allocation failed err=%d" , error );
@@ -590,7 +686,15 @@ static int start_read(const struct device *dev,
590686 /* Buffer is filled in chunks, each chunk composed of number of samples equal to number
591687 * of active channels. Buffer pointer is advanced and reloaded after each chunk.
592688 */
593- nrfx_saadc_buffer_set (samples_buffer , active_channel_cnt );
689+ nrfx_err = nrfx_saadc_buffer_set (
690+ samples_buffer ,
691+ (m_data .internal_timer_enabled
692+ ? (active_channel_cnt * (1 + sequence -> options -> extra_samplings ))
693+ : active_channel_cnt ));
694+ if (nrfx_err != NRFX_SUCCESS ) {
695+ LOG_ERR ("Failed to set buffer: %08x" , nrfx_err );
696+ return - EINVAL ;
697+ }
594698
595699 adc_context_start_read (& m_data .ctx , sequence );
596700
@@ -633,11 +737,15 @@ static void event_handler(const nrfx_saadc_evt_t *event)
633737 if (event -> type == NRFX_SAADC_EVT_DONE ) {
634738 dmm_buffer_in_release (
635739 m_data .mem_reg , m_data .user_buffer ,
636- NRFX_SAADC_SAMPLES_TO_BYTES (m_data .active_channel_cnt ),
740+ (m_data .internal_timer_enabled
741+ ? (NRFX_SAADC_SAMPLES_TO_BYTES (m_data .active_channel_cnt ) *
742+ (1 + m_data .ctx .sequence .options -> extra_samplings ))
743+ : NRFX_SAADC_SAMPLES_TO_BYTES (m_data .active_channel_cnt )),
637744 event -> data .done .p_buffer );
638745
639746 if (has_single_ended (& m_data .ctx .sequence )) {
640- correct_single_ended (& m_data .ctx .sequence , m_data .user_buffer );
747+ correct_single_ended (& m_data .ctx .sequence , m_data .user_buffer ,
748+ event -> data .done .size );
641749 }
642750 adc_context_on_sampling_done (& m_data .ctx , DEVICE_DT_INST_GET (0 ));
643751 } else if (event -> type == NRFX_SAADC_EVT_CALIBRATEDONE ) {
@@ -646,13 +754,17 @@ static void event_handler(const nrfx_saadc_evt_t *event)
646754 LOG_ERR ("Cannot start sampling: 0x%08x" , err );
647755 adc_context_complete (& m_data .ctx , - EIO );
648756 }
757+ } else if (event -> type == NRFX_SAADC_EVT_FINISHED ) {
758+ adc_context_complete (& m_data .ctx , 0 );
649759 }
650760}
651761
652762static int init_saadc (const struct device * dev )
653763{
654764 nrfx_err_t err ;
655765
766+ k_timer_init (& m_data .timer , adc_context_on_timer_expired , NULL );
767+
656768 /* The priority value passed here is ignored (see nrfx_glue.h). */
657769 err = nrfx_saadc_init (0 );
658770 if (err != NRFX_SUCCESS ) {
0 commit comments