copterust / vl53l0x

vl53l0x
Other
11 stars 8 forks source link

Use interrupts with GPIO1? #8

Closed ChocolateLoverRaj closed 10 months ago

ChocolateLoverRaj commented 10 months ago

I'm new to this sensor. My sensor has a GPIO1 pin, and this documentation says that GPIO1 can be connected to use interrupts instead of polling. Is it possible for this library to support GPIO1? I heard that interrupts use less power, and I'm going to be running an ESP32-C3 and a VL53L0X off of a laptop battery or a AA battery.

little-arhat commented 10 months ago

General wokflow with interrupt based reading: 1) connect interrupt pin from the device to your board 2) enable interrupts on the device (if needed) 3) install interrupt handler in your code 4) once triggered, read measurement from the device

Example of reading mpu9250 readings using embassy.

For VL5310x we'll need to check if special setup is needed for the device and expose settings.

little-arhat commented 10 months ago

In init_hardware we enable interrupts and in read fns we clear interrupt flag, so you should be able to install interrupt handler in your code and read once triggered using read_range_mm (it should then not block or return error).

bofh commented 10 months ago

According to the code interrupt should happen when new sample is available.

ChocolateLoverRaj commented 10 months ago

@little-arhat I followed your instructions and it worked

gpio1.set_pull(Pull::Up).unwrap();
gpio1.set_interrupt_type(InterruptType::NegEdge).unwrap();
gpio1.enable_interrupt().unwrap();

// In the loop
gpio1.wait_for_falling_edge().await.unwrap();
ChocolateLoverRaj commented 10 months ago

It would be nice if there was a struct that could handle the interrupt for you though. Something like this:

let mut vl53l0x = VL53L0x::new_with_gpio1(i2c, peripherals.pins.gpio1).unwrap(); // I connected the VL53L0X's GPIO1 to my ESP32-C3's GPIO1

vl53l0x.set_measurement_timing_budget(20_000).unwrap();
vl53l0x.start_continuous(0).unwrap();

loop {
    let distance = vl53l0x.read_range_async().await.unwrap(); 
}
ChocolateLoverRaj commented 10 months ago

Btw I made a wrapper around this: https://github.com/ChocolateLoverRaj/rust-esp32c3-examples/blob/main/VL53L0X/src/async_vl53l0x.rs

bofh commented 10 months ago

I think wrapper is a good way to go here as it will keep flexibility in driver usage. Say I want to use that interrupt for something else in my main application (performance measurement, timestamping, etc.) and probably adding real async feature would require async i2c, hal, etc.?

ChocolateLoverRaj commented 10 months ago

Say I want to use that interrupt for something else in my main application

@bofh what do u mean by "that interrupt"? Is there a finite amount of interrupts and using gpio1 for interrupts will interfere with other interrupts? Also, If async was added to this crate itself, there would still be two options: with or without gpio1 pin.

probably adding real async feature would require async i2c, hal, etc.?

I tried looking for async i2c, but I didn't see any structs or libraries for that. If you know one can you please send a link so that I can convert as much sync code to async as possible?

I think wrapper is a good way to go here as it will keep flexibility in driver usage

Should I publish my wrapper as a crate on crates.io?

little-arhat commented 10 months ago

Current version of this library is implemented against mostly sync version of embedded-hal. Async version is relatively recent. You can take a look at dependent crates to find libs implementing it async-hal and thus async version of i2c. For exampl, embassy.

"That interrupt" — you can connect multiple devices emitting interrupts to interrupt pin of your board. For example, you can think of detection app, connected to motion sensor, temp sensor, etc — each warking up main up on interrupt.

"Should I publish" — note, GPIO1 pin of the sensor is not the same as GPIO1 pin on your board, and it's up engineer to assemble and connect device pins to board pins, so in that sense your wrapper is quite restrictive, as it forces to use board's GPIO1 pin.

(Aslo, keep in mind, async is not the only way to build interrupt-driven programs in rust in a safe way: there are other approaches, like rtic — that's why it's reasonable to keep device library responsible for comms without imposing anything else on user).

ChocolateLoverRaj commented 10 months ago

My wrapper actually lets you use any pin - https://github.com/ChocolateLoverRaj/rust-esp32c3-examples/blob/main/VL53L0X%2Fsrc%2Fmain.rs#L32. In that line the gpio1 can be replaced by any other gpio1.

bofh commented 10 months ago

Hey, closing this issue as original question was answered. @ChocolateLoverRaj thank you for C3 example, feel free to add link to crate (or wrapper if you will not release it) to readme!

bofh commented 10 months ago

Interesting things about interrupt pin and async in new release: https://blog.rust-embedded.org/embedded-hal-v1/