Skip to content

How to get several delays #131

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
JPFrancoia opened this issue Nov 5, 2019 · 8 comments
Open

How to get several delays #131

JPFrancoia opened this issue Nov 5, 2019 · 8 comments

Comments

@JPFrancoia
Copy link

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 ?

@TheZoq2
Copy link
Member

TheZoq2 commented Nov 5, 2019

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

@JPFrancoia
Copy link
Author

JPFrancoia commented Nov 6, 2019

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

@TheZoq2
Copy link
Member

TheZoq2 commented Nov 7, 2019

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

@therealprof
Copy link
Member

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

@jkristell
Copy link

jkristell commented Nov 7, 2019

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.

@geomatsi
Copy link
Contributor

geomatsi commented Nov 7, 2019

As an alternative solution, I once attempted to create a shared-bus proxy for timers: see Rahix/shared-bus#5. But after review and discussion it turned out that it was not a good idea after all.

@geomatsi
Copy link
Contributor

geomatsi commented Nov 7, 2019

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.

@thalesfragoso
Copy link
Member

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants