Skip to content

Commit

Permalink
Merge pull request #230 from stm32-rs/spi-dma
Browse files Browse the repository at this point in the history
SPI RX/TX DMA and move to `embedded-dma` (continuation of #165)
  • Loading branch information
korken89 committed Jun 20, 2021
2 parents ceb1a29 + ebb37d6 commit 3819ddc
Show file tree
Hide file tree
Showing 10 changed files with 1,128 additions and 228 deletions.
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ edition = "2018"
cortex-m = "0.6.3"
nb = "0.1.1"
stm32l4 = "0.13.0"
embedded-dma = "0.1"
bxcan = ">=0.4, <0.6"

[dependencies.rand_core]
Expand Down Expand Up @@ -124,6 +125,10 @@ required-features = ["rt"]
name = "rtic_frame_serial_dma"
required-features = ["rt", "stm32l4x2"]

[[example]]
name = "spi_dma_rxtx"
required-features = ["rt", "stm32l4x2"]

[[example]]
name = "serial_echo_rtic"
required-features = ["rt", "stm32l4x3"]
Expand Down
2 changes: 1 addition & 1 deletion examples/lptim_rtic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ const APP: () = {
}

#[task(binds = LPTIM1, resources = [lptim, led])]
fn timer_tick(mut ctx: timer_tick::Context) {
fn timer_tick(ctx: timer_tick::Context) {
let timer_tick::Resources { lptim, led } = ctx.resources;
if lptim.is_event_triggered(Event::AutoReloadMatch) {
lptim.clear_event_flag(Event::AutoReloadMatch);
Expand Down
19 changes: 10 additions & 9 deletions examples/rtic_frame_serial_dma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

use hal::{
dma::{self, DMAFrame, FrameReader, FrameSender},
pac::USART2,
prelude::*,
rcc::{ClockSecuritySystem, CrystalBypass, MsiFreq},
serial::{self, Config, Serial},
Expand All @@ -23,6 +24,8 @@ use heapless::{
use panic_halt as _;
use rtic::app;
use stm32l4xx_hal as hal;
use stm32l4xx_hal::dma::{RxDma, TxDma};
use stm32l4xx_hal::serial::{Rx, Tx};

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

#[init]
Expand Down Expand Up @@ -88,16 +90,15 @@ const APP: () = {
let fr = if let Some(dma_buf) = SerialDMAPool::alloc() {
// Set up the first reader frame
let dma_buf = dma_buf.init(DMAFrame::new());
serial_rx.frame_read(dma_ch6, dma_buf)
serial_rx.with_dma(dma_ch6).frame_reader(dma_buf)
} else {
unreachable!()
};

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

init::LateResources {
rx: serial_rx,
frame_reader: fr,
frame_sender: fs,
}
Expand All @@ -106,10 +107,10 @@ const APP: () = {
/// This task handles the character match interrupt at required by the `FrameReader`
///
/// It will echo the buffer back to the serial.
#[task(binds = USART2, resources = [rx, frame_reader, frame_sender], priority = 3)]
#[task(binds = USART2, resources = [frame_reader, frame_sender], priority = 3)]
fn serial_isr(cx: serial_isr::Context) {
// Check for character match
if cx.resources.rx.is_character_match(true) {
if cx.resources.frame_reader.check_character_match(true) {
if let Some(dma_buf) = SerialDMAPool::alloc() {
let dma_buf = dma_buf.init(DMAFrame::new());
let buf = cx.resources.frame_reader.character_match_interrupt(dma_buf);
Expand All @@ -123,7 +124,7 @@ const APP: () = {
/// This task handles the RX transfer complete interrupt at required by the `FrameReader`
///
/// In this case we are discarding if a frame gets full as no character match was received
#[task(binds = DMA1_CH6, resources = [rx, frame_reader], priority = 3)]
#[task(binds = DMA1_CH6, resources = [frame_reader], priority = 3)]
fn serial_rx_dma_isr(cx: serial_rx_dma_isr::Context) {
if let Some(dma_buf) = SerialDMAPool::alloc() {
let dma_buf = dma_buf.init(DMAFrame::new());
Expand Down
4 changes: 2 additions & 2 deletions examples/serial_dma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ extern crate stm32l4xx_hal as hal;
// #[macro_use(block)]
// extern crate nb;

use crate::hal::dma::Half;
use crate::hal::dma::{CircReadDma, Half};
use crate::hal::prelude::*;
use crate::hal::serial::{Config, Serial};
use crate::rt::ExceptionFrame;
Expand Down Expand Up @@ -68,7 +68,7 @@ fn main() -> ! {

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

let mut circ_buffer = rx.circ_read(channels.5, buf);
let mut circ_buffer = rx.with_dma(channels.5).circ_read(buf);

for _ in 0..2 {
while circ_buffer.readable_half().unwrap() != Half::First {}
Expand Down
3 changes: 2 additions & 1 deletion examples/serial_dma_partial_peek.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ extern crate stm32l4xx_hal as hal;

use crate::cortex_m::asm;
use crate::hal::delay::Delay;
use crate::hal::dma::CircReadDma;
use crate::hal::prelude::*;
use crate::hal::serial::{Config, Serial};
use crate::rt::ExceptionFrame;
Expand Down Expand Up @@ -71,7 +72,7 @@ fn main() -> ! {

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

let mut circ_buffer = rx.circ_read(channels.5, buf);
let mut circ_buffer = rx.with_dma(channels.5).circ_read(buf);

// wait for 3 seconds, enter data on serial
timer.delay_ms(1000_u32);
Expand Down
4 changes: 2 additions & 2 deletions examples/serial_dma_us2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ extern crate stm32l4xx_hal as hal;
// #[macro_use(block)]
// extern crate nb;

use crate::hal::dma::Half;
use crate::hal::dma::{CircReadDma, Half};
use crate::hal::prelude::*;
use crate::hal::serial::{Config, Serial};
use crate::rt::ExceptionFrame;
Expand Down Expand Up @@ -67,7 +67,7 @@ fn main() -> ! {

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

let mut circ_buffer = rx.circ_read(channels.6, buf);
let mut circ_buffer = rx.with_dma(channels.6).circ_read(buf);

for _ in 0..2 {
while circ_buffer.readable_half().unwrap() != Half::First {}
Expand Down
101 changes: 101 additions & 0 deletions examples/spi_dma_rxtx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//! Test the SPI in RX/TX (transfer) DMA mode
#![deny(unsafe_code)]
#![no_main]
#![no_std]

use panic_rtt_target as _;
use rtt_target::rprintln;
use stm32l4xx_hal::{
dma::TransferDma,
gpio::{Speed, State as PinState},
hal::spi::{Mode, Phase, Polarity},
prelude::*,
rcc::MsiFreq,
spi::Spi,
};

#[rtic::app(device = stm32l4xx_hal::pac, peripherals = true)]
const APP: () = {
#[init]
fn init(cx: init::Context) {
static mut DMA_BUF: [u8; 5] = [0xf0, 0xaa, 0x00, 0xff, 0x0f];

rtt_target::rtt_init_print!();
rprintln!("Initializing... ");

let dp = cx.device;

let mut flash = dp.FLASH.constrain();
let mut rcc = dp.RCC.constrain();
let mut pwr = dp.PWR.constrain(&mut rcc.apb1r1);
let mut gpiob = dp.GPIOB.split(&mut rcc.ahb2);
let dma1_channels = dp.DMA1.split(&mut rcc.ahb1);

//
// Initialize the clocks to 80 MHz
//
rprintln!(" - Clock init");
let clocks = rcc
.cfgr
.msi(MsiFreq::RANGE4M)
.sysclk(80.mhz())
.freeze(&mut flash.acr, &mut pwr);

//
// Initialize the SPI
//
let sck = gpiob
.pb3
.into_af5(&mut gpiob.moder, &mut gpiob.afrl)
.set_speed(Speed::High);
let miso = gpiob
.pb4
.into_af5(&mut gpiob.moder, &mut gpiob.afrl)
.set_speed(Speed::High);
let mosi = gpiob
.pb5
.into_af5(&mut gpiob.moder, &mut gpiob.afrl)
.set_speed(Speed::High);
let mut dummy_cs = gpiob.pb6.into_push_pull_output_with_state(
&mut gpiob.moder,
&mut gpiob.otyper,
PinState::High,
);
let spi = Spi::spi1(
dp.SPI1,
(sck, miso, mosi),
Mode {
phase: Phase::CaptureOnFirstTransition,
polarity: Polarity::IdleLow,
},
100.khz(),
clocks,
&mut rcc.apb2,
);

// Create DMA SPI
let dma_spi = spi.with_rxtx_dma(dma1_channels.2, dma1_channels.3);

// Check the buffer before using it
rprintln!("buf pre: 0x{:x?}", &DMA_BUF);

// Perform transfer and wait for it to finish (blocking), this can also be done using
// interrupts on the desired DMA channel
dummy_cs.set_low().ok();
let transfer = dma_spi.transfer(DMA_BUF);
let (buf, _dma_spi) = transfer.wait();
dummy_cs.set_high().ok();

// Inspect the extracted buffer, if the MISO is connected to VCC or GND it will be all 0 or
// 1.
rprintln!("buf post: 0x{:x?}", &buf);
}

// Idle function so RTT keeps working
#[idle]
fn idle(_cx: idle::Context) -> ! {
loop {
continue;
}
}
};
Loading

0 comments on commit 3819ddc

Please sign in to comment.