With after pulls/#11 `mpu.all()` transaction taking 10ns on my device
little-arhat opened this issue · 4 comments
When I updated my mpu version, I saw a second peak on the SPI clock bus, and when looking into it, I found this PR.
As you can see at the bottom of the screen capture, it eats into my time budget.
this is captured with this program:
#[allow(non_snake_case)]
#[interrupt(resources = [LED1, EXTI, MPU, FILTER], priority = 2)]
fn EXTI15_10() {
resources.LED1.set_high();
resources.EXTI.pr.modify(|_, w| w.pr15().set_bit());
let b = resources.MPU.all();
resources.LED1.set_low();
}
the purple trace is the LED1
here is another run with unscaled_all
:
#[allow(non_snake_case)]
#[interrupt(resources = [LED1, EXTI, MPU, FILTER], priority = 2)]
fn EXTI15_10() {
resources.LED1.set_high();
resources.EXTI.pr.modify(|_, w| w.pr15().set_bit());
let b = resources.MPU.unscaled_all();
resources.LED1.set_low();
}
Originally posted by @nraynaud in #11 (comment)
Previously, we've been reading acc, gyro and mag data in one go, like this:
pub fn all(&mut self) -> Result<MargMeasurements, E> {
let buffer = self.dev.read_many::<U21>(Register::ACCEL_XOUT_H)?;
...
with #11 merged, we do it slightly differently:
pub fn all(&mut self) -> Result<MargMeasurements, E> {
let atg_buffer = Device::read_many::<U15>(&mut self.dev, Register::ACCEL_XOUT_H)?;
let mag_buffer = AK8963::read_xyz(&mut self.dev)?;
...
where, AK8963::read_xyz
is needed to allow different implementations for spi
and imu
. However, as read_xyz
for spi
device is implemented like another transaction, we introduce extra overhead.
We have to come up with different implementation, that doesn't incur penalty.
it's getting complicated, what do you think of exposing an API for so that the user does their communication themselve?
Sorry for the trouble; I neglected to highlight that change in #11.
Since the I2C implementation is using I2C passthrough, we perform a direct query of the AK8963. Given the existing abstractions in this crate, this turned into the double transaction, as @little-arhat noted. It was the most straight-forward implementation when I put it together, but there is the overhead of a needless transaction for SPI-based communication.
A resolution could be to move the full 9-DOF query down into the device level. A SPI device can perform the whole 6DOF + temp + mag reading in one transaction; the I2C device would perform the two calls. I could put this together if we're interested, but I welcome any other approaches!
@nraynaud, what might an API for manual communication look like? To take it to the extreme: users are free to steal the register numbers from this crate and implement their own I2C / SPI calls. What could the middle-ground look like?
@mciantyre I guess we can add SixDOFDevice and then users can implement those two however they like.