1+ use core:: marker:: PhantomData ;
2+
3+ #[ cfg( esp32c3) ]
4+ use Interrupt :: APB_ADC as InterruptSource ;
5+ #[ cfg( esp32c6) ]
6+ use Interrupt :: APB_SARADC as InterruptSource ;
7+
18#[ cfg( not( esp32h2) ) ]
29pub use self :: calibration:: * ;
310use super :: { AdcCalSource , AdcConfig , Attenuation } ;
411#[ cfg( any( esp32c6, esp32h2) ) ]
512use crate :: clock:: clocks_ll:: regi2c_write_mask;
613#[ cfg( any( esp32c2, esp32c3, esp32c6) ) ]
714use crate :: efuse:: Efuse ;
15+ #[ cfg( any( esp32c3, esp32c6) ) ]
16+ use crate :: {
17+ analog:: adc:: asynch:: AdcFuture ,
18+ interrupt:: { InterruptConfigurable , InterruptHandler } ,
19+ peripherals:: Interrupt ,
20+ Async ,
21+ } ;
822use crate :: {
923 peripheral:: PeripheralRef ,
1024 peripherals:: APB_SARADC ,
1125 system:: { GenericPeripheralGuard , Peripheral } ,
26+ Blocking ,
1227} ;
1328
1429mod calibration;
@@ -384,14 +399,15 @@ impl super::CalibrationAccess for crate::peripherals::ADC2 {
384399}
385400
386401/// Analog-to-Digital Converter peripheral driver.
387- pub struct Adc < ' d , ADCI > {
402+ pub struct Adc < ' d , ADCI , Dm : crate :: DriverMode > {
388403 _adc : PeripheralRef < ' d , ADCI > ,
389404 attenuations : [ Option < Attenuation > ; NUM_ATTENS ] ,
390405 active_channel : Option < u8 > ,
391406 _guard : GenericPeripheralGuard < { Peripheral :: ApbSarAdc as u8 } > ,
407+ _phantom : PhantomData < Dm > ,
392408}
393409
394- impl < ' d , ADCI > Adc < ' d , ADCI >
410+ impl < ' d , ADCI > Adc < ' d , ADCI , Blocking >
395411where
396412 ADCI : RegisterAccess + ' d ,
397413{
@@ -415,6 +431,26 @@ where
415431 attenuations : config. attenuations ,
416432 active_channel : None ,
417433 _guard : guard,
434+ _phantom : PhantomData ,
435+ }
436+ }
437+
438+ #[ cfg( any( esp32c3, esp32c6) ) ]
439+ /// Reconfigures the ADC driver to operate in asynchronous mode.
440+ pub fn into_async ( mut self ) -> Adc < ' d , ADCI , Async > {
441+ self . set_interrupt_handler ( asynch:: adc_interrupt_handler) ;
442+
443+ // Reset interrupt flags and disable oneshot reading to normalize state before
444+ // entering async mode, otherwise there can be '0' readings, happening initially
445+ // using ADC2
446+ ADCI :: reset ( ) ;
447+
448+ Adc {
449+ _adc : self . _adc ,
450+ attenuations : self . attenuations ,
451+ active_channel : self . active_channel ,
452+ _guard : self . _guard ,
453+ _phantom : PhantomData ,
418454 }
419455 }
420456
@@ -493,6 +529,22 @@ where
493529 }
494530}
495531
532+ impl < ADCI > crate :: private:: Sealed for Adc < ' _ , ADCI , Blocking > { }
533+
534+ #[ cfg( any( esp32c3, esp32c6) ) ]
535+ impl < ADCI > InterruptConfigurable for Adc < ' _ , ADCI , Blocking > {
536+ fn set_interrupt_handler ( & mut self , handler : InterruptHandler ) {
537+ for core in crate :: Cpu :: other ( ) {
538+ crate :: interrupt:: disable ( core, InterruptSource ) ;
539+ }
540+ unsafe { crate :: interrupt:: bind_interrupt ( InterruptSource , handler. handler ( ) ) } ;
541+ unwrap ! ( crate :: interrupt:: enable(
542+ InterruptSource ,
543+ handler. priority( )
544+ ) ) ;
545+ }
546+ }
547+
496548#[ cfg( any( esp32c2, esp32c3, esp32c6) ) ]
497549impl super :: AdcCalEfuse for crate :: peripherals:: ADC1 {
498550 fn init_code ( atten : Attenuation ) -> Option < u16 > {
@@ -582,3 +634,201 @@ mod adc_implementation {
582634 ]
583635 }
584636}
637+
638+ #[ cfg( any( esp32c3, esp32c6) ) ]
639+ impl < ' d , ADCI > Adc < ' d , ADCI , Async >
640+ where
641+ ADCI : RegisterAccess + ' d ,
642+ {
643+ /// Create a new instance in [crate::Blocking] mode.
644+ pub fn into_blocking ( self ) -> Adc < ' d , ADCI , Blocking > {
645+ crate :: interrupt:: disable ( crate :: Cpu :: current ( ) , InterruptSource ) ;
646+ Adc {
647+ _adc : self . _adc ,
648+ attenuations : self . attenuations ,
649+ active_channel : self . active_channel ,
650+ _guard : self . _guard ,
651+ _phantom : PhantomData ,
652+ }
653+ }
654+
655+ /// Request that the ADC begin a conversion on the specified pin
656+ ///
657+ /// This method takes an [AdcPin](super::AdcPin) reference, as it is
658+ /// expected that the ADC will be able to sample whatever channel
659+ /// underlies the pin.
660+ pub async fn read_oneshot < PIN , CS > ( & mut self , pin : & mut super :: AdcPin < PIN , ADCI , CS > ) -> u16
661+ where
662+ ADCI : asynch:: AsyncAccess ,
663+ PIN : super :: AdcChannel ,
664+ CS : super :: AdcCalScheme < ADCI > ,
665+ {
666+ let channel = PIN :: CHANNEL ;
667+ if self . attenuations [ channel as usize ] . is_none ( ) {
668+ panic ! ( "Channel {} is not configured reading!" , channel) ;
669+ }
670+
671+ // Set ADC unit calibration according used scheme for pin
672+ ADCI :: set_init_code ( pin. cal_scheme . adc_cal ( ) ) ;
673+
674+ let attenuation = self . attenuations [ channel as usize ] . unwrap ( ) as u8 ;
675+ ADCI :: config_onetime_sample ( channel, attenuation) ;
676+ ADCI :: start_onetime_sample ( ) ;
677+
678+ // Wait for ADC to finish conversion and get value
679+ let adc_ready_future = AdcFuture :: new ( self ) ;
680+ adc_ready_future. await ;
681+ let converted_value = ADCI :: read_data ( ) ;
682+
683+ // There is a hardware limitation. If the APB clock frequency is high, the step
684+ // of this reg signal: ``onetime_start`` may not be captured by the
685+ // ADC digital controller (when its clock frequency is too slow). A rough
686+ // estimate for this step should be at least 3 ADC digital controller
687+ // clock cycle.
688+ //
689+ // This limitation will be removed in hardware future versions.
690+ // We reset ``onetime_start`` in `reset` and assume enough time has passed until
691+ // the next sample is requested.
692+
693+ ADCI :: reset ( ) ;
694+
695+ // Postprocess converted value according to calibration scheme used for pin
696+ pin. cal_scheme . adc_val ( converted_value)
697+ }
698+ }
699+
700+ #[ cfg( any( esp32c3, esp32c6) ) ]
701+ /// Async functionality
702+ pub ( crate ) mod asynch {
703+ use core:: {
704+ marker:: PhantomData ,
705+ pin:: Pin ,
706+ task:: { Context , Poll } ,
707+ } ;
708+
709+ use procmacros:: handler;
710+
711+ use crate :: { asynch:: AtomicWaker , peripherals:: APB_SARADC , Async } ;
712+
713+ #[ handler]
714+ pub ( crate ) fn adc_interrupt_handler ( ) {
715+ let saradc = APB_SARADC :: regs ( ) ;
716+ let interrupt_status = saradc. int_st ( ) . read ( ) ;
717+
718+ if interrupt_status. adc1_done ( ) . bit_is_set ( ) {
719+ handle_async ( crate :: peripherals:: ADC1 )
720+ }
721+
722+ #[ cfg( esp32c3) ]
723+ if interrupt_status. adc2_done ( ) . bit_is_set ( ) {
724+ handle_async ( crate :: peripherals:: ADC2 )
725+ }
726+ }
727+
728+ fn handle_async < ADCI : AsyncAccess > ( _instance : ADCI ) {
729+ ADCI :: waker ( ) . wake ( ) ;
730+ ADCI :: disable_interrupt ( ) ;
731+ }
732+
733+ #[ doc( hidden) ]
734+ pub trait AsyncAccess {
735+ /// Enable the ADC interrupt
736+ fn enable_interrupt ( ) ;
737+
738+ /// Disable the ADC interrupt
739+ fn disable_interrupt ( ) ;
740+
741+ /// Clear the ADC interrupt
742+ fn clear_interrupt ( ) ;
743+
744+ /// Obtain the waker for the ADC interrupt
745+ fn waker ( ) -> & ' static AtomicWaker ;
746+ }
747+
748+ impl AsyncAccess for crate :: peripherals:: ADC1 {
749+ fn enable_interrupt ( ) {
750+ APB_SARADC :: regs ( )
751+ . int_ena ( )
752+ . modify ( |_, w| w. adc1_done ( ) . set_bit ( ) ) ;
753+ }
754+
755+ fn disable_interrupt ( ) {
756+ APB_SARADC :: regs ( )
757+ . int_ena ( )
758+ . modify ( |_, w| w. adc1_done ( ) . clear_bit ( ) ) ;
759+ }
760+
761+ fn clear_interrupt ( ) {
762+ APB_SARADC :: regs ( )
763+ . int_clr ( )
764+ . write ( |w| w. adc1_done ( ) . clear_bit_by_one ( ) ) ;
765+ }
766+
767+ fn waker ( ) -> & ' static AtomicWaker {
768+ static WAKER : AtomicWaker = AtomicWaker :: new ( ) ;
769+
770+ & WAKER
771+ }
772+ }
773+
774+ #[ cfg( esp32c3) ]
775+ impl AsyncAccess for crate :: peripherals:: ADC2 {
776+ fn enable_interrupt ( ) {
777+ APB_SARADC :: regs ( )
778+ . int_ena ( )
779+ . modify ( |_, w| w. adc2_done ( ) . set_bit ( ) ) ;
780+ }
781+
782+ fn disable_interrupt ( ) {
783+ APB_SARADC :: regs ( )
784+ . int_ena ( )
785+ . modify ( |_, w| w. adc2_done ( ) . clear_bit ( ) ) ;
786+ }
787+
788+ fn clear_interrupt ( ) {
789+ APB_SARADC :: regs ( )
790+ . int_clr ( )
791+ . write ( |w| w. adc2_done ( ) . clear_bit_by_one ( ) ) ;
792+ }
793+
794+ fn waker ( ) -> & ' static AtomicWaker {
795+ static WAKER : AtomicWaker = AtomicWaker :: new ( ) ;
796+
797+ & WAKER
798+ }
799+ }
800+
801+ #[ must_use = "futures do nothing unless you `.await` or poll them" ]
802+ pub ( crate ) struct AdcFuture < ADCI : AsyncAccess > {
803+ phantom : PhantomData < ADCI > ,
804+ }
805+
806+ impl < ADCI : AsyncAccess > AdcFuture < ADCI > {
807+ pub fn new ( _self : & super :: Adc < ' _ , ADCI , Async > ) -> Self {
808+ Self {
809+ phantom : PhantomData ,
810+ }
811+ }
812+ }
813+
814+ impl < ADCI : AsyncAccess + super :: RegisterAccess > core:: future:: Future for AdcFuture < ADCI > {
815+ type Output = ( ) ;
816+
817+ fn poll ( self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Self :: Output > {
818+ if ADCI :: is_done ( ) {
819+ ADCI :: clear_interrupt ( ) ;
820+ Poll :: Ready ( ( ) )
821+ } else {
822+ ADCI :: waker ( ) . register ( cx. waker ( ) ) ;
823+ ADCI :: enable_interrupt ( ) ;
824+ Poll :: Pending
825+ }
826+ }
827+ }
828+
829+ impl < ADCI : AsyncAccess > Drop for AdcFuture < ADCI > {
830+ fn drop ( & mut self ) {
831+ ADCI :: disable_interrupt ( ) ;
832+ }
833+ }
834+ }
0 commit comments