Skip to content

Commit 34fc0c3

Browse files
authored
Merge pull request #228 from akloboucnik/lptimer-irq-fix
Fix LPTIMx configuration on start
2 parents 2b7bd5b + ab77028 commit 34fc0c3

File tree

3 files changed

+130
-9
lines changed

3 files changed

+130
-9
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,6 @@ required-features = ["rt", "stm32l4x6", "otg_fs"]
139139
name = "i2c_write"
140140
required-features = ["stm32l4x1"]
141141

142+
[[example]]
143+
name = "lptim_rtic"
144+
required-features = ["rt", "stm32l4x2"]

examples/lptim_rtic.rs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
//! Test with
2+
//! cargo flash --release --features stm32l4x2,rt --chip STM32L452RETx --example lptim_rtic --target thumbv7em-none-eabi
3+
//! on Nucleo-L452-P board
4+
#![deny(unsafe_code)]
5+
#![no_main]
6+
#![no_std]
7+
extern crate panic_rtt_target;
8+
9+
use rtt_target::rprintln;
10+
use stm32l4xx_hal::{
11+
flash::ACR,
12+
gpio::{gpiob::PB13, Output, PushPull, State},
13+
lptimer::{ClockSource, Event, LowPowerTimer, LowPowerTimerConfig, PreScaler},
14+
pac::LPTIM1,
15+
prelude::*,
16+
pwr::Pwr,
17+
rcc::{ClockSecuritySystem, Clocks, CrystalBypass, RccExt, CFGR},
18+
time::U32Ext,
19+
};
20+
21+
// this is the LD4 on Nucleo-L452-P
22+
type Led = PB13<Output<PushPull>>;
23+
type Timer = LowPowerTimer<LPTIM1>;
24+
25+
pub fn configure_clock_tree(cfgr: CFGR, acr: &mut ACR, pwr: &mut Pwr) -> Clocks {
26+
cfgr.lse(CrystalBypass::Disable, ClockSecuritySystem::Disable)
27+
.sysclk(80.mhz())
28+
.freeze(acr, pwr)
29+
}
30+
31+
#[rtic::app(device = stm32l4xx_hal::pac, peripherals = true)]
32+
const APP: () = {
33+
struct Resources {
34+
led: Led,
35+
lptim: Timer,
36+
}
37+
38+
#[init]
39+
fn init(ctx: init::Context) -> init::LateResources {
40+
rtt_target::rtt_init_print!();
41+
42+
rprintln!("Init start");
43+
let device = ctx.device;
44+
// Configure the clock.
45+
let mut rcc = device.RCC.constrain();
46+
let mut flash = device.FLASH.constrain();
47+
let mut pwr = device.PWR.constrain(&mut rcc.apb1r1);
48+
let mut gpiob = device.GPIOB.split(&mut rcc.ahb2);
49+
let clocks = configure_clock_tree(rcc.cfgr, &mut flash.acr, &mut pwr);
50+
51+
// PB13 is a user led on Nucleo-L452-P board
52+
let led = gpiob.pb13.into_push_pull_output_with_state(
53+
&mut gpiob.moder,
54+
&mut gpiob.otyper,
55+
State::Low,
56+
);
57+
rprintln!("Clocks = {:#?}", clocks);
58+
let lptim_config = LowPowerTimerConfig::default()
59+
.clock_source(ClockSource::LSE)
60+
.prescaler(PreScaler::U1)
61+
.arr_value(32_768u16); // roughly 1s
62+
let mut lptim = LowPowerTimer::lptim1(
63+
device.LPTIM1,
64+
lptim_config,
65+
&mut rcc.apb1r1,
66+
&mut rcc.ccipr,
67+
clocks,
68+
);
69+
lptim.listen(Event::AutoReloadMatch);
70+
init::LateResources { lptim, led }
71+
}
72+
73+
#[task(binds = LPTIM1, resources = [lptim, led])]
74+
fn timer_tick(mut ctx: timer_tick::Context) {
75+
let timer_tick::Resources { lptim, led } = ctx.resources;
76+
if lptim.is_event_triggered(Event::AutoReloadMatch) {
77+
lptim.clear_event_flag(Event::AutoReloadMatch);
78+
rprintln!("LPTIM1 tick");
79+
80+
if led.is_set_high().unwrap() {
81+
led.set_low().unwrap();
82+
} else {
83+
led.set_high().unwrap();
84+
}
85+
}
86+
}
87+
88+
#[idle]
89+
fn idle(_ctx: idle::Context) -> ! {
90+
loop {
91+
// See https://github.com/probe-rs/probe-rs/issues/350
92+
core::hint::spin_loop();
93+
}
94+
}
95+
96+
extern "C" {
97+
fn LCD();
98+
}
99+
};

src/lptimer.rs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -201,17 +201,9 @@ macro_rules! hal {
201201

202202
instance.enable();
203203

204-
// Write compare, arr, and continous mode start register _after_ enabling lptim
205204
instance.start_continuous_mode();
206-
207-
// This operation is sound as arr_value is a u16, and there are 16 writeable bits
208-
instance
209-
.lptim
210-
.arr
211-
.write(|w| unsafe { w.bits(arr_value as u32) });
212-
205+
instance.set_autoreload(arr_value);
213206
instance.set_compare_match(compare_value);
214-
215207
instance
216208
}
217209

@@ -264,9 +256,36 @@ macro_rules! hal {
264256
/// Set the compare match field for this LowPowerTimer
265257
#[inline]
266258
pub fn set_compare_match(&mut self, value: u16) {
259+
// clear compare register update ok flag
260+
self.lptim.icr.write(|w| w.cmpokcf().set_bit());
261+
267262
// This operation is sound as compare_value is a u16, and there are 16 writeable bits
268263
// Additionally, the LPTIM peripheral will always be in the enabled state when this code is called
269264
self.lptim.cmp.write(|w| unsafe { w.bits(value as u32) });
265+
266+
// wait for compare register update ok interrupt to be signalled
267+
// (see RM0394 Rev 4, sec 30.4.10 for further explanation and
268+
// sec. 30.7.1, Bit 4 for register field description)
269+
while self.lptim.isr.read().cmpok().bit_is_clear() {}
270+
}
271+
272+
/// Set auto reload register
273+
/// has to be used _after_ enabling of lptim
274+
#[inline(always)]
275+
pub fn set_autoreload(&mut self, arr_value: u16) {
276+
// clear autoreload register OK interrupt flag
277+
self.lptim.icr.write(|w| w.arrokcf().set_bit());
278+
279+
// Write autoreload value
280+
// This operation is sound as arr_value is a u16, and there are 16 writeable bits
281+
self.lptim
282+
.arr
283+
.write(|w| unsafe { w.bits(arr_value as u32) });
284+
285+
// wait for autoreload write ok interrupt to be signalled
286+
// (see RM0394 Rev 4, sec 30.4.10 for further explanation and
287+
// sec. 30.7.1, Bit 4 for register field description)
288+
while self.lptim.isr.read().arrok().bit_is_clear() {}
270289
}
271290

272291
/// Get the current counter value for this LowPowerTimer

0 commit comments

Comments
 (0)