mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-25 00:02:28 +00:00
Merge pull request #3007 from liarokapisv/spi_v3-fix-rx
Add proper rxonly support for spi_v3 and force tx dma stream requirem…
This commit is contained in:
commit
7532a06f67
@ -72,7 +72,7 @@ rand_core = "0.6.3"
|
|||||||
sdio-host = "0.5.0"
|
sdio-host = "0.5.0"
|
||||||
critical-section = "1.1"
|
critical-section = "1.1"
|
||||||
#stm32-metapac = { version = "15" }
|
#stm32-metapac = { version = "15" }
|
||||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-34c0188a682b32c32ff147d377e0629b1ebe8318" }
|
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad633a3e266151ea4d8fad630031a075ee02ab34" }
|
||||||
|
|
||||||
vcell = "0.1.3"
|
vcell = "0.1.3"
|
||||||
nb = "1.0.0"
|
nb = "1.0.0"
|
||||||
@ -97,7 +97,7 @@ proc-macro2 = "1.0.36"
|
|||||||
quote = "1.0.15"
|
quote = "1.0.15"
|
||||||
|
|
||||||
#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
|
#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
|
||||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-34c0188a682b32c32ff147d377e0629b1ebe8318", default-features = false, features = ["metadata"]}
|
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad633a3e266151ea4d8fad630031a075ee02ab34", default-features = false, features = ["metadata"]}
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["rt"]
|
default = ["rt"]
|
||||||
|
@ -48,6 +48,7 @@ impl<'d> ChannelAndRequest<'d> {
|
|||||||
Transfer::new_write_raw(&mut self.channel, self.request, buf, peri_addr, options)
|
Transfer::new_write_raw(&mut self.channel, self.request, buf, peri_addr, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub unsafe fn write_repeated<'a, W: Word>(
|
pub unsafe fn write_repeated<'a, W: Word>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
repeated: &'a W,
|
repeated: &'a W,
|
||||||
|
@ -169,7 +169,7 @@ impl<'d> I2S<'d> {
|
|||||||
ws: impl Peripheral<P = impl WsPin<T>> + 'd,
|
ws: impl Peripheral<P = impl WsPin<T>> + 'd,
|
||||||
ck: impl Peripheral<P = impl CkPin<T>> + 'd,
|
ck: impl Peripheral<P = impl CkPin<T>> + 'd,
|
||||||
mck: impl Peripheral<P = impl MckPin<T>> + 'd,
|
mck: impl Peripheral<P = impl MckPin<T>> + 'd,
|
||||||
txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
|
#[cfg(not(spi_v3))] txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
|
||||||
rxdma: impl Peripheral<P = impl RxDma<T>> + 'd,
|
rxdma: impl Peripheral<P = impl RxDma<T>> + 'd,
|
||||||
freq: Hertz,
|
freq: Hertz,
|
||||||
config: Config,
|
config: Config,
|
||||||
@ -190,7 +190,15 @@ impl<'d> I2S<'d> {
|
|||||||
|
|
||||||
let mut spi_cfg = SpiConfig::default();
|
let mut spi_cfg = SpiConfig::default();
|
||||||
spi_cfg.frequency = freq;
|
spi_cfg.frequency = freq;
|
||||||
let spi = Spi::new_internal(peri, txdma, rxdma, spi_cfg);
|
let spi = Spi::new_internal(
|
||||||
|
peri,
|
||||||
|
#[cfg(not(spi_v3))]
|
||||||
|
new_dma!(txdma),
|
||||||
|
#[cfg(spi_v3)]
|
||||||
|
None,
|
||||||
|
new_dma!(rxdma),
|
||||||
|
spi_cfg,
|
||||||
|
);
|
||||||
|
|
||||||
// TODO move i2s to the new mux infra.
|
// TODO move i2s to the new mux infra.
|
||||||
//#[cfg(all(rcc_f4, not(stm32f410)))]
|
//#[cfg(all(rcc_f4, not(stm32f410)))]
|
||||||
|
@ -508,6 +508,7 @@ impl<'d> Spi<'d, Async> {
|
|||||||
peri: impl Peripheral<P = T> + 'd,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
sck: impl Peripheral<P = impl SckPin<T>> + 'd,
|
sck: impl Peripheral<P = impl SckPin<T>> + 'd,
|
||||||
miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
|
miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
|
||||||
|
#[cfg(any(spi_v1, spi_f1, spi_v2))] tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
|
||||||
rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
|
rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@ -516,6 +517,9 @@ impl<'d> Spi<'d, Async> {
|
|||||||
new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
|
new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
|
||||||
None,
|
None,
|
||||||
new_pin!(miso, AFType::Input, Speed::VeryHigh),
|
new_pin!(miso, AFType::Input, Speed::VeryHigh),
|
||||||
|
#[cfg(any(spi_v1, spi_f1, spi_v2))]
|
||||||
|
new_dma!(tx_dma),
|
||||||
|
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||||
None,
|
None,
|
||||||
new_dma!(rx_dma),
|
new_dma!(rx_dma),
|
||||||
config,
|
config,
|
||||||
@ -584,11 +588,11 @@ impl<'d> Spi<'d, Async> {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) fn new_internal<T: Instance>(
|
pub(crate) fn new_internal<T: Instance>(
|
||||||
peri: impl Peripheral<P = T> + 'd,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
|
tx_dma: Option<ChannelAndRequest<'d>>,
|
||||||
rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
|
rx_dma: Option<ChannelAndRequest<'d>>,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self::new_inner(peri, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config)
|
Self::new_inner(peri, None, None, None, tx_dma, rx_dma, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SPI write, using DMA.
|
/// SPI write, using DMA.
|
||||||
@ -622,12 +626,100 @@ impl<'d> Spi<'d, Async> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// SPI read, using DMA.
|
/// SPI read, using DMA.
|
||||||
|
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||||
|
pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
|
||||||
|
if data.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let regs = self.info.regs;
|
||||||
|
|
||||||
|
regs.cr1().modify(|w| {
|
||||||
|
w.set_spe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
let comm = regs.cfg2().modify(|w| {
|
||||||
|
let prev = w.comm();
|
||||||
|
w.set_comm(vals::Comm::RECEIVER);
|
||||||
|
prev
|
||||||
|
});
|
||||||
|
|
||||||
|
#[cfg(spi_v3)]
|
||||||
|
let i2scfg = regs.i2scfgr().modify(|w| {
|
||||||
|
w.i2smod().then(|| {
|
||||||
|
let prev = w.i2scfg();
|
||||||
|
w.set_i2scfg(match prev {
|
||||||
|
vals::I2scfg::SLAVERX | vals::I2scfg::SLAVEFULLDUPLEX => vals::I2scfg::SLAVERX,
|
||||||
|
vals::I2scfg::MASTERRX | vals::I2scfg::MASTERFULLDUPLEX => vals::I2scfg::MASTERRX,
|
||||||
|
_ => panic!("unsupported configuration"),
|
||||||
|
});
|
||||||
|
prev
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let rx_src = regs.rx_ptr();
|
||||||
|
|
||||||
|
for mut chunk in data.chunks_mut(u16::max_value().into()) {
|
||||||
|
self.set_word_size(W::CONFIG);
|
||||||
|
set_rxdmaen(regs, true);
|
||||||
|
|
||||||
|
let tsize = chunk.len();
|
||||||
|
|
||||||
|
let transfer = unsafe {
|
||||||
|
self.rx_dma
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.read(rx_src, &mut chunk, Default::default())
|
||||||
|
};
|
||||||
|
|
||||||
|
regs.cr2().modify(|w| {
|
||||||
|
w.set_tsize(tsize as u16);
|
||||||
|
});
|
||||||
|
|
||||||
|
regs.cr1().modify(|w| {
|
||||||
|
w.set_spe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
regs.cr1().modify(|w| {
|
||||||
|
w.set_cstart(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
transfer.await;
|
||||||
|
|
||||||
|
finish_dma(regs);
|
||||||
|
}
|
||||||
|
|
||||||
|
regs.cr1().modify(|w| {
|
||||||
|
w.set_spe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
regs.cfg2().modify(|w| {
|
||||||
|
w.set_comm(comm);
|
||||||
|
});
|
||||||
|
|
||||||
|
regs.cr2().modify(|w| {
|
||||||
|
w.set_tsize(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
#[cfg(spi_v3)]
|
||||||
|
if let Some(i2scfg) = i2scfg {
|
||||||
|
regs.i2scfgr().modify(|w| {
|
||||||
|
w.set_i2scfg(i2scfg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SPI read, using DMA.
|
||||||
|
#[cfg(any(spi_v1, spi_f1, spi_v2))]
|
||||||
pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
|
pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
|
||||||
if data.is_empty() {
|
if data.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.set_word_size(W::CONFIG);
|
self.set_word_size(W::CONFIG);
|
||||||
|
|
||||||
self.info.regs.cr1().modify(|w| {
|
self.info.regs.cr1().modify(|w| {
|
||||||
w.set_spe(false);
|
w.set_spe(false);
|
||||||
});
|
});
|
||||||
@ -907,7 +999,13 @@ fn finish_dma(regs: Regs) {
|
|||||||
while regs.sr().read().ftlvl().to_bits() > 0 {}
|
while regs.sr().read().ftlvl().to_bits() > 0 {}
|
||||||
|
|
||||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||||
while !regs.sr().read().txc() {}
|
{
|
||||||
|
if regs.cr2().read().tsize() == 0 {
|
||||||
|
while !regs.sr().read().txc() {}
|
||||||
|
} else {
|
||||||
|
while !regs.sr().read().eot() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
||||||
while regs.sr().read().bsy() {}
|
while regs.sr().read().bsy() {}
|
||||||
|
|
||||||
|
@ -8,27 +8,33 @@ use defmt::assert_eq;
|
|||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_stm32::spi::{self, Spi};
|
use embassy_stm32::spi::{self, Spi};
|
||||||
use embassy_stm32::time::Hertz;
|
use embassy_stm32::time::Hertz;
|
||||||
|
use embassy_stm32::{into_ref, Peripheral as _};
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_stm32::init(config());
|
let p = embassy_stm32::init(config());
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
let spi = peri!(p, SPI);
|
let spi_peri = peri!(p, SPI);
|
||||||
let sck = peri!(p, SPI_SCK);
|
let sck = peri!(p, SPI_SCK);
|
||||||
let mosi = peri!(p, SPI_MOSI);
|
let mosi = peri!(p, SPI_MOSI);
|
||||||
let miso = peri!(p, SPI_MISO);
|
let miso = peri!(p, SPI_MISO);
|
||||||
let tx_dma = peri!(p, SPI_TX_DMA);
|
let tx_dma = peri!(p, SPI_TX_DMA);
|
||||||
let rx_dma = peri!(p, SPI_RX_DMA);
|
let rx_dma = peri!(p, SPI_RX_DMA);
|
||||||
|
|
||||||
|
into_ref!(spi_peri, sck, mosi, miso, tx_dma, rx_dma);
|
||||||
|
|
||||||
let mut spi_config = spi::Config::default();
|
let mut spi_config = spi::Config::default();
|
||||||
spi_config.frequency = Hertz(1_000_000);
|
spi_config.frequency = Hertz(1_000_000);
|
||||||
|
|
||||||
let mut spi = Spi::new(
|
let mut spi = Spi::new(
|
||||||
spi, sck, // Arduino D13
|
spi_peri.reborrow(),
|
||||||
mosi, // Arduino D11
|
sck.reborrow(), // Arduino D13
|
||||||
miso, // Arduino D12
|
mosi.reborrow(), // Arduino D11
|
||||||
tx_dma, rx_dma, spi_config,
|
miso.reborrow(), // Arduino D12
|
||||||
|
tx_dma.reborrow(),
|
||||||
|
rx_dma.reborrow(),
|
||||||
|
spi_config,
|
||||||
);
|
);
|
||||||
|
|
||||||
let data: [u8; 9] = [0x00, 0xFF, 0xAA, 0x55, 0xC0, 0xFF, 0xEE, 0xC0, 0xDE];
|
let data: [u8; 9] = [0x00, 0xFF, 0xAA, 0x55, 0xC0, 0xFF, 0xEE, 0xC0, 0xDE];
|
||||||
@ -76,6 +82,55 @@ async fn main(_spawner: Spawner) {
|
|||||||
spi.blocking_read(&mut buf).unwrap();
|
spi.blocking_read(&mut buf).unwrap();
|
||||||
spi.write(&buf).await.unwrap();
|
spi.write(&buf).await.unwrap();
|
||||||
|
|
||||||
|
core::mem::drop(spi);
|
||||||
|
|
||||||
|
// test rx-only configuration
|
||||||
|
|
||||||
|
// stm32f207zg - spi_v1
|
||||||
|
// stm32f103c8 - spi_f1
|
||||||
|
// stm32g491re - spi_v2
|
||||||
|
// stm32h753zi - spi_v3
|
||||||
|
// stm32h563zi - spi_v4
|
||||||
|
// stm32wba52cg - spi_v5
|
||||||
|
|
||||||
|
#[cfg(any(stm32f207zg, stm32f103c8, stm32g491re, stm32h753zi, stm32h563zi, stm32wba52cg))]
|
||||||
|
{
|
||||||
|
let mut spi = {
|
||||||
|
#[cfg(stm32f207zg, stm32f103c8, stm32g491re)]
|
||||||
|
{
|
||||||
|
Spi::new_rxonly(
|
||||||
|
spi_peri.reborrow(),
|
||||||
|
sck.reborrow(),
|
||||||
|
miso.reborrow(),
|
||||||
|
tx_dma.reborrow(),
|
||||||
|
rx_dma.reborrow(),
|
||||||
|
spi_config,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
#[cfg(stm32h753zi, stm32h563zi, stm32wba52cg)]
|
||||||
|
{
|
||||||
|
Spi::new_rxonly(
|
||||||
|
spi_peri.reborrow(),
|
||||||
|
sck.reborrow(),
|
||||||
|
miso.reborrow(),
|
||||||
|
rx_dma.reborrow(),
|
||||||
|
spi_config,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
use embassy_stm32::gpio;
|
||||||
|
let mut mosi = gpio::Output::new(mosi.reborrow(), gpio::Level::Low, gpio::Speed::Low);
|
||||||
|
|
||||||
|
mosi.set_high();
|
||||||
|
spi.read(&mut buf).await.unwrap();
|
||||||
|
assert_eq!(buf, [0xff; 9]);
|
||||||
|
|
||||||
|
mosi.set_low();
|
||||||
|
spi.read(&mut buf).await.unwrap();
|
||||||
|
assert_eq!(buf, [0x00; 9]);
|
||||||
|
};
|
||||||
|
|
||||||
info!("Test OK");
|
info!("Test OK");
|
||||||
cortex_m::asm::bkpt();
|
cortex_m::asm::bkpt();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user