stm32f1xx-hal
stm32f1xx-hal copied to clipboard
How to get several delays
Hi,
I use an I2C sensor that needs a delay
:
let device_peripherals = pac::Peripherals::take().unwrap();
let cortex_peripherals = cortex_m::Peripherals::take().unwrap();
// ...some code...
let mut delay = Delay::new(cortex_peripherals.SYST, clocks);
let mut sensor = BME280::new_primary(i2c, delay);
sensor.init().unwrap();
loop {
// ...do some stuff...
// delay.delay_ms(3000 as u32);
}
In the loop, I'd like to do some stuff, and wait 3 seconds before looping again. But I can't use the delay
object: it's moved to the I2C sensor. I also can't create a new one, since cortex_peripherals.SYST
is moved to the first delay.
What I could do is free SYST
I guess, and re-initialise the I2C sensor at every loop, but it seems over complicated. I could also re-write the I2C driver, but that also seems overkill.
Is there an easy way to wait in the loop that I don't know about ?
This is indeed a probem. Timing and delays in general is something we should probably improve.
For now, you can try doing something like this
use nb::block;
let timer = Timer::tim2(...);
loop {
timer.start(1.hz());
let iterations = 3;
while iterations > 0 {
block!(timer.wait());
}
}
Ok thanks I'll try that.
However, if I want to use two I2C sensors that both use a delay, I'll be in a dead end right? In this case, should I rewrite the drivers to make use a reference to delay
instead of moving the plain object?
Out of curiosity (please keep in mind that I'm no expert in electronics), why not base delays on timers?
EDIT:
your solution works perfectly with:
let mut timer = Timer::tim2(device_peripherals.TIM2, 1.hz(), clocks, &mut rcc.apb1);
loop {
timer.start(1.hz());
let mut iterations = 3;
while iterations > 0 {
block!(timer.wait());
iterations -= 1;
}
}
However, if I want to use two I2C sensors that both use a delay, I'll be in a dead end right?
Not quite, you could make a wrapper struct around the timersand impl the relevant Delay
traits on that struct.
In this case, should I rewrite the drivers to make use a reference to delay instead of moving the plain object?
This is probably the correct option. Though it would mean that you have to pass the delay to every function that uses it rather than storing it in the struct. You could probably also wrap the delay object in some sort of mutex, impl Delay for that wrapped object and have it shared between both.
Out of curiosity (please keep in mind that I'm no expert in electronics), why not base delays on timers?
There is no electronical reason as far as I'm aware. It's just that nobody has bothered implementing that yet :)
Indeed, there're HAL impls which have it, but not in the STM32 domain it seems.
Indeed, there're HAL impls which have it, but not in the STM32 domain it seems.
I was sure I used them for stm32f4xx, but maybe not. Hmm.
As an alternative solution, I once attempted to create a shared-bus proxy for timers: see https://github.com/Rahix/shared-bus/pull/5. But after review and discussion it turned out that it was not a good idea after all.
If you plan to use RTFM, then you may implement blocking (polling) delays on top of rtfm::Instant, which in its turn is built on top of SysTick. Otherwise it looks like the most straightforward option is to re-use RTFM approach and to implement Delay traits on top of SysTick or any free running timer.
You can also use https://crates.io/crates/asm-delay, but with that you have pretty much no precision if the code of the delay can be interrupted.