Skip to content

Commit d317c61

Browse files
authored
spi: Add SPI master implementation (#53)
This adds a master mode implementation for the SPI peripheral. The driver is split such that the core logic is implemented in spi.rs, and the rest is contained within a submodule: - User configuration is split off into the config module - The transaction module encapsulates the different transaction types (read, write, transfer, transfer inplace). Buffer management is abstracted into the transaction type to enable non-blocking usage the peripheral. - The public facing APIs are mostly implemented in the hal module (embedded-hal trait implementations), and the nonblocking module, which exposes a NonBlocking trait that a user needs to explicitly use in order to use the non-blocking APIs (expected to be the less used case, this avoids polluting the public API too much).
1 parent dcf2744 commit d317c61

File tree

10 files changed

+2312
-0
lines changed

10 files changed

+2312
-0
lines changed

examples/spi.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#![deny(warnings)]
2+
#![no_main]
3+
#![no_std]
4+
5+
use cortex_m_rt::entry;
6+
mod utilities;
7+
use embedded_hal::{delay::DelayNs, spi::SpiBus};
8+
use stm32h5xx_hal::{delay::Delay, pac, prelude::*, spi, time::MilliSeconds};
9+
10+
use log::info;
11+
12+
const TEST_STR: &[u8] = b"TEST SPI TESTING, TESTING, TESTING";
13+
14+
#[entry]
15+
fn main() -> ! {
16+
utilities::logger::init();
17+
let cp = cortex_m::Peripherals::take().unwrap();
18+
let dp = pac::Peripherals::take().unwrap();
19+
20+
// Constrain and Freeze power
21+
info!("Setup PWR... ");
22+
let pwr = dp.PWR.constrain();
23+
let pwrcfg = pwr.freeze();
24+
25+
// Constrain and Freeze clock
26+
info!("Setup RCC... ");
27+
let rcc = dp.RCC.constrain();
28+
let ccdr = rcc
29+
.sys_ck(192.MHz())
30+
.pll1_q_ck(64.MHz())
31+
.freeze(pwrcfg, &dp.SBS);
32+
33+
// Acquire the GPIOB peripheral. This also enables the clock for
34+
// GPIOB in the RCC register.
35+
let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB);
36+
37+
let sck = gpiob.pb13.into_alternate();
38+
let miso = gpiob.pb14.into_alternate();
39+
let mosi = gpiob.pb15.into_alternate();
40+
41+
info!("");
42+
info!("stm32h5xx-hal example - SPI");
43+
info!("");
44+
45+
// Initialise the SPI peripheral.
46+
let mut spi = dp.SPI2.spi(
47+
(sck, miso, mosi),
48+
spi::MODE_0,
49+
1.MHz(),
50+
ccdr.peripheral.SPI2,
51+
&ccdr.clocks,
52+
);
53+
54+
// Write short fixed data
55+
spi.write(&[0x11u8]).unwrap();
56+
spi.write(&[0x11u8, 0x22, 0x33]).unwrap();
57+
58+
info!("Transfer starting");
59+
let mut delay = Delay::new(cp.SYST, &ccdr.clocks);
60+
let duration = MilliSeconds::secs(1).to_millis();
61+
// Echo what is received on the SPI
62+
let write = TEST_STR;
63+
let read = &mut [0u8; TEST_STR.len()];
64+
loop {
65+
spi.transfer(read, write).unwrap();
66+
delay.delay_ms(duration);
67+
}
68+
}

examples/spi_send_frames.rs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//! This example shows off the FrameTransaction mode of hardware chip select functionality.
2+
//!
3+
//! For more docs, see https://docs.rs/stm32h7xx-hal/latest/stm32h7xx_hal/spi/index.html
4+
//!
5+
6+
#![deny(warnings)]
7+
#![no_main]
8+
#![no_std]
9+
10+
use cortex_m_rt::entry;
11+
use cortex_m_semihosting::debug;
12+
use embedded_hal::spi::{Operation, SpiDevice};
13+
mod utilities;
14+
use spi::Spi;
15+
use stm32h5xx_hal::{
16+
pac,
17+
prelude::*,
18+
spi::{self, CommunicationMode},
19+
};
20+
21+
use log::info;
22+
23+
#[entry]
24+
fn main() -> ! {
25+
utilities::logger::init();
26+
// let cp = cortex_m::Peripherals::take().unwrap();
27+
let dp = pac::Peripherals::take().unwrap();
28+
29+
// Constrain and Freeze power
30+
info!("Setup PWR... ");
31+
let pwr = dp.PWR.constrain();
32+
let pwrcfg = pwr.freeze();
33+
34+
// Constrain and Freeze clock
35+
info!("Setup RCC... ");
36+
let rcc = dp.RCC.constrain();
37+
let ccdr = rcc
38+
.sys_ck(192.MHz())
39+
.pll1_q_ck(64.MHz())
40+
.freeze(pwrcfg, &dp.SBS);
41+
42+
// Acquire the GPIOB peripheral. This also enables the clock for
43+
// GPIOB in the RCC register.
44+
let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB);
45+
46+
let sck = gpiob.pb13.into_alternate();
47+
let miso = gpiob.pb14.into_alternate();
48+
let mosi = gpiob.pb15.into_alternate();
49+
// Because we want to use the hardware chip select, we need to provide that too
50+
let hcs = gpiob.pb4.into_alternate();
51+
52+
info!("");
53+
info!("stm32h5xx-hal example - SPI Frame Transactions");
54+
info!("");
55+
56+
// Initialise the SPI peripheral.
57+
let mut spi: Spi<_, u8> = dp.SPI2.spi(
58+
// Give ownership of the pins
59+
(sck, miso, mosi, hcs),
60+
// Create a config with the hardware chip select given
61+
spi::Config::new(spi::MODE_0)
62+
// Put 1 us idle time between every word sent
63+
.inter_word_delay(0.000001)
64+
// Specify that we use the hardware cs
65+
.hardware_cs(spi::HardwareCS {
66+
// See the docs of the HardwareCSMode to see what the different modes do
67+
mode: spi::HardwareCSMode::FrameTransaction,
68+
// Put 1 us between the CS being asserted and the first clock
69+
assertion_delay: 0.000001,
70+
// Our CS should be high when not active and low when asserted
71+
polarity: spi::Polarity::IdleHigh,
72+
})
73+
.communication_mode(CommunicationMode::SimplexTransmitter),
74+
1.MHz(),
75+
ccdr.peripheral.SPI2,
76+
&ccdr.clocks,
77+
);
78+
79+
spi.write(&[0, 1, 2]).unwrap();
80+
spi.write(&[0, 1, 2, 3, 4, 5, 6]).unwrap();
81+
82+
// Compose multiple operations into a single compound transfer using Operations
83+
let mut ops = [
84+
Operation::Write(&[0x11u8, 0x22, 0x33]),
85+
Operation::Write(&[0x44u8, 0x55, 0x66]),
86+
];
87+
88+
spi.transaction(&mut ops).unwrap();
89+
90+
loop {
91+
debug::exit(debug::EXIT_SUCCESS);
92+
}
93+
}

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ pub mod icache;
7373
#[cfg(feature = "device-selected")]
7474
pub mod delay;
7575

76+
#[cfg(feature = "device-selected")]
77+
pub mod spi;
78+
7679
#[cfg(feature = "device-selected")]
7780
mod sealed {
7881
pub trait Sealed {}

src/prelude.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ pub use crate::i2c::I2cExt as _stm32h5xx_hal_i2c_I2cExt;
66
pub use crate::icache::ICacheExt as _stm32h5xx_hal_icache_ICacheExt;
77
pub use crate::pwr::PwrExt as _stm32h5xx_hal_pwr_PwrExt;
88
pub use crate::rcc::RccExt as _stm32h5xx_hal_rcc_RccExt;
9+
pub use crate::spi::SpiExt as _stm32h5xx_hal_spi_SpiExt;
910

1011
pub use crate::time::U32Ext as _;
1112
pub use fugit::{ExtU32 as _, RateExtU32 as _};

0 commit comments

Comments
 (0)