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,25 @@ 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
110+ static void adc_context_on_timer_expired (struct k_timer * timer_id );
111+
109112static struct driver_data m_data = {
110- ADC_CONTEXT_INIT_TIMER (m_data , ctx ),
111113 ADC_CONTEXT_INIT_LOCK (m_data , ctx ),
112114 ADC_CONTEXT_INIT_SYNC (m_data , ctx ),
115+ .timer = Z_TIMER_INITIALIZER (m_data .timer , \
116+ adc_context_on_timer_expired , \
117+ NULL ),
113118 .mem_reg = DMM_DEV_TO_REG (DT_NODELABEL (adc )),
119+ .internal_timer_enabled = false,
114120};
115121
122+ /* Maximum value of the internal timer interval in microseconds. */
123+ #define ADC_INTERNAL_TIMER_INTERVAL_MAX_US 128U
124+
116125/* Forward declaration */
117126static void event_handler (const nrfx_saadc_evt_t * event );
118127
@@ -385,22 +394,57 @@ static void adc_context_start_sampling(struct adc_context *ctx)
385394
386395static void adc_context_update_buffer_pointer (struct adc_context * ctx , bool repeat )
387396{
388- void * samples_buffer ;
397+ if (!m_data .internal_timer_enabled ) {
398+ void * samples_buffer ;
399+
400+ if (!repeat ) {
401+ m_data .user_buffer =
402+ (uint16_t * )m_data .user_buffer + m_data .active_channel_cnt ;
403+ }
404+
405+ int error = dmm_buffer_in_prepare (
406+ m_data .mem_reg , m_data .user_buffer ,
407+ NRFX_SAADC_SAMPLES_TO_BYTES (m_data .active_channel_cnt ), & samples_buffer );
408+ if (error != 0 ) {
409+ LOG_ERR ("DMM buffer allocation failed err=%d" , error );
410+ adc_context_complete (ctx , - EIO );
411+ }
389412
390- if (!repeat ) {
391- m_data .user_buffer = (uint16_t * )m_data .user_buffer + m_data .active_channel_cnt ;
413+ nrfx_err_t nrfx_err =
414+ nrfx_saadc_buffer_set (samples_buffer , m_data .active_channel_cnt );
415+ if (nrfx_err != NRFX_SUCCESS ) {
416+ LOG_ERR ("Failed to set buffer: %08x" , nrfx_err );
417+ adc_context_complete (ctx , - EIO );
418+ }
392419 }
420+ }
393421
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 );
422+ static inline void adc_context_enable_timer (struct adc_context * ctx )
423+ {
424+ if (!m_data .internal_timer_enabled ) {
425+ k_timer_start (& m_data .timer , K_NO_WAIT , K_USEC (ctx -> options .interval_us ));
426+ } else {
427+ nrfx_err_t ret = nrfx_saadc_mode_trigger ();
428+
429+ if (ret != NRFX_SUCCESS ) {
430+ LOG_ERR ("Cannot start sampling: %d" , ret );
431+ adc_context_complete (& m_data .ctx , - EIO );
432+ }
401433 }
434+ }
435+
436+ static inline void adc_context_disable_timer (struct adc_context * ctx )
437+ {
438+ if (!m_data .internal_timer_enabled ) {
439+ k_timer_stop (& m_data .timer );
440+ }
441+ }
442+
443+ static void adc_context_on_timer_expired (struct k_timer * timer_id )
444+ {
445+ ARG_UNUSED (timer_id );
402446
403- nrfx_saadc_buffer_set ( samples_buffer , m_data .active_channel_cnt );
447+ adc_context_request_next_sampling ( & m_data .ctx );
404448}
405449
406450static int get_resolution (const struct adc_sequence * sequence , nrf_saadc_resolution_t * resolution )
@@ -490,31 +534,70 @@ static int check_buffer_size(const struct adc_sequence *sequence, uint8_t active
490534 return 0 ;
491535}
492536
537+ static inline void single_ended_channel_cut_negative_sample (uint16_t channel_bit ,
538+ uint8_t single_ended_channels ,
539+ int16_t * * sample )
540+ {
541+ if ((channel_bit & single_ended_channels ) && (* sample < 0 )) {
542+ * * sample = 0 ;
543+ }
544+
545+ (* sample )++ ;
546+ }
547+
493548static bool has_single_ended (const struct adc_sequence * sequence )
494549{
495550 return sequence -> channels & m_data .single_ended_channels ;
496551}
497552
498- static void correct_single_ended (const struct adc_sequence * sequence , nrf_saadc_value_t * buffer )
553+ static void correct_single_ended (const struct adc_sequence * sequence ,
554+ nrf_saadc_value_t * buffer ,
555+ uint16_t buffer_size )
499556{
500- uint16_t channel_bit = BIT (0 );
501557 uint8_t selected_channels = sequence -> channels ;
502558 uint8_t single_ended_channels = m_data .single_ended_channels ;
503559 int16_t * sample = (int16_t * )buffer ;
504560
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 ;
561+ for (uint16_t channel_bit = BIT (0 ); channel_bit <= single_ended_channels ;
562+ channel_bit <<= 1 ) {
563+ if (!(channel_bit & selected_channels )) {
564+ continue ;
565+ }
566+
567+ if (m_data .internal_timer_enabled ) {
568+ if (!(channel_bit & single_ended_channels )) {
569+ continue ;
509570 }
510571
511- sample ++ ;
572+ for (int i = 0 ; i < buffer_size ; i ++ ) {
573+ if (sample [i ] < 0 ) {
574+ sample [i ] = 0 ;
575+ }
576+ }
577+ } else {
578+ single_ended_channel_cut_negative_sample (channel_bit ,
579+ single_ended_channels ,
580+ & sample );
512581 }
513-
514- channel_bit <<= 1 ;
515582 }
516583}
517584
585+ /* The internal timer runs at 16 MHz, so to convert the interval in microseconds
586+ * to the internal timer CC value, we can use the formula:
587+ * interval_cc = interval_us * 16 MHz
588+ * where 16 MHz is the frequency of the internal timer.
589+ *
590+ * The maximum value for interval_cc is 2047, which corresponds to
591+ * approximately 7816 Hz ~ 128us.
592+ * The minimum value for interval_cc is depends on the SoC.
593+ */
594+ static inline uint16_t interval_to_cc (uint16_t interval_us )
595+ {
596+ NRFX_ASSERT ((interval_us <= ADC_INTERNAL_TIMER_INTERVAL_MAX_US ) && (interval_us > 0 ));
597+
598+ return (interval_us * 16 ) - 1 ;
599+ }
600+
518601static int start_read (const struct device * dev ,
519602 const struct adc_sequence * sequence )
520603{
@@ -562,10 +645,33 @@ static int start_read(const struct device *dev,
562645 return error ;
563646 }
564647
565- nrfx_err = nrfx_saadc_simple_mode_set (selected_channels ,
566- resolution ,
567- oversampling ,
568- event_handler );
648+ if ((active_channel_cnt == 1 ) &&
649+ (sequence -> options != NULL ) &&
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,13 +768,17 @@ 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
652776static int init_saadc (const struct device * dev )
653777{
654778 nrfx_err_t err ;
655779
780+ // k_timer_init(&m_data.timer, adc_context_on_timer_expired, NULL);
781+
656782 /* The priority value passed here is ignored (see nrfx_glue.h). */
657783 err = nrfx_saadc_init (0 );
658784 if (err != NRFX_SUCCESS ) {
0 commit comments