Skip to content

Commit 3819ddc

Browse files
authored
Merge pull request #230 from stm32-rs/spi-dma
SPI RX/TX DMA and move to `embedded-dma` (continuation of #165)
2 parents ceb1a29 + ebb37d6 commit 3819ddc

File tree

10 files changed

+1128
-228
lines changed

10 files changed

+1128
-228
lines changed

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ edition = "2018"
2424
cortex-m = "0.6.3"
2525
nb = "0.1.1"
2626
stm32l4 = "0.13.0"
27+
embedded-dma = "0.1"
2728
bxcan = ">=0.4, <0.6"
2829

2930
[dependencies.rand_core]
@@ -124,6 +125,10 @@ required-features = ["rt"]
124125
name = "rtic_frame_serial_dma"
125126
required-features = ["rt", "stm32l4x2"]
126127

128+
[[example]]
129+
name = "spi_dma_rxtx"
130+
required-features = ["rt", "stm32l4x2"]
131+
127132
[[example]]
128133
name = "serial_echo_rtic"
129134
required-features = ["rt", "stm32l4x3"]

examples/lptim_rtic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ const APP: () = {
7171
}
7272

7373
#[task(binds = LPTIM1, resources = [lptim, led])]
74-
fn timer_tick(mut ctx: timer_tick::Context) {
74+
fn timer_tick(ctx: timer_tick::Context) {
7575
let timer_tick::Resources { lptim, led } = ctx.resources;
7676
if lptim.is_event_triggered(Event::AutoReloadMatch) {
7777
lptim.clear_event_flag(Event::AutoReloadMatch);

examples/rtic_frame_serial_dma.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
use hal::{
1414
dma::{self, DMAFrame, FrameReader, FrameSender},
15+
pac::USART2,
1516
prelude::*,
1617
rcc::{ClockSecuritySystem, CrystalBypass, MsiFreq},
1718
serial::{self, Config, Serial},
@@ -23,6 +24,8 @@ use heapless::{
2324
use panic_halt as _;
2425
use rtic::app;
2526
use stm32l4xx_hal as hal;
27+
use stm32l4xx_hal::dma::{RxDma, TxDma};
28+
use stm32l4xx_hal::serial::{Rx, Tx};
2629

2730
// The pool gives out `Box<DMAFrame>`s that can hold 8 bytes
2831
pool!(
@@ -33,9 +36,8 @@ pool!(
3336
#[app(device = stm32l4xx_hal::stm32, peripherals = true)]
3437
const APP: () = {
3538
struct Resources {
36-
rx: serial::Rx<hal::stm32::USART2>,
37-
frame_reader: FrameReader<Box<SerialDMAPool>, dma::dma1::C6, 8>,
38-
frame_sender: FrameSender<Box<SerialDMAPool>, dma::dma1::C7, 8>,
39+
frame_reader: FrameReader<Box<SerialDMAPool>, RxDma<Rx<USART2>, dma::dma1::C6>, 8>,
40+
frame_sender: FrameSender<Box<SerialDMAPool>, TxDma<Tx<USART2>, dma::dma1::C7>, 8>,
3941
}
4042

4143
#[init]
@@ -88,16 +90,15 @@ const APP: () = {
8890
let fr = if let Some(dma_buf) = SerialDMAPool::alloc() {
8991
// Set up the first reader frame
9092
let dma_buf = dma_buf.init(DMAFrame::new());
91-
serial_rx.frame_read(dma_ch6, dma_buf)
93+
serial_rx.with_dma(dma_ch6).frame_reader(dma_buf)
9294
} else {
9395
unreachable!()
9496
};
9597

9698
// Serial frame sender (DMA based)
97-
let fs: FrameSender<Box<SerialDMAPool>, _, 8> = serial_tx.frame_sender(dma_ch7);
99+
let fs: FrameSender<Box<SerialDMAPool>, _, 8> = serial_tx.with_dma(dma_ch7).frame_sender();
98100

99101
init::LateResources {
100-
rx: serial_rx,
101102
frame_reader: fr,
102103
frame_sender: fs,
103104
}
@@ -106,10 +107,10 @@ const APP: () = {
106107
/// This task handles the character match interrupt at required by the `FrameReader`
107108
///
108109
/// It will echo the buffer back to the serial.
109-
#[task(binds = USART2, resources = [rx, frame_reader, frame_sender], priority = 3)]
110+
#[task(binds = USART2, resources = [frame_reader, frame_sender], priority = 3)]
110111
fn serial_isr(cx: serial_isr::Context) {
111112
// Check for character match
112-
if cx.resources.rx.is_character_match(true) {
113+
if cx.resources.frame_reader.check_character_match(true) {
113114
if let Some(dma_buf) = SerialDMAPool::alloc() {
114115
let dma_buf = dma_buf.init(DMAFrame::new());
115116
let buf = cx.resources.frame_reader.character_match_interrupt(dma_buf);
@@ -123,7 +124,7 @@ const APP: () = {
123124
/// This task handles the RX transfer complete interrupt at required by the `FrameReader`
124125
///
125126
/// In this case we are discarding if a frame gets full as no character match was received
126-
#[task(binds = DMA1_CH6, resources = [rx, frame_reader], priority = 3)]
127+
#[task(binds = DMA1_CH6, resources = [frame_reader], priority = 3)]
127128
fn serial_rx_dma_isr(cx: serial_rx_dma_isr::Context) {
128129
if let Some(dma_buf) = SerialDMAPool::alloc() {
129130
let dma_buf = dma_buf.init(DMAFrame::new());

examples/serial_dma.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ extern crate stm32l4xx_hal as hal;
1818
// #[macro_use(block)]
1919
// extern crate nb;
2020

21-
use crate::hal::dma::Half;
21+
use crate::hal::dma::{CircReadDma, Half};
2222
use crate::hal::prelude::*;
2323
use crate::hal::serial::{Config, Serial};
2424
use crate::rt::ExceptionFrame;
@@ -68,7 +68,7 @@ fn main() -> ! {
6868

6969
let buf = singleton!(: [[u8; 8]; 2] = [[0; 8]; 2]).unwrap();
7070

71-
let mut circ_buffer = rx.circ_read(channels.5, buf);
71+
let mut circ_buffer = rx.with_dma(channels.5).circ_read(buf);
7272

7373
for _ in 0..2 {
7474
while circ_buffer.readable_half().unwrap() != Half::First {}

examples/serial_dma_partial_peek.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ extern crate stm32l4xx_hal as hal;
2020

2121
use crate::cortex_m::asm;
2222
use crate::hal::delay::Delay;
23+
use crate::hal::dma::CircReadDma;
2324
use crate::hal::prelude::*;
2425
use crate::hal::serial::{Config, Serial};
2526
use crate::rt::ExceptionFrame;
@@ -71,7 +72,7 @@ fn main() -> ! {
7172

7273
let buf = singleton!(: [[u8; 8]; 2] = [[0; 8]; 2]).unwrap();
7374

74-
let mut circ_buffer = rx.circ_read(channels.5, buf);
75+
let mut circ_buffer = rx.with_dma(channels.5).circ_read(buf);
7576

7677
// wait for 3 seconds, enter data on serial
7778
timer.delay_ms(1000_u32);

examples/serial_dma_us2.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ extern crate stm32l4xx_hal as hal;
1818
// #[macro_use(block)]
1919
// extern crate nb;
2020

21-
use crate::hal::dma::Half;
21+
use crate::hal::dma::{CircReadDma, Half};
2222
use crate::hal::prelude::*;
2323
use crate::hal::serial::{Config, Serial};
2424
use crate::rt::ExceptionFrame;
@@ -67,7 +67,7 @@ fn main() -> ! {
6767

6868
let buf = singleton!(: [[u8; 8]; 2] = [[0; 8]; 2]).unwrap();
6969

70-
let mut circ_buffer = rx.circ_read(channels.6, buf);
70+
let mut circ_buffer = rx.with_dma(channels.6).circ_read(buf);
7171

7272
for _ in 0..2 {
7373
while circ_buffer.readable_half().unwrap() != Half::First {}

examples/spi_dma_rxtx.rs

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
//! Test the SPI in RX/TX (transfer) DMA mode
2+
#![deny(unsafe_code)]
3+
#![no_main]
4+
#![no_std]
5+
6+
use panic_rtt_target as _;
7+
use rtt_target::rprintln;
8+
use stm32l4xx_hal::{
9+
dma::TransferDma,
10+
gpio::{Speed, State as PinState},
11+
hal::spi::{Mode, Phase, Polarity},
12+
prelude::*,
13+
rcc::MsiFreq,
14+
spi::Spi,
15+
};
16+
17+
#[rtic::app(device = stm32l4xx_hal::pac, peripherals = true)]
18+
const APP: () = {
19+
#[init]
20+
fn init(cx: init::Context) {
21+
static mut DMA_BUF: [u8; 5] = [0xf0, 0xaa, 0x00, 0xff, 0x0f];
22+
23+
rtt_target::rtt_init_print!();
24+
rprintln!("Initializing... ");
25+
26+
let dp = cx.device;
27+
28+
let mut flash = dp.FLASH.constrain();
29+
let mut rcc = dp.RCC.constrain();
30+
let mut pwr = dp.PWR.constrain(&mut rcc.apb1r1);
31+
let mut gpiob = dp.GPIOB.split(&mut rcc.ahb2);
32+
let dma1_channels = dp.DMA1.split(&mut rcc.ahb1);
33+
34+
//
35+
// Initialize the clocks to 80 MHz
36+
//
37+
rprintln!(" - Clock init");
38+
let clocks = rcc
39+
.cfgr
40+
.msi(MsiFreq::RANGE4M)
41+
.sysclk(80.mhz())
42+
.freeze(&mut flash.acr, &mut pwr);
43+
44+
//
45+
// Initialize the SPI
46+
//
47+
let sck = gpiob
48+
.pb3
49+
.into_af5(&mut gpiob.moder, &mut gpiob.afrl)
50+
.set_speed(Speed::High);
51+
let miso = gpiob
52+
.pb4
53+
.into_af5(&mut gpiob.moder, &mut gpiob.afrl)
54+
.set_speed(Speed::High);
55+
let mosi = gpiob
56+
.pb5
57+
.into_af5(&mut gpiob.moder, &mut gpiob.afrl)
58+
.set_speed(Speed::High);
59+
let mut dummy_cs = gpiob.pb6.into_push_pull_output_with_state(
60+
&mut gpiob.moder,
61+
&mut gpiob.otyper,
62+
PinState::High,
63+
);
64+
let spi = Spi::spi1(
65+
dp.SPI1,
66+
(sck, miso, mosi),
67+
Mode {
68+
phase: Phase::CaptureOnFirstTransition,
69+
polarity: Polarity::IdleLow,
70+
},
71+
100.khz(),
72+
clocks,
73+
&mut rcc.apb2,
74+
);
75+
76+
// Create DMA SPI
77+
let dma_spi = spi.with_rxtx_dma(dma1_channels.2, dma1_channels.3);
78+
79+
// Check the buffer before using it
80+
rprintln!("buf pre: 0x{:x?}", &DMA_BUF);
81+
82+
// Perform transfer and wait for it to finish (blocking), this can also be done using
83+
// interrupts on the desired DMA channel
84+
dummy_cs.set_low().ok();
85+
let transfer = dma_spi.transfer(DMA_BUF);
86+
let (buf, _dma_spi) = transfer.wait();
87+
dummy_cs.set_high().ok();
88+
89+
// Inspect the extracted buffer, if the MISO is connected to VCC or GND it will be all 0 or
90+
// 1.
91+
rprintln!("buf post: 0x{:x?}", &buf);
92+
}
93+
94+
// Idle function so RTT keeps working
95+
#[idle]
96+
fn idle(_cx: idle::Context) -> ! {
97+
loop {
98+
continue;
99+
}
100+
}
101+
};

0 commit comments

Comments
 (0)