-
Notifications
You must be signed in to change notification settings - Fork 218
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
SPI: Implement more SPI traits from embedded-hal 1.0.0-alpha.8 (#101)
* common/spi: Turn fifo size into const instead of hard-coding it into the code in various places. * common/spi: Alias `write_bytes` to `send_bytes` since they share the same interface and the same code anyway. * common/spi: Implement `read_bytes` as counterpart to `send_bytes` that is responsible only for reading bytes received via SPI. * common/spi: Rewrite `transfer` to use `send_bytes` and `read_bytes` under the hood and remove duplicate code. * common/spi: Create submodule for embedded_hal_1 that is re-exported when the `eh1` feature flag is active. This removes lots of duplicate `#[cfg(...)]` macros previously part of the code. * common/spi: Implement `SpiBus` and `SpiBusWrite` traits from the `embedded-hal 1.0.0-alpha.8`. * common/spi: Make `mosi` pin optional * esp32-hal: Add new SPI example with `eh1` traits * esp32-hal/examples/spi_eh1: Add huge transfer and bump the SPI speed to 1 MHz. * common/spi: Apply rustfmt * common/spi: Use `memcpy` to read from registers This cuts down the time between consecutive transfers from about 2 ms to less than 1 ms. * WIP: common/spi: Use `ptr::copy` to fill write FIFO cutting down the time between transfers from just below 1 ms to ~370 us. The implementation is currently broken in that it will always fill the entire FIFO from the input it is given, even if that isn't FIFO-sized... * common/spi: Add more documentation * esp32/examples/spi_eh1: Fix `transfer_in_place` * esp32/examples/spi_eh1: Add conditional compile and compile a dummy instead when the "eh1" feature isn't present. * esp32-hal: Ignore spi_eh1 example in normal builds, where the feature flag "eh1" isn't given. Building the example directly via `cargo build --example spi_eh1_loopback` will now print an error that this requires a feature flag to be active. * common/spi: Use `write_bytes` and drop `send_bytes` instead. Previoulsy, both served the same purpose, but `send_bytes` was introduced more recently and is hence less likely to cause breaking changes in existing code. * common/spi: Fix mosi pin setup * Add SPI examples with ehal 1.0.0-alpha8 traits to all targets. * common/spi: Fix `read` behavior The previous `read` implementation would only read the contents of the SPI receive FIFO and return that as data. However, the `SpiBusRead` trait defines that while reading, bytes should be written out to the bus (Because SPI is transactional, without writing nothing can be read). Reimplements the `embedded-hal` traits to correctly implement this behavior. * common/spi: Use full FIFO size on all variants All esp variants except for the esp32s2 have a 64 byte FIFO, whereas the esp32s2 has a 72 byte FIFO. * common/spi: Use common pad byte for empty writes * common/spi: Fix reading bytes from FIFO by reverting to the old method of reading 32 bytes at a time and assembling the return buffer from that. It turns out that the previous `core::slice::from_raw_parts()` doesn't work for the esp32s2 and esp32s3 variants, returning bogus data even though the correct data is present in the registers. * common/spi: Fix typos * examples: Fix spi_eh1_loopback examples
- Loading branch information
Showing
9 changed files
with
743 additions
and
107 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
//! SPI loopback test | ||
//! | ||
//! Folowing pins are used: | ||
//! SCLK GPIO19 | ||
//! MISO GPIO25 | ||
//! MOSI GPIO23 | ||
//! CS GPIO22 | ||
//! | ||
//! Depending on your target and the board you are using you have to change the | ||
//! pins. | ||
//! | ||
//! This example transfers data via SPI. | ||
//! Connect MISO and MOSI pins to see the outgoing data is read as incoming | ||
//! data. | ||
|
||
#![no_std] | ||
#![no_main] | ||
|
||
use core::fmt::Write; | ||
|
||
use esp32_hal::{ | ||
clock::ClockControl, | ||
gpio::IO, | ||
pac::Peripherals, | ||
prelude::*, | ||
spi::{Spi, SpiMode}, | ||
timer::TimerGroup, | ||
Delay, | ||
Rtc, | ||
Serial, | ||
}; | ||
use panic_halt as _; | ||
use xtensa_lx_rt::entry; | ||
|
||
use embedded_hal_1::spi::blocking::SpiBus; | ||
|
||
#[entry] | ||
fn main() -> ! { | ||
let peripherals = Peripherals::take().unwrap(); | ||
let mut system = peripherals.DPORT.split(); | ||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); | ||
|
||
// Disable the watchdog timers. For the ESP32-C3, this includes the Super WDT, | ||
// the RTC WDT, and the TIMG WDTs. | ||
let mut rtc = Rtc::new(peripherals.RTC_CNTL); | ||
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks); | ||
let mut wdt = timer_group0.wdt; | ||
let mut serial0 = Serial::new(peripherals.UART0); | ||
|
||
wdt.disable(); | ||
rtc.rwdt.disable(); | ||
|
||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); | ||
let sclk = io.pins.gpio19; | ||
let miso = io.pins.gpio25; | ||
let mosi = io.pins.gpio23; | ||
let cs = io.pins.gpio22; | ||
|
||
let mut spi = Spi::new( | ||
peripherals.SPI2, | ||
sclk, | ||
mosi, | ||
miso, | ||
cs, | ||
1000u32.kHz(), | ||
SpiMode::Mode0, | ||
&mut system.peripheral_clock_control, | ||
&clocks, | ||
); | ||
|
||
let mut delay = Delay::new(&clocks); | ||
writeln!(serial0, "=== SPI example with embedded-hal-1 traits ===").unwrap(); | ||
|
||
loop { | ||
// --- Symmetric transfer (Read as much as we write) --- | ||
write!(serial0, "Starting symmetric transfer...").unwrap(); | ||
let write = [0xde, 0xad, 0xbe, 0xef]; | ||
let mut read: [u8; 4] = [0x00u8; 4]; | ||
|
||
SpiBus::transfer(&mut spi, &mut read[..], &write[..]).expect("Symmetric transfer failed"); | ||
assert_eq!(write, read); | ||
writeln!(serial0, " SUCCESS").unwrap(); | ||
delay.delay_ms(250u32); | ||
|
||
|
||
// --- Asymmetric transfer (Read more than we write) --- | ||
write!(serial0, "Starting asymetric transfer (read > write)...").unwrap(); | ||
let mut read: [u8; 4] = [0x00; 4]; | ||
|
||
SpiBus::transfer(&mut spi, &mut read[0..2], &write[..]).expect("Asymmetric transfer failed"); | ||
assert_eq!(write[0], read[0]); | ||
assert_eq!(read[2], 0x00u8); | ||
writeln!(serial0, " SUCCESS").unwrap(); | ||
delay.delay_ms(250u32); | ||
|
||
|
||
// --- Symmetric transfer with huge buffer --- | ||
// Only your RAM is the limit! | ||
write!(serial0, "Starting huge transfer...").unwrap(); | ||
let mut write = [0x55u8; 4096]; | ||
for byte in 0..write.len() { | ||
write[byte] = byte as u8; | ||
} | ||
let mut read = [0x00u8; 4096]; | ||
|
||
SpiBus::transfer(&mut spi, &mut read[..], &write[..]).expect("Huge transfer failed"); | ||
assert_eq!(write, read); | ||
writeln!(serial0, " SUCCESS").unwrap(); | ||
delay.delay_ms(250u32); | ||
|
||
|
||
// --- Symmetric transfer with huge buffer in-place (No additional allocation needed) --- | ||
write!(serial0, "Starting huge transfer (in-place)...").unwrap(); | ||
let mut write = [0x55u8; 4096]; | ||
for byte in 0..write.len() { | ||
write[byte] = byte as u8; | ||
} | ||
|
||
SpiBus::transfer_in_place(&mut spi, &mut write[..]).expect("Huge transfer failed"); | ||
for byte in 0..write.len() { | ||
assert_eq!(write[byte], byte as u8); | ||
} | ||
writeln!(serial0, " SUCCESS").unwrap(); | ||
delay.delay_ms(250u32); | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
//! SPI loopback test | ||
//! | ||
//! Folowing pins are used: | ||
//! SCLK GPIO6 | ||
//! MISO GPIO2 | ||
//! MOSI GPIO7 | ||
//! CS GPIO10 | ||
//! | ||
//! Depending on your target and the board you are using you have to change the | ||
//! pins. | ||
//! | ||
//! This example transfers data via SPI. | ||
//! Connect MISO and MOSI pins to see the outgoing data is read as incoming | ||
//! data. | ||
|
||
#![no_std] | ||
#![no_main] | ||
|
||
use core::fmt::Write; | ||
|
||
use esp32c3_hal::{ | ||
clock::ClockControl, | ||
gpio::IO, | ||
pac::Peripherals, | ||
prelude::*, | ||
spi::{Spi, SpiMode}, | ||
timer::TimerGroup, | ||
Delay, | ||
Rtc, | ||
Serial, | ||
}; | ||
use panic_halt as _; | ||
use riscv_rt::entry; | ||
|
||
use embedded_hal_1::spi::blocking::SpiBus; | ||
|
||
#[entry] | ||
fn main() -> ! { | ||
let peripherals = Peripherals::take().unwrap(); | ||
let mut system = peripherals.SYSTEM.split(); | ||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); | ||
|
||
// Disable the watchdog timers. For the ESP32-C3, this includes the Super WDT, | ||
// the RTC WDT, and the TIMG WDTs. | ||
let mut rtc = Rtc::new(peripherals.RTC_CNTL); | ||
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks); | ||
let mut wdt0 = timer_group0.wdt; | ||
let timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks); | ||
let mut wdt1 = timer_group1.wdt; | ||
|
||
let mut serial0 = Serial::new(peripherals.UART0); | ||
|
||
rtc.swd.disable(); | ||
rtc.rwdt.disable(); | ||
wdt0.disable(); | ||
wdt1.disable(); | ||
|
||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); | ||
let sclk = io.pins.gpio6; | ||
let miso = io.pins.gpio2; | ||
let mosi = io.pins.gpio7; | ||
let cs = io.pins.gpio10; | ||
|
||
let mut spi = Spi::new( | ||
peripherals.SPI2, | ||
sclk, | ||
mosi, | ||
miso, | ||
cs, | ||
1000u32.kHz(), | ||
SpiMode::Mode0, | ||
&mut system.peripheral_clock_control, | ||
&clocks, | ||
); | ||
|
||
let mut delay = Delay::new(&clocks); | ||
writeln!(serial0, "=== SPI example with embedded-hal-1 traits ===").unwrap(); | ||
|
||
loop { | ||
// --- Symmetric transfer (Read as much as we write) --- | ||
write!(serial0, "Starting symmetric transfer...").unwrap(); | ||
let write = [0xde, 0xad, 0xbe, 0xef]; | ||
let mut read: [u8; 4] = [0x00u8; 4]; | ||
|
||
SpiBus::transfer(&mut spi, &mut read[..], &write[..]).expect("Symmetric transfer failed"); | ||
assert_eq!(write, read); | ||
writeln!(serial0, " SUCCESS").unwrap(); | ||
delay.delay_ms(250u32); | ||
|
||
|
||
// --- Asymmetric transfer (Read more than we write) --- | ||
write!(serial0, "Starting asymetric transfer (read > write)...").unwrap(); | ||
let mut read: [u8; 4] = [0x00; 4]; | ||
|
||
SpiBus::transfer(&mut spi, &mut read[0..2], &write[..]).expect("Asymmetric transfer failed"); | ||
assert_eq!(write[0], read[0]); | ||
assert_eq!(read[2], 0x00u8); | ||
writeln!(serial0, " SUCCESS").unwrap(); | ||
delay.delay_ms(250u32); | ||
|
||
|
||
// --- Symmetric transfer with huge buffer --- | ||
// Only your RAM is the limit! | ||
write!(serial0, "Starting huge transfer...").unwrap(); | ||
let mut write = [0x55u8; 4096]; | ||
for byte in 0..write.len() { | ||
write[byte] = byte as u8; | ||
} | ||
let mut read = [0x00u8; 4096]; | ||
|
||
SpiBus::transfer(&mut spi, &mut read[..], &write[..]).expect("Huge transfer failed"); | ||
assert_eq!(write, read); | ||
writeln!(serial0, " SUCCESS").unwrap(); | ||
delay.delay_ms(250u32); | ||
|
||
|
||
// --- Symmetric transfer with huge buffer in-place (No additional allocation needed) --- | ||
write!(serial0, "Starting huge transfer (in-place)...").unwrap(); | ||
let mut write = [0x55u8; 4096]; | ||
for byte in 0..write.len() { | ||
write[byte] = byte as u8; | ||
} | ||
|
||
SpiBus::transfer_in_place(&mut spi, &mut write[..]).expect("Huge transfer failed"); | ||
for byte in 0..write.len() { | ||
assert_eq!(write[byte], byte as u8); | ||
} | ||
writeln!(serial0, " SUCCESS").unwrap(); | ||
delay.delay_ms(250u32); | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.