golemparts / rppal

A Rust library that provides access to the Raspberry Pi's GPIO, I2C, PWM, SPI and UART peripherals.
MIT License
1.24k stars 98 forks source link

Update SimpleHalSpiDevice transaction to execute all the operations together in a transaction #152

Closed whatisbyandby closed 3 months ago

whatisbyandby commented 3 months ago

This should resolve Issue https://github.com/golemparts/rppal/issues/151

whatisbyandby commented 3 months ago

I finished the code, and it seems to be working as expected when I interact with the RFM69 chip I have connected to the Raspberry Pi. I wanted to submit the code, so you could provide feedback, but before it's merged I'd like to ensure everything looks good on the oscilloscope. I should have time to do that tomorrow.

Cheers

golemparts commented 3 months ago

Thanks for the PR! From a quick glance, the code changes look good. I won't have time to run any tests on this myself, so I'm looking forward to your results before merging.

whatisbyandby commented 3 months ago

I think things are looking good.

Here is the code snippet I used for testing

use embedded_hal::spi::{Operation, SpiDevice};
use rppal::spi::{Bus, Mode, Segment, SimpleHalSpiDevice, SlaveSelect, Spi};
use std::time::Instant;

fn main() {
    let spi = Spi::new(Bus::Spi0, SlaveSelect::Ss0, 1_000_000, Mode::Mode1).unwrap();

    let mut read_buff: [u8; 1] = [0x00];
    let write_buff:[u8; 1] = [0x01];

    let segments = [Segment::with_write(&write_buff), Segment::with_read(&mut read_buff)];

    spi.transfer_segments(&segments).unwrap();

    // Verify the spi_device.transactions executes all operations in the same transaction
    let mut spi_device = SimpleHalSpiDevice::new(spi);
    let mut operations = [Operation::Write(&write_buff), Operation::Read(&mut read_buff)];

    let now = Instant::now();
    spi_device.transaction(&mut operations).unwrap();
    let elapsed = now.elapsed();

    // Verify the delay is actually adding a delay
    let mut read_buff_with_delay: [u8; 1] = [0x00];

    let mut operations_with_delay = [Operation::Write(&write_buff), Operation::DelayNs(65_000), Operation::Read(&mut read_buff_with_delay), Operation::DelayNs(65_000)];

    let now_with_delay = Instant::now();
    spi_device.transaction(&mut operations_with_delay).unwrap();
    let elapsed_with_delay = now_with_delay.elapsed();

    println!("No Delay: {:?}", elapsed);
    println!("With Delay: {:?}", elapsed_with_delay);

    let difference = elapsed_with_delay.checked_sub(elapsed).unwrap();
    println!("Difference: {:?}", difference);

}

and the results

image SDS00001 SDS00002

So now the operations seems to be all executed while the CS pin is held low, and the delay seems to be getting applied. The delay doesn't seem to be super precise, and it tends to add more delay that is specified, but I'm not sure how large of a concern that is.