stm32: add stm32u5 GPDMA, SPIv4 support, add HIL tests.

This commit is contained in:
Dario Nieuwenhuis
2022-04-26 23:57:26 +02:00
parent a39d796c3d
commit 009bb8e4e1
16 changed files with 447 additions and 59 deletions

View File

@ -109,7 +109,7 @@ fn main() {
for p in METADATA.peripherals {
if let Some(r) = &p.registers {
if r.kind == "dma" || r.kind == "bdma" {
if r.kind == "dma" || r.kind == "bdma" || r.kind == "gpdma" {
if p.name == "BDMA1" {
// BDMA1 in H7 doesn't use DMAMUX, which breaks
continue;
@ -214,7 +214,7 @@ fn main() {
// ========
// Generate fns to enable GPIO, DMA in RCC
for kind in ["dma", "bdma", "dmamux", "gpio"] {
for kind in ["dma", "bdma", "dmamux", "gpdma", "gpio"] {
let mut gg = TokenStream::new();
for p in METADATA.peripherals {
@ -528,11 +528,17 @@ fn main() {
let peri = format_ident!("{}", p.name);
let channel = if let Some(channel) = &ch.channel {
// Chip with DMA/BDMA, without DMAMUX
let channel = format_ident!("{}", channel);
quote!({channel: #channel})
} else if let Some(dmamux) = &ch.dmamux {
// Chip with DMAMUX
let dmamux = format_ident!("{}", dmamux);
quote!({dmamux: #dmamux})
} else if let Some(dma) = &ch.dma {
// Chip with GPDMA
let dma = format_ident!("{}", dma);
quote!({dma: #dma})
} else {
unreachable!();
};
@ -606,6 +612,7 @@ fn main() {
let mut dma_channel_count: usize = 0;
let mut bdma_channel_count: usize = 0;
let mut gpdma_channel_count: usize = 0;
for ch in METADATA.dma_channels {
let mut row = Vec::new();
@ -626,6 +633,10 @@ fn main() {
num = bdma_channel_count;
bdma_channel_count += 1;
}
"gpdma" => {
num = gpdma_channel_count;
gpdma_channel_count += 1;
}
_ => panic!("bad dma channel kind {}", bi.kind),
}
@ -650,6 +661,7 @@ fn main() {
g.extend(quote! {
pub(crate) const DMA_CHANNEL_COUNT: usize = #dma_channel_count;
pub(crate) const BDMA_CHANNEL_COUNT: usize = #bdma_channel_count;
pub(crate) const GPDMA_CHANNEL_COUNT: usize = #gpdma_channel_count;
});
for irq in METADATA.interrupts {

View File

@ -0,0 +1,293 @@
use core::sync::atomic::{fence, Ordering};
use core::task::Waker;
use embassy::interrupt::{Interrupt, InterruptExt};
use embassy::waitqueue::AtomicWaker;
use crate::_generated::GPDMA_CHANNEL_COUNT;
use crate::interrupt;
use crate::pac;
use crate::pac::gpdma::{vals, Gpdma};
use super::{Request, TransferOptions, Word, WordSize};
impl From<WordSize> for vals::ChTr1Dw {
fn from(raw: WordSize) -> Self {
match raw {
WordSize::OneByte => Self::BYTE,
WordSize::TwoBytes => Self::HALFWORD,
WordSize::FourBytes => Self::WORD,
}
}
}
struct ChannelState {
waker: AtomicWaker,
}
impl ChannelState {
const fn new() -> Self {
Self {
waker: AtomicWaker::new(),
}
}
}
struct State {
channels: [ChannelState; GPDMA_CHANNEL_COUNT],
}
impl State {
const fn new() -> Self {
const CH: ChannelState = ChannelState::new();
Self {
channels: [CH; GPDMA_CHANNEL_COUNT],
}
}
}
static STATE: State = State::new();
/// safety: must be called only once
pub(crate) unsafe fn init() {
foreach_interrupt! {
($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => {
interrupt::$irq::steal().enable();
};
}
crate::_generated::init_gpdma();
}
foreach_dma_channel! {
($channel_peri:ident, $dma_peri:ident, gpdma, $channel_num:expr, $index:expr, $dmamux:tt) => {
impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri {
unsafe fn start_write<W: Word>(&mut self, request: Request, buf: *const [W], reg_addr: *mut W, options: TransferOptions) {
let (ptr, len) = super::slice_ptr_parts(buf);
low_level_api::start_transfer(
pac::$dma_peri,
$channel_num,
request,
low_level_api::Dir::MemoryToPeripheral,
reg_addr as *const u32,
ptr as *mut u32,
len,
true,
W::bits(),
options,
)
}
unsafe fn start_write_repeated<W: Word>(&mut self, request: Request, repeated: W, count: usize, reg_addr: *mut W, options: TransferOptions) {
let buf = [repeated];
low_level_api::start_transfer(
pac::$dma_peri,
$channel_num,
request,
low_level_api::Dir::MemoryToPeripheral,
reg_addr as *const u32,
buf.as_ptr() as *mut u32,
count,
false,
W::bits(),
options,
)
}
unsafe fn start_read<W: Word>(&mut self, request: Request, reg_addr: *const W, buf: *mut [W], options: TransferOptions) {
let (ptr, len) = super::slice_ptr_parts_mut(buf);
low_level_api::start_transfer(
pac::$dma_peri,
$channel_num,
request,
low_level_api::Dir::PeripheralToMemory,
reg_addr as *const u32,
ptr as *mut u32,
len,
true,
W::bits(),
options,
);
}
unsafe fn start_double_buffered_read<W: Word>(
&mut self,
_request: Request,
_reg_addr: *const W,
_buffer0: *mut W,
_buffer1: *mut W,
_buffer_len: usize,
_options: TransferOptions,
) {
panic!("Unsafe double buffered mode is unavailable on GPBDMA");
}
unsafe fn set_buffer0<W: Word>(&mut self, _buffer: *mut W) {
panic!("Unsafe double buffered mode is unavailable on GPBDMA");
}
unsafe fn set_buffer1<W: Word>(&mut self, _buffer: *mut W) {
panic!("Unsafe double buffered mode is unavailable on GPBDMA");
}
unsafe fn is_buffer0_accessible(&mut self) -> bool {
panic!("Unsafe double buffered mode is unavailable on GPBDMA");
}
fn request_stop(&mut self) {
unsafe {low_level_api::request_stop(pac::$dma_peri, $channel_num);}
}
fn is_running(&self) -> bool {
unsafe {low_level_api::is_running(pac::$dma_peri, $channel_num)}
}
fn remaining_transfers(&mut self) -> u16 {
unsafe {low_level_api::get_remaining_transfers(pac::$dma_peri, $channel_num)}
}
fn set_waker(&mut self, waker: &Waker) {
unsafe {low_level_api::set_waker($index, waker )}
}
fn on_irq() {
unsafe {
low_level_api::on_irq_inner(pac::$dma_peri, $channel_num, $index);
}
}
}
impl crate::dma::Channel for crate::peripherals::$channel_peri { }
};
}
mod low_level_api {
use super::*;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Dir {
MemoryToPeripheral,
PeripheralToMemory,
}
pub unsafe fn start_transfer(
dma: Gpdma,
channel_number: u8,
request: Request,
dir: Dir,
peri_addr: *const u32,
mem_addr: *mut u32,
mem_len: usize,
incr_mem: bool,
data_size: WordSize,
_options: TransferOptions,
) {
// "Preceding reads and writes cannot be moved past subsequent writes."
fence(Ordering::SeqCst);
let ch = dma.ch(channel_number as _);
ch.llr().write(|_| {}); // no linked list
ch.tr1().write(|w| {
w.set_sdw(data_size.into());
w.set_ddw(data_size.into());
w.set_sinc(dir == Dir::MemoryToPeripheral && incr_mem);
w.set_dinc(dir == Dir::PeripheralToMemory && incr_mem);
});
ch.tr2().write(|w| {
w.set_dreq(match dir {
Dir::MemoryToPeripheral => vals::ChTr2Dreq::DESTINATIONPERIPHERAL,
Dir::PeripheralToMemory => vals::ChTr2Dreq::SOURCEPERIPHERAL,
});
w.set_reqsel(request);
});
ch.br1().write(|w| {
// BNDT is specified as bytes, not as number of transfers.
w.set_bndt((mem_len * data_size.bytes()) as u16)
});
match dir {
Dir::MemoryToPeripheral => {
ch.sar().write_value(mem_addr as _);
ch.dar().write_value(peri_addr as _);
}
Dir::PeripheralToMemory => {
ch.sar().write_value(peri_addr as _);
ch.dar().write_value(mem_addr as _);
}
}
ch.cr().write(|w| {
// Enable interrupts
w.set_tcie(true);
w.set_useie(true);
w.set_dteie(true);
w.set_suspie(true);
// Start it
w.set_en(true);
});
}
/// Stops the DMA channel.
pub unsafe fn request_stop(dma: Gpdma, channel_number: u8) {
// get a handle on the channel itself
let ch = dma.ch(channel_number as _);
// Disable the channel. Keep the IEs enabled so the irqs still fire.
ch.cr().write(|w| {
w.set_tcie(true);
w.set_useie(true);
w.set_dteie(true);
w.set_suspie(true);
});
// "Subsequent reads and writes cannot be moved ahead of preceding reads."
fence(Ordering::SeqCst);
}
/// Gets the running status of the channel
pub unsafe fn is_running(dma: Gpdma, ch: u8) -> bool {
let ch = dma.ch(ch as _);
!ch.sr().read().idlef()
}
/// Gets the total remaining transfers for the channel
/// Note: this will be zero for transfers that completed without cancellation.
pub unsafe fn get_remaining_transfers(dma: Gpdma, ch: u8) -> u16 {
// get a handle on the channel itself
let ch = dma.ch(ch as _);
// read the remaining transfer count. If this is zero, the transfer completed fully.
ch.br1().read().bndt()
}
/// Sets the waker for the specified DMA channel
pub unsafe fn set_waker(state_number: usize, waker: &Waker) {
STATE.channels[state_number].waker.register(waker);
}
/// Safety: Must be called with a matching set of parameters for a valid dma channel
pub unsafe fn on_irq_inner(dma: Gpdma, channel_num: u8, state_index: u8) {
let channel_num = channel_num as usize;
let state_index = state_index as usize;
let ch = dma.ch(channel_num);
let sr = ch.sr().read();
if sr.dtef() {
panic!(
"DMA: data transfer error on DMA@{:08x} channel {}",
dma.0 as u32, channel_num
);
}
if sr.usef() {
panic!(
"DMA: user settings error on DMA@{:08x} channel {}",
dma.0 as u32, channel_num
);
}
if sr.suspf() || sr.tcf() {
ch.cr().write(|w| w.set_reset(true));
STATE.channels[state_index].waker.wake();
}
}
}

View File

@ -4,6 +4,8 @@ pub(crate) mod bdma;
pub(crate) mod dma;
#[cfg(dmamux)]
mod dmamux;
#[cfg(gpdma)]
mod gpdma;
#[cfg(dmamux)]
pub use dmamux::*;
@ -24,9 +26,9 @@ pub mod low_level {
pub(crate) use transfers::*;
#[cfg(any(bdma_v2, dma_v2, dmamux))]
#[cfg(any(bdma_v2, dma_v2, dmamux, gpdma))]
pub type Request = u8;
#[cfg(not(any(bdma_v2, dma_v2, dmamux)))]
#[cfg(not(any(bdma_v2, dma_v2, dmamux, gpdma)))]
pub type Request = ();
pub(crate) mod sealed {
@ -118,11 +120,24 @@ pub(crate) mod sealed {
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum WordSize {
OneByte,
TwoBytes,
FourBytes,
}
impl WordSize {
pub fn bytes(&self) -> usize {
match self {
Self::OneByte => 1,
Self::TwoBytes => 2,
Self::FourBytes => 4,
}
}
}
pub trait Word: sealed::Word {
fn bits() -> WordSize;
}
@ -148,7 +163,8 @@ impl Word for u32 {
}
}
#[derive(Debug, PartialEq)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Burst {
/// Single transfer
Single,
@ -160,7 +176,8 @@ pub enum Burst {
Incr16,
}
#[derive(Debug, PartialEq)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum FlowControl {
/// Flow control by DMA
Dma,
@ -168,6 +185,8 @@ pub enum FlowControl {
Peripheral,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct TransferOptions {
/// Peripheral burst transfer configuration
pub pburst: Burst,
@ -299,6 +318,8 @@ pub(crate) unsafe fn init() {
dma::init();
#[cfg(dmamux)]
dmamux::init();
#[cfg(gpdma)]
gpdma::init();
}
// TODO: replace transmutes with core::ptr::metadata once it's stable

View File

@ -100,13 +100,13 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
unborrow!(sck, mosi, miso);
unsafe {
sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
#[cfg(any(spi_v2, spi_v3))]
#[cfg(any(spi_v2, spi_v3, spi_v4))]
sck.set_speed(crate::gpio::Speed::VeryHigh);
mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
#[cfg(any(spi_v2, spi_v3))]
#[cfg(any(spi_v2, spi_v3, spi_v4))]
mosi.set_speed(crate::gpio::Speed::VeryHigh);
miso.set_as_af(miso.af_num(), AFType::Input);
#[cfg(any(spi_v2, spi_v3))]
#[cfg(any(spi_v2, spi_v3, spi_v4))]
miso.set_speed(crate::gpio::Speed::VeryHigh);
}
@ -137,10 +137,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
unborrow!(sck, miso);
unsafe {
sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
#[cfg(any(spi_v2, spi_v3))]
#[cfg(any(spi_v2, spi_v3, spi_v4))]
sck.set_speed(crate::gpio::Speed::VeryHigh);
miso.set_as_af(miso.af_num(), AFType::Input);
#[cfg(any(spi_v2, spi_v3))]
#[cfg(any(spi_v2, spi_v3, spi_v4))]
miso.set_speed(crate::gpio::Speed::VeryHigh);
}
@ -171,10 +171,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
unborrow!(sck, mosi);
unsafe {
sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
#[cfg(any(spi_v2, spi_v3))]
#[cfg(any(spi_v2, spi_v3, spi_v4))]
sck.set_speed(crate::gpio::Speed::VeryHigh);
mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
#[cfg(any(spi_v2, spi_v3))]
#[cfg(any(spi_v2, spi_v3, spi_v4))]
mosi.set_speed(crate::gpio::Speed::VeryHigh);
}
@ -260,7 +260,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
w.set_spe(true);
});
}
#[cfg(spi_v3)]
#[cfg(any(spi_v3, spi_v4))]
unsafe {
T::REGS.ifcr().write(|w| w.0 = 0xffff_ffff);
T::REGS.cfg2().modify(|w| {
@ -285,7 +285,6 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
});
T::REGS.cr2().modify(|w| {
w.set_tsize(0);
w.set_tser(0);
});
T::REGS.cr1().modify(|w| {
w.set_ssi(false);
@ -320,7 +319,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
});
}
#[cfg(spi_v3)]
#[cfg(any(spi_v3, spi_v4))]
unsafe {
T::REGS.cfg2().modify(|w| {
w.set_cpha(cpha);
@ -333,7 +332,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
pub fn get_current_config(&self) -> Config {
#[cfg(any(spi_v1, spi_f1, spi_v2))]
let cfg = unsafe { T::REGS.cr1().read() };
#[cfg(spi_v3)]
#[cfg(any(spi_v3, spi_v4))]
let cfg = unsafe { T::REGS.cfg2().read() };
let polarity = if cfg.cpol() == vals::Cpol::IDLELOW {
Polarity::IdleLow
@ -386,7 +385,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
w.set_spe(true);
});
}
#[cfg(spi_v3)]
#[cfg(any(spi_v3, spi_v4))]
unsafe {
T::REGS.cr1().modify(|w| {
w.set_csusp(true);
@ -435,7 +434,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
T::REGS.cr1().modify(|w| {
w.set_spe(true);
});
#[cfg(spi_v3)]
#[cfg(any(spi_v3, spi_v4))]
T::REGS.cr1().modify(|w| {
w.set_cstart(true);
});
@ -466,7 +465,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
}
// SPIv3 clears rxfifo on SPE=0
#[cfg(not(spi_v3))]
#[cfg(not(any(spi_v3, spi_v4)))]
flush_rx_fifo(T::REGS);
let clock_byte_count = data.len();
@ -495,7 +494,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
T::REGS.cr1().modify(|w| {
w.set_spe(true);
});
#[cfg(spi_v3)]
#[cfg(any(spi_v3, spi_v4))]
T::REGS.cr1().modify(|w| {
w.set_cstart(true);
});
@ -533,7 +532,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
}
// SPIv3 clears rxfifo on SPE=0
#[cfg(not(spi_v3))]
#[cfg(not(any(spi_v3, spi_v4)))]
flush_rx_fifo(T::REGS);
let rx_request = self.rxdma.request();
@ -557,7 +556,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
T::REGS.cr1().modify(|w| {
w.set_spe(true);
});
#[cfg(spi_v3)]
#[cfg(any(spi_v3, spi_v4))]
T::REGS.cr1().modify(|w| {
w.set_cstart(true);
});
@ -642,9 +641,9 @@ impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> {
}
}
#[cfg(not(spi_v3))]
#[cfg(not(any(spi_v3, spi_v4)))]
use vals::Br;
#[cfg(spi_v3)]
#[cfg(any(spi_v3, spi_v4))]
use vals::Mbr as Br;
fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br {
@ -670,17 +669,17 @@ trait RegsExt {
impl RegsExt for Regs {
fn tx_ptr<W>(&self) -> *mut W {
#[cfg(not(spi_v3))]
#[cfg(not(any(spi_v3, spi_v4)))]
let dr = self.dr();
#[cfg(spi_v3)]
#[cfg(any(spi_v3, spi_v4))]
let dr = self.txdr();
dr.ptr() as *mut W
}
fn rx_ptr<W>(&self) -> *mut W {
#[cfg(not(spi_v3))]
#[cfg(not(any(spi_v3, spi_v4)))]
let dr = self.dr();
#[cfg(spi_v3)]
#[cfg(any(spi_v3, spi_v4))]
let dr = self.rxdr();
dr.ptr() as *mut W
}
@ -690,22 +689,22 @@ fn check_error_flags(sr: regs::Sr) -> Result<(), Error> {
if sr.ovr() {
return Err(Error::Overrun);
}
#[cfg(not(any(spi_f1, spi_v3)))]
#[cfg(not(any(spi_f1, spi_v3, spi_v4)))]
if sr.fre() {
return Err(Error::Framing);
}
#[cfg(spi_v3)]
#[cfg(any(spi_v3, spi_v4))]
if sr.tifre() {
return Err(Error::Framing);
}
if sr.modf() {
return Err(Error::ModeFault);
}
#[cfg(not(spi_v3))]
#[cfg(not(any(spi_v3, spi_v4)))]
if sr.crcerr() {
return Err(Error::Crc);
}
#[cfg(spi_v3)]
#[cfg(any(spi_v3, spi_v4))]
if sr.crce() {
return Err(Error::Crc);
}
@ -719,11 +718,11 @@ fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> {
check_error_flags(sr)?;
#[cfg(not(spi_v3))]
#[cfg(not(any(spi_v3, spi_v4)))]
if sr.txe() {
return Ok(());
}
#[cfg(spi_v3)]
#[cfg(any(spi_v3, spi_v4))]
if sr.txp() {
return Ok(());
}
@ -736,11 +735,11 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> {
check_error_flags(sr)?;
#[cfg(not(spi_v3))]
#[cfg(not(any(spi_v3, spi_v4)))]
if sr.rxne() {
return Ok(());
}
#[cfg(spi_v3)]
#[cfg(any(spi_v3, spi_v4))]
if sr.rxp() {
return Ok(());
}
@ -749,11 +748,11 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> {
fn flush_rx_fifo(regs: Regs) {
unsafe {
#[cfg(not(spi_v3))]
#[cfg(not(any(spi_v3, spi_v4)))]
while regs.sr().read().rxne() {
let _ = regs.dr().read();
}
#[cfg(spi_v3)]
#[cfg(any(spi_v3, spi_v4))]
while regs.sr().read().rxp() {
let _ = regs.rxdr().read();
}
@ -762,11 +761,11 @@ fn flush_rx_fifo(regs: Regs) {
fn set_txdmaen(regs: Regs, val: bool) {
unsafe {
#[cfg(not(spi_v3))]
#[cfg(not(any(spi_v3, spi_v4)))]
regs.cr2().modify(|reg| {
reg.set_txdmaen(val);
});
#[cfg(spi_v3)]
#[cfg(any(spi_v3, spi_v4))]
regs.cfg1().modify(|reg| {
reg.set_txdmaen(val);
});
@ -775,11 +774,11 @@ fn set_txdmaen(regs: Regs, val: bool) {
fn set_rxdmaen(regs: Regs, val: bool) {
unsafe {
#[cfg(not(spi_v3))]
#[cfg(not(any(spi_v3, spi_v4)))]
regs.cr2().modify(|reg| {
reg.set_rxdmaen(val);
});
#[cfg(spi_v3)]
#[cfg(any(spi_v3, spi_v4))]
regs.cfg1().modify(|reg| {
reg.set_rxdmaen(val);
});
@ -791,21 +790,21 @@ fn finish_dma(regs: Regs) {
#[cfg(spi_v2)]
while regs.sr().read().ftlvl() > 0 {}
#[cfg(spi_v3)]
#[cfg(any(spi_v3, spi_v4))]
while !regs.sr().read().txc() {}
#[cfg(not(spi_v3))]
#[cfg(not(any(spi_v3, spi_v4)))]
while regs.sr().read().bsy() {}
regs.cr1().modify(|w| {
w.set_spe(false);
});
#[cfg(not(spi_v3))]
#[cfg(not(any(spi_v3, spi_v4)))]
regs.cr2().modify(|reg| {
reg.set_txdmaen(false);
reg.set_rxdmaen(false);
});
#[cfg(spi_v3)]
#[cfg(any(spi_v3, spi_v4))]
regs.cfg1().modify(|reg| {
reg.set_txdmaen(false);
reg.set_rxdmaen(false);
@ -819,7 +818,7 @@ fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> {
unsafe {
ptr::write_volatile(regs.tx_ptr(), tx_word);
#[cfg(spi_v3)]
#[cfg(any(spi_v3, spi_v4))]
regs.cr1().modify(|reg| reg.set_cstart(true));
}
@ -1018,7 +1017,7 @@ pub(crate) mod sealed {
}
}
#[cfg(spi_v3)]
#[cfg(any(spi_v3, spi_v4))]
pub fn dsize(&self) -> u8 {
match self {
WordSize::EightBit => 0b0111,
@ -1026,7 +1025,7 @@ pub(crate) mod sealed {
}
}
#[cfg(spi_v3)]
#[cfg(any(spi_v3, spi_v4))]
pub fn _frxth(&self) -> vals::Fthlv {
match self {
WordSize::EightBit => vals::Fthlv::ONEFRAME,

View File

@ -42,7 +42,19 @@ macro_rules! dma_trait_impl {
}
};
// No DMAMUX
// DMAMUX
(crate::$mod:ident::$trait:ident, $instance:ident, {dma: $dma:ident}, $request:expr) => {
impl<T> crate::$mod::$trait<crate::peripherals::$instance> for T
where
T: crate::dma::Channel,
{
fn request(&self) -> crate::dma::Request {
$request
}
}
};
// DMA/GPDMA, without DMAMUX
(crate::$mod:ident::$trait:ident, $instance:ident, {channel: $channel:ident}, $request:expr) => {
impl crate::$mod::$trait<crate::peripherals::$instance> for crate::peripherals::$channel {
fn request(&self) -> crate::dma::Request {