@@ -41,6 +41,7 @@ use crate::{
41
41
} ,
42
42
pac, Ratio ,
43
43
} ;
44
+ use core:: cmp:: min;
44
45
use paste:: paste;
45
46
use void:: Void ;
46
47
@@ -104,6 +105,7 @@ pub(crate) mod sealed {
104
105
fn set_cr ( & mut self , cr : Cr ) ;
105
106
fn cmp ( & self ) -> u16 ;
106
107
fn set_cmp ( & mut self , cmp : u16 ) ;
108
+ fn autoreload ( & self ) -> u16 ;
107
109
fn set_autoreload ( & mut self , ar : u16 ) ;
108
110
unsafe fn cnt ( ) -> u16 ;
109
111
fn set_or ( & mut self , or : u32 ) ;
@@ -177,6 +179,11 @@ macro_rules! impl_lptim_base_for {
177
179
self . cmp. write( |w| w. cmp( ) . bits( cmp) ) ;
178
180
}
179
181
182
+ #[ inline( always) ]
183
+ fn autoreload( & self ) -> u16 {
184
+ self . arr. read( ) . arr( ) . bits( )
185
+ }
186
+
180
187
#[ inline( always) ]
181
188
fn set_autoreload( & mut self , ar: u16 ) {
182
189
self . arr. write( |w| w. arr( ) . bits( ar) ) ;
@@ -497,6 +504,68 @@ pub trait LpTim: sealed::LpTim {
497
504
. set_trg_filter ( filter)
498
505
} )
499
506
}
507
+
508
+ /// Set the maximum duty cycle (autoreload value).
509
+ ///
510
+ /// This is used to control the frequency of the PWM output.
511
+ ///
512
+ /// This function does not poll for completion, use [`isr`](Self::isr)
513
+ /// and [`ARROK`](irq::ARROK) to determine when the value has been updated.
514
+ ///
515
+ /// # Example
516
+ ///
517
+ /// Set the frequency to 50Hz (20ms period) for servo motor control.
518
+ ///
519
+ /// ```no_run
520
+ /// use stm32wlxx_hal::{
521
+ /// gpio,
522
+ /// lptim::{self, LpTim, LpTim1},
523
+ /// pac,
524
+ /// };
525
+ ///
526
+ /// let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
527
+ ///
528
+ /// // enable the HSI16 source clock
529
+ /// dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
530
+ /// while dp.RCC.cr.read().hsirdy().is_not_ready() {}
531
+ ///
532
+ /// let pc: gpio::PortC = gpio::PortC::split(dp.GPIOC, &mut dp.RCC);
533
+ ///
534
+ /// let mut lptim1: LpTim1 = LpTim1::new(
535
+ /// dp.LPTIM1,
536
+ /// lptim::Clk::Hsi16,
537
+ /// lptim::Prescaler::Div8,
538
+ /// &mut dp.RCC,
539
+ /// );
540
+ /// cortex_m::interrupt::free(|cs| lptim1.new_output_pin(pc.c1, cs));
541
+ ///
542
+ /// // 20ms period to control PWM servo motors
543
+ /// const SERVO_FREQ_HZ: u32 = 50;
544
+ ///
545
+ /// // source_freq / prescaler = 16_000_000 MHz / 8 = 2 Mhz
546
+ /// let lptim1_freq_hz = lptim1.hz().to_integer();
547
+ ///
548
+ /// // 2MHz / 50Hz = 40_000
549
+ /// let max_duty: u32 = lptim1_freq_hz / SERVO_FREQ_HZ;
550
+ ///
551
+ /// lptim1.set_max_duty(max_duty.try_into().unwrap());
552
+ /// ```
553
+ #[ inline]
554
+ fn set_max_duty ( & mut self , duty : u16 ) {
555
+ if !self . is_enabled ( ) {
556
+ const CR : Cr = Cr :: RESET . enable ( ) ;
557
+ self . as_mut_tim ( ) . set_cr ( CR ) ;
558
+
559
+ // RM0461 Rev 4 "Timer enable":
560
+ // After setting the ENABLE bit, a delay of two counter
561
+ // clock is needed before the LPTIM is actually enabled.
562
+ const MAX_SYS_FREQ : u32 = 48_000_000 ;
563
+ let delay: u32 = ( MAX_SYS_FREQ * 2 ) / self . hz ( ) . to_integer ( ) ;
564
+ cortex_m:: asm:: delay ( delay) ;
565
+ }
566
+
567
+ self . as_mut_tim ( ) . set_autoreload ( duty) ;
568
+ }
500
569
}
501
570
502
571
impl LpTim for LpTim1 {
@@ -712,7 +781,7 @@ macro_rules! impl_eh_pwmpin_for {
712
781
}
713
782
714
783
fn get_max_duty( & self ) -> Self :: Duty {
715
- u16 :: MAX
784
+ self . as_tim ( ) . autoreload ( )
716
785
}
717
786
718
787
fn set_duty( & mut self , duty: Self :: Duty ) {
@@ -729,10 +798,8 @@ macro_rules! impl_eh_pwmpin_for {
729
798
}
730
799
731
800
// can only be modified when enabled
732
- self . as_mut_tim( ) . set_autoreload( u16 :: MAX ) ;
733
- self . as_mut_tim( ) . set_cmp( duty) ;
734
- while Self :: isr( ) & ( irq:: ARROK | irq:: CMPOK ) == 0 { }
735
- unsafe { self . set_icr( irq:: ARROK | irq:: CMPOK ) } ;
801
+ let max_duty: u16 = self . get_max_duty( ) ;
802
+ self . as_mut_tim( ) . set_cmp( min( max_duty, duty) ) ;
736
803
}
737
804
}
738
805
} ;
0 commit comments