Skip to content

Commit bb738fe

Browse files
committed
adding spi slave
1 parent b0479f0 commit bb738fe

File tree

4 files changed

+396
-20
lines changed

4 files changed

+396
-20
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

8+
## [Unreleased]
9+
10+
### Changed
11+
12+
- `Spi` can be operated as `Slave` [#487]
13+
14+
[#487]: https://github.com/stm32-rs/stm32f4xx-hal/pull/487
15+
816
## [v0.13.1] - 2022-04-20
917

1018
### Fixed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,3 +474,7 @@ required-features = ["device-selected"]
474474
name = "hd44780"
475475
required-features = ["device-selected"]
476476

477+
[[example]]
478+
name = "spi_slave_dma_rtic"
479+
required-features = ["stm32f411", "rtic"]
480+

examples/spi_slave_dma_rtic.rs

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
#![deny(unsafe_code)]
2+
#![deny(warnings)]
3+
#![no_main]
4+
#![no_std]
5+
6+
#[rtic::app(device = stm32f4xx_hal::pac, peripherals = true, dispatchers = [TIM2])]
7+
mod app {
8+
9+
use embedded_hal::spi::{Mode, Phase, Polarity};
10+
use hal::{
11+
dma::{
12+
config::DmaConfig, traits::StreamISR, MemoryToPeripheral, PeripheralToMemory, Stream0,
13+
Stream5, StreamsTuple, Transfer,
14+
},
15+
gpio::{gpioc::PC13, GpioExt, Output, PushPull},
16+
pac::{DMA1, SPI3},
17+
prelude::*,
18+
rcc::RccExt,
19+
spi::{Rx, Spi, Tx},
20+
};
21+
use panic_semihosting as _;
22+
use systick_monotonic::*;
23+
24+
use stm32f4xx_hal as hal;
25+
26+
const ARRAY_SIZE: usize = 3;
27+
28+
type TxTransfer =
29+
Transfer<Stream5<DMA1>, 0, Tx<SPI3>, MemoryToPeripheral, &'static mut [u8; ARRAY_SIZE]>;
30+
31+
type RxTransfer =
32+
Transfer<Stream0<DMA1>, 0, Rx<SPI3>, PeripheralToMemory, &'static mut [u8; ARRAY_SIZE]>;
33+
34+
#[shared]
35+
struct Shared {
36+
led: PC13<Output<PushPull>>,
37+
tx_transfer: TxTransfer,
38+
rx_transfer: RxTransfer,
39+
}
40+
41+
#[local]
42+
struct Local {
43+
rx_buffer: Option<&'static mut [u8; ARRAY_SIZE]>,
44+
tx_buffer: Option<&'static mut [u8; ARRAY_SIZE]>,
45+
}
46+
47+
#[monotonic(binds = SysTick, default = true)]
48+
type MyMono = Systick<1000>; // 1000 Hz / 1 ms granularity
49+
50+
#[init()]
51+
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
52+
let mut core = cx.core;
53+
core.DWT.enable_cycle_counter();
54+
55+
let device_peripherals: hal::pac::Peripherals = cx.device;
56+
57+
let rcc = device_peripherals.RCC;
58+
let rcc = rcc.constrain();
59+
let clocks = rcc.cfgr.sysclk(100.MHz()).pclk1(36.MHz()).freeze();
60+
61+
let mono = Systick::new(core.SYST, 100_000_000);
62+
63+
let gpioc = device_peripherals.GPIOC.split();
64+
let mut led = gpioc.pc13.into_push_pull_output();
65+
66+
let gpiob = device_peripherals.GPIOB;
67+
let spi = device_peripherals.SPI3;
68+
69+
let gpiob = gpiob.split();
70+
71+
let sck = gpiob.pb3.into_alternate();
72+
let miso = gpiob.pb4.into_alternate();
73+
let mosi = gpiob.pb5.into_alternate();
74+
75+
let mode = Mode {
76+
polarity: Polarity::IdleLow,
77+
phase: Phase::CaptureOnFirstTransition,
78+
};
79+
80+
let spi3 = Spi::new_slave(spi, (sck, miso, mosi), mode, 8_000_000.Hz(), &clocks);
81+
82+
let (tx, rx) = spi3.use_dma().txrx();
83+
84+
let streams = StreamsTuple::new(device_peripherals.DMA1);
85+
let tx_stream = streams.5;
86+
let rx_stream = streams.0;
87+
88+
let rx_buffer = cortex_m::singleton!(: [u8; ARRAY_SIZE] = [0; ARRAY_SIZE]).unwrap();
89+
let tx_buffer = cortex_m::singleton!(: [u8; ARRAY_SIZE] = [1,2,3]).unwrap();
90+
91+
let mut rx_transfer = Transfer::init_peripheral_to_memory(
92+
rx_stream,
93+
rx,
94+
rx_buffer,
95+
None,
96+
DmaConfig::default()
97+
.memory_increment(true)
98+
.fifo_enable(true)
99+
.fifo_error_interrupt(true)
100+
.transfer_complete_interrupt(true),
101+
);
102+
103+
let mut tx_transfer = Transfer::init_memory_to_peripheral(
104+
tx_stream,
105+
tx,
106+
tx_buffer,
107+
None,
108+
DmaConfig::default()
109+
.memory_increment(true)
110+
.fifo_enable(true)
111+
.fifo_error_interrupt(true)
112+
.transfer_complete_interrupt(true),
113+
);
114+
115+
rx_transfer.start(|_rx| {});
116+
tx_transfer.start(|_tx| {});
117+
118+
led.set_high();
119+
120+
let rx_buffer2 = cortex_m::singleton!(: [u8; ARRAY_SIZE] = [0; ARRAY_SIZE]).unwrap();
121+
let tx_buffer2 = cortex_m::singleton!(: [u8; ARRAY_SIZE] = [4,5,6]).unwrap();
122+
123+
(
124+
Shared {
125+
led,
126+
tx_transfer,
127+
rx_transfer,
128+
},
129+
Local {
130+
rx_buffer: Some(rx_buffer2),
131+
tx_buffer: Some(tx_buffer2),
132+
},
133+
init::Monotonics(mono),
134+
)
135+
}
136+
137+
// The led lights up if the first byte we receive is a 1, it turns off otherwise
138+
#[task(binds = DMA1_STREAM0, shared = [rx_transfer, led], local = [rx_buffer])]
139+
fn on_receiving(cx: on_receiving::Context) {
140+
let on_receiving::Context { mut shared, local } = cx;
141+
if Stream0::<DMA1>::get_fifo_error_flag() {
142+
shared
143+
.rx_transfer
144+
.lock(|spi_dma| spi_dma.clear_fifo_error_interrupt());
145+
}
146+
if Stream0::<DMA1>::get_transfer_complete_flag() {
147+
shared
148+
.rx_transfer
149+
.lock(|spi_dma| spi_dma.clear_transfer_complete_interrupt());
150+
let filled_buffer = shared.rx_transfer.lock(|spi_dma| {
151+
let (result, _) = spi_dma
152+
.next_transfer(local.rx_buffer.take().unwrap())
153+
.unwrap();
154+
result
155+
});
156+
match filled_buffer[0] {
157+
1 => shared.led.lock(|led| led.set_low()),
158+
_ => shared.led.lock(|led| led.set_high()),
159+
}
160+
*local.rx_buffer = Some(filled_buffer);
161+
}
162+
}
163+
164+
// We either send [1,2,3] or [4,5,6] depending on which buffer was loaded
165+
#[task(binds = DMA1_STREAM5, shared = [tx_transfer, led], local = [tx_buffer])]
166+
fn on_sending(cx: on_sending::Context) {
167+
let on_sending::Context { mut shared, local } = cx;
168+
if Stream5::<DMA1>::get_fifo_error_flag() {
169+
shared
170+
.tx_transfer
171+
.lock(|spi_dma| spi_dma.clear_fifo_error_interrupt());
172+
}
173+
if Stream5::<DMA1>::get_transfer_complete_flag() {
174+
shared
175+
.tx_transfer
176+
.lock(|spi_dma| spi_dma.clear_transfer_complete_interrupt());
177+
let filled_buffer = shared.tx_transfer.lock(|spi_dma| {
178+
let (result, _) = spi_dma
179+
.next_transfer(local.tx_buffer.take().unwrap())
180+
.unwrap();
181+
result
182+
});
183+
*local.tx_buffer = Some(filled_buffer);
184+
}
185+
}
186+
}

0 commit comments

Comments
 (0)