stm32f1xx-hal icon indicating copy to clipboard operation
stm32f1xx-hal copied to clipboard

How to get several delays

Open JPFrancoia opened this issue 5 years ago • 8 comments

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 ?

JPFrancoia avatar Nov 05 '19 20:11 JPFrancoia

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());
    }
}

TheZoq2 avatar Nov 05 '19 20:11 TheZoq2

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;
        }
    }

JPFrancoia avatar Nov 06 '19 17:11 JPFrancoia

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 :)

TheZoq2 avatar Nov 07 '19 08:11 TheZoq2

Indeed, there're HAL impls which have it, but not in the STM32 domain it seems.

therealprof avatar Nov 07 '19 09:11 therealprof

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.

jkristell avatar Nov 07 '19 09:11 jkristell

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.

geomatsi avatar Nov 07 '19 10:11 geomatsi

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.

geomatsi avatar Nov 07 '19 10:11 geomatsi

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.

thalesfragoso avatar Nov 22 '19 20:11 thalesfragoso