Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SPI RX/TX DMA and move to embedded-dma (continuation of #165) #230

Merged
merged 12 commits into from
Jun 20, 2021
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;
}
}
};