Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Added

- `count_down` constructor for `Timer` -> `CountDownTimer` without start [#382]
- Implementation of RTIC Monotonic for TIM2 & TIM5 under `rtic` feature [#380]
- `IoPin` for `Output<OpenDrain>> <-> Input<Floating>>` [#374]

[#382]: https://github.com/stm32-rs/stm32f4xx-hal/pull/382
[#380]: https://github.com/stm32-rs/stm32f4xx-hal/pull/380
[#374]: https://github.com/stm32-rs/stm32f4xx-hal/pull/374

### Changed

- [breaking-change] Remove all deprecated
- [breaking-change] Bump `stm32f4` to 0.14. Update RTIC based examples to use `rtic` 0.6 [#367]
- [breaking-change] Bump `bxcan` to 0.6 [#371]

Expand Down
3 changes: 2 additions & 1 deletion examples/analog-stopwatch-with-spi-ssd1306.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ fn main() -> ! {
disp.flush().unwrap();

// Create a 1ms periodic interrupt from TIM2
let mut timer = Timer::new(dp.TIM2, &clocks).start_count_down(1.hz());
let mut timer = Timer::new(dp.TIM2, &clocks).count_down();
timer.start(1.hz());
timer.listen(Event::TimeOut);

free(|cs| {
Expand Down
3 changes: 2 additions & 1 deletion examples/blinky-timer-irq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ fn main() -> ! {
cortex_m::interrupt::free(|cs| *G_LED.borrow(cs).borrow_mut() = Some(led));

// Set up a timer expiring after 1s
let mut timer = Timer::new(dp.TIM2, &clocks).start_count_down(1.hz());
let mut timer = Timer::new(dp.TIM2, &clocks).count_down();
timer.start(1.hz());

// Generate an interrupt when the timer expires
timer.listen(Event::TimeOut);
Expand Down
3 changes: 2 additions & 1 deletion examples/stopwatch-with-ssd1306-and-interrupts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ fn main() -> ! {
disp.flush().unwrap();

// Create a 1ms periodic interrupt from TIM2
let mut timer = Timer::new(dp.TIM2, &clocks).start_count_down(1.hz());
let mut timer = Timer::new(dp.TIM2, &clocks).count_down();
timer.start(1.hz());
timer.listen(Event::TimeOut);

free(|cs| {
Expand Down
3 changes: 2 additions & 1 deletion examples/timer-periph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ fn main() -> ! {
let clocks = rcc.cfgr.sysclk(24.mhz()).freeze();

// Create a timer based on SysTick
let mut timer = Timer::new(dp.TIM1, &clocks).start_count_down(1.hz());
let mut timer = Timer::new(dp.TIM1, &clocks).count_down();
timer.start(1.hz());

hprintln!("hello!").unwrap();
// wait until timer expires
Expand Down
3 changes: 2 additions & 1 deletion examples/timer-syst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ fn main() -> ! {
let clocks = rcc.cfgr.sysclk(24.mhz()).freeze();

// Create a timer based on SysTick
let mut timer = Timer::syst(cp.SYST, &clocks).start_count_down(24.hz());
let mut timer = Timer::syst(cp.SYST, &clocks).count_down();
timer.start(24.hz());

hprintln!("hello!").unwrap();
// wait until timer expires
Expand Down
16 changes: 9 additions & 7 deletions src/delay/timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ use core::cmp::max;
use cast::{u16, u32};
use embedded_hal::blocking::delay::{DelayMs, DelayUs};

use crate::{pac, rcc::Clocks, timer::Timer};
use crate::{
pac,
rcc::Clocks,
timer::{General, Timer},
};

use super::Delay;

Expand All @@ -17,25 +21,23 @@ macro_rules! hal {
$(
fn $waitfn(tim: &mut $TIM, prescaler: u16, auto_reload_register: u32) {
// Write Prescaler (PSC)
tim.psc.write(|w| w.psc().bits(prescaler));
tim.set_prescaler(prescaler);

// Write Auto-Reload Register (ARR)
// Note: Make it impossible to set the ARR value to 0, since this
// would cause an infinite loop.
tim.arr.write(|w| unsafe { w.bits(max(1, auto_reload_register)) });
tim.set_auto_reload(max(1, auto_reload_register)).unwrap();

// Trigger update event (UEV) in the event generation register (EGR)
// in order to immediately apply the config
tim.cr1.modify(|_, w| w.urs().set_bit());
tim.egr.write(|w| w.ug().set_bit());
tim.cr1.modify(|_, w| w.urs().clear_bit());
tim.trigger_update();

// Configure the counter in one-pulse mode (counter stops counting at
// the next updateevent, clearing the CEN bit) and enable the counter.
tim.cr1.write(|w| w.opm().set_bit().cen().set_bit());

// Wait for CEN bit to clear
while tim.cr1.read().cen().is_enabled() { /* wait */ }
while tim.is_counter_enabled() { /* wait */ }
}

impl Timer<$TIM> {
Expand Down
183 changes: 26 additions & 157 deletions src/pwm.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
use crate::{bb, hal as pwm, time::Hertz, timer::Timer};
use cast::{u16, u32};
use crate::{
bb, hal as pwm,
time::Hertz,
timer::{General, Timer},
};
use cast::u16;
use core::{marker::PhantomData, mem::MaybeUninit};

pub trait Pins<TIM, P> {
Expand Down Expand Up @@ -112,19 +116,19 @@ macro_rules! pwm_pin {
//NOTE(unsafe) atomic read with no side effects
#[inline]
pub fn get_duty(&self) -> u16 {
unsafe { (*<$TIMX>::ptr()).$ccr.read().ccr().bits() as u16 }
unsafe { (*<$TIMX>::ptr()).$ccr.read().bits() as u16 }
}

//NOTE(unsafe) atomic read with no side effects
#[inline]
pub fn get_max_duty(&self) -> u16 {
unsafe { (*<$TIMX>::ptr()).arr.read().arr().bits() as u16 }
unsafe { (*<$TIMX>::ptr()).arr.read().bits() as u16 }
}

//NOTE(unsafe) atomic write with no side effects
#[inline]
pub fn set_duty(&mut self, duty: u16) {
unsafe { (*<$TIMX>::ptr()).$ccr.write(|w| w.ccr().bits(duty.into())) }
unsafe { (*<$TIMX>::ptr()).$ccr.write(|w| w.bits(duty.into())) }
}
}

Expand Down Expand Up @@ -153,7 +157,7 @@ macro_rules! pwm_all_channels {
($($TIMX:ident,)+) => {
$(
impl Timer<crate::pac::$TIMX> {
pub fn pwm<P, PINS, T>(self, _pins: PINS, freq: T) -> PINS::Channels
pub fn pwm<P, PINS, T>(mut self, _pins: PINS, freq: T) -> PINS::Channels
where
PINS: Pins<crate::pac::$TIMX, P>,
T: Into<Hertz>,
Expand Down Expand Up @@ -182,14 +186,12 @@ macro_rules! pwm_all_channels {

let ticks = self.clk.0 / freq.into().0;
let psc = (ticks - 1) / (1 << 16);
self.tim.psc.write(|w| w.psc().bits(u16(psc).unwrap()) );
let arr = u16(ticks / (psc + 1)).unwrap();
self.tim.arr.write(|w| unsafe { w.bits(u32(arr)) });
self.tim.set_prescaler(u16(psc).unwrap());
let arr = ticks / (psc + 1);
self.tim.set_auto_reload(arr).unwrap();

// Trigger update event to load the registers
self.tim.cr1.modify(|_, w| w.urs().set_bit());
self.tim.egr.write(|w| w.ug().set_bit());
self.tim.cr1.modify(|_, w| w.urs().clear_bit());
self.tim.trigger_update();

let _tim = &self.tim;
brk!($TIMX, _tim);
Expand Down Expand Up @@ -220,7 +222,7 @@ macro_rules! pwm_2_channels {
($($TIMX:ident,)+) => {
$(
impl Timer<crate::pac::$TIMX> {
pub fn pwm<P, PINS, T>(self, _pins: PINS, freq: T) -> PINS::Channels
pub fn pwm<P, PINS, T>(mut self, _pins: PINS, freq: T) -> PINS::Channels
where
PINS: Pins<crate::pac::$TIMX, P>,
T: Into<Hertz>,
Expand All @@ -245,14 +247,12 @@ macro_rules! pwm_2_channels {

let ticks = self.clk.0 / freq.into().0;
let psc = (ticks - 1) / (1 << 16);
self.tim.psc.write(|w| w.psc().bits(u16(psc).unwrap()) );
let arr = u16(ticks / (psc + 1)).unwrap();
self.tim.arr.write(|w| unsafe { w.bits(u32(arr)) });
self.tim.set_prescaler(u16(psc).unwrap());
let arr = ticks / (psc + 1);
self.tim.set_auto_reload(arr).unwrap();

// Trigger update event to load the registers
self.tim.cr1.modify(|_, w| w.urs().set_bit());
self.tim.egr.write(|w| w.ug().set_bit());
self.tim.cr1.modify(|_, w| w.urs().clear_bit());
self.tim.trigger_update();

self.tim.cr1.write(|w|
w.opm()
Expand All @@ -275,7 +275,7 @@ macro_rules! pwm_1_channel {
($($TIMX:ident,)+) => {
$(
impl Timer<crate::pac::$TIMX> {
pub fn pwm<P, PINS, T>(self, _pins: PINS, freq: T) -> PINS::Channels
pub fn pwm<P, PINS, T>(mut self, _pins: PINS, freq: T) -> PINS::Channels
where
PINS: Pins<crate::pac::$TIMX, P>,
T: Into<Hertz>,
Expand All @@ -295,14 +295,12 @@ macro_rules! pwm_1_channel {

let ticks = self.clk.0 / freq.into().0;
let psc = (ticks - 1) / (1 << 16);
self.tim.psc.write(|w| w.psc().bits(u16(psc).unwrap()) );
let arr = u16(ticks / (psc + 1)).unwrap();
self.tim.arr.write(|w| unsafe { w.bits(u32(arr)) });
self.tim.set_prescaler(u16(psc).unwrap());
let arr = ticks / (psc + 1);
self.tim.set_auto_reload(arr).unwrap();

// Trigger update event to load the registers
self.tim.cr1.modify(|_, w| w.urs().set_bit());
self.tim.egr.write(|w| w.ug().set_bit());
self.tim.cr1.modify(|_, w| w.urs().clear_bit());
self.tim.trigger_update();

self.tim.cr1.write(|w|
w.cen()
Expand All @@ -318,133 +316,7 @@ macro_rules! pwm_1_channel {
};
}

#[cfg(feature = "stm32f410")]
macro_rules! pwm_pin_tim5 {
($TIMX:ty, $C:ty, $ccr: ident, $bit:literal) => {
impl PwmChannels<$TIMX, $C> {
//NOTE(unsafe) atomic write with no side effects
#[inline]
pub fn disable(&mut self) {
unsafe { bb::clear(&(*<$TIMX>::ptr()).ccer, 0) }
}

//NOTE(unsafe) atomic write with no side effects
#[inline]
pub fn enable(&mut self) {
unsafe { bb::set(&(*<$TIMX>::ptr()).ccer, 0) }
}

//NOTE(unsafe) atomic read with no side effects
#[inline]
pub fn get_duty(&self) -> u16 {
unsafe { (*<$TIMX>::ptr()).$ccr.read().ccr1_l().bits() as u16 }
}

//NOTE(unsafe) atomic read with no side effects
#[inline]
pub fn get_max_duty(&self) -> u16 {
unsafe { (*<$TIMX>::ptr()).arr.read().arr_l().bits() as u16 }
}

//NOTE(unsafe) atomic write with no side effects
#[inline]
pub fn set_duty(&mut self, duty: u16) {
unsafe {
(*<$TIMX>::ptr())
.$ccr
.write(|w| w.ccr1_l().bits(duty.into()))
}
}
}

impl pwm::PwmPin for PwmChannels<$TIMX, $C> {
type Duty = u16;
fn disable(&mut self) {
self.disable()
}
fn enable(&mut self) {
self.enable()
}
fn get_duty(&self) -> Self::Duty {
self.get_duty()
}
fn get_max_duty(&self) -> Self::Duty {
self.get_max_duty()
}
fn set_duty(&mut self, duty: Self::Duty) {
self.set_duty(duty)
}
}
};
}

#[cfg(feature = "stm32f410")]
macro_rules! pwm_tim5_f410 {
($($TIMX:ident,)+) => {
$(
impl Timer<crate::pac::$TIMX> {
pub fn pwm<P, PINS, T>(self, _pins: PINS, freq: T) -> PINS::Channels
where
PINS: Pins<crate::pac::$TIMX, P>,
T: Into<Hertz>,
{
if PINS::C1 {
self.tim.ccmr1_output()
.modify(|_, w| w.oc1pe().set_bit().oc1m().pwm_mode1() );
}
if PINS::C2 {
self.tim.ccmr1_output()
.modify(|_, w| w.oc2pe().set_bit().oc2m().pwm_mode1() );
}
if PINS::C3 {
self.tim.ccmr2_output()
.modify(|_, w| w.oc3pe().set_bit().oc3m().pwm_mode1() );
}
if PINS::C4 {
self.tim.ccmr2_output()
.modify(|_, w| w.oc4pe().set_bit().oc4m().pwm_mode1() );
}

// The reference manual is a bit ambiguous about when enabling this bit is really
// necessary, but since we MUST enable the preload for the output channels then we
// might as well enable for the auto-reload too
self.tim.cr1.modify(|_, w| w.arpe().set_bit());

let ticks = self.clk.0 / freq.into().0;
let psc = (ticks - 1) / (1 << 16);
self.tim.psc.write(|w| w.psc().bits(u16(psc).unwrap()) );
let arr = u16(ticks / (psc + 1)).unwrap();
self.tim.arr.write(|w| unsafe { w.arr_l().bits(arr) });

// Trigger update event to load the registers
self.tim.cr1.modify(|_, w| w.urs().set_bit());
self.tim.egr.write(|w| w.ug().set_bit());
self.tim.cr1.modify(|_, w| w.urs().clear_bit());

self.tim.cr1.write(|w|
w.cms()
.bits(0b00)
.dir()
.clear_bit()
.opm()
.clear_bit()
.cen()
.set_bit()
);
//NOTE(unsafe) `PINS::Channels` is a ZST
unsafe { MaybeUninit::uninit().assume_init() }
}
}

pwm_pin_tim5!(crate::pac::$TIMX, C1, ccr1, 0);
pwm_pin_tim5!(crate::pac::$TIMX, C2, ccr2, 4);
pwm_pin_tim5!(crate::pac::$TIMX, C3, ccr3, 8);
pwm_pin_tim5!(crate::pac::$TIMX, C4, ccr4, 12);
)+
};
}

pwm_all_channels!(TIM1,);
pwm_all_channels!(TIM1, TIM5,);

pwm_2_channels!(TIM9,);

Expand All @@ -468,7 +340,7 @@ pwm_1_channel!(TIM11,);
feature = "stm32f469",
feature = "stm32f479"
))]
pwm_all_channels!(TIM2, TIM3, TIM4, TIM5,);
pwm_all_channels!(TIM2, TIM3, TIM4,);

#[cfg(any(
feature = "stm32f401",
Expand Down Expand Up @@ -543,6 +415,3 @@ pwm_2_channels!(TIM12,);
feature = "stm32f479"
))]
pwm_1_channel!(TIM13, TIM14,);

#[cfg(feature = "stm32f410")]
pwm_tim5_f410!(TIM5,);
Loading