diff --git a/Cargo.toml b/Cargo.toml index 08875d34a..c5e23e62b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -179,6 +179,10 @@ required-features = ["rt-selected"] name = "usart_dma" required-features = ["rt-selected", "845"] +[[example]] +name = "ctimer_blink" +required-features = ["rt-selected", "845"] + [[example]] name = "ctimer_fade" required-features = ["rt-selected", "845"] diff --git a/examples/ctimer_blink.rs b/examples/ctimer_blink.rs new file mode 100644 index 000000000..ccfb965c4 --- /dev/null +++ b/examples/ctimer_blink.rs @@ -0,0 +1,73 @@ +#![no_main] +#![no_std] + +extern crate panic_rtt_target; + +use lpc8xx_hal::{ + cortex_m_rt::entry, ctimer::Channels123, delay::Delay, prelude::*, + CorePeripherals, Peripherals, +}; + +#[entry] +fn main() -> ! { + rtt_target::rtt_init_print!(); + + // Get access to the device's peripherals. Since only one instance of this + // struct can exist, the call to `take` returns an `Option`. + // If we tried to call the method a second time, it would return `None`, but + // we're only calling it the one time here, so we can safely `unwrap` the + // `Option` without causing a panic. + let cp = CorePeripherals::take().unwrap(); + let p = Peripherals::take().unwrap(); + + // Initialize the APIs of the peripherals we need. + let swm = p.SWM.split(); + let mut delay = Delay::new(cp.SYST); + let mut syscon = p.SYSCON.split(); + + let mut handle = swm.handle.enable(&mut syscon.handle); + + // Select pin for the RGB LED + let green = p.pins.pio1_0.into_swm_pin(); + let blue = p.pins.pio1_1.into_swm_pin(); + let red = p.pins.pio1_2.into_swm_pin(); + + // Configure the LED pins. The API tracks the state of pins at compile time, + // to prevent any mistakes. + let (red, _) = swm.movable_functions.t0_mat0.assign(red, &mut handle); + let (green, _) = swm.movable_functions.t0_mat1.assign(green, &mut handle); + let (blue, _) = swm.movable_functions.t0_mat2.assign(blue, &mut handle); + + const MAX_PERIOD: u32 = 12_000_000; + const MIN_PERIOD: u32 = MAX_PERIOD / 12; + + let periods = (MIN_PERIOD..MAX_PERIOD).step_by(MIN_PERIOD as usize); + + let mut ctimer = p + .CTIMER0 + .enable(MAX_PERIOD, 0, &mut syscon.handle) + .attach(red) + .attach(green) + .attach(blue); + + loop { + for period in periods.clone().rev() { + ctimer.set_period(period); + + ctimer.set_duty(Channels123::Channel1, period / 8); + ctimer.set_duty(Channels123::Channel2, period / 4); + ctimer.set_duty(Channels123::Channel3, period / 2); + + delay.delay_ms(period / 12_000); + } + for period in periods.clone() { + ctimer.set_period(period); + + ctimer.set_duty(Channels123::Channel1, period / 8); + ctimer.set_duty(Channels123::Channel2, period / 4); + ctimer.set_duty(Channels123::Channel3, period / 2); + + delay.delay_ms(period / 12_000); + } + } +} diff --git a/examples/ctimer_fade.rs b/examples/ctimer_fade.rs index 03dcba461..571b20ce1 100644 --- a/examples/ctimer_fade.rs +++ b/examples/ctimer_fade.rs @@ -26,10 +26,6 @@ fn main() -> ! { let mut handle = swm.handle.enable(&mut syscon.handle); - // Use 8 bit pwm - let (red_pwm, green_pwm, blue_pwm) = - p.CTIMER0.start_pwm(256, 0, &mut syscon.handle); - // Select pin for the RGB LED let green = p.pins.pio1_0.into_swm_pin(); let blue = p.pins.pio1_1.into_swm_pin(); @@ -41,10 +37,18 @@ fn main() -> ! { let (green, _) = swm.movable_functions.t0_mat1.assign(green, &mut handle); let (blue, _) = swm.movable_functions.t0_mat2.assign(blue, &mut handle); - let mut red = red_pwm.attach(red); - let mut green = green_pwm.attach(green); - let mut blue = blue_pwm.attach(blue); - // Fade each color after anothe + // Use 8 bit pwm + let ctimer = p + .CTIMER0 + .enable(256, 0, &mut syscon.handle) + .attach(red) + .attach(green) + .attach(blue); + let mut red = ctimer.channels.channel1; + let mut green = ctimer.channels.channel2; + let mut blue = ctimer.channels.channel3; + + // Fade each color after another loop { for i in 0..red.get_max_duty() { delay.delay_ms(4_u8); diff --git a/src/ctimer.rs b/src/ctimer.rs deleted file mode 100644 index 20c4e7c44..000000000 --- a/src/ctimer.rs +++ /dev/null @@ -1,223 +0,0 @@ -//! API for the CTimer peripheral -//! -//! Currently, only PWM output functionality is implemented. -//! -//! # Example -//! -//! ```no_run -//! use lpc8xx_hal::{ -//! delay::Delay, -//! prelude::*, -//! Peripherals, -//! pac::CorePeripherals, -//! }; -//! -//! let cp = CorePeripherals::take().unwrap(); -//! let p = Peripherals::take().unwrap(); -//! -//! let swm = p.SWM.split(); -//! let mut delay = Delay::new(cp.SYST); -//! let mut syscon = p.SYSCON.split(); -//! -//! let mut swm_handle = swm.handle.enable(&mut syscon.handle); -//! -//! // Use 8 bit pwm -//! let (pwm_channel,_, _ ) = -//! p.CTIMER0.start_pwm(256, 0, &mut syscon.handle); -//! -//! let pwm_output = p.pins.pio1_2.into_swm_pin(); -//! -//! let (pwm_output, _) = swm.movable_functions.t0_mat0.assign( -//! pwm_output, -//! &mut swm_handle, -//! ); -//! -//! let mut pwm_pin = pwm_channel.attach(pwm_output); -//! loop { -//! for i in 0..pwm_pin.get_max_duty() { -//! delay.delay_ms(4_u8); -//! pwm_pin.set_duty(i); -//! } -//! } -//! ``` - -use crate::{ - pac::{ - ctimer0::{MR, MSR}, - CTIMER0, - }, - pins, - reg_proxy::RegProxy, - swm::{self, T0_MAT0, T0_MAT1, T0_MAT2}, - syscon, -}; - -use core::marker::PhantomData; -use embedded_hal::PwmPin; - -/// Interface to a CTimer peripheral -/// -/// Controls the CTimer. Use [`Peripherals`] to gain access to an instance of -/// this struct. -/// -/// Please refer to the [module documentation] for more information. -/// -/// [`Peripherals`]: ../struct.Peripherals.html -/// [module documentation]: index.html -pub struct CTimer { - ct: CTIMER0, -} - -/// A detached [`CTimerPwmPin`] -/// -/// Use `attach` to assign an output to it. -/// -/// [`CTimerPwmPin`]: struct.CTimerPwmPin.html -pub struct DetachedPwmPin { - number: u8, - mr: RegProxy, - msr: RegProxy, - output: PhantomData, -} - -/// Represents a pwm channel assigned to an output pin -/// -/// # `embedded-hal` traits -/// - [`embedded_hal::PwmPin`] -/// -/// [`embedded_hal::PwmPin`]: #impl-PwmPin -pub struct CTimerPwmPin { - mr: RegProxy, - msr: RegProxy, - number: u8, -} - -impl CTimer { - pub(crate) fn new(ct: CTIMER0) -> Self { - Self { ct } - } - - /// Start the PWM timer, with a predefined period and prescaler - /// - /// The `period` sets resolution of the pwm and is returned with - /// `get_max_duty`. - pub fn start_pwm( - self, - period: u32, - prescaler: u32, - syscon: &mut syscon::Handle, - ) -> ( - DetachedPwmPin, - DetachedPwmPin, - DetachedPwmPin, - ) { - syscon.enable_clock(&self.ct); - unsafe { self.ct.pr.write(|w| w.prval().bits(prescaler)) }; - // Use MAT3 to reset the counter - unsafe { self.ct.mr[3].write(|w| w.match_().bits(period)) }; - self.ct.mcr.write(|w| { - w.mr3r().set_bit(); - // Use shadow registers for the pwm output matches - w.mr0rl().set_bit(); - w.mr1rl().set_bit(); - w.mr2rl().set_bit() - }); - - self.ct.pwmc.write(|w| { - w.pwmen0().set_bit(); - w.pwmen1().set_bit(); - w.pwmen2().set_bit() - }); - - // Start the timer - self.ct.tcr.write(|w| w.cen().set_bit()); - ( - DetachedPwmPin { - number: 0, - mr: RegProxy::new(), - msr: RegProxy::new(), - output: PhantomData {}, - }, - DetachedPwmPin { - number: 1, - mr: RegProxy::new(), - msr: RegProxy::new(), - output: PhantomData {}, - }, - DetachedPwmPin { - number: 2, - mr: RegProxy::new(), - msr: RegProxy::new(), - output: PhantomData {}, - }, - ) - } - - /// Return the raw peripheral - /// - /// This method serves as an escape hatch from the HAL API. It returns the - /// raw peripheral, allowing you to do whatever you want with it, without - /// limitations imposed by the API. - /// - /// If you are using this method because a feature you need is missing from - /// the HAL API, please [open an issue] or, if an issue for your feature - /// request already exists, comment on the existing issue, so we can - /// prioritize it accordingly. - /// - /// [open an issue]: https://github.com/lpc-rs/lpc8xx-hal/issues - pub fn free(self) -> CTIMER0 { - self.ct - } -} - -impl DetachedPwmPin { - /// Assigns a pin to a `DetachedPwmPin`, - /// allowing it to be used as a pwm output - pub fn attach( - self, - _: swm::Function>, - ) -> CTimerPwmPin - where - PWM: pins::Trait, - { - CTimerPwmPin { - mr: self.mr, - msr: self.msr, - number: self.number, - } - } -} - -impl PwmPin for CTimerPwmPin { - type Duty = u32; - /// The behaviour of `enable` is implementation defined and does nothing in - /// this implementation - fn enable(&mut self) {} - - /// The behaviour of `disable` is implementation defined and does nothing in - /// this implementation - // Accessing pwmc would require some kind of lock, which is inconvenient - // and would involve a hidden `CriticalSection` - fn disable(&mut self) {} - - /// Returns the current duty cycle - fn get_duty(&self) -> Self::Duty { - self.msr[self.number as usize].read().match_shadow().bits() - } - - /// Returns the maximum duty cycle value - fn get_max_duty(&self) -> Self::Duty { - self.mr[3].read().match_().bits() - } - - /// Sets a new duty cycle - fn set_duty(&mut self, duty: Self::Duty) { - unsafe { - self.msr[self.number as usize] - .write(|w| w.match_shadow().bits(duty)) - }; - } -} - -reg!(MR, [MR; 4], CTIMER0, mr); -reg!(MSR, [MSR; 4], CTIMER0, msr); diff --git a/src/ctimer/channel.rs b/src/ctimer/channel.rs new file mode 100644 index 000000000..8bf7a7a2e --- /dev/null +++ b/src/ctimer/channel.rs @@ -0,0 +1,139 @@ +//! Contains types related to CTIMER PWM channels + +use core::{convert::Infallible, marker::PhantomData}; + +use embedded_hal::PwmPin; +use embedded_hal_alpha::pwm::PwmPin as PwmPinAlpha; + +use crate::{ + init_state::Enabled, + pac::{ + ctimer0::{MR, MSR}, + CTIMER0, + }, + reg_proxy::RegProxy, +}; + +use self::state::Attached; + +/// A CTIMER PWM channel +pub struct Channel { + mr: RegProxy, + msr: RegProxy, + channel: PhantomData, + peripheral_state: PhantomData, + _state: PhantomData, +} + +impl Channel { + pub(super) fn new() -> Self { + Self { + mr: RegProxy::new(), + msr: RegProxy::new(), + channel: PhantomData, + peripheral_state: PhantomData, + _state: PhantomData, + } + } +} + +impl PwmPin for Channel +where + T: Trait, +{ + type Duty = u32; + + /// The behaviour of `enable` is implementation defined and does nothing in + /// this implementation + fn enable(&mut self) {} + + /// The behaviour of `disable` is implementation defined and does nothing in + /// this implementation + // Accessing pwmc would require some kind of lock, which is inconvenient + // and would involve a hidden `CriticalSection` + fn disable(&mut self) {} + + /// Returns the current duty cycle + fn get_duty(&self) -> Self::Duty { + self.msr[T::ID as usize].read().match_shadow().bits() + } + + /// Returns the maximum duty cycle value + fn get_max_duty(&self) -> Self::Duty { + self.mr[3].read().match_().bits() + } + + /// Sets a new duty cycle + fn set_duty(&mut self, duty: Self::Duty) { + unsafe { + self.msr[T::ID as usize].write(|w| w.match_shadow().bits(duty)) + }; + } +} + +impl PwmPinAlpha for Channel +where + T: Trait, +{ + type Error = Infallible; + type Duty = u32; + + /// The behaviour of `enable` is implementation defined and does nothing in + /// this implementation + fn try_enable(&mut self) -> Result<(), Self::Error> { + Ok(()) + } + + /// The behaviour of `disable` is implementation defined and does nothing in + /// this implementation + // Accessing pwmc would require some kind of lock, which is inconvenient + // and would involve a hidden `CriticalSection` + fn try_disable(&mut self) -> Result<(), Self::Error> { + Ok(()) + } + + /// Returns the current duty cycle + fn try_get_duty(&self) -> Result { + Ok(self.msr[T::ID as usize].read().match_shadow().bits()) + } + + /// Returns the maximum duty cycle value + fn try_get_max_duty(&self) -> Result { + Ok(self.mr[3].read().match_().bits()) + } + + /// Sets a new duty cycle + fn try_set_duty(&mut self, duty: Self::Duty) -> Result<(), Self::Error> { + unsafe { + Ok(self.msr[T::ID as usize].write(|w| w.match_shadow().bits(duty))) + } + } +} + +/// Implemented for all CTIMER PWM channels +pub trait Trait: private::Sealed { + /// Identifies the channel + const ID: u8; + + /// The SWM function that needs to be assigned to this channels output pin + type Output; +} + +/// Contains types that indicate which state a channel is in +pub mod state { + /// Indicates that a channel is detached + /// + /// Detached channels don't have an output function assigned and can't be + /// used for PWM output. + pub struct Detached; + + /// Indicates that a channel is attached + pub struct Attached; +} + +pub(super) mod private { + pub trait Sealed {} +} + +reg!(MR, [MR; 4], CTIMER0, mr); +reg!(MSR, [MSR; 4], CTIMER0, msr); diff --git a/src/ctimer/gen.rs b/src/ctimer/gen.rs new file mode 100644 index 000000000..a596cf84e --- /dev/null +++ b/src/ctimer/gen.rs @@ -0,0 +1,51 @@ +use crate::swm; + +use super::channel::{self, Channel}; + +macro_rules! channels { + ( + $( + $channel:ident: + $field: ident, + $id:expr, + $output:ident, + $state:ident; + )* + ) => { + /// Contains all CTIMER PWM channels + /// + /// Can be accessed via `CTIMER`. + #[allow(missing_docs)] + pub struct Channels { + $(pub $field: Channel<$channel, PeripheralState, $state>,)* + } + + impl + Channels + { + pub(super) fn new() -> Self { + Self { + $($field: Channel::new(),)* + } + } + } + + $( + /// Identifies a CTIMER PWM channel + pub struct $channel; + + impl channel::private::Sealed for $channel {} + + impl channel::Trait for $channel { + const ID: u8 = $id; + type Output = swm::$output; + } + )* + }; +} + +channels! { + Channel1: channel1, 0, T0_MAT0, State1; + Channel2: channel2, 1, T0_MAT1, State2; + Channel3: channel3, 2, T0_MAT2, State3; +} diff --git a/src/ctimer/mod.rs b/src/ctimer/mod.rs new file mode 100644 index 000000000..d669d6395 --- /dev/null +++ b/src/ctimer/mod.rs @@ -0,0 +1,54 @@ +//! API for the CTIMER peripheral +//! +//! Currently, only PWM output functionality is implemented. +//! +//! # Example +//! +//! ```no_run +//! use lpc8xx_hal::{ +//! delay::Delay, +//! prelude::*, +//! Peripherals, +//! pac::CorePeripherals, +//! }; +//! +//! let cp = CorePeripherals::take().unwrap(); +//! let p = Peripherals::take().unwrap(); +//! +//! let swm = p.SWM.split(); +//! let mut delay = Delay::new(cp.SYST); +//! let mut syscon = p.SYSCON.split(); +//! +//! let mut swm_handle = swm.handle.enable(&mut syscon.handle); +//! +//! let pwm_output = p.pins.pio1_2.into_swm_pin(); +//! +//! let (pwm_output, _) = swm.movable_functions.t0_mat0.assign( +//! pwm_output, +//! &mut swm_handle, +//! ); +//! +//! // Use 8 bit pwm +//! let ctimer = p.CTIMER0 +//! .enable(256, 0, &mut syscon.handle) +//! .attach(pwm_output); +//! +//! let mut pwm_pin = ctimer.channels.channel1; +//! loop { +//! for i in 0..pwm_pin.get_max_duty() { +//! delay.delay_ms(4_u8); +//! pwm_pin.set_duty(i); +//! } +//! } +//! ``` + +pub mod channel; + +mod gen; +mod peripheral; + +pub use self::{ + channel::Channel, + gen::*, + peripheral::{Channels1, Channels12, Channels123, CTIMER}, +}; diff --git a/src/ctimer/peripheral.rs b/src/ctimer/peripheral.rs new file mode 100644 index 000000000..5b40769ed --- /dev/null +++ b/src/ctimer/peripheral.rs @@ -0,0 +1,613 @@ +use core::convert::Infallible; + +use embedded_hal::{Pwm, PwmPin as _}; +use embedded_hal_alpha::pwm::{Pwm as PwmAlpha, PwmPin as _}; + +use crate::{ + init_state::{Disabled, Enabled}, + pac::CTIMER0, + swm, syscon, +}; + +use super::{ + channel::{ + self, + state::{Attached, Detached}, + }, + gen::{Channel1, Channel2, Channel3, Channels}, +}; + +/// Interface to a CTimer peripheral +/// +/// Controls the CTimer. Use [`Peripherals`] to gain access to an instance of +/// this struct. +/// +/// Please refer to the [module documentation] for more information. +/// +/// [`Peripherals`]: ../struct.Peripherals.html +/// [module documentation]: index.html +pub struct CTIMER { + /// The PWM channels of this CTIMER + pub channels: Channels, + + inner: CTIMER0, + state: State, +} + +impl CTIMER { + pub(crate) fn new(ct: CTIMER0) -> Self { + Self { + channels: Channels::new(), + inner: ct, + state: Disabled, + } + } +} + +impl + CTIMER +{ + /// Start the PWM timer, with a predefined period and prescaler + /// + /// The `period` sets resolution of the pwm and is returned with + /// `get_max_duty`. + pub fn enable( + self, + period: u32, + prescaler: u32, + syscon: &mut syscon::Handle, + ) -> CTIMER { + syscon.enable_clock(&self.inner); + + let mut self_ = CTIMER { + channels: Channels::new(), + inner: self.inner, + state: Enabled(()), + }; + + unsafe { self_.inner.pr.write(|w| w.prval().bits(prescaler)) }; + self_.set_period(period); + self_.inner.mcr.write(|w| { + w.mr3r().set_bit(); + // Use shadow registers for the pwm output matches + w.mr0rl().set_bit(); + w.mr1rl().set_bit(); + w.mr2rl().set_bit() + }); + + self_.inner.pwmc.write(|w| { + w.pwmen0().set_bit(); + w.pwmen1().set_bit(); + w.pwmen2().set_bit() + }); + + // Start the timer + self_.inner.tcr.write(|w| w.cen().set_bit()); + + self_ + } +} + +impl CTIMER { + /// Attach an output function to channel 1 + /// + /// This function is only available if no output functions has been attached + /// to channel 1. + pub fn attach( + self, + _: swm::Function< + ::Output, + swm::state::Assigned, + >, + ) -> CTIMER { + CTIMER { + channels: Channels::new(), + inner: self.inner, + state: self.state, + } + } +} + +impl CTIMER { + /// Attach an output function to channel 2 + /// + /// This function is only available if an output function has been attached + /// to channel 1, but no output functions has been attached to channel 2. + pub fn attach( + self, + _: swm::Function< + ::Output, + swm::state::Assigned, + >, + ) -> CTIMER { + CTIMER { + channels: Channels::new(), + inner: self.inner, + state: self.state, + } + } +} + +impl CTIMER { + /// Attach an output function to channel 3 + /// + /// This function is only available if output functions have been attached + /// to channels 1 and 2, but no output functions has been attached to + /// channel 3. + pub fn attach( + self, + _: swm::Function< + ::Output, + swm::state::Assigned, + >, + ) -> CTIMER { + CTIMER { + channels: Channels::new(), + inner: self.inner, + state: self.state, + } + } +} + +impl + CTIMER +{ + /// Disable the CTIMER + /// + /// This method is only available, if `CTIMER` is in the [`Enabled`] state. + /// Code that attempts to call this method when the peripheral is already + /// disabled will not compile. + /// + /// Consumes this instance of `CTIMER` and returns another instance that has + /// its `State` type parameter set to [`Disabled`]. + /// + /// [`Enabled`]: ../init_state/struct.Enabled.html + /// [`Disabled`]: ../init_state/struct.Disabled.html + pub fn disable( + self, + syscon: &mut syscon::Handle, + ) -> CTIMER { + syscon.disable_clock(&self.inner); + + CTIMER { + channels: Channels::new(), + inner: self.inner, + state: Disabled, + } + } + + // Private methods + + fn get_period(&self) -> u32 { + self.inner.mr[3].read().match_().bits() + } + + fn get_max_duty(&self) -> u32 { + self.get_period() + } + + fn set_period(&mut self, period: u32) { + // Use MAT3 to reset the counter + unsafe { self.inner.mr[3].write(|w| w.match_().bits(period)) }; + + // Reset counter. Otherwise we can run into the case where the counter + // is already larger than period, and won't be reset until it wrapped. + self.inner.tcr.modify(|_, w| w.crst().enabled()); + self.inner.tcr.modify(|_, w| w.crst().disabled()); + } +} + +impl + CTIMER +{ + /// Return the raw peripheral + /// + /// This method serves as an escape hatch from the HAL API. It returns the + /// raw peripheral, allowing you to do whatever you want with it, without + /// limitations imposed by the API. + /// + /// If you are using this method because a feature you need is missing from + /// the HAL API, please [open an issue] or, if an issue for your feature + /// request already exists, comment on the existing issue, so we can + /// prioritize it accordingly. + /// + /// [open an issue]: https://github.com/lpc-rs/lpc8xx-hal/issues + pub fn free(self) -> CTIMER0 { + self.inner + } +} + +impl Pwm for CTIMER { + type Channel = Channels1; + type Time = u32; + type Duty = u32; + + fn disable(&mut self, channel: Self::Channel) { + match channel { + Self::Channel::Channel1 => self.channels.channel1.disable(), + } + } + + fn enable(&mut self, channel: Self::Channel) { + match channel { + Self::Channel::Channel1 => self.channels.channel1.enable(), + } + } + + fn get_period(&self) -> Self::Time { + self.get_period() + } + + fn get_duty(&self, channel: Self::Channel) -> Self::Duty { + match channel { + Self::Channel::Channel1 => self.channels.channel1.get_duty(), + } + } + + fn get_max_duty(&self) -> Self::Duty { + self.get_max_duty() + } + + fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { + match channel { + Self::Channel::Channel1 => self.channels.channel1.set_duty(duty), + } + } + + fn set_period

(&mut self, period: P) + where + P: Into, + { + self.set_period(period.into()) + } +} + +impl Pwm for CTIMER { + type Channel = Channels12; + type Time = u32; + type Duty = u32; + + fn disable(&mut self, channel: Self::Channel) { + match channel { + Self::Channel::Channel1 => self.channels.channel1.disable(), + Self::Channel::Channel2 => self.channels.channel2.disable(), + } + } + + fn enable(&mut self, channel: Self::Channel) { + match channel { + Self::Channel::Channel1 => self.channels.channel1.enable(), + Self::Channel::Channel2 => self.channels.channel2.enable(), + } + } + + fn get_period(&self) -> Self::Time { + self.get_period() + } + + fn get_duty(&self, channel: Self::Channel) -> Self::Duty { + match channel { + Self::Channel::Channel1 => self.channels.channel1.get_duty(), + Self::Channel::Channel2 => self.channels.channel2.get_duty(), + } + } + + fn get_max_duty(&self) -> Self::Duty { + self.get_max_duty() + } + + fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { + match channel { + Self::Channel::Channel1 => self.channels.channel1.set_duty(duty), + Self::Channel::Channel2 => self.channels.channel2.set_duty(duty), + } + } + + fn set_period

(&mut self, period: P) + where + P: Into, + { + self.set_period(period.into()) + } +} + +impl Pwm for CTIMER { + type Channel = Channels123; + type Time = u32; + type Duty = u32; + + fn disable(&mut self, channel: Self::Channel) { + match channel { + Self::Channel::Channel1 => self.channels.channel1.disable(), + Self::Channel::Channel2 => self.channels.channel2.disable(), + Self::Channel::Channel3 => self.channels.channel3.disable(), + } + } + + fn enable(&mut self, channel: Self::Channel) { + match channel { + Self::Channel::Channel1 => self.channels.channel1.enable(), + Self::Channel::Channel2 => self.channels.channel2.enable(), + Self::Channel::Channel3 => self.channels.channel3.enable(), + } + } + + fn get_period(&self) -> Self::Time { + self.get_period() + } + + fn get_duty(&self, channel: Self::Channel) -> Self::Duty { + match channel { + Self::Channel::Channel1 => self.channels.channel1.get_duty(), + Self::Channel::Channel2 => self.channels.channel2.get_duty(), + Self::Channel::Channel3 => self.channels.channel3.get_duty(), + } + } + + fn get_max_duty(&self) -> Self::Duty { + self.get_max_duty() + } + + fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { + match channel { + Self::Channel::Channel1 => self.channels.channel1.set_duty(duty), + Self::Channel::Channel2 => self.channels.channel2.set_duty(duty), + Self::Channel::Channel3 => self.channels.channel3.set_duty(duty), + } + } + + fn set_period

(&mut self, period: P) + where + P: Into, + { + self.set_period(period.into()) + } +} + +impl PwmAlpha for CTIMER { + type Error = Infallible; + type Channel = Channels1; + type Time = u32; + type Duty = u32; + + fn try_disable( + &mut self, + channel: Self::Channel, + ) -> Result<(), Self::Error> { + match channel { + Self::Channel::Channel1 => self.channels.channel1.try_disable(), + } + } + + fn try_enable( + &mut self, + channel: Self::Channel, + ) -> Result<(), Self::Error> { + match channel { + Self::Channel::Channel1 => self.channels.channel1.try_enable(), + } + } + + fn try_get_period(&self) -> Result { + Ok(self.get_period()) + } + + fn try_get_duty( + &self, + channel: Self::Channel, + ) -> Result { + match channel { + Self::Channel::Channel1 => self.channels.channel1.try_get_duty(), + } + } + + fn try_get_max_duty(&self) -> Result { + Ok(self.get_max_duty()) + } + + fn try_set_duty( + &mut self, + channel: Self::Channel, + duty: Self::Duty, + ) -> Result<(), Self::Error> { + match channel { + Self::Channel::Channel1 => { + self.channels.channel1.try_set_duty(duty) + } + } + } + + fn try_set_period

(&mut self, period: P) -> Result<(), Self::Error> + where + P: Into, + { + Ok(self.set_period(period.into())) + } +} + +impl PwmAlpha for CTIMER { + type Error = Infallible; + type Channel = Channels12; + type Time = u32; + type Duty = u32; + + fn try_disable( + &mut self, + channel: Self::Channel, + ) -> Result<(), Self::Error> { + match channel { + Self::Channel::Channel1 => self.channels.channel1.try_disable(), + Self::Channel::Channel2 => self.channels.channel2.try_disable(), + } + } + + fn try_enable( + &mut self, + channel: Self::Channel, + ) -> Result<(), Self::Error> { + match channel { + Self::Channel::Channel1 => self.channels.channel1.try_enable(), + Self::Channel::Channel2 => self.channels.channel2.try_enable(), + } + } + + fn try_get_period(&self) -> Result { + Ok(self.get_period()) + } + + fn try_get_duty( + &self, + channel: Self::Channel, + ) -> Result { + match channel { + Self::Channel::Channel1 => self.channels.channel1.try_get_duty(), + Self::Channel::Channel2 => self.channels.channel2.try_get_duty(), + } + } + + fn try_get_max_duty(&self) -> Result { + Ok(self.get_max_duty()) + } + + fn try_set_duty( + &mut self, + channel: Self::Channel, + duty: Self::Duty, + ) -> Result<(), Self::Error> { + match channel { + Self::Channel::Channel1 => { + self.channels.channel1.try_set_duty(duty) + } + Self::Channel::Channel2 => { + self.channels.channel2.try_set_duty(duty) + } + } + } + + fn try_set_period

(&mut self, period: P) -> Result<(), Self::Error> + where + P: Into, + { + Ok(self.set_period(period.into())) + } +} + +impl PwmAlpha for CTIMER { + type Error = Infallible; + type Channel = Channels123; + type Time = u32; + type Duty = u32; + + fn try_disable( + &mut self, + channel: Self::Channel, + ) -> Result<(), Self::Error> { + match channel { + Self::Channel::Channel1 => self.channels.channel1.try_disable(), + Self::Channel::Channel2 => self.channels.channel2.try_disable(), + Self::Channel::Channel3 => self.channels.channel3.try_disable(), + } + } + + fn try_enable( + &mut self, + channel: Self::Channel, + ) -> Result<(), Self::Error> { + match channel { + Self::Channel::Channel1 => self.channels.channel1.try_enable(), + Self::Channel::Channel2 => self.channels.channel2.try_enable(), + Self::Channel::Channel3 => self.channels.channel3.try_enable(), + } + } + + fn try_get_period(&self) -> Result { + Ok(self.get_period()) + } + + fn try_get_duty( + &self, + channel: Self::Channel, + ) -> Result { + match channel { + Self::Channel::Channel1 => self.channels.channel1.try_get_duty(), + Self::Channel::Channel2 => self.channels.channel2.try_get_duty(), + Self::Channel::Channel3 => self.channels.channel3.try_get_duty(), + } + } + + fn try_get_max_duty(&self) -> Result { + Ok(self.get_max_duty()) + } + + fn try_set_duty( + &mut self, + channel: Self::Channel, + duty: Self::Duty, + ) -> Result<(), Self::Error> { + match channel { + Self::Channel::Channel1 => { + self.channels.channel1.try_set_duty(duty) + } + Self::Channel::Channel2 => { + self.channels.channel2.try_set_duty(duty) + } + Self::Channel::Channel3 => { + self.channels.channel3.try_set_duty(duty) + } + } + } + + fn try_set_period

(&mut self, period: P) -> Result<(), Self::Error> + where + P: Into, + { + Ok(self.set_period(period.into())) + } +} + +/// The available channels, if only channel 1 is attached +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Channels1 { + /// Channel 1 + Channel1, +} + +/// The available channels, if only channels 1 and 2 are attached +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Channels12 { + /// Channel 1 + Channel1, + + /// Channel 2 + Channel2, +} + +/// The available channels, if channels 1, 2, and 2 are attached +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Channels123 { + /// Channel 1 + Channel1, + + /// Channel 2 + Channel2, + + /// Channel 3 + Channel3, +} + +impl From for Channels123 { + fn from(from: Channels1) -> Self { + match from { + Channels1::Channel1 => Self::Channel1, + } + } +} + +impl From for Channels123 { + fn from(from: Channels12) -> Self { + match from { + Channels12::Channel1 => Self::Channel1, + Channels12::Channel2 => Self::Channel2, + } + } +} diff --git a/src/lib.rs b/src/lib.rs index f52e7fe34..acab9b2ce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -157,7 +157,7 @@ pub use lpc845_pac as pac; pub use self::adc::ADC; #[cfg(feature = "845")] -pub use self::ctimer::CTimer; +pub use self::ctimer::CTIMER; pub use self::dma::DMA; pub use self::gpio::GPIO; pub use self::i2c::I2C; @@ -173,6 +173,9 @@ pub use self::wkt::WKT; pub use pac::CorePeripherals; +#[cfg(feature = "845")] +use ctimer::channel::state::Detached; + /// Provides access to all peripherals /// /// This is the entry point to the HAL API. Before you can do anything else, you @@ -216,7 +219,7 @@ pub struct Peripherals { /// Standard counter/timer (CTIMER) #[cfg(feature = "845")] - pub CTIMER0: CTimer, + pub CTIMER0: CTIMER, /// DMA controller pub DMA: DMA, @@ -505,7 +508,7 @@ impl Peripherals { // HAL peripherals ADC: ADC::new(p.ADC0), #[cfg(feature = "845")] - CTIMER0: CTimer::new(p.CTIMER0), + CTIMER0: CTIMER::new(p.CTIMER0), DMA: DMA::new(p.DMA0), GPIO: GPIO::new(p.GPIO), I2C0: I2C::new(p.I2C0),