Skip to content

Commit b88151f

Browse files
bors[bot]apeng2012
andauthored
Merge #408
408: Spi slave mode r=burrbull a=apeng2012 Co-authored-by: apeng2012 <peng89769975@163.com>
2 parents 1137a42 + c0c2c03 commit b88151f

File tree

3 files changed

+411
-48
lines changed

3 files changed

+411
-48
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1313

1414
### Added
1515

16+
- Spi Slave mode
1617
- Reexport gpio pins to `gpio` mod
1718
- Added the ability to specify the word size (8 or 9 bits) for `Serial` (USART). When using parity, the parity bit is included in the number of bits of the word.
1819
- `blocking::serial::Write` for `Tx` and `Serial`. `core::fmt::Write` for `Serial`

examples/spi-slave.rs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
//! SPI slave mode test
2+
//!
3+
//! spi1 master <-> spi2 slave
4+
//! PA5 <-SCK-> PB13
5+
//! PA6 <-MISO-> PB14
6+
//! PA7 <-MOSI-> PB15
7+
8+
#![allow(clippy::empty_loop)]
9+
#![no_std]
10+
#![no_main]
11+
12+
use cortex_m_rt::entry;
13+
use panic_halt as _;
14+
15+
use cortex_m::{asm, singleton};
16+
use embedded_hal::spi::{Mode, Phase, Polarity};
17+
pub const MODE: Mode = Mode {
18+
phase: Phase::CaptureOnSecondTransition,
19+
polarity: Polarity::IdleHigh,
20+
};
21+
22+
use stm32f1xx_hal::{
23+
gpio::{
24+
gpiob::{PB13, PB14, PB15},
25+
Alternate, Floating, Input, PushPull,
26+
},
27+
pac::{self, interrupt, Peripherals, SPI2},
28+
prelude::*,
29+
spi::{Event, Slave, Spi, Spi2NoRemap},
30+
};
31+
32+
type SlaveSpi = Spi<
33+
SPI2,
34+
Spi2NoRemap,
35+
(
36+
PB13<Input<Floating>>,
37+
PB14<Alternate<PushPull>>,
38+
PB15<Input<Floating>>,
39+
),
40+
u8,
41+
Slave,
42+
>;
43+
44+
static mut SPI2SLAVE: Option<SlaveSpi> = None;
45+
46+
#[entry]
47+
fn main() -> ! {
48+
let dp = Peripherals::take().unwrap();
49+
50+
let mut flash = dp.FLASH.constrain();
51+
let rcc = dp.RCC.constrain();
52+
53+
let clocks = rcc.cfgr.freeze(&mut flash.acr);
54+
55+
let mut afio = dp.AFIO.constrain();
56+
let mut gpioa = dp.GPIOA.split();
57+
let mut gpiob = dp.GPIOB.split();
58+
59+
// SPI1
60+
let sck = gpioa.pa5.into_alternate_push_pull(&mut gpioa.crl);
61+
let miso = gpioa.pa6;
62+
let mosi = gpioa.pa7.into_alternate_push_pull(&mut gpioa.crl);
63+
64+
let spi1 = Spi::spi1(
65+
dp.SPI1,
66+
(sck, miso, mosi),
67+
&mut afio.mapr,
68+
MODE,
69+
10.kHz(),
70+
clocks,
71+
);
72+
73+
// SPI2
74+
let sck = gpiob.pb13;
75+
let miso = gpiob.pb14.into_alternate_push_pull(&mut gpiob.crh);
76+
let mosi = gpiob.pb15;
77+
78+
let spi2 = Spi::spi2_slave(dp.SPI2, (sck, miso, mosi), MODE);
79+
80+
// Set up the DMA device
81+
let dma = dp.DMA1.split();
82+
83+
let master_spi_dma = spi1.with_rx_tx_dma(dma.2, dma.3);
84+
let slave_spi_dma = spi2.with_rx_tx_dma(dma.4, dma.5);
85+
86+
let master_buf = singleton!(: [u8; 12] = [0; 12]).unwrap();
87+
let slave_buf = singleton!(: [u8; 12] = [0; 12]).unwrap();
88+
89+
// Make sure the buffers are the same length
90+
let slave_transfer = slave_spi_dma.read_write(slave_buf, b"hello,master");
91+
let master_transfer = master_spi_dma.read_write(master_buf, b"hello, slave");
92+
93+
let (buffer, spi1_dma) = master_transfer.wait();
94+
let (_buffer, spi2_dma) = slave_transfer.wait();
95+
96+
asm::bkpt();
97+
98+
// test SPI with interrupts
99+
let (mut spi2, _, _) = spi2_dma.release();
100+
101+
spi2.listen(Event::Rxne);
102+
spi2.listen(Event::Txe);
103+
spi2.listen(Event::Error);
104+
105+
cortex_m::interrupt::free(|_| unsafe {
106+
SPI2SLAVE.replace(spi2);
107+
});
108+
109+
unsafe {
110+
cortex_m::peripheral::NVIC::unmask(pac::Interrupt::SPI2);
111+
}
112+
113+
let master_transfer = spi1_dma.read_write(buffer.0, buffer.1);
114+
let (_buffer, _spi1_dma) = master_transfer.wait();
115+
116+
loop {}
117+
}
118+
119+
const R_BUFFER_LEN: usize = 16;
120+
static mut R_BUFFER: &mut [u8; R_BUFFER_LEN] = &mut [0; R_BUFFER_LEN];
121+
static mut RIDX: usize = 0;
122+
123+
const W_BUFFER_LEN: usize = 3;
124+
static W_BUFFER: &[u8; W_BUFFER_LEN] = &[1, 2, 3];
125+
static mut WIDX: usize = 0;
126+
127+
#[interrupt]
128+
unsafe fn SPI2() {
129+
cortex_m::interrupt::free(|_| {
130+
if let Some(spi2) = SPI2SLAVE.as_mut() {
131+
if spi2.is_overrun() {
132+
// mcu processing speed is not enough
133+
asm::bkpt();
134+
}
135+
if spi2.is_rx_not_empty() {
136+
if let Ok(w) = nb::block!(spi2.read()) {
137+
R_BUFFER[RIDX] = w;
138+
RIDX += 1;
139+
if RIDX >= R_BUFFER_LEN - 1 {
140+
RIDX = 0;
141+
}
142+
}
143+
}
144+
if spi2.is_tx_empty() {
145+
if let Ok(()) = nb::block!(spi2.send(W_BUFFER[WIDX])) {
146+
WIDX += 1;
147+
if WIDX >= W_BUFFER_LEN {
148+
WIDX = 0;
149+
}
150+
}
151+
}
152+
}
153+
})
154+
}

0 commit comments

Comments
 (0)