diff --git a/examples/simple/examples/dma.rs b/examples/simple/examples/dma.rs index 4cf34bd..affd1b0 100644 --- a/examples/simple/examples/dma.rs +++ b/examples/simple/examples/dma.rs @@ -49,9 +49,12 @@ fn main() -> ! { enable_and_init_irq_router(&mut dp.sysconfig, &dp.irq_router); // Safety: The DMA control block has an alignment rule of 128 and we constructed it directly // statically. - let dma = Dma::new(&mut dp.sysconfig, dp.dma, DmaCfg::default(), unsafe { - core::ptr::addr_of_mut!(DMA_CTRL_BLOCK) - }) + let dma = Dma::new( + &mut dp.sysconfig, + dp.dma, + DmaCfg::default(), + core::ptr::addr_of_mut!(DMA_CTRL_BLOCK), + ) .expect("error creating DMA"); let (mut dma0, _, _, _) = dma.split(); let mut delay_ms = CountdownTimer::new(&mut dp.sysconfig, dp.tim0, &clocks); diff --git a/va416xx-hal/src/pwm.rs b/va416xx-hal/src/pwm.rs index 1d472e4..9d92cc9 100644 --- a/va416xx-hal/src/pwm.rs +++ b/va416xx-hal/src/pwm.rs @@ -16,7 +16,9 @@ use crate::{clock::Clocks, gpio::DynPinId}; const DUTY_MAX: u16 = u16::MAX; -pub struct PwmBase { +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub(crate) struct PwmCommon { clock: Hertz, /// For PWMB, this is the upper limit current_duty: u16, @@ -34,129 +36,13 @@ enum StatusSelPwm { pub struct PwmA {} pub struct PwmB {} -//================================================================================================== -// Common -//================================================================================================== - -macro_rules! pwm_common_func { - () => { - #[inline] - fn enable_pwm_a(&mut self) { - self.reg - .reg_block() - .ctrl() - .modify(|_, w| unsafe { w.status_sel().bits(StatusSelPwm::PwmA as u8) }); - } - - #[inline] - fn enable_pwm_b(&mut self) { - self.reg - .reg_block() - .ctrl() - .modify(|_, w| unsafe { w.status_sel().bits(StatusSelPwm::PwmB as u8) }); - } - - #[inline] - pub fn get_period(&self) -> Hertz { - self.pwm_base.current_period - } - - #[inline] - pub fn set_period(&mut self, period: impl Into) { - self.pwm_base.current_period = period.into(); - // Avoid division by 0 - if self.pwm_base.current_period.raw() == 0 { - return; - } - self.pwm_base.current_rst_val = - self.pwm_base.clock.raw() / self.pwm_base.current_period.raw(); - self.reg - .reg_block() - .rst_value() - .write(|w| unsafe { w.bits(self.pwm_base.current_rst_val) }); - } - - #[inline] - pub fn disable(&mut self) { - self.reg - .reg_block() - .ctrl() - .modify(|_, w| w.enable().clear_bit()); - } - - #[inline] - pub fn enable(&mut self) { - self.reg - .reg_block() - .ctrl() - .modify(|_, w| w.enable().set_bit()); - } - - #[inline] - pub fn period(&self) -> Hertz { - self.pwm_base.current_period - } - - #[inline(always)] - pub fn duty(&self) -> u16 { - self.pwm_base.current_duty - } - }; -} - -macro_rules! pwmb_func { - () => { - pub fn pwmb_lower_limit(&self) -> u16 { - self.pwm_base.current_lower_limit - } - - pub fn pwmb_upper_limit(&self) -> u16 { - self.pwm_base.current_duty - } - - /// Set the lower limit for PWMB - /// - /// The PWM signal will be 1 as long as the current RST counter is larger than - /// the lower limit. For example, with a lower limit of 0.5 and and an upper limit - /// of 0.7, Only a fixed period between 0.5 * period and 0.7 * period will be in a high - /// state - pub fn set_pwmb_lower_limit(&mut self, duty: u16) { - self.pwm_base.current_lower_limit = duty; - let pwmb_val: u64 = (self.pwm_base.current_rst_val as u64 - * self.pwm_base.current_lower_limit as u64) - / DUTY_MAX as u64; - self.reg - .reg_block() - .pwmb_value() - .write(|w| unsafe { w.bits(pwmb_val as u32) }); - } - - /// Set the higher limit for PWMB - /// - /// The PWM signal will be 1 as long as the current RST counter is smaller than - /// the higher limit. For example, with a lower limit of 0.5 and and an upper limit - /// of 0.7, Only a fixed period between 0.5 * period and 0.7 * period will be in a high - /// state - pub fn set_pwmb_upper_limit(&mut self, duty: u16) { - self.pwm_base.current_duty = duty; - let pwma_val: u64 = (self.pwm_base.current_rst_val as u64 - * self.pwm_base.current_duty as u64) - / DUTY_MAX as u64; - self.reg - .reg_block() - .pwma_value() - .write(|w| unsafe { w.bits(pwma_val as u32) }); - } - }; -} - //================================================================================================== // Strongly typed PWM pin //================================================================================================== pub struct PwmPin { reg: TimAndPinRegister, - pwm_base: PwmBase, + inner: ReducedPwmPin, mode: PhantomData, } @@ -172,13 +58,17 @@ where initial_period: impl Into + Copy, ) -> Self { let mut pin = PwmPin { - pwm_base: PwmBase { - current_duty: 0, - current_lower_limit: 0, - current_period: initial_period.into(), - current_rst_val: 0, - clock: Tim::clock(clocks), - }, + inner: ReducedPwmPin::::new( + Tim::ID, + Pin::DYN, + PwmCommon { + clock: Tim::clock(clocks), + current_duty: 0, + current_lower_limit: 0, + current_period: initial_period.into(), + current_rst_val: 0, + }, + ), reg: unsafe { TimAndPinRegister::new(pin_and_tim.0, pin_and_tim.1) }, mode: PhantomData, }; @@ -190,11 +80,53 @@ where pin } + pub fn downgrade(self) -> ReducedPwmPin { + self.inner + } + pub fn release(self) -> (Pin, Tim) { self.reg.release() } - pwm_common_func!(); + #[inline] + fn enable_pwm_a(&mut self) { + self.inner.enable_pwm_a(); + } + + #[inline] + fn enable_pwm_b(&mut self) { + self.inner.enable_pwm_b(); + } + + #[inline] + pub fn get_period(&self) -> Hertz { + self.inner.get_period() + } + + #[inline] + pub fn set_period(&mut self, period: impl Into) { + self.inner.set_period(period); + } + + #[inline] + pub fn disable(&mut self) { + self.inner.disable(); + } + + #[inline] + pub fn enable(&mut self) { + self.inner.enable(); + } + + #[inline] + pub fn period(&self) -> Hertz { + self.inner.period() + } + + #[inline(always)] + pub fn duty(&self) -> u16 { + self.inner.duty() + } } impl From> for PwmPin @@ -204,7 +136,7 @@ where fn from(other: PwmPin) -> Self { let mut pwmb = Self { reg: other.reg, - pwm_base: other.pwm_base, + inner: other.inner.into(), mode: PhantomData, }; pwmb.enable_pwm_b(); @@ -219,7 +151,7 @@ where fn from(other: PwmPin) -> Self { let mut pwmb = Self { reg: other.reg, - pwm_base: other.pwm_base, + inner: other.inner.into(), mode: PhantomData, }; pwmb.enable_pwm_a(); @@ -267,33 +199,105 @@ where /// Reduced version where type information is deleted pub struct ReducedPwmPin { - reg: TimDynRegister, - pwm_base: PwmBase, - pin_id: DynPinId, + dyn_reg: TimDynRegister, + common: PwmCommon, mode: PhantomData, } -impl From> for ReducedPwmPin { - fn from(pwm_pin: PwmPin) -> Self { - ReducedPwmPin { - reg: TimDynRegister::from(pwm_pin.reg), - pwm_base: pwm_pin.pwm_base, - pin_id: PIN::DYN, +impl ReducedPwmPin { + pub(crate) fn new(tim_id: u8, pin_id: DynPinId, common: PwmCommon) -> Self { + Self { + dyn_reg: TimDynRegister { tim_id, pin_id }, + common, mode: PhantomData, } } + + #[inline] + fn enable_pwm_a(&mut self) { + self.dyn_reg + .reg_block() + .ctrl() + .modify(|_, w| unsafe { w.status_sel().bits(StatusSelPwm::PwmA as u8) }); + } + + #[inline] + fn enable_pwm_b(&mut self) { + self.dyn_reg + .reg_block() + .ctrl() + .modify(|_, w| unsafe { w.status_sel().bits(StatusSelPwm::PwmB as u8) }); + } + + #[inline] + pub fn get_period(&self) -> Hertz { + self.common.current_period + } + + #[inline] + pub fn set_period(&mut self, period: impl Into) { + self.common.current_period = period.into(); + // Avoid division by 0 + if self.common.current_period.raw() == 0 { + return; + } + self.common.current_rst_val = self.common.clock.raw() / self.common.current_period.raw(); + self.dyn_reg + .reg_block() + .rst_value() + .write(|w| unsafe { w.bits(self.common.current_rst_val) }); + } + + #[inline] + pub fn disable(&mut self) { + self.dyn_reg + .reg_block() + .ctrl() + .modify(|_, w| w.enable().clear_bit()); + } + + #[inline] + pub fn enable(&mut self) { + self.dyn_reg + .reg_block() + .ctrl() + .modify(|_, w| w.enable().set_bit()); + } + + #[inline] + pub fn period(&self) -> Hertz { + self.common.current_period + } + + #[inline(always)] + pub fn duty(&self) -> u16 { + self.common.current_duty + } } -impl ReducedPwmPin { - pwm_common_func!(); +impl From> for ReducedPwmPin +where + (Pin, Tim): ValidTimAndPin, +{ + fn from(value: PwmPin) -> Self { + value.downgrade() + } +} + +impl From> for ReducedPwmPin +where + (Pin, Tim): ValidTimAndPin, +{ + fn from(value: PwmPin) -> Self { + value.downgrade() + } } impl From> for ReducedPwmPin { fn from(other: ReducedPwmPin) -> Self { let mut pwmb = Self { - reg: other.reg, - pwm_base: other.pwm_base, - pin_id: other.pin_id, + dyn_reg: other.dyn_reg, + common: other.common, mode: PhantomData, }; pwmb.enable_pwm_b(); @@ -304,9 +308,8 @@ impl From> for ReducedPwmPin { impl From> for ReducedPwmPin { fn from(other: ReducedPwmPin) -> Self { let mut pwmb = Self { - reg: other.reg, - pwm_base: other.pwm_base, - pin_id: other.pin_id, + dyn_reg: other.dyn_reg, + common: other.common, mode: PhantomData, }; pwmb.enable_pwm_a(); @@ -318,15 +321,83 @@ impl From> for ReducedPwmPin { // PWMB implementations //================================================================================================== -impl PwmPin +impl PwmPin where - (PIN, TIM): ValidTimAndPin, + (Pin, Tim): ValidTimAndPin, { - pwmb_func!(); + pub fn pwmb_lower_limit(&self) -> u16 { + self.inner.pwmb_lower_limit() + } + + pub fn pwmb_upper_limit(&self) -> u16 { + self.inner.pwmb_upper_limit() + } + + /// Set the lower limit for PWMB + /// + /// The PWM signal will be 1 as long as the current RST counter is larger than + /// the lower limit. For example, with a lower limit of 0.5 and and an upper limit + /// of 0.7, Only a fixed period between 0.5 * period and 0.7 * period will be in a high + /// state + pub fn set_pwmb_lower_limit(&mut self, duty: u16) { + self.inner.set_pwmb_lower_limit(duty); + } + + /// Set the higher limit for PWMB + /// + /// The PWM signal will be 1 as long as the current RST counter is smaller than + /// the higher limit. For example, with a lower limit of 0.5 and and an upper limit + /// of 0.7, Only a fixed period between 0.5 * period and 0.7 * period will be in a high + /// state + pub fn set_pwmb_upper_limit(&mut self, duty: u16) { + self.inner.set_pwmb_upper_limit(duty); + } } impl ReducedPwmPin { - pwmb_func!(); + #[inline(always)] + pub fn pwmb_lower_limit(&self) -> u16 { + self.common.current_lower_limit + } + + #[inline(always)] + pub fn pwmb_upper_limit(&self) -> u16 { + self.common.current_duty + } + + /// Set the lower limit for PWMB + /// + /// The PWM signal will be 1 as long as the current RST counter is larger than + /// the lower limit. For example, with a lower limit of 0.5 and and an upper limit + /// of 0.7, Only a fixed period between 0.5 * period and 0.7 * period will be in a high + /// state + #[inline(always)] + pub fn set_pwmb_lower_limit(&mut self, duty: u16) { + self.common.current_lower_limit = duty; + let pwmb_val: u64 = (self.common.current_rst_val as u64 + * self.common.current_lower_limit as u64) + / DUTY_MAX as u64; + self.dyn_reg + .reg_block() + .pwmb_value() + .write(|w| unsafe { w.bits(pwmb_val as u32) }); + } + + /// Set the higher limit for PWMB + /// + /// The PWM signal will be 1 as long as the current RST counter is smaller than + /// the higher limit. For example, with a lower limit of 0.5 and and an upper limit + /// of 0.7, Only a fixed period between 0.5 * period and 0.7 * period will be in a high + /// state + pub fn set_pwmb_upper_limit(&mut self, duty: u16) { + self.common.current_duty = duty; + let pwma_val: u64 = (self.common.current_rst_val as u64 * self.common.current_duty as u64) + / DUTY_MAX as u64; + self.dyn_reg + .reg_block() + .pwma_value() + .write(|w| unsafe { w.bits(pwma_val as u32) }); + } } //================================================================================================== @@ -349,11 +420,11 @@ impl embedded_hal::pwm::SetDutyCycle for ReducedPwmPin { #[inline] fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { - self.pwm_base.current_duty = duty; - let pwma_val: u64 = (self.pwm_base.current_rst_val as u64 - * (DUTY_MAX as u64 - self.pwm_base.current_duty as u64)) + self.common.current_duty = duty; + let pwma_val: u64 = (self.common.current_rst_val as u64 + * (DUTY_MAX as u64 - self.common.current_duty as u64)) / DUTY_MAX as u64; - self.reg + self.dyn_reg .reg_block() .pwma_value() .write(|w| unsafe { w.bits(pwma_val as u32) }); @@ -369,15 +440,7 @@ impl embedded_hal::pwm::SetDutyCycle for PwmPin Result<(), Self::Error> { - self.pwm_base.current_duty = duty; - let pwma_val: u64 = (self.pwm_base.current_rst_val as u64 - * (DUTY_MAX as u64 - self.pwm_base.current_duty as u64)) - / DUTY_MAX as u64; - self.reg - .reg_block() - .pwma_value() - .write(|w| unsafe { w.bits(pwma_val as u32) }); - Ok(()) + self.inner.set_duty_cycle(duty) } } diff --git a/va416xx-hal/src/timer.rs b/va416xx-hal/src/timer.rs index 9060610..ba1e823 100644 --- a/va416xx-hal/src/timer.rs +++ b/va416xx-hal/src/timer.rs @@ -502,10 +502,10 @@ unsafe impl TimRegInterface for TimAndPinRegister From> for TimDynRegister {