Merge pull request #2325 from embassy-rs/stm32-docs
stm32: finish docs.
This commit is contained in:
commit
e5912972ec
@ -16,6 +16,7 @@ use crate::interrupt::Priority;
|
|||||||
use crate::pac;
|
use crate::pac;
|
||||||
use crate::pac::gpdma::vals;
|
use crate::pac::gpdma::vals;
|
||||||
|
|
||||||
|
/// GPDMA transfer options.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
@ -113,10 +114,13 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::gpdma::Gpdma, channel_num: usize, in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// DMA request type alias. (also known as DMA channel number in some chips)
|
||||||
pub type Request = u8;
|
pub type Request = u8;
|
||||||
|
|
||||||
|
/// DMA channel.
|
||||||
#[cfg(dmamux)]
|
#[cfg(dmamux)]
|
||||||
pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {}
|
pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {}
|
||||||
|
/// DMA channel.
|
||||||
#[cfg(not(dmamux))]
|
#[cfg(not(dmamux))]
|
||||||
pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {}
|
pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {}
|
||||||
|
|
||||||
@ -131,12 +135,14 @@ pub(crate) mod sealed {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// DMA transfer.
|
||||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||||
pub struct Transfer<'a, C: Channel> {
|
pub struct Transfer<'a, C: Channel> {
|
||||||
channel: PeripheralRef<'a, C>,
|
channel: PeripheralRef<'a, C>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, C: Channel> Transfer<'a, C> {
|
impl<'a, C: Channel> Transfer<'a, C> {
|
||||||
|
/// Create a new read DMA transfer (peripheral to memory).
|
||||||
pub unsafe fn new_read<W: Word>(
|
pub unsafe fn new_read<W: Word>(
|
||||||
channel: impl Peripheral<P = C> + 'a,
|
channel: impl Peripheral<P = C> + 'a,
|
||||||
request: Request,
|
request: Request,
|
||||||
@ -147,6 +153,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
|
|||||||
Self::new_read_raw(channel, request, peri_addr, buf, options)
|
Self::new_read_raw(channel, request, peri_addr, buf, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new read DMA transfer (peripheral to memory), using raw pointers.
|
||||||
pub unsafe fn new_read_raw<W: Word>(
|
pub unsafe fn new_read_raw<W: Word>(
|
||||||
channel: impl Peripheral<P = C> + 'a,
|
channel: impl Peripheral<P = C> + 'a,
|
||||||
request: Request,
|
request: Request,
|
||||||
@ -172,6 +179,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new write DMA transfer (memory to peripheral).
|
||||||
pub unsafe fn new_write<W: Word>(
|
pub unsafe fn new_write<W: Word>(
|
||||||
channel: impl Peripheral<P = C> + 'a,
|
channel: impl Peripheral<P = C> + 'a,
|
||||||
request: Request,
|
request: Request,
|
||||||
@ -182,6 +190,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
|
|||||||
Self::new_write_raw(channel, request, buf, peri_addr, options)
|
Self::new_write_raw(channel, request, buf, peri_addr, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new write DMA transfer (memory to peripheral), using raw pointers.
|
||||||
pub unsafe fn new_write_raw<W: Word>(
|
pub unsafe fn new_write_raw<W: Word>(
|
||||||
channel: impl Peripheral<P = C> + 'a,
|
channel: impl Peripheral<P = C> + 'a,
|
||||||
request: Request,
|
request: Request,
|
||||||
@ -207,6 +216,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly.
|
||||||
pub unsafe fn new_write_repeated<W: Word>(
|
pub unsafe fn new_write_repeated<W: Word>(
|
||||||
channel: impl Peripheral<P = C> + 'a,
|
channel: impl Peripheral<P = C> + 'a,
|
||||||
request: Request,
|
request: Request,
|
||||||
@ -297,6 +307,9 @@ impl<'a, C: Channel> Transfer<'a, C> {
|
|||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request the transfer to stop.
|
||||||
|
///
|
||||||
|
/// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
|
||||||
pub fn request_stop(&mut self) {
|
pub fn request_stop(&mut self) {
|
||||||
let ch = self.channel.regs().ch(self.channel.num());
|
let ch = self.channel.regs().ch(self.channel.num());
|
||||||
ch.cr().modify(|w| {
|
ch.cr().modify(|w| {
|
||||||
@ -304,6 +317,10 @@ impl<'a, C: Channel> Transfer<'a, C> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return whether this transfer is still running.
|
||||||
|
///
|
||||||
|
/// If this returns `false`, it can be because either the transfer finished, or
|
||||||
|
/// it was requested to stop early with [`request_stop`](Self::request_stop).
|
||||||
pub fn is_running(&mut self) -> bool {
|
pub fn is_running(&mut self) -> bool {
|
||||||
let ch = self.channel.regs().ch(self.channel.num());
|
let ch = self.channel.regs().ch(self.channel.num());
|
||||||
let sr = ch.sr().read();
|
let sr = ch.sr().read();
|
||||||
@ -317,6 +334,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
|
|||||||
ch.br1().read().bndt()
|
ch.br1().read().bndt()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Blocking wait until the transfer finishes.
|
||||||
pub fn blocking_wait(mut self) {
|
pub fn blocking_wait(mut self) {
|
||||||
while self.is_running() {}
|
while self.is_running() {}
|
||||||
|
|
||||||
|
@ -68,22 +68,22 @@ mod sealed {
|
|||||||
pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {}
|
pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {}
|
||||||
|
|
||||||
/// HRTIM PWM pin.
|
/// HRTIM PWM pin.
|
||||||
pub struct PwmPin<'d, Perip, Channel> {
|
pub struct PwmPin<'d, T, C> {
|
||||||
_pin: PeripheralRef<'d, AnyPin>,
|
_pin: PeripheralRef<'d, AnyPin>,
|
||||||
phantom: PhantomData<(Perip, Channel)>,
|
phantom: PhantomData<(T, C)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// HRTIM complementary PWM pin.
|
/// HRTIM complementary PWM pin.
|
||||||
pub struct ComplementaryPwmPin<'d, Perip, Channel> {
|
pub struct ComplementaryPwmPin<'d, T, C> {
|
||||||
_pin: PeripheralRef<'d, AnyPin>,
|
_pin: PeripheralRef<'d, AnyPin>,
|
||||||
phantom: PhantomData<(Perip, Channel)>,
|
phantom: PhantomData<(T, C)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! advanced_channel_impl {
|
macro_rules! advanced_channel_impl {
|
||||||
($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => {
|
($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => {
|
||||||
impl<'d, Perip: Instance> PwmPin<'d, Perip, $channel<Perip>> {
|
impl<'d, T: Instance> PwmPin<'d, T, $channel<T>> {
|
||||||
#[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
|
#[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
|
||||||
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self {
|
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self {
|
||||||
into_ref!(pin);
|
into_ref!(pin);
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
pin.set_low();
|
pin.set_low();
|
||||||
@ -98,9 +98,9 @@ macro_rules! advanced_channel_impl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, Perip: Instance> ComplementaryPwmPin<'d, Perip, $channel<Perip>> {
|
impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel<T>> {
|
||||||
#[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")]
|
#[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")]
|
||||||
pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self {
|
pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<T>> + 'd) -> Self {
|
||||||
into_ref!(pin);
|
into_ref!(pin);
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
pin.set_low();
|
pin.set_low();
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! Inter-Process Communication Controller (IPCC)
|
||||||
|
|
||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
@ -41,6 +43,7 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_RX> for Receive
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TX interrupt handler.
|
||||||
pub struct TransmitInterruptHandler {}
|
pub struct TransmitInterruptHandler {}
|
||||||
|
|
||||||
impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for TransmitInterruptHandler {
|
impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for TransmitInterruptHandler {
|
||||||
@ -72,6 +75,7 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for Transmi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// IPCC config.
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
#[derive(Clone, Copy, Default)]
|
#[derive(Clone, Copy, Default)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
@ -79,6 +83,8 @@ pub struct Config {
|
|||||||
// reserved for future use
|
// reserved for future use
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Channel.
|
||||||
|
#[allow(missing_docs)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub enum IpccChannel {
|
pub enum IpccChannel {
|
||||||
@ -90,9 +96,11 @@ pub enum IpccChannel {
|
|||||||
Channel6 = 5,
|
Channel6 = 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// IPCC driver.
|
||||||
pub struct Ipcc;
|
pub struct Ipcc;
|
||||||
|
|
||||||
impl Ipcc {
|
impl Ipcc {
|
||||||
|
/// Enable IPCC.
|
||||||
pub fn enable(_config: Config) {
|
pub fn enable(_config: Config) {
|
||||||
IPCC::enable_and_reset();
|
IPCC::enable_and_reset();
|
||||||
IPCC::set_cpu2(true);
|
IPCC::set_cpu2(true);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#![cfg_attr(not(test), no_std)]
|
#![cfg_attr(not(test), no_std)]
|
||||||
#![allow(async_fn_in_trait)]
|
#![allow(async_fn_in_trait)]
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
//! ## Feature flags
|
//! ## Feature flags
|
||||||
#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
|
#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
|
||||||
@ -79,6 +80,7 @@ pub(crate) mod _generated {
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
#![allow(unused_imports)]
|
#![allow(unused_imports)]
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
#![allow(missing_docs)]
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
|
include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
|
||||||
}
|
}
|
||||||
@ -149,15 +151,33 @@ use crate::interrupt::Priority;
|
|||||||
pub use crate::pac::NVIC_PRIO_BITS;
|
pub use crate::pac::NVIC_PRIO_BITS;
|
||||||
use crate::rcc::sealed::RccPeripheral;
|
use crate::rcc::sealed::RccPeripheral;
|
||||||
|
|
||||||
|
/// `embassy-stm32` global configuration.
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
|
/// RCC config.
|
||||||
pub rcc: rcc::Config,
|
pub rcc: rcc::Config,
|
||||||
|
|
||||||
|
/// Enable debug during sleep.
|
||||||
|
///
|
||||||
|
/// May incrase power consumption. Defaults to true.
|
||||||
#[cfg(dbgmcu)]
|
#[cfg(dbgmcu)]
|
||||||
pub enable_debug_during_sleep: bool,
|
pub enable_debug_during_sleep: bool,
|
||||||
|
|
||||||
|
/// BDMA interrupt priority.
|
||||||
|
///
|
||||||
|
/// Defaults to P0 (highest).
|
||||||
#[cfg(bdma)]
|
#[cfg(bdma)]
|
||||||
pub bdma_interrupt_priority: Priority,
|
pub bdma_interrupt_priority: Priority,
|
||||||
|
|
||||||
|
/// DMA interrupt priority.
|
||||||
|
///
|
||||||
|
/// Defaults to P0 (highest).
|
||||||
#[cfg(dma)]
|
#[cfg(dma)]
|
||||||
pub dma_interrupt_priority: Priority,
|
pub dma_interrupt_priority: Priority,
|
||||||
|
|
||||||
|
/// GPDMA interrupt priority.
|
||||||
|
///
|
||||||
|
/// Defaults to P0 (highest).
|
||||||
#[cfg(gpdma)]
|
#[cfg(gpdma)]
|
||||||
pub gpdma_interrupt_priority: Priority,
|
pub gpdma_interrupt_priority: Priority,
|
||||||
}
|
}
|
||||||
@ -178,7 +198,11 @@ impl Default for Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize embassy.
|
/// Initialize the `embassy-stm32` HAL with the provided configuration.
|
||||||
|
///
|
||||||
|
/// This returns the peripheral singletons that can be used for creating drivers.
|
||||||
|
///
|
||||||
|
/// This should only be called once at startup, otherwise it panics.
|
||||||
pub fn init(config: Config) -> Peripherals {
|
pub fn init(config: Config) -> Peripherals {
|
||||||
critical_section::with(|cs| {
|
critical_section::with(|cs| {
|
||||||
let p = Peripherals::take_with_cs(cs);
|
let p = Peripherals::take_with_cs(cs);
|
||||||
|
@ -1,50 +1,53 @@
|
|||||||
/// The STM32 line of microcontrollers support various deep-sleep modes which exploit clock-gating
|
//! Low-power support.
|
||||||
/// to reduce power consumption. `embassy-stm32` provides a low-power executor, [`Executor`] which
|
//!
|
||||||
/// can use knowledge of which peripherals are currently blocked upon to transparently and safely
|
//! The STM32 line of microcontrollers support various deep-sleep modes which exploit clock-gating
|
||||||
/// enter such low-power modes (currently, only `STOP2`) when idle.
|
//! to reduce power consumption. `embassy-stm32` provides a low-power executor, [`Executor`] which
|
||||||
///
|
//! can use knowledge of which peripherals are currently blocked upon to transparently and safely
|
||||||
/// The executor determines which peripherals are active by their RCC state; consequently,
|
//! enter such low-power modes (currently, only `STOP2`) when idle.
|
||||||
/// low-power states can only be entered if all peripherals have been `drop`'d. There are a few
|
//!
|
||||||
/// exceptions to this rule:
|
//! The executor determines which peripherals are active by their RCC state; consequently,
|
||||||
///
|
//! low-power states can only be entered if all peripherals have been `drop`'d. There are a few
|
||||||
/// * `GPIO`
|
//! exceptions to this rule:
|
||||||
/// * `RCC`
|
//!
|
||||||
///
|
//! * `GPIO`
|
||||||
/// Since entering and leaving low-power modes typically incurs a significant latency, the
|
//! * `RCC`
|
||||||
/// low-power executor will only attempt to enter when the next timer event is at least
|
//!
|
||||||
/// [`time_driver::MIN_STOP_PAUSE`] in the future.
|
//! Since entering and leaving low-power modes typically incurs a significant latency, the
|
||||||
///
|
//! low-power executor will only attempt to enter when the next timer event is at least
|
||||||
/// Currently there is no macro analogous to `embassy_executor::main` for this executor;
|
//! [`time_driver::MIN_STOP_PAUSE`] in the future.
|
||||||
/// consequently one must define their entrypoint manually. Moveover, you must relinquish control
|
//!
|
||||||
/// of the `RTC` peripheral to the executor. This will typically look like
|
//! Currently there is no macro analogous to `embassy_executor::main` for this executor;
|
||||||
///
|
//! consequently one must define their entrypoint manually. Moveover, you must relinquish control
|
||||||
/// ```rust,no_run
|
//! of the `RTC` peripheral to the executor. This will typically look like
|
||||||
/// use embassy_executor::Spawner;
|
//!
|
||||||
/// use embassy_stm32::low_power::Executor;
|
//! ```rust,no_run
|
||||||
/// use embassy_stm32::rtc::{Rtc, RtcConfig};
|
//! use embassy_executor::Spawner;
|
||||||
/// use static_cell::make_static;
|
//! use embassy_stm32::low_power::Executor;
|
||||||
///
|
//! use embassy_stm32::rtc::{Rtc, RtcConfig};
|
||||||
/// #[cortex_m_rt::entry]
|
//! use static_cell::make_static;
|
||||||
/// fn main() -> ! {
|
//!
|
||||||
/// Executor::take().run(|spawner| {
|
//! #[cortex_m_rt::entry]
|
||||||
/// unwrap!(spawner.spawn(async_main(spawner)));
|
//! fn main() -> ! {
|
||||||
/// });
|
//! Executor::take().run(|spawner| {
|
||||||
/// }
|
//! unwrap!(spawner.spawn(async_main(spawner)));
|
||||||
///
|
//! });
|
||||||
/// #[embassy_executor::task]
|
//! }
|
||||||
/// async fn async_main(spawner: Spawner) {
|
//!
|
||||||
/// // initialize the platform...
|
//! #[embassy_executor::task]
|
||||||
/// let mut config = embassy_stm32::Config::default();
|
//! async fn async_main(spawner: Spawner) {
|
||||||
/// let p = embassy_stm32::init(config);
|
//! // initialize the platform...
|
||||||
///
|
//! let mut config = embassy_stm32::Config::default();
|
||||||
/// // give the RTC to the executor...
|
//! let p = embassy_stm32::init(config);
|
||||||
/// let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
|
//!
|
||||||
/// let rtc = make_static!(rtc);
|
//! // give the RTC to the executor...
|
||||||
/// embassy_stm32::low_power::stop_with_rtc(rtc);
|
//! let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
|
||||||
///
|
//! let rtc = make_static!(rtc);
|
||||||
/// // your application here...
|
//! embassy_stm32::low_power::stop_with_rtc(rtc);
|
||||||
/// }
|
//!
|
||||||
/// ```
|
//! // your application here...
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
|
||||||
use core::arch::asm;
|
use core::arch::asm;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
@ -64,6 +67,7 @@ static mut EXECUTOR: Option<Executor> = None;
|
|||||||
foreach_interrupt! {
|
foreach_interrupt! {
|
||||||
(RTC, rtc, $block:ident, WKUP, $irq:ident) => {
|
(RTC, rtc, $block:ident, WKUP, $irq:ident) => {
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
unsafe fn $irq() {
|
unsafe fn $irq() {
|
||||||
EXECUTOR.as_mut().unwrap().on_wakeup_irq();
|
EXECUTOR.as_mut().unwrap().on_wakeup_irq();
|
||||||
}
|
}
|
||||||
@ -75,10 +79,15 @@ pub(crate) unsafe fn on_wakeup_irq() {
|
|||||||
EXECUTOR.as_mut().unwrap().on_wakeup_irq();
|
EXECUTOR.as_mut().unwrap().on_wakeup_irq();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configure STOP mode with RTC.
|
||||||
pub fn stop_with_rtc(rtc: &'static Rtc) {
|
pub fn stop_with_rtc(rtc: &'static Rtc) {
|
||||||
unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc)
|
unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get whether the core is ready to enter the given stop mode.
|
||||||
|
///
|
||||||
|
/// This will return false if some peripheral driver is in use that
|
||||||
|
/// prevents entering the given stop mode.
|
||||||
pub fn stop_ready(stop_mode: StopMode) -> bool {
|
pub fn stop_ready(stop_mode: StopMode) -> bool {
|
||||||
match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() {
|
match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() {
|
||||||
Some(StopMode::Stop2) => true,
|
Some(StopMode::Stop2) => true,
|
||||||
@ -87,10 +96,13 @@ pub fn stop_ready(stop_mode: StopMode) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Available stop modes.
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
pub enum StopMode {
|
pub enum StopMode {
|
||||||
|
/// STOP 1
|
||||||
Stop1,
|
Stop1,
|
||||||
|
/// STOP 2
|
||||||
Stop2,
|
Stop2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
|
//! Operational Amplifier (OPAMP)
|
||||||
#![macro_use]
|
#![macro_use]
|
||||||
|
|
||||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||||
|
|
||||||
use crate::Peripheral;
|
use crate::Peripheral;
|
||||||
|
|
||||||
|
/// Gain
|
||||||
|
#[allow(missing_docs)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum OpAmpGain {
|
pub enum OpAmpGain {
|
||||||
Mul1,
|
Mul1,
|
||||||
@ -13,6 +16,8 @@ pub enum OpAmpGain {
|
|||||||
Mul16,
|
Mul16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Speed
|
||||||
|
#[allow(missing_docs)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum OpAmpSpeed {
|
pub enum OpAmpSpeed {
|
||||||
Normal,
|
Normal,
|
||||||
@ -180,6 +185,7 @@ impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Opamp instance trait.
|
||||||
pub trait Instance: sealed::Instance + 'static {}
|
pub trait Instance: sealed::Instance + 'static {}
|
||||||
|
|
||||||
pub(crate) mod sealed {
|
pub(crate) mod sealed {
|
||||||
@ -198,8 +204,11 @@ pub(crate) mod sealed {
|
|||||||
pub trait OutputPin<T: Instance> {}
|
pub trait OutputPin<T: Instance> {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Non-inverting pin trait.
|
||||||
pub trait NonInvertingPin<T: Instance>: sealed::NonInvertingPin<T> {}
|
pub trait NonInvertingPin<T: Instance>: sealed::NonInvertingPin<T> {}
|
||||||
|
/// Inverting pin trait.
|
||||||
pub trait InvertingPin<T: Instance>: sealed::InvertingPin<T> {}
|
pub trait InvertingPin<T: Instance>: sealed::InvertingPin<T> {}
|
||||||
|
/// Output pin trait.
|
||||||
pub trait OutputPin<T: Instance>: sealed::OutputPin<T> {}
|
pub trait OutputPin<T: Instance>: sealed::OutputPin<T> {}
|
||||||
|
|
||||||
macro_rules! impl_opamp_external_output {
|
macro_rules! impl_opamp_external_output {
|
||||||
|
@ -80,6 +80,7 @@ impl<'d, T: Instance> Rng<'d, T> {
|
|||||||
let _ = self.next_u32();
|
let _ = self.next_u32();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reset the RNG.
|
||||||
#[cfg(not(rng_v1))]
|
#[cfg(not(rng_v1))]
|
||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) {
|
||||||
T::regs().cr().write(|reg| {
|
T::regs().cr().write(|reg| {
|
||||||
|
@ -293,6 +293,7 @@ pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma<T> = NoDma> {
|
|||||||
|
|
||||||
#[cfg(sdmmc_v1)]
|
#[cfg(sdmmc_v1)]
|
||||||
impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
|
impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
|
||||||
|
/// Create a new SDMMC driver, with 1 data lane.
|
||||||
pub fn new_1bit(
|
pub fn new_1bit(
|
||||||
sdmmc: impl Peripheral<P = T> + 'd,
|
sdmmc: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
@ -327,6 +328,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new SDMMC driver, with 4 data lanes.
|
||||||
pub fn new_4bit(
|
pub fn new_4bit(
|
||||||
sdmmc: impl Peripheral<P = T> + 'd,
|
sdmmc: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
|
@ -13,15 +13,19 @@ use crate::gpio::{AnyPin, OutputType};
|
|||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
use crate::Peripheral;
|
use crate::Peripheral;
|
||||||
|
|
||||||
pub struct ComplementaryPwmPin<'d, Perip, Channel> {
|
/// Complementary PWM pin wrapper.
|
||||||
|
///
|
||||||
|
/// This wraps a pin to make it usable with PWM.
|
||||||
|
pub struct ComplementaryPwmPin<'d, T, C> {
|
||||||
_pin: PeripheralRef<'d, AnyPin>,
|
_pin: PeripheralRef<'d, AnyPin>,
|
||||||
phantom: PhantomData<(Perip, Channel)>,
|
phantom: PhantomData<(T, C)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! complementary_channel_impl {
|
macro_rules! complementary_channel_impl {
|
||||||
($new_chx:ident, $channel:ident, $pin_trait:ident) => {
|
($new_chx:ident, $channel:ident, $pin_trait:ident) => {
|
||||||
impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> {
|
impl<'d, T: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> {
|
||||||
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd, output_type: OutputType) -> Self {
|
#[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")]
|
||||||
|
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self {
|
||||||
into_ref!(pin);
|
into_ref!(pin);
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
pin.set_low();
|
pin.set_low();
|
||||||
@ -43,11 +47,13 @@ complementary_channel_impl!(new_ch2, Ch2, Channel2ComplementaryPin);
|
|||||||
complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin);
|
complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin);
|
||||||
complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin);
|
complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin);
|
||||||
|
|
||||||
|
/// PWM driver with support for standard and complementary outputs.
|
||||||
pub struct ComplementaryPwm<'d, T> {
|
pub struct ComplementaryPwm<'d, T> {
|
||||||
inner: PeripheralRef<'d, T>,
|
inner: PeripheralRef<'d, T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
|
impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
|
||||||
|
/// Create a new complementary PWM driver.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
tim: impl Peripheral<P = T> + 'd,
|
tim: impl Peripheral<P = T> + 'd,
|
||||||
_ch1: Option<PwmPin<'d, T, Ch1>>,
|
_ch1: Option<PwmPin<'d, T, Ch1>>,
|
||||||
@ -72,7 +78,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
|
|||||||
let mut this = Self { inner: tim };
|
let mut this = Self { inner: tim };
|
||||||
|
|
||||||
this.inner.set_counting_mode(counting_mode);
|
this.inner.set_counting_mode(counting_mode);
|
||||||
this.set_freq(freq);
|
this.set_frequency(freq);
|
||||||
this.inner.start();
|
this.inner.start();
|
||||||
|
|
||||||
this.inner.enable_outputs();
|
this.inner.enable_outputs();
|
||||||
@ -88,17 +94,23 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
|
|||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enable the given channel.
|
||||||
pub fn enable(&mut self, channel: Channel) {
|
pub fn enable(&mut self, channel: Channel) {
|
||||||
self.inner.enable_channel(channel, true);
|
self.inner.enable_channel(channel, true);
|
||||||
self.inner.enable_complementary_channel(channel, true);
|
self.inner.enable_complementary_channel(channel, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Disable the given channel.
|
||||||
pub fn disable(&mut self, channel: Channel) {
|
pub fn disable(&mut self, channel: Channel) {
|
||||||
self.inner.enable_complementary_channel(channel, false);
|
self.inner.enable_complementary_channel(channel, false);
|
||||||
self.inner.enable_channel(channel, false);
|
self.inner.enable_channel(channel, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_freq(&mut self, freq: Hertz) {
|
/// Set PWM frequency.
|
||||||
|
///
|
||||||
|
/// Note: when you call this, the max duty value changes, so you will have to
|
||||||
|
/// call `set_duty` on all channels with the duty calculated based on the new max duty.
|
||||||
|
pub fn set_frequency(&mut self, freq: Hertz) {
|
||||||
let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
|
let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
|
||||||
2u8
|
2u8
|
||||||
} else {
|
} else {
|
||||||
@ -107,15 +119,22 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
|
|||||||
self.inner.set_frequency(freq * multiplier);
|
self.inner.set_frequency(freq * multiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get max duty value.
|
||||||
|
///
|
||||||
|
/// This value depends on the configured frequency and the timer's clock rate from RCC.
|
||||||
pub fn get_max_duty(&self) -> u16 {
|
pub fn get_max_duty(&self) -> u16 {
|
||||||
self.inner.get_max_compare_value() + 1
|
self.inner.get_max_compare_value() + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the duty for a given channel.
|
||||||
|
///
|
||||||
|
/// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
|
||||||
pub fn set_duty(&mut self, channel: Channel, duty: u16) {
|
pub fn set_duty(&mut self, channel: Channel, duty: u16) {
|
||||||
assert!(duty <= self.get_max_duty());
|
assert!(duty <= self.get_max_duty());
|
||||||
self.inner.set_compare_value(channel, duty)
|
self.inner.set_compare_value(channel, duty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the output polarity for a given channel.
|
||||||
pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
|
pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
|
||||||
self.inner.set_output_polarity(channel, polarity);
|
self.inner.set_output_polarity(channel, polarity);
|
||||||
self.inner.set_complementary_output_polarity(channel, polarity);
|
self.inner.set_complementary_output_polarity(channel, polarity);
|
||||||
|
@ -17,17 +17,27 @@ pub mod low_level {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) mod sealed {
|
pub(crate) mod sealed {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
/// Basic 16-bit timer instance.
|
||||||
pub trait Basic16bitInstance: RccPeripheral {
|
pub trait Basic16bitInstance: RccPeripheral {
|
||||||
|
/// Interrupt for this timer.
|
||||||
type Interrupt: interrupt::typelevel::Interrupt;
|
type Interrupt: interrupt::typelevel::Interrupt;
|
||||||
|
|
||||||
|
/// Get access to the basic 16bit timer registers.
|
||||||
|
///
|
||||||
|
/// Note: This works even if the timer is more capable, because registers
|
||||||
|
/// for the less capable timers are a subset. This allows writing a driver
|
||||||
|
/// for a given set of capabilities, and having it transparently work with
|
||||||
|
/// more capable timers.
|
||||||
fn regs() -> crate::pac::timer::TimBasic;
|
fn regs() -> crate::pac::timer::TimBasic;
|
||||||
|
|
||||||
|
/// Start the timer.
|
||||||
fn start(&mut self) {
|
fn start(&mut self) {
|
||||||
Self::regs().cr1().modify(|r| r.set_cen(true));
|
Self::regs().cr1().modify(|r| r.set_cen(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Stop the timer.
|
||||||
fn stop(&mut self) {
|
fn stop(&mut self) {
|
||||||
Self::regs().cr1().modify(|r| r.set_cen(false));
|
Self::regs().cr1().modify(|r| r.set_cen(false));
|
||||||
}
|
}
|
||||||
@ -63,6 +73,9 @@ pub(crate) mod sealed {
|
|||||||
regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
|
regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clear update interrupt.
|
||||||
|
///
|
||||||
|
/// Returns whether the update interrupt flag was set.
|
||||||
fn clear_update_interrupt(&mut self) -> bool {
|
fn clear_update_interrupt(&mut self) -> bool {
|
||||||
let regs = Self::regs();
|
let regs = Self::regs();
|
||||||
let sr = regs.sr().read();
|
let sr = regs.sr().read();
|
||||||
@ -76,14 +89,17 @@ pub(crate) mod sealed {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enable/disable the update interrupt.
|
||||||
fn enable_update_interrupt(&mut self, enable: bool) {
|
fn enable_update_interrupt(&mut self, enable: bool) {
|
||||||
Self::regs().dier().write(|r| r.set_uie(enable));
|
Self::regs().dier().write(|r| r.set_uie(enable));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enable/disable autoreload preload.
|
||||||
fn set_autoreload_preload(&mut self, enable: bool) {
|
fn set_autoreload_preload(&mut self, enable: bool) {
|
||||||
Self::regs().cr1().modify(|r| r.set_arpe(enable));
|
Self::regs().cr1().modify(|r| r.set_arpe(enable));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the timer frequency.
|
||||||
fn get_frequency(&self) -> Hertz {
|
fn get_frequency(&self) -> Hertz {
|
||||||
let timer_f = Self::frequency();
|
let timer_f = Self::frequency();
|
||||||
|
|
||||||
@ -95,9 +111,17 @@ pub(crate) mod sealed {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gneral-purpose 16-bit timer instance.
|
||||||
pub trait GeneralPurpose16bitInstance: Basic16bitInstance {
|
pub trait GeneralPurpose16bitInstance: Basic16bitInstance {
|
||||||
|
/// Get access to the general purpose 16bit timer registers.
|
||||||
|
///
|
||||||
|
/// Note: This works even if the timer is more capable, because registers
|
||||||
|
/// for the less capable timers are a subset. This allows writing a driver
|
||||||
|
/// for a given set of capabilities, and having it transparently work with
|
||||||
|
/// more capable timers.
|
||||||
fn regs_gp16() -> crate::pac::timer::TimGp16;
|
fn regs_gp16() -> crate::pac::timer::TimGp16;
|
||||||
|
|
||||||
|
/// Set counting mode.
|
||||||
fn set_counting_mode(&mut self, mode: CountingMode) {
|
fn set_counting_mode(&mut self, mode: CountingMode) {
|
||||||
let (cms, dir) = mode.into();
|
let (cms, dir) = mode.into();
|
||||||
|
|
||||||
@ -110,19 +134,29 @@ pub(crate) mod sealed {
|
|||||||
Self::regs_gp16().cr1().modify(|r| r.set_cms(cms))
|
Self::regs_gp16().cr1().modify(|r| r.set_cms(cms))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get counting mode.
|
||||||
fn get_counting_mode(&self) -> CountingMode {
|
fn get_counting_mode(&self) -> CountingMode {
|
||||||
let cr1 = Self::regs_gp16().cr1().read();
|
let cr1 = Self::regs_gp16().cr1().read();
|
||||||
(cr1.cms(), cr1.dir()).into()
|
(cr1.cms(), cr1.dir()).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set clock divider.
|
||||||
fn set_clock_division(&mut self, ckd: vals::Ckd) {
|
fn set_clock_division(&mut self, ckd: vals::Ckd) {
|
||||||
Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd));
|
Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gneral-purpose 32-bit timer instance.
|
||||||
pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance {
|
pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance {
|
||||||
|
/// Get access to the general purpose 32bit timer registers.
|
||||||
|
///
|
||||||
|
/// Note: This works even if the timer is more capable, because registers
|
||||||
|
/// for the less capable timers are a subset. This allows writing a driver
|
||||||
|
/// for a given set of capabilities, and having it transparently work with
|
||||||
|
/// more capable timers.
|
||||||
fn regs_gp32() -> crate::pac::timer::TimGp32;
|
fn regs_gp32() -> crate::pac::timer::TimGp32;
|
||||||
|
|
||||||
|
/// Set timer frequency.
|
||||||
fn set_frequency(&mut self, frequency: Hertz) {
|
fn set_frequency(&mut self, frequency: Hertz) {
|
||||||
let f = frequency.0;
|
let f = frequency.0;
|
||||||
assert!(f > 0);
|
assert!(f > 0);
|
||||||
@ -140,6 +174,7 @@ pub(crate) mod sealed {
|
|||||||
regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
|
regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get timer frequency.
|
||||||
fn get_frequency(&self) -> Hertz {
|
fn get_frequency(&self) -> Hertz {
|
||||||
let timer_f = Self::frequency();
|
let timer_f = Self::frequency();
|
||||||
|
|
||||||
@ -151,141 +186,177 @@ pub(crate) mod sealed {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Advanced control timer instance.
|
||||||
pub trait AdvancedControlInstance: GeneralPurpose16bitInstance {
|
pub trait AdvancedControlInstance: GeneralPurpose16bitInstance {
|
||||||
|
/// Get access to the advanced timer registers.
|
||||||
fn regs_advanced() -> crate::pac::timer::TimAdv;
|
fn regs_advanced() -> crate::pac::timer::TimAdv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Capture/Compare 16-bit timer instance.
|
||||||
pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance {
|
pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance {
|
||||||
|
/// Set input capture filter.
|
||||||
fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) {
|
fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) {
|
||||||
let raw_channel = channel.raw();
|
let raw_channel = channel.index();
|
||||||
Self::regs_gp16()
|
Self::regs_gp16()
|
||||||
.ccmr_input(raw_channel / 2)
|
.ccmr_input(raw_channel / 2)
|
||||||
.modify(|r| r.set_icf(raw_channel % 2, icf));
|
.modify(|r| r.set_icf(raw_channel % 2, icf));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clear input interrupt.
|
||||||
fn clear_input_interrupt(&mut self, channel: Channel) {
|
fn clear_input_interrupt(&mut self, channel: Channel) {
|
||||||
Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.raw(), false));
|
Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enable input interrupt.
|
||||||
fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) {
|
fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) {
|
||||||
Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.raw(), enable));
|
Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set input capture prescaler.
|
||||||
fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) {
|
fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) {
|
||||||
let raw_channel = channel.raw();
|
let raw_channel = channel.index();
|
||||||
Self::regs_gp16()
|
Self::regs_gp16()
|
||||||
.ccmr_input(raw_channel / 2)
|
.ccmr_input(raw_channel / 2)
|
||||||
.modify(|r| r.set_icpsc(raw_channel % 2, factor));
|
.modify(|r| r.set_icpsc(raw_channel % 2, factor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set input TI selection.
|
||||||
fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) {
|
fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) {
|
||||||
let raw_channel = channel.raw();
|
let raw_channel = channel.index();
|
||||||
Self::regs_gp16()
|
Self::regs_gp16()
|
||||||
.ccmr_input(raw_channel / 2)
|
.ccmr_input(raw_channel / 2)
|
||||||
.modify(|r| r.set_ccs(raw_channel % 2, tisel.into()));
|
.modify(|r| r.set_ccs(raw_channel % 2, tisel.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set input capture mode.
|
||||||
fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
|
fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
|
||||||
Self::regs_gp16().ccer().modify(|r| match mode {
|
Self::regs_gp16().ccer().modify(|r| match mode {
|
||||||
InputCaptureMode::Rising => {
|
InputCaptureMode::Rising => {
|
||||||
r.set_ccnp(channel.raw(), false);
|
r.set_ccnp(channel.index(), false);
|
||||||
r.set_ccp(channel.raw(), false);
|
r.set_ccp(channel.index(), false);
|
||||||
}
|
}
|
||||||
InputCaptureMode::Falling => {
|
InputCaptureMode::Falling => {
|
||||||
r.set_ccnp(channel.raw(), false);
|
r.set_ccnp(channel.index(), false);
|
||||||
r.set_ccp(channel.raw(), true);
|
r.set_ccp(channel.index(), true);
|
||||||
}
|
}
|
||||||
InputCaptureMode::BothEdges => {
|
InputCaptureMode::BothEdges => {
|
||||||
r.set_ccnp(channel.raw(), true);
|
r.set_ccnp(channel.index(), true);
|
||||||
r.set_ccp(channel.raw(), true);
|
r.set_ccp(channel.index(), true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enable timer outputs.
|
||||||
fn enable_outputs(&mut self);
|
fn enable_outputs(&mut self);
|
||||||
|
|
||||||
|
/// Set output compare mode.
|
||||||
fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) {
|
fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) {
|
||||||
let r = Self::regs_gp16();
|
let r = Self::regs_gp16();
|
||||||
let raw_channel: usize = channel.raw();
|
let raw_channel: usize = channel.index();
|
||||||
r.ccmr_output(raw_channel / 2)
|
r.ccmr_output(raw_channel / 2)
|
||||||
.modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
|
.modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set output polarity.
|
||||||
fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
|
fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
|
||||||
Self::regs_gp16()
|
Self::regs_gp16()
|
||||||
.ccer()
|
.ccer()
|
||||||
.modify(|w| w.set_ccp(channel.raw(), polarity.into()));
|
.modify(|w| w.set_ccp(channel.index(), polarity.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enable/disable a channel.
|
||||||
fn enable_channel(&mut self, channel: Channel, enable: bool) {
|
fn enable_channel(&mut self, channel: Channel, enable: bool) {
|
||||||
Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.raw(), enable));
|
Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set compare value for a channel.
|
||||||
fn set_compare_value(&mut self, channel: Channel, value: u16) {
|
fn set_compare_value(&mut self, channel: Channel, value: u16) {
|
||||||
Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value));
|
Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get capture value for a channel.
|
||||||
fn get_capture_value(&mut self, channel: Channel) -> u16 {
|
fn get_capture_value(&mut self, channel: Channel) -> u16 {
|
||||||
Self::regs_gp16().ccr(channel.raw()).read().ccr()
|
Self::regs_gp16().ccr(channel.index()).read().ccr()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
|
||||||
fn get_max_compare_value(&self) -> u16 {
|
fn get_max_compare_value(&self) -> u16 {
|
||||||
Self::regs_gp16().arr().read().arr()
|
Self::regs_gp16().arr().read().arr()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get compare value for a channel.
|
||||||
fn get_compare_value(&self, channel: Channel) -> u16 {
|
fn get_compare_value(&self, channel: Channel) -> u16 {
|
||||||
Self::regs_gp16().ccr(channel.raw()).read().ccr()
|
Self::regs_gp16().ccr(channel.index()).read().ccr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Capture/Compare 16-bit timer instance with complementary pin support.
|
||||||
pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance {
|
pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance {
|
||||||
|
/// Set complementary output polarity.
|
||||||
fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
|
fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
|
||||||
Self::regs_advanced()
|
Self::regs_advanced()
|
||||||
.ccer()
|
.ccer()
|
||||||
.modify(|w| w.set_ccnp(channel.raw(), polarity.into()));
|
.modify(|w| w.set_ccnp(channel.index(), polarity.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set clock divider for the dead time.
|
||||||
fn set_dead_time_clock_division(&mut self, value: vals::Ckd) {
|
fn set_dead_time_clock_division(&mut self, value: vals::Ckd) {
|
||||||
Self::regs_advanced().cr1().modify(|w| w.set_ckd(value));
|
Self::regs_advanced().cr1().modify(|w| w.set_ckd(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set dead time, as a fraction of the max duty value.
|
||||||
fn set_dead_time_value(&mut self, value: u8) {
|
fn set_dead_time_value(&mut self, value: u8) {
|
||||||
Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value));
|
Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enable/disable a complementary channel.
|
||||||
fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) {
|
fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) {
|
||||||
Self::regs_advanced()
|
Self::regs_advanced()
|
||||||
.ccer()
|
.ccer()
|
||||||
.modify(|w| w.set_ccne(channel.raw(), enable));
|
.modify(|w| w.set_ccne(channel.index(), enable));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Capture/Compare 32-bit timer instance.
|
||||||
pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance {
|
pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance {
|
||||||
|
/// Set comapre value for a channel.
|
||||||
fn set_compare_value(&mut self, channel: Channel, value: u32) {
|
fn set_compare_value(&mut self, channel: Channel, value: u32) {
|
||||||
Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value));
|
Self::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get capture value for a channel.
|
||||||
fn get_capture_value(&mut self, channel: Channel) -> u32 {
|
fn get_capture_value(&mut self, channel: Channel) -> u32 {
|
||||||
Self::regs_gp32().ccr(channel.raw()).read().ccr()
|
Self::regs_gp32().ccr(channel.index()).read().ccr()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
|
||||||
fn get_max_compare_value(&self) -> u32 {
|
fn get_max_compare_value(&self) -> u32 {
|
||||||
Self::regs_gp32().arr().read().arr()
|
Self::regs_gp32().arr().read().arr()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get compare value for a channel.
|
||||||
fn get_compare_value(&self, channel: Channel) -> u32 {
|
fn get_compare_value(&self, channel: Channel) -> u32 {
|
||||||
Self::regs_gp32().ccr(channel.raw()).read().ccr()
|
Self::regs_gp32().ccr(channel.index()).read().ccr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Timer channel.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum Channel {
|
pub enum Channel {
|
||||||
|
/// Channel 1.
|
||||||
Ch1,
|
Ch1,
|
||||||
|
/// Channel 2.
|
||||||
Ch2,
|
Ch2,
|
||||||
|
/// Channel 3.
|
||||||
Ch3,
|
Ch3,
|
||||||
|
/// Channel 4.
|
||||||
Ch4,
|
Ch4,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Channel {
|
impl Channel {
|
||||||
pub fn raw(&self) -> usize {
|
/// Get the channel index (0..3)
|
||||||
|
pub fn index(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Channel::Ch1 => 0,
|
Channel::Ch1 => 0,
|
||||||
Channel::Ch2 => 1,
|
Channel::Ch2 => 1,
|
||||||
@ -295,17 +366,25 @@ impl Channel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Input capture mode.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum InputCaptureMode {
|
pub enum InputCaptureMode {
|
||||||
|
/// Rising edge only.
|
||||||
Rising,
|
Rising,
|
||||||
|
/// Falling edge only.
|
||||||
Falling,
|
Falling,
|
||||||
|
/// Both rising or falling edges.
|
||||||
BothEdges,
|
BothEdges,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Input TI selection.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum InputTISelection {
|
pub enum InputTISelection {
|
||||||
|
/// Normal
|
||||||
Normal,
|
Normal,
|
||||||
|
/// Alternate
|
||||||
Alternate,
|
Alternate,
|
||||||
|
/// TRC
|
||||||
TRC,
|
TRC,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,6 +398,7 @@ impl From<InputTISelection> for stm32_metapac::timer::vals::CcmrInputCcs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Timer counting mode.
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||||
pub enum CountingMode {
|
pub enum CountingMode {
|
||||||
@ -345,6 +425,7 @@ pub enum CountingMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CountingMode {
|
impl CountingMode {
|
||||||
|
/// Return whether this mode is edge-aligned (up or down).
|
||||||
pub fn is_edge_aligned(&self) -> bool {
|
pub fn is_edge_aligned(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true,
|
CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true,
|
||||||
@ -352,6 +433,7 @@ impl CountingMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return whether this mode is center-aligned.
|
||||||
pub fn is_center_aligned(&self) -> bool {
|
pub fn is_center_aligned(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
CountingMode::CenterAlignedDownInterrupts
|
CountingMode::CenterAlignedDownInterrupts
|
||||||
@ -386,16 +468,34 @@ impl From<(vals::Cms, vals::Dir)> for CountingMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Output compare mode.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum OutputCompareMode {
|
pub enum OutputCompareMode {
|
||||||
|
/// The comparison between the output compare register TIMx_CCRx and
|
||||||
|
/// the counter TIMx_CNT has no effect on the outputs.
|
||||||
|
/// (this mode is used to generate a timing base).
|
||||||
Frozen,
|
Frozen,
|
||||||
|
/// Set channel to active level on match. OCxREF signal is forced high when the
|
||||||
|
/// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx).
|
||||||
ActiveOnMatch,
|
ActiveOnMatch,
|
||||||
|
/// Set channel to inactive level on match. OCxREF signal is forced low when the
|
||||||
|
/// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx).
|
||||||
InactiveOnMatch,
|
InactiveOnMatch,
|
||||||
|
/// Toggle - OCxREF toggles when TIMx_CNT=TIMx_CCRx.
|
||||||
Toggle,
|
Toggle,
|
||||||
|
/// Force inactive level - OCxREF is forced low.
|
||||||
ForceInactive,
|
ForceInactive,
|
||||||
|
/// Force active level - OCxREF is forced high.
|
||||||
ForceActive,
|
ForceActive,
|
||||||
|
/// PWM mode 1 - In upcounting, channel is active as long as TIMx_CNT<TIMx_CCRx
|
||||||
|
/// else inactive. In downcounting, channel is inactive (OCxREF=0) as long as
|
||||||
|
/// TIMx_CNT>TIMx_CCRx else active (OCxREF=1).
|
||||||
PwmMode1,
|
PwmMode1,
|
||||||
|
/// PWM mode 2 - In upcounting, channel is inactive as long as
|
||||||
|
/// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as
|
||||||
|
/// TIMx_CNT>TIMx_CCRx else inactive.
|
||||||
PwmMode2,
|
PwmMode2,
|
||||||
|
// TODO: there's more modes here depending on the chip family.
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm {
|
impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm {
|
||||||
@ -413,9 +513,12 @@ impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Timer output pin polarity.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum OutputPolarity {
|
pub enum OutputPolarity {
|
||||||
|
/// Active high (higher duty value makes the pin spend more time high).
|
||||||
ActiveHigh,
|
ActiveHigh,
|
||||||
|
/// Active low (higher duty value makes the pin spend more time low).
|
||||||
ActiveLow,
|
ActiveLow,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,24 +531,31 @@ impl From<OutputPolarity> for bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Basic 16-bit timer instance.
|
||||||
pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {}
|
pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {}
|
||||||
|
|
||||||
|
/// Gneral-purpose 16-bit timer instance.
|
||||||
pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {}
|
pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {}
|
||||||
|
|
||||||
|
/// Gneral-purpose 32-bit timer instance.
|
||||||
pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {}
|
pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {}
|
||||||
|
|
||||||
|
/// Advanced control timer instance.
|
||||||
pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {}
|
pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {}
|
||||||
|
|
||||||
|
/// Capture/Compare 16-bit timer instance.
|
||||||
pub trait CaptureCompare16bitInstance:
|
pub trait CaptureCompare16bitInstance:
|
||||||
sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static
|
sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Capture/Compare 16-bit timer instance with complementary pin support.
|
||||||
pub trait ComplementaryCaptureCompare16bitInstance:
|
pub trait ComplementaryCaptureCompare16bitInstance:
|
||||||
sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static
|
sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Capture/Compare 32-bit timer instance.
|
||||||
pub trait CaptureCompare32bitInstance:
|
pub trait CaptureCompare32bitInstance:
|
||||||
sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static
|
sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static
|
||||||
{
|
{
|
||||||
|
@ -9,23 +9,30 @@ use crate::gpio::sealed::AFType;
|
|||||||
use crate::gpio::AnyPin;
|
use crate::gpio::AnyPin;
|
||||||
use crate::Peripheral;
|
use crate::Peripheral;
|
||||||
|
|
||||||
|
/// Counting direction
|
||||||
pub enum Direction {
|
pub enum Direction {
|
||||||
|
/// Counting up.
|
||||||
Upcounting,
|
Upcounting,
|
||||||
|
/// Counting down.
|
||||||
Downcounting,
|
Downcounting,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Ch1;
|
/// Channel 1 marker type.
|
||||||
pub struct Ch2;
|
pub enum Ch1 {}
|
||||||
|
/// Channel 2 marker type.
|
||||||
|
pub enum Ch2 {}
|
||||||
|
|
||||||
pub struct QeiPin<'d, Perip, Channel> {
|
/// Wrapper for using a pin with QEI.
|
||||||
|
pub struct QeiPin<'d, T, Channel> {
|
||||||
_pin: PeripheralRef<'d, AnyPin>,
|
_pin: PeripheralRef<'d, AnyPin>,
|
||||||
phantom: PhantomData<(Perip, Channel)>,
|
phantom: PhantomData<(T, Channel)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! channel_impl {
|
macro_rules! channel_impl {
|
||||||
($new_chx:ident, $channel:ident, $pin_trait:ident) => {
|
($new_chx:ident, $channel:ident, $pin_trait:ident) => {
|
||||||
impl<'d, Perip: CaptureCompare16bitInstance> QeiPin<'d, Perip, $channel> {
|
impl<'d, T: CaptureCompare16bitInstance> QeiPin<'d, T, $channel> {
|
||||||
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self {
|
#[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")]
|
||||||
|
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self {
|
||||||
into_ref!(pin);
|
into_ref!(pin);
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
pin.set_low();
|
pin.set_low();
|
||||||
@ -45,11 +52,13 @@ macro_rules! channel_impl {
|
|||||||
channel_impl!(new_ch1, Ch1, Channel1Pin);
|
channel_impl!(new_ch1, Ch1, Channel1Pin);
|
||||||
channel_impl!(new_ch2, Ch2, Channel2Pin);
|
channel_impl!(new_ch2, Ch2, Channel2Pin);
|
||||||
|
|
||||||
|
/// Quadrature decoder driver.
|
||||||
pub struct Qei<'d, T> {
|
pub struct Qei<'d, T> {
|
||||||
_inner: PeripheralRef<'d, T>,
|
_inner: PeripheralRef<'d, T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
|
impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
|
||||||
|
/// Create a new quadrature decoder driver.
|
||||||
pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self {
|
pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self {
|
||||||
Self::new_inner(tim)
|
Self::new_inner(tim)
|
||||||
}
|
}
|
||||||
@ -84,6 +93,7 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
|
|||||||
Self { _inner: tim }
|
Self { _inner: tim }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get direction.
|
||||||
pub fn read_direction(&self) -> Direction {
|
pub fn read_direction(&self) -> Direction {
|
||||||
match T::regs_gp16().cr1().read().dir() {
|
match T::regs_gp16().cr1().read().dir() {
|
||||||
vals::Dir::DOWN => Direction::Downcounting,
|
vals::Dir::DOWN => Direction::Downcounting,
|
||||||
@ -91,6 +101,7 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get count.
|
||||||
pub fn count(&self) -> u16 {
|
pub fn count(&self) -> u16 {
|
||||||
T::regs_gp16().cnt().read().cnt()
|
T::regs_gp16().cnt().read().cnt()
|
||||||
}
|
}
|
||||||
|
@ -11,20 +11,28 @@ use crate::gpio::{AnyPin, OutputType};
|
|||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
use crate::Peripheral;
|
use crate::Peripheral;
|
||||||
|
|
||||||
pub struct Ch1;
|
/// Channel 1 marker type.
|
||||||
pub struct Ch2;
|
pub enum Ch1 {}
|
||||||
pub struct Ch3;
|
/// Channel 2 marker type.
|
||||||
pub struct Ch4;
|
pub enum Ch2 {}
|
||||||
|
/// Channel 3 marker type.
|
||||||
|
pub enum Ch3 {}
|
||||||
|
/// Channel 4 marker type.
|
||||||
|
pub enum Ch4 {}
|
||||||
|
|
||||||
pub struct PwmPin<'d, Perip, Channel> {
|
/// PWM pin wrapper.
|
||||||
|
///
|
||||||
|
/// This wraps a pin to make it usable with PWM.
|
||||||
|
pub struct PwmPin<'d, T, C> {
|
||||||
_pin: PeripheralRef<'d, AnyPin>,
|
_pin: PeripheralRef<'d, AnyPin>,
|
||||||
phantom: PhantomData<(Perip, Channel)>,
|
phantom: PhantomData<(T, C)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! channel_impl {
|
macro_rules! channel_impl {
|
||||||
($new_chx:ident, $channel:ident, $pin_trait:ident) => {
|
($new_chx:ident, $channel:ident, $pin_trait:ident) => {
|
||||||
impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> {
|
impl<'d, T: CaptureCompare16bitInstance> PwmPin<'d, T, $channel> {
|
||||||
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd, output_type: OutputType) -> Self {
|
#[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
|
||||||
|
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self {
|
||||||
into_ref!(pin);
|
into_ref!(pin);
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
pin.set_low();
|
pin.set_low();
|
||||||
@ -46,11 +54,13 @@ channel_impl!(new_ch2, Ch2, Channel2Pin);
|
|||||||
channel_impl!(new_ch3, Ch3, Channel3Pin);
|
channel_impl!(new_ch3, Ch3, Channel3Pin);
|
||||||
channel_impl!(new_ch4, Ch4, Channel4Pin);
|
channel_impl!(new_ch4, Ch4, Channel4Pin);
|
||||||
|
|
||||||
|
/// Simple PWM driver.
|
||||||
pub struct SimplePwm<'d, T> {
|
pub struct SimplePwm<'d, T> {
|
||||||
inner: PeripheralRef<'d, T>,
|
inner: PeripheralRef<'d, T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
|
impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
|
||||||
|
/// Create a new simple PWM driver.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
tim: impl Peripheral<P = T> + 'd,
|
tim: impl Peripheral<P = T> + 'd,
|
||||||
_ch1: Option<PwmPin<'d, T, Ch1>>,
|
_ch1: Option<PwmPin<'d, T, Ch1>>,
|
||||||
@ -71,7 +81,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
|
|||||||
let mut this = Self { inner: tim };
|
let mut this = Self { inner: tim };
|
||||||
|
|
||||||
this.inner.set_counting_mode(counting_mode);
|
this.inner.set_counting_mode(counting_mode);
|
||||||
this.set_freq(freq);
|
this.set_frequency(freq);
|
||||||
this.inner.start();
|
this.inner.start();
|
||||||
|
|
||||||
this.inner.enable_outputs();
|
this.inner.enable_outputs();
|
||||||
@ -87,15 +97,21 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
|
|||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enable the given channel.
|
||||||
pub fn enable(&mut self, channel: Channel) {
|
pub fn enable(&mut self, channel: Channel) {
|
||||||
self.inner.enable_channel(channel, true);
|
self.inner.enable_channel(channel, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Disable the given channel.
|
||||||
pub fn disable(&mut self, channel: Channel) {
|
pub fn disable(&mut self, channel: Channel) {
|
||||||
self.inner.enable_channel(channel, false);
|
self.inner.enable_channel(channel, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_freq(&mut self, freq: Hertz) {
|
/// Set PWM frequency.
|
||||||
|
///
|
||||||
|
/// Note: when you call this, the max duty value changes, so you will have to
|
||||||
|
/// call `set_duty` on all channels with the duty calculated based on the new max duty.
|
||||||
|
pub fn set_frequency(&mut self, freq: Hertz) {
|
||||||
let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
|
let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
|
||||||
2u8
|
2u8
|
||||||
} else {
|
} else {
|
||||||
@ -104,15 +120,22 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
|
|||||||
self.inner.set_frequency(freq * multiplier);
|
self.inner.set_frequency(freq * multiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get max duty value.
|
||||||
|
///
|
||||||
|
/// This value depends on the configured frequency and the timer's clock rate from RCC.
|
||||||
pub fn get_max_duty(&self) -> u16 {
|
pub fn get_max_duty(&self) -> u16 {
|
||||||
self.inner.get_max_compare_value() + 1
|
self.inner.get_max_compare_value() + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the duty for a given channel.
|
||||||
|
///
|
||||||
|
/// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
|
||||||
pub fn set_duty(&mut self, channel: Channel, duty: u16) {
|
pub fn set_duty(&mut self, channel: Channel, duty: u16) {
|
||||||
assert!(duty <= self.get_max_duty());
|
assert!(duty <= self.get_max_duty());
|
||||||
self.inner.set_compare_value(channel, duty)
|
self.inner.set_compare_value(channel, duty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the output polarity for a given channel.
|
||||||
pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
|
pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
|
||||||
self.inner.set_output_polarity(channel, polarity);
|
self.inner.set_output_polarity(channel, polarity);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! Universal Serial Bus (USB)
|
||||||
|
|
||||||
use crate::interrupt;
|
use crate::interrupt;
|
||||||
use crate::rcc::RccPeripheral;
|
use crate::rcc::RccPeripheral;
|
||||||
|
|
||||||
@ -10,7 +12,9 @@ pub(crate) mod sealed {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// USB instance trait.
|
||||||
pub trait Instance: sealed::Instance + RccPeripheral + 'static {
|
pub trait Instance: sealed::Instance + RccPeripheral + 'static {
|
||||||
|
/// Interrupt for this USB instance.
|
||||||
type Interrupt: interrupt::typelevel::Interrupt;
|
type Interrupt: interrupt::typelevel::Interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,6 +244,7 @@ struct EndpointData {
|
|||||||
used_out: bool,
|
used_out: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// USB driver.
|
||||||
pub struct Driver<'d, T: Instance> {
|
pub struct Driver<'d, T: Instance> {
|
||||||
phantom: PhantomData<&'d mut T>,
|
phantom: PhantomData<&'d mut T>,
|
||||||
alloc: [EndpointData; EP_COUNT],
|
alloc: [EndpointData; EP_COUNT],
|
||||||
@ -251,6 +252,7 @@ pub struct Driver<'d, T: Instance> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> Driver<'d, T> {
|
impl<'d, T: Instance> Driver<'d, T> {
|
||||||
|
/// Create a new USB driver.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
_usb: impl Peripheral<P = T> + 'd,
|
_usb: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
@ -465,6 +467,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// USB bus.
|
||||||
pub struct Bus<'d, T: Instance> {
|
pub struct Bus<'d, T: Instance> {
|
||||||
phantom: PhantomData<&'d mut T>,
|
phantom: PhantomData<&'d mut T>,
|
||||||
ep_types: [EpType; EP_COUNT - 1],
|
ep_types: [EpType; EP_COUNT - 1],
|
||||||
@ -640,6 +643,7 @@ trait Dir {
|
|||||||
fn waker(i: usize) -> &'static AtomicWaker;
|
fn waker(i: usize) -> &'static AtomicWaker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Marker type for the "IN" direction.
|
||||||
pub enum In {}
|
pub enum In {}
|
||||||
impl Dir for In {
|
impl Dir for In {
|
||||||
fn dir() -> Direction {
|
fn dir() -> Direction {
|
||||||
@ -652,6 +656,7 @@ impl Dir for In {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Marker type for the "OUT" direction.
|
||||||
pub enum Out {}
|
pub enum Out {}
|
||||||
impl Dir for Out {
|
impl Dir for Out {
|
||||||
fn dir() -> Direction {
|
fn dir() -> Direction {
|
||||||
@ -664,6 +669,7 @@ impl Dir for Out {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// USB endpoint.
|
||||||
pub struct Endpoint<'d, T: Instance, D> {
|
pub struct Endpoint<'d, T: Instance, D> {
|
||||||
_phantom: PhantomData<(&'d mut T, D)>,
|
_phantom: PhantomData<(&'d mut T, D)>,
|
||||||
info: EndpointInfo,
|
info: EndpointInfo,
|
||||||
@ -813,6 +819,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// USB control pipe.
|
||||||
pub struct ControlPipe<'d, T: Instance> {
|
pub struct ControlPipe<'d, T: Instance> {
|
||||||
_phantom: PhantomData<&'d mut T>,
|
_phantom: PhantomData<&'d mut T>,
|
||||||
max_packet_size: u16,
|
max_packet_size: u16,
|
||||||
|
@ -20,7 +20,9 @@ pub(crate) mod sealed {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// USB OTG instance.
|
||||||
pub trait Instance: sealed::Instance + RccPeripheral {
|
pub trait Instance: sealed::Instance + RccPeripheral {
|
||||||
|
/// Interrupt for this USB OTG instance.
|
||||||
type Interrupt: interrupt::typelevel::Interrupt;
|
type Interrupt: interrupt::typelevel::Interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,6 +204,7 @@ pub enum PhyType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PhyType {
|
impl PhyType {
|
||||||
|
/// Get whether this PHY is any of the internal types.
|
||||||
pub fn internal(&self) -> bool {
|
pub fn internal(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true,
|
PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true,
|
||||||
@ -211,6 +212,7 @@ impl PhyType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get whether this PHY is any of the high-speed types.
|
||||||
pub fn high_speed(&self) -> bool {
|
pub fn high_speed(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
PhyType::InternalFullSpeed => false,
|
PhyType::InternalFullSpeed => false,
|
||||||
@ -218,7 +220,7 @@ impl PhyType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_dspd(&self) -> vals::Dspd {
|
fn to_dspd(&self) -> vals::Dspd {
|
||||||
match self {
|
match self {
|
||||||
PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL,
|
PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL,
|
||||||
PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED,
|
PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED,
|
||||||
@ -230,6 +232,7 @@ impl PhyType {
|
|||||||
/// Indicates that [State::ep_out_buffers] is empty.
|
/// Indicates that [State::ep_out_buffers] is empty.
|
||||||
const EP_OUT_BUFFER_EMPTY: u16 = u16::MAX;
|
const EP_OUT_BUFFER_EMPTY: u16 = u16::MAX;
|
||||||
|
|
||||||
|
/// USB OTG driver state.
|
||||||
pub struct State<const EP_COUNT: usize> {
|
pub struct State<const EP_COUNT: usize> {
|
||||||
/// Holds received SETUP packets. Available if [State::ep0_setup_ready] is true.
|
/// Holds received SETUP packets. Available if [State::ep0_setup_ready] is true.
|
||||||
ep0_setup_data: UnsafeCell<[u8; 8]>,
|
ep0_setup_data: UnsafeCell<[u8; 8]>,
|
||||||
@ -247,6 +250,7 @@ unsafe impl<const EP_COUNT: usize> Send for State<EP_COUNT> {}
|
|||||||
unsafe impl<const EP_COUNT: usize> Sync for State<EP_COUNT> {}
|
unsafe impl<const EP_COUNT: usize> Sync for State<EP_COUNT> {}
|
||||||
|
|
||||||
impl<const EP_COUNT: usize> State<EP_COUNT> {
|
impl<const EP_COUNT: usize> State<EP_COUNT> {
|
||||||
|
/// Create a new State.
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
const NEW_AW: AtomicWaker = AtomicWaker::new();
|
const NEW_AW: AtomicWaker = AtomicWaker::new();
|
||||||
const NEW_BUF: UnsafeCell<*mut u8> = UnsafeCell::new(0 as _);
|
const NEW_BUF: UnsafeCell<*mut u8> = UnsafeCell::new(0 as _);
|
||||||
@ -271,6 +275,7 @@ struct EndpointData {
|
|||||||
fifo_size_words: u16,
|
fifo_size_words: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// USB driver config.
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
@ -297,6 +302,7 @@ impl Default for Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// USB driver.
|
||||||
pub struct Driver<'d, T: Instance> {
|
pub struct Driver<'d, T: Instance> {
|
||||||
config: Config,
|
config: Config,
|
||||||
phantom: PhantomData<&'d mut T>,
|
phantom: PhantomData<&'d mut T>,
|
||||||
@ -527,6 +533,7 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// USB bus.
|
||||||
pub struct Bus<'d, T: Instance> {
|
pub struct Bus<'d, T: Instance> {
|
||||||
config: Config,
|
config: Config,
|
||||||
phantom: PhantomData<&'d mut T>,
|
phantom: PhantomData<&'d mut T>,
|
||||||
@ -1092,6 +1099,7 @@ trait Dir {
|
|||||||
fn dir() -> Direction;
|
fn dir() -> Direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Marker type for the "IN" direction.
|
||||||
pub enum In {}
|
pub enum In {}
|
||||||
impl Dir for In {
|
impl Dir for In {
|
||||||
fn dir() -> Direction {
|
fn dir() -> Direction {
|
||||||
@ -1099,6 +1107,7 @@ impl Dir for In {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Marker type for the "OUT" direction.
|
||||||
pub enum Out {}
|
pub enum Out {}
|
||||||
impl Dir for Out {
|
impl Dir for Out {
|
||||||
fn dir() -> Direction {
|
fn dir() -> Direction {
|
||||||
@ -1106,6 +1115,7 @@ impl Dir for Out {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// USB endpoint.
|
||||||
pub struct Endpoint<'d, T: Instance, D> {
|
pub struct Endpoint<'d, T: Instance, D> {
|
||||||
_phantom: PhantomData<(&'d mut T, D)>,
|
_phantom: PhantomData<(&'d mut T, D)>,
|
||||||
info: EndpointInfo,
|
info: EndpointInfo,
|
||||||
@ -1299,6 +1309,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// USB control pipe.
|
||||||
pub struct ControlPipe<'d, T: Instance> {
|
pub struct ControlPipe<'d, T: Instance> {
|
||||||
_phantom: PhantomData<&'d mut T>,
|
_phantom: PhantomData<&'d mut T>,
|
||||||
max_packet_size: u16,
|
max_packet_size: u16,
|
||||||
|
@ -6,6 +6,7 @@ use stm32_metapac::iwdg::vals::{Key, Pr};
|
|||||||
|
|
||||||
use crate::rcc::LSI_FREQ;
|
use crate::rcc::LSI_FREQ;
|
||||||
|
|
||||||
|
/// Independent watchdog (IWDG) driver.
|
||||||
pub struct IndependentWatchdog<'d, T: Instance> {
|
pub struct IndependentWatchdog<'d, T: Instance> {
|
||||||
wdg: PhantomData<&'d mut T>,
|
wdg: PhantomData<&'d mut T>,
|
||||||
}
|
}
|
||||||
@ -64,10 +65,12 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> {
|
|||||||
IndependentWatchdog { wdg: PhantomData }
|
IndependentWatchdog { wdg: PhantomData }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unleash (start) the watchdog.
|
||||||
pub fn unleash(&mut self) {
|
pub fn unleash(&mut self) {
|
||||||
T::regs().kr().write(|w| w.set_key(Key::START));
|
T::regs().kr().write(|w| w.set_key(Key::START));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pet (reload, refresh) the watchdog.
|
||||||
pub fn pet(&mut self) {
|
pub fn pet(&mut self) {
|
||||||
T::regs().kr().write(|w| w.set_key(Key::RESET));
|
T::regs().kr().write(|w| w.set_key(Key::RESET));
|
||||||
}
|
}
|
||||||
@ -79,6 +82,7 @@ mod sealed {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// IWDG instance trait.
|
||||||
pub trait Instance: sealed::Instance {}
|
pub trait Instance: sealed::Instance {}
|
||||||
|
|
||||||
foreach_peripheral!(
|
foreach_peripheral!(
|
||||||
|
@ -110,7 +110,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
&mut dp.DMA1_CH2,
|
&mut dp.DMA1_CH2,
|
||||||
5,
|
5,
|
||||||
color_list[color_list_index],
|
color_list[color_list_index],
|
||||||
pac::TIM3.ccr(pwm_channel.raw()).as_ptr() as *mut _,
|
pac::TIM3.ccr(pwm_channel.index()).as_ptr() as *mut _,
|
||||||
dma_transfer_option,
|
dma_transfer_option,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
@ -85,7 +85,7 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
|
|||||||
|
|
||||||
let mut this = Self { inner: tim };
|
let mut this = Self { inner: tim };
|
||||||
|
|
||||||
this.set_freq(freq);
|
this.set_frequency(freq);
|
||||||
this.inner.start();
|
this.inner.start();
|
||||||
|
|
||||||
let r = T::regs_gp32();
|
let r = T::regs_gp32();
|
||||||
@ -102,14 +102,14 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable(&mut self, channel: Channel) {
|
pub fn enable(&mut self, channel: Channel) {
|
||||||
T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), true));
|
T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), true));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disable(&mut self, channel: Channel) {
|
pub fn disable(&mut self, channel: Channel) {
|
||||||
T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), false));
|
T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), false));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_freq(&mut self, freq: Hertz) {
|
pub fn set_frequency(&mut self, freq: Hertz) {
|
||||||
<T as embassy_stm32::timer::low_level::GeneralPurpose32bitInstance>::set_frequency(&mut self.inner, freq);
|
<T as embassy_stm32::timer::low_level::GeneralPurpose32bitInstance>::set_frequency(&mut self.inner, freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,6 +119,6 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
|
|||||||
|
|
||||||
pub fn set_duty(&mut self, channel: Channel, duty: u32) {
|
pub fn set_duty(&mut self, channel: Channel, duty: u32) {
|
||||||
defmt::assert!(duty < self.get_max_duty());
|
defmt::assert!(duty < self.get_max_duty());
|
||||||
T::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(duty))
|
T::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(duty))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user