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
@@ -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
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+ 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
406446static 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+
518580static 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
653750static 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