Make SPIv3 work with DMA.

Add both DMA and non-DMA example to H7.
This commit is contained in:
Bob McWhirter 2021-07-21 14:09:24 -04:00
parent 34dfe28d3a
commit a1dac21bdf
5 changed files with 318 additions and 11 deletions

View File

@ -88,7 +88,11 @@ pub(crate) unsafe fn do_transfer(
w.set_dir(dir); w.set_dir(dir);
w.set_msize(vals::Size::BITS8); w.set_msize(vals::Size::BITS8);
w.set_psize(vals::Size::BITS8); w.set_psize(vals::Size::BITS8);
if incr_mem {
w.set_minc(vals::Inc::INCREMENTED); w.set_minc(vals::Inc::INCREMENTED);
} else {
w.set_minc(vals::Inc::FIXED);
}
w.set_pinc(vals::Inc::FIXED); w.set_pinc(vals::Inc::FIXED);
w.set_teie(true); w.set_teie(true);
w.set_tcie(true); w.set_tcie(true);

View File

@ -1,7 +1,7 @@
#![macro_use] #![macro_use]
#[cfg_attr(spi_v1, path = "v1.rs")] //#[cfg_attr(spi_v1, path = "v1.rs")]
#[cfg_attr(spi_v2, path = "v2.rs")] //#[cfg_attr(spi_v2, path = "v2.rs")]
#[cfg_attr(spi_v3, path = "v3.rs")] #[cfg_attr(spi_v3, path = "v3.rs")]
mod _version; mod _version;
use crate::{dma, peripherals, rcc::RccPeripheral}; use crate::{dma, peripherals, rcc::RccPeripheral};

View File

@ -18,7 +18,7 @@ use embassy_extras::unborrow;
use embassy_traits::spi as traits; use embassy_traits::spi as traits;
pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
use futures::future::join; use futures::future::join3;
impl WordSize { impl WordSize {
fn dsize(&self) -> u8 { fn dsize(&self) -> u8 {
@ -110,7 +110,6 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
w.set_crcen(false); w.set_crcen(false);
w.set_mbr(spi::vals::Mbr(br)); w.set_mbr(spi::vals::Mbr(br));
w.set_dsize(WordSize::EightBit.dsize()); w.set_dsize(WordSize::EightBit.dsize());
//w.set_fthlv(WordSize::EightBit.frxth());
}); });
T::regs().cr2().modify(|w| { T::regs().cr2().modify(|w| {
w.set_tsize(0); w.set_tsize(0);
@ -182,16 +181,40 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
where where
Tx: TxDmaChannel<T>, Tx: TxDmaChannel<T>,
{ {
Self::set_word_size(WordSize::EightBit);
unsafe {
T::regs().cr1().modify(|w| {
w.set_spe(false);
});
}
let request = self.txdma.request(); let request = self.txdma.request();
let dst = T::regs().txdr().ptr() as *mut u8; let dst = T::regs().txdr().ptr() as *mut u8;
let f = self.txdma.write(request, write, dst); let f = self.txdma.write(request, write, dst);
unsafe { unsafe {
T::regs().cfg1().modify(|reg| { T::regs().cfg1().modify(|reg| {
reg.set_txdmaen(true); reg.set_txdmaen(true);
}); });
T::regs().cr1().modify(|w| {
w.set_spe(true);
});
T::regs().cr1().modify(|w| {
w.set_cstart(true);
});
} }
f.await; f.await;
unsafe {
T::regs().cfg1().modify(|reg| {
reg.set_rxdmaen(false);
reg.set_txdmaen(false);
});
T::regs().cr1().modify(|w| {
w.set_spe(false);
});
}
Ok(()) Ok(())
} }
@ -201,6 +224,16 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
Tx: TxDmaChannel<T>, Tx: TxDmaChannel<T>,
Rx: RxDmaChannel<T>, Rx: RxDmaChannel<T>,
{ {
Self::set_word_size(WordSize::EightBit);
unsafe {
T::regs().cr1().modify(|w| {
w.set_spe(false);
});
T::regs().cfg1().modify(|reg| {
reg.set_rxdmaen(true);
});
}
let clock_byte_count = read.len(); let clock_byte_count = read.len();
let rx_request = self.rxdma.request(); let rx_request = self.rxdma.request();
@ -217,11 +250,25 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
unsafe { unsafe {
T::regs().cfg1().modify(|reg| { T::regs().cfg1().modify(|reg| {
reg.set_txdmaen(true); reg.set_txdmaen(true);
reg.set_rxdmaen(true); });
T::regs().cr1().modify(|w| {
w.set_spe(true);
});
T::regs().cr1().modify(|w| {
w.set_cstart(true);
}); });
} }
let r = join(tx_f, rx_f).await; join3(tx_f, rx_f, Self::wait_for_idle()).await;
unsafe {
T::regs().cfg1().modify(|reg| {
reg.set_rxdmaen(false);
reg.set_txdmaen(false);
});
T::regs().cr1().modify(|w| {
w.set_spe(false);
});
}
Ok(()) Ok(())
} }
@ -231,11 +278,21 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
Tx: TxDmaChannel<T>, Tx: TxDmaChannel<T>,
Rx: RxDmaChannel<T>, Rx: RxDmaChannel<T>,
{ {
let clock_byte_count = read.len(); Self::set_word_size(WordSize::EightBit);
unsafe {
T::regs().cr1().modify(|w| {
w.set_spe(false);
});
T::regs().cfg1().modify(|reg| {
reg.set_rxdmaen(true);
});
}
let rx_request = self.rxdma.request(); let rx_request = self.rxdma.request();
let rx_src = T::regs().rxdr().ptr() as *mut u8; let rx_src = T::regs().rxdr().ptr() as *mut u8;
let rx_f = self.rxdma.read(rx_request, rx_src, read); let rx_f = self
.rxdma
.read(rx_request, rx_src, &mut read[0..write.len()]);
let tx_request = self.txdma.request(); let tx_request = self.txdma.request();
let tx_dst = T::regs().txdr().ptr() as *mut u8; let tx_dst = T::regs().txdr().ptr() as *mut u8;
@ -244,13 +301,38 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
unsafe { unsafe {
T::regs().cfg1().modify(|reg| { T::regs().cfg1().modify(|reg| {
reg.set_txdmaen(true); reg.set_txdmaen(true);
reg.set_rxdmaen(true); });
T::regs().cr1().modify(|w| {
w.set_spe(true);
});
T::regs().cr1().modify(|w| {
w.set_cstart(true);
}); });
} }
let r = join(tx_f, rx_f).await; join3(tx_f, rx_f, Self::wait_for_idle()).await;
unsafe {
T::regs().cfg1().modify(|reg| {
reg.set_rxdmaen(false);
reg.set_txdmaen(false);
});
T::regs().cr1().modify(|w| {
w.set_spe(false);
});
}
Ok(()) Ok(())
} }
async fn wait_for_idle() {
unsafe {
while !T::regs().sr().read().txc() {
// spin
}
while T::regs().sr().read().rxplvl().0 > 0 {
// spin
}
}
}
} }
impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> {

View File

@ -0,0 +1,112 @@
#![no_std]
#![no_main]
#![feature(trait_alias)]
#![feature(min_type_alias_impl_trait)]
#![feature(impl_trait_in_bindings)]
#![feature(type_alias_impl_trait)]
#![allow(incomplete_features)]
#[path = "../example_common.rs"]
mod example_common;
use core::fmt::Write;
use embassy::executor::Executor;
use embassy::time::Clock;
use embassy::util::Forever;
use embassy_stm32::dma::NoDma;
use example_common::*;
use embedded_hal::blocking::spi::Transfer;
use hal::prelude::*;
use stm32h7xx_hal as hal;
use cortex_m_rt::entry;
use stm32h7::stm32h743 as pac;
use heapless::String;
use embassy_stm32::spi::{Spi, Config};
use embassy_stm32::time::Hertz;
#[embassy::task]
async fn main_task() {
let p = embassy_stm32::init(Default::default());
let mut spi = Spi::new(
p.SPI3,
p.PB3,
p.PB5,
p.PB4,
NoDma,
NoDma,
Hertz(1_000_000),
Config::default(),
);
for n in 0u32.. {
let mut write: String<128> = String::new();
core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
unsafe {
let result = spi.transfer(write.as_bytes_mut());
if let Err(_) = result {
defmt::panic!("crap");
}
}
info!("read via spi: {}", write.as_bytes());
}
}
struct ZeroClock;
impl Clock for ZeroClock {
fn now(&self) -> u64 {
0
}
}
static EXECUTOR: Forever<Executor> = Forever::new();
#[entry]
fn main() -> ! {
info!("Hello World!");
let pp = pac::Peripherals::take().unwrap();
let pwrcfg = pp.PWR.constrain().freeze();
let rcc = pp.RCC.constrain();
rcc.sys_ck(96.mhz())
.pclk1(48.mhz())
.pclk2(48.mhz())
.pclk3(48.mhz())
.pclk4(48.mhz())
.pll1_q_ck(48.mhz())
.freeze(pwrcfg, &pp.SYSCFG);
let pp = unsafe { pac::Peripherals::steal() };
pp.DBGMCU.cr.modify(|_, w| {
w.dbgsleep_d1().set_bit();
w.dbgstby_d1().set_bit();
w.dbgstop_d1().set_bit();
w.d1dbgcken().set_bit();
w
});
pp.RCC.ahb4enr.modify(|_, w| {
w.gpioaen().set_bit();
w.gpioben().set_bit();
w.gpiocen().set_bit();
w.gpioden().set_bit();
w.gpioeen().set_bit();
w.gpiofen().set_bit();
w
});
unsafe { embassy::time::set_clock(&ZeroClock) };
let executor = EXECUTOR.put(Executor::new());
executor.run(|spawner| {
unwrap!(spawner.spawn(main_task()));
})
}

View File

@ -0,0 +1,109 @@
#![no_std]
#![no_main]
#![feature(trait_alias)]
#![feature(min_type_alias_impl_trait)]
#![feature(impl_trait_in_bindings)]
#![feature(type_alias_impl_trait)]
#![allow(incomplete_features)]
#[path = "../example_common.rs"]
mod example_common;
use core::fmt::Write;
use embassy::executor::Executor;
use embassy::time::Clock;
use embassy::util::Forever;
use example_common::*;
use embassy_traits::spi::FullDuplex;
use hal::prelude::*;
use stm32h7xx_hal as hal;
use cortex_m_rt::entry;
use stm32h7::stm32h743 as pac;
use heapless::String;
use embassy_stm32::spi::{Spi, Config};
use embassy_stm32::time::Hertz;
use core::str::from_utf8;
#[embassy::task]
async fn main_task() {
let p = embassy_stm32::init(Default::default());
let mut spi = Spi::new(
p.SPI3,
p.PB3,
p.PB5,
p.PB4,
p.DMA1_CH3,
p.DMA1_CH4,
Hertz(1_000_000),
Config::default(),
);
for n in 0u32.. {
let mut write: String<128> = String::new();
let mut read = [0;128];
core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
// read_write will slice the &mut read down to &write's actual length.
spi.read_write(&mut read, write.as_bytes()).await.ok();
info!("read via spi+dma: {}", from_utf8(&read).unwrap());
}
}
struct ZeroClock;
impl Clock for ZeroClock {
fn now(&self) -> u64 {
0
}
}
static EXECUTOR: Forever<Executor> = Forever::new();
#[entry]
fn main() -> ! {
info!("Hello World!");
let pp = pac::Peripherals::take().unwrap();
let pwrcfg = pp.PWR.constrain().freeze();
let rcc = pp.RCC.constrain();
rcc.sys_ck(96.mhz())
.pclk1(48.mhz())
.pclk2(48.mhz())
.pclk3(48.mhz())
.pclk4(48.mhz())
.pll1_q_ck(48.mhz())
.freeze(pwrcfg, &pp.SYSCFG);
let pp = unsafe { pac::Peripherals::steal() };
pp.DBGMCU.cr.modify(|_, w| {
w.dbgsleep_d1().set_bit();
w.dbgstby_d1().set_bit();
w.dbgstop_d1().set_bit();
w.d1dbgcken().set_bit();
w
});
pp.RCC.ahb4enr.modify(|_, w| {
w.gpioaen().set_bit();
w.gpioben().set_bit();
w.gpiocen().set_bit();
w.gpioden().set_bit();
w.gpioeen().set_bit();
w.gpiofen().set_bit();
w
});
unsafe { embassy::time::set_clock(&ZeroClock) };
let executor = EXECUTOR.put(Executor::new());
executor.run(|spawner| {
unwrap!(spawner.spawn(main_task()));
})
}