use core::convert::Infallible;
use core::future::Future;
use core::pin::Pin;
use core::sync::atomic::{AtomicU32, Ordering};
use core::task::{Context, Poll};
use embassy_hal_internal::{Peri, PeripheralType};
use embassy_sync::waitqueue::AtomicWaker;
use pac::peripherals::lptim::LPTIM;
use crate::pac;
#[cfg(feature = "dma")]
use crate::dma::{
DmaChannel, DmaNode, DmaRequest, ReadableRingBuffer, RingError, Transfer, WritableRingBuffer,
request as dma_request,
};
const CR_ENABLE: u32 = 1 << 0;
const CR_SNGSTRT: u32 = 1 << 1;
const CR_CNTSTRT: u32 = 1 << 2;
const CR_COUNTRST: u32 = 1 << 3;
const CR_RSTARE: u32 = 1 << 4;
#[cfg(feature = "dma")]
const DIER_CC1DE: u32 = 1 << 16;
#[cfg(feature = "dma")]
const DIER_UEDE: u32 = 1 << 23;
#[cfg(feature = "dma")]
const DIER_CC2DE: u32 = 1 << 25;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LptimId {
Lptim1,
Lptim2,
Lptim3,
Lptim4,
Lptim5,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Channel {
Ch1,
Ch2,
}
impl Channel {
const fn event(self) -> Event {
match self {
Self::Ch1 => Event::CaptureCompare1,
Self::Ch2 => Event::CaptureCompare2,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Event {
CaptureCompare1 = 0,
AutoReloadMatch = 1,
ExternalTrigger = 2,
Update = 7,
CaptureCompare2 = 9,
OverCapture1 = 12,
OverCapture2 = 13,
}
impl Event {
const fn mask(self) -> u32 {
1 << self as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum TriggerEdge {
Software = 0,
Rising = 1,
Falling = 2,
Both = 3,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Edge {
Rising = 0,
Falling = 1,
Both = 2,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Polarity {
ActiveHigh,
ActiveLow,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error {
FrequencyOutOfRange,
DmaUnavailable,
}
pub struct State {
pending: AtomicU32,
waker: AtomicWaker,
}
impl State {
pub(crate) const fn new() -> Self {
Self {
pending: AtomicU32::new(0),
waker: AtomicWaker::new(),
}
}
fn on_interrupt(&self, regs: LPTIM) {
let pending = regs.ISR().read().0 & regs.DIER().read().0 & 0x0000_ffff;
if pending != 0 {
self.pending.fetch_or(pending, Ordering::AcqRel);
regs.ICR().write(|w| w.0 = pending);
regs.DIER().modify(|w| w.0 &= !pending);
self.waker.wake();
}
}
}
pub(crate) trait SealedInstance {
fn regs() -> LPTIM;
fn state() -> &'static State;
}
#[allow(private_bounds)]
pub trait Instance: SealedInstance + PeripheralType {
const IRQ: Option<u16>;
const ID: LptimId;
}
macro_rules! impl_lptim {
($instance:ident, $base:expr, $id:ident, $irq:expr) => {
impl crate::lptim::SealedInstance for crate::peripherals::$instance {
#[inline]
fn regs() -> crate::pac::peripherals::lptim::LPTIM {
unsafe { crate::pac::peripherals::lptim::LPTIM::from_ptr($base as *mut ()) }
}
#[inline]
fn state() -> &'static crate::lptim::State {
static STATE: crate::lptim::State = crate::lptim::State::new();
&STATE
}
}
impl crate::lptim::Instance for crate::peripherals::$instance {
const IRQ: ::core::option::Option<u16> = $irq;
const ID: crate::lptim::LptimId = crate::lptim::LptimId::$id;
}
};
}
pub(crate) use impl_lptim;
pub fn on_interrupt<T: Instance>() {
T::state().on_interrupt(T::regs());
}
pub struct LowPowerTimer {
regs: LPTIM,
#[cfg(feature = "dma")]
id: LptimId,
clock_hz: u32,
state: &'static State,
}
impl LowPowerTimer {
pub fn new<T: Instance>(peri: Peri<'static, T>, clock_hz: u32) -> Self {
let _ = peri;
Self::over(T::regs(), T::ID, clock_hz, T::state())
}
#[allow(unused_variables)]
fn over(regs: LPTIM, id: LptimId, clock_hz: u32, state: &'static State) -> Self {
assert!(clock_hz > 0);
regs.CR().write(|w| w.0 = 0);
regs.DIER().write(|w| w.0 = 0);
regs.ICR().write(|w| w.0 = 0x01ff_ffff);
regs.CFGR().write(|w| w.0 = 0);
regs.CCMR1().write(|w| w.0 = 0);
regs.CR().write(|w| w.0 = CR_ENABLE);
Self {
regs,
#[cfg(feature = "dma")]
id,
clock_hz,
state,
}
}
pub fn enable(&mut self) {
self.regs.CR().modify(|w| w.0 |= CR_ENABLE);
}
pub fn disable(&mut self) {
self.regs.CR().write(|w| w.0 = 0);
}
pub fn is_enabled(&self) -> bool {
self.regs.CR().read().0 & CR_ENABLE != 0
}
pub fn start_continuous(&mut self) {
self.enable();
self.regs.CR().modify(|w| w.0 |= CR_CNTSTRT);
}
pub fn start_single(&mut self) {
self.enable();
self.regs.CR().modify(|w| w.0 |= CR_SNGSTRT);
}
pub fn reset_counter(&mut self) {
self.regs.CR().modify(|w| w.0 |= CR_COUNTRST);
}
pub fn set_reset_after_read(&mut self, enabled: bool) {
self.regs.CR().modify(|w| {
if enabled {
w.0 |= CR_RSTARE;
} else {
w.0 &= !CR_RSTARE;
}
});
}
pub fn counter(&self) -> u16 {
self.regs.CNT().read().CNT()
}
pub fn set_period(&mut self, prescaler_log2: u8, autoreload: u16) {
assert!(prescaler_log2 <= 7);
self.regs.CFGR().modify(|w| w.set_PRESC(prescaler_log2));
self.regs.ARR().write(|w| w.set_ARR(autoreload));
}
pub fn set_frequency(&mut self, frequency_hz: u32) -> Result<(), Error> {
let (prescaler, autoreload) = compute_period(self.clock_hz, frequency_hz)?;
self.set_period(prescaler, autoreload);
Ok(())
}
pub fn autoreload(&self) -> u16 {
self.regs.ARR().read().ARR()
}
pub fn set_repetition(&mut self, repetitions: u8) {
self.regs.RCR().write(|w| w.set_REP(repetitions));
}
pub fn configure_trigger(&mut self, source: u8, edge: TriggerEdge, filter: u8) {
assert!(source <= 7 && filter <= 3);
self.regs.CFGR().modify(|w| {
w.set_TRIGSEL(source);
w.set_TRIGEN(edge as u8);
w.set_TRGFLT(filter);
});
}
pub fn set_timeout_mode(&mut self, enabled: bool) {
self.regs.CFGR().modify(|w| w.set_TIMOUT(enabled));
}
pub fn configure_external_counter(&mut self, polarity: Edge, filter: u8) {
assert!(filter <= 3);
self.regs.CFGR().modify(|w| {
w.set_CKSEL(true);
w.set_CKPOL(polarity as u8);
w.set_CKFLT(filter);
w.set_COUNTMODE(true);
w.set_ENC(false);
});
}
pub fn configure_encoder(&mut self, filter: u8) {
assert!(filter <= 3);
self.regs.CFGR().modify(|w| {
w.set_CKSEL(true);
w.set_CKFLT(filter);
w.set_COUNTMODE(true);
w.set_ENC(true);
});
}
pub fn configure_internal_clock(&mut self) {
self.regs.CFGR().modify(|w| {
w.set_CKSEL(false);
w.set_COUNTMODE(false);
w.set_ENC(false);
});
}
pub fn wait_event(&mut self, event: Event) -> WaitEvent<'_> {
let mask = event.mask();
self.state.pending.fetch_and(!mask, Ordering::AcqRel);
self.regs.ICR().write(|w| w.0 = mask);
self.regs.DIER().modify(|w| w.0 |= mask);
WaitEvent {
timer: self,
event,
complete: false,
}
}
pub fn into_pwm(mut self, frequency_hz: u32) -> Result<Pwm, Error> {
self.set_frequency(frequency_hz)?;
self.regs.CFGR().modify(|w| {
w.set_WAVE(false);
w.set_PRELOAD(true);
});
self.regs.CCMR1().modify(|w| {
w.set_CC1SEL(false);
w.set_CC2SEL(false);
});
self.start_continuous();
Ok(Pwm { timer: self })
}
pub fn into_input_capture(mut self) -> InputCapture {
self.set_period(0, u16::MAX);
self.start_continuous();
InputCapture { timer: self }
}
fn disable_event(&mut self, event: Event) {
self.regs.DIER().modify(|w| w.0 &= !event.mask());
}
#[cfg(feature = "dma")]
fn capture_request(&self, channel: Channel) -> Result<DmaRequest, Error> {
match (self.id, channel) {
(LptimId::Lptim1, Channel::Ch1) => Ok(dma_request::LPTIM1_IC1),
(LptimId::Lptim1, Channel::Ch2) => Ok(dma_request::LPTIM1_IC2),
(LptimId::Lptim2, Channel::Ch1) => Ok(dma_request::LPTIM2_IC1),
(LptimId::Lptim2, Channel::Ch2) => Ok(dma_request::LPTIM2_IC2),
(LptimId::Lptim3, Channel::Ch1) => Ok(dma_request::LPTIM3_IC1),
(LptimId::Lptim3, Channel::Ch2) => Ok(dma_request::LPTIM3_IC2),
(LptimId::Lptim4, Channel::Ch1) => Ok(dma_request::LPTIM4_IC1),
(LptimId::Lptim4, Channel::Ch2) => Ok(dma_request::LPTIM4_IC2),
(LptimId::Lptim5, _) => Err(Error::DmaUnavailable),
}
}
#[cfg(feature = "dma")]
fn update_request(&self) -> Result<DmaRequest, Error> {
match self.id {
LptimId::Lptim1 => Ok(dma_request::LPTIM1_UE),
LptimId::Lptim2 => Ok(dma_request::LPTIM2_UE),
LptimId::Lptim3 => Ok(dma_request::LPTIM3_UE),
LptimId::Lptim4 => Ok(dma_request::LPTIM4_UE),
LptimId::Lptim5 => Err(Error::DmaUnavailable),
}
}
}
pub struct WaitEvent<'a> {
timer: &'a mut LowPowerTimer,
event: Event,
complete: bool,
}
impl Future for WaitEvent<'_> {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
let event = self.event;
let mask = event.mask();
if self.timer.state.pending.fetch_and(!mask, Ordering::AcqRel) & mask != 0
|| self.timer.regs.ISR().read().0 & mask != 0
{
self.timer.regs.ICR().write(|w| w.0 = mask);
self.timer.disable_event(event);
self.complete = true;
return Poll::Ready(());
}
self.timer.state.waker.register(cx.waker());
if self.timer.state.pending.fetch_and(!mask, Ordering::AcqRel) & mask != 0 {
self.timer.disable_event(event);
self.complete = true;
Poll::Ready(())
} else {
Poll::Pending
}
}
}
impl Drop for WaitEvent<'_> {
fn drop(&mut self) {
if !self.complete {
self.timer.disable_event(self.event);
}
}
}
pub struct Pwm {
timer: LowPowerTimer,
}
impl Pwm {
pub fn max_duty_cycle(&self) -> u16 {
self.timer.autoreload().saturating_add(1)
}
pub fn set_frequency(&mut self, frequency_hz: u32) -> Result<(), Error> {
self.timer.set_frequency(frequency_hz)
}
pub fn enable(&mut self, channel: Channel) {
self.timer.regs.CCMR1().modify(|w| match channel {
Channel::Ch1 => w.set_CC1E(true),
Channel::Ch2 => w.set_CC2E(true),
});
}
pub fn disable(&mut self, channel: Channel) {
self.timer.regs.CCMR1().modify(|w| match channel {
Channel::Ch1 => w.set_CC1E(false),
Channel::Ch2 => w.set_CC2E(false),
});
}
pub fn set_polarity(&mut self, channel: Channel, polarity: Polarity) {
let value = u8::from(matches!(polarity, Polarity::ActiveLow));
self.timer.regs.CCMR1().modify(|w| match channel {
Channel::Ch1 => w.set_CC1P(value),
Channel::Ch2 => w.set_CC2P(value),
});
}
pub fn set_duty_cycle(&mut self, channel: Channel, duty: u16) {
let duty = duty.min(self.max_duty_cycle());
match channel {
Channel::Ch1 => self.timer.regs.CCR1().write(|w| w.set_CCR1(duty)),
Channel::Ch2 => self.timer.regs.CCR2().write(|w| w.set_CCR2(duty)),
}
}
pub fn duty_cycle(&self, channel: Channel) -> u16 {
match channel {
Channel::Ch1 => self.timer.regs.CCR1().read().CCR1(),
Channel::Ch2 => self.timer.regs.CCR2().read().CCR2(),
}
}
pub fn channel(&mut self, channel: Channel) -> PwmChannel<'_> {
PwmChannel { pwm: self, channel }
}
pub fn free(mut self) -> LowPowerTimer {
self.timer.disable();
self.timer
}
#[cfg(feature = "dma")]
pub fn into_ring_buffered_channel<'a>(
self,
channel: Channel,
dma: &'a mut DmaChannel,
buffer: &'a mut [u16],
node: &'a mut DmaNode,
) -> Result<RingBufferedPwm<'a>, Error> {
let request = self.timer.update_request()?;
let destination = compare_ptr(self.timer.regs, channel);
let ring = unsafe { dma.write_circular(buffer, destination, request, node) };
Ok(RingBufferedPwm {
pwm: self,
channel,
ring: Some(ring),
})
}
#[cfg(feature = "dma")]
pub fn write_dma<'a>(
&'a mut self,
channel: Channel,
dma: &'a mut DmaChannel,
values: &'a [u16],
) -> Result<LptimDmaTransfer<'a>, Error> {
let request = self.timer.update_request()?;
let destination = compare_ptr(self.timer.regs, channel);
let transfer = unsafe { dma.write_peripheral(values, destination, request) };
self.timer.regs.DIER().modify(|w| w.0 |= DIER_UEDE);
Ok(LptimDmaTransfer {
transfer: Some(transfer),
regs: self.timer.regs,
dma_enable: DIER_UEDE,
})
}
}
pub struct PwmChannel<'a> {
pwm: &'a mut Pwm,
channel: Channel,
}
impl PwmChannel<'_> {
pub fn enable(&mut self) {
self.pwm.enable(self.channel);
}
pub fn disable(&mut self) {
self.pwm.disable(self.channel);
}
pub fn set_polarity(&mut self, polarity: Polarity) {
self.pwm.set_polarity(self.channel, polarity);
}
pub fn max_duty_cycle(&self) -> u16 {
self.pwm.max_duty_cycle()
}
pub fn set_duty_cycle(&mut self, duty: u16) {
self.pwm.set_duty_cycle(self.channel, duty);
}
}
impl embedded_hal::pwm::ErrorType for PwmChannel<'_> {
type Error = Infallible;
}
impl embedded_hal::pwm::SetDutyCycle for PwmChannel<'_> {
fn max_duty_cycle(&self) -> u16 {
PwmChannel::max_duty_cycle(self)
}
fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
PwmChannel::set_duty_cycle(self, duty);
Ok(())
}
}
pub struct InputCapture {
timer: LowPowerTimer,
}
impl InputCapture {
pub fn configure_channel(
&mut self,
channel: Channel,
edge: Edge,
filter: u8,
prescaler: u8,
input_selection: u8,
) {
assert!(filter <= 3 && prescaler <= 3 && input_selection <= 3);
self.timer.regs.CCMR1().modify(|w| match channel {
Channel::Ch1 => {
w.set_CC1SEL(true);
w.set_CC1E(true);
w.set_CC1P(edge as u8);
w.set_IC1F(filter);
w.set_IC1PSC(prescaler);
}
Channel::Ch2 => {
w.set_CC2SEL(true);
w.set_CC2E(true);
w.set_CC2P(edge as u8);
w.set_IC2F(filter);
w.set_IC2PSC(prescaler);
}
});
self.timer.regs.CFGR2().modify(|w| match channel {
Channel::Ch1 => w.set_IC1SEL(input_selection),
Channel::Ch2 => w.set_IC2SEL(input_selection),
});
}
pub fn capture(&self, channel: Channel) -> u16 {
match channel {
Channel::Ch1 => self.timer.regs.CCR1().read().CCR1(),
Channel::Ch2 => self.timer.regs.CCR2().read().CCR2(),
}
}
pub fn overcaptured(&self, channel: Channel) -> bool {
let status = self.timer.regs.ISR().read().0;
status
& match channel {
Channel::Ch1 => Event::OverCapture1.mask(),
Channel::Ch2 => Event::OverCapture2.mask(),
}
!= 0
}
pub fn wait_capture(&mut self, channel: Channel) -> WaitEvent<'_> {
self.timer.wait_event(channel.event())
}
#[cfg(feature = "dma")]
pub fn into_ring_buffered_channel<'a>(
self,
channel: Channel,
dma: &'a mut DmaChannel,
buffer: &'a mut [u16],
node: &'a mut DmaNode,
) -> Result<RingBufferedCapture<'a>, Error> {
let request = self.timer.capture_request(channel)?;
let source = compare_ptr(self.timer.regs, channel).cast_const();
let ring = unsafe { dma.read_circular(source, buffer, request, node) };
Ok(RingBufferedCapture {
capture: self,
channel,
ring: Some(ring),
})
}
#[cfg(feature = "dma")]
pub fn read_dma<'a>(
&'a mut self,
channel: Channel,
dma: &'a mut DmaChannel,
values: &'a mut [u16],
) -> Result<LptimDmaTransfer<'a>, Error> {
let request = self.timer.capture_request(channel)?;
let source = compare_ptr(self.timer.regs, channel).cast_const();
let transfer = unsafe { dma.read_peripheral(source, values, request) };
let enable = capture_dma_enable(channel);
self.timer.regs.DIER().modify(|w| w.0 |= enable);
Ok(LptimDmaTransfer {
transfer: Some(transfer),
regs: self.timer.regs,
dma_enable: enable,
})
}
}
#[cfg(feature = "dma")]
fn compare_ptr(regs: LPTIM, channel: Channel) -> *mut u16 {
match channel {
Channel::Ch1 => regs.CCR1().as_ptr().cast(),
Channel::Ch2 => regs.CCR2().as_ptr().cast(),
}
}
#[cfg(feature = "dma")]
const fn capture_dma_enable(channel: Channel) -> u32 {
match channel {
Channel::Ch1 => DIER_CC1DE,
Channel::Ch2 => DIER_CC2DE,
}
}
#[cfg(feature = "dma")]
pub struct LptimDmaTransfer<'a> {
transfer: Option<Transfer<'a>>,
regs: LPTIM,
dma_enable: u32,
}
#[cfg(feature = "dma")]
impl Future for LptimDmaTransfer<'_> {
type Output = Result<(), crate::dma::Error>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
let result = Pin::new(
this.transfer
.as_mut()
.expect("transfer polled after completion"),
)
.poll(cx);
if result.is_ready() {
drop(this.transfer.take());
this.regs.DIER().modify(|w| w.0 &= !this.dma_enable);
}
result
}
}
#[cfg(feature = "dma")]
impl LptimDmaTransfer<'_> {
pub fn wait_blocking(mut self) -> Result<(), crate::dma::Error> {
let result = self
.transfer
.take()
.expect("transfer already consumed")
.wait_blocking();
self.regs.DIER().modify(|w| w.0 &= !self.dma_enable);
result
}
}
#[cfg(feature = "dma")]
impl Drop for LptimDmaTransfer<'_> {
fn drop(&mut self) {
drop(self.transfer.take());
self.regs.DIER().modify(|w| w.0 &= !self.dma_enable);
}
}
#[cfg(feature = "dma")]
pub struct RingBufferedPwm<'a> {
pwm: Pwm,
channel: Channel,
ring: Option<WritableRingBuffer<'a, u16>>,
}
#[cfg(feature = "dma")]
impl<'a> RingBufferedPwm<'a> {
pub fn write_immediate(&mut self, values: &[u16]) -> Result<(usize, usize), RingError> {
self.ring_mut().write_immediate(values)
}
pub fn start(&mut self) {
self.pwm.timer.regs.DIER().modify(|w| w.0 |= DIER_UEDE);
self.ring_mut().start();
}
pub fn write(&mut self, values: &[u16]) -> Result<(usize, usize), RingError> {
self.ring_mut().write(values)
}
pub async fn write_exact(&mut self, values: &[u16]) -> Result<usize, RingError> {
self.ring_mut().write_exact(values).await
}
pub fn len(&self) -> Result<usize, RingError> {
self.ring.as_ref().expect("ring has been released").len()
}
pub fn is_empty(&self) -> Result<bool, RingError> {
self.ring
.as_ref()
.expect("ring has been released")
.is_empty()
}
pub fn capacity(&self) -> usize {
self.ring
.as_ref()
.expect("ring has been released")
.capacity()
}
pub fn pause(&mut self) {
self.ring_mut().pause();
}
pub fn resume(&mut self) {
self.ring_mut().resume();
}
pub fn is_running(&self) -> bool {
self.ring
.as_ref()
.expect("ring has been released")
.is_running()
}
pub async fn stop(&mut self) {
self.ring_mut().stop().await;
self.pwm.timer.regs.DIER().modify(|w| w.0 &= !DIER_UEDE);
}
pub const fn channel(&self) -> Channel {
self.channel
}
fn ring_mut(&mut self) -> &mut WritableRingBuffer<'a, u16> {
self.ring.as_mut().expect("ring has been released")
}
}
#[cfg(feature = "dma")]
impl Drop for RingBufferedPwm<'_> {
fn drop(&mut self) {
drop(self.ring.take());
self.pwm.timer.regs.DIER().modify(|w| w.0 &= !DIER_UEDE);
}
}
#[cfg(feature = "dma")]
pub struct RingBufferedCapture<'a> {
capture: InputCapture,
channel: Channel,
ring: Option<ReadableRingBuffer<'a, u16>>,
}
#[cfg(feature = "dma")]
impl<'a> RingBufferedCapture<'a> {
pub fn start(&mut self) {
let enable = capture_dma_enable(self.channel);
self.capture.timer.regs.DIER().modify(|w| w.0 |= enable);
self.ring_mut().start();
}
pub fn read(&mut self, values: &mut [u16]) -> Result<(usize, usize), RingError> {
self.ring_mut().read(values)
}
pub async fn read_exact(&mut self, values: &mut [u16]) -> Result<usize, RingError> {
self.ring_mut().read_exact(values).await
}
pub fn read_latest(&mut self, values: &mut [u16]) -> Result<usize, RingError> {
self.ring_mut().read_latest(values)
}
pub fn len(&self) -> Result<usize, RingError> {
self.ring.as_ref().expect("ring has been released").len()
}
pub fn is_empty(&self) -> Result<bool, RingError> {
self.ring
.as_ref()
.expect("ring has been released")
.is_empty()
}
pub fn capacity(&self) -> usize {
self.ring
.as_ref()
.expect("ring has been released")
.capacity()
}
pub fn pause(&mut self) {
self.ring_mut().pause();
}
pub fn resume(&mut self) {
self.ring_mut().resume();
}
pub fn is_running(&self) -> bool {
self.ring
.as_ref()
.expect("ring has been released")
.is_running()
}
pub async fn stop(&mut self) {
self.ring_mut().stop().await;
let enable = capture_dma_enable(self.channel);
self.capture.timer.regs.DIER().modify(|w| w.0 &= !enable);
}
fn ring_mut(&mut self) -> &mut ReadableRingBuffer<'a, u16> {
self.ring.as_mut().expect("ring has been released")
}
}
#[cfg(feature = "dma")]
impl Drop for RingBufferedCapture<'_> {
fn drop(&mut self) {
drop(self.ring.take());
let enable = capture_dma_enable(self.channel);
self.capture.timer.regs.DIER().modify(|w| w.0 &= !enable);
}
}
fn compute_period(clock_hz: u32, frequency_hz: u32) -> Result<(u8, u16), Error> {
if frequency_hz == 0 || frequency_hz > clock_hz {
return Err(Error::FrequencyOutOfRange);
}
let ticks = clock_hz / frequency_hz;
for prescaler in 0..=7 {
let divided = ticks / (1u32 << prescaler);
if (1..=u16::MAX as u32 + 1).contains(÷d) {
return Ok((prescaler, (divided - 1) as u16));
}
}
Err(Error::FrequencyOutOfRange)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn selects_smallest_prescaler() {
assert_eq!(compute_period(32_768, 1), Ok((0, 32_767)));
assert_eq!(compute_period(100_000_000, 100), Ok((4, 62_499)));
}
#[test]
fn configures_pwm_and_capture_channels() {
static STATE: State = State::new();
let mut registers = [0u32; 256];
let timer = unsafe {
LowPowerTimer::over(
LPTIM::from_ptr(registers.as_mut_ptr().cast()),
LptimId::Lptim1,
32_768,
&STATE,
)
};
let mut pwm = timer.into_pwm(128).unwrap();
pwm.enable(Channel::Ch2);
pwm.set_duty_cycle(Channel::Ch2, 64);
assert_ne!(registers[0x2c / 4] & (1 << 17), 0);
assert_eq!(registers[0x34 / 4], 64);
}
}