Merge #1294
1294: Add support for `QSPI` in `stm32` r=Dirbaio a=Mirror0 Implemented with help of Tomasz Grześ <tomasz.grzes@gmail.com>. Tested only on stm32f777zi. Co-authored-by: Mateusz Butkiewicz <mateusz@github.butkiewicz.dev>
This commit is contained in:
commit
754bb802ba
@ -427,6 +427,12 @@ fn main() {
|
|||||||
(("sdmmc", "D6"), quote!(crate::sdmmc::D6Pin)),
|
(("sdmmc", "D6"), quote!(crate::sdmmc::D6Pin)),
|
||||||
(("sdmmc", "D6"), quote!(crate::sdmmc::D7Pin)),
|
(("sdmmc", "D6"), quote!(crate::sdmmc::D7Pin)),
|
||||||
(("sdmmc", "D8"), quote!(crate::sdmmc::D8Pin)),
|
(("sdmmc", "D8"), quote!(crate::sdmmc::D8Pin)),
|
||||||
|
(("quadspi", "BK1_IO0"), quote!(crate::qspi::D0Pin)),
|
||||||
|
(("quadspi", "BK1_IO1"), quote!(crate::qspi::D1Pin)),
|
||||||
|
(("quadspi", "BK1_IO2"), quote!(crate::qspi::D2Pin)),
|
||||||
|
(("quadspi", "BK1_IO3"), quote!(crate::qspi::D3Pin)),
|
||||||
|
(("quadspi", "CLK"), quote!(crate::qspi::SckPin)),
|
||||||
|
(("quadspi", "BK1_NCS"), quote!(crate::qspi::NSSPin)),
|
||||||
].into();
|
].into();
|
||||||
|
|
||||||
for p in METADATA.peripherals {
|
for p in METADATA.peripherals {
|
||||||
@ -507,6 +513,7 @@ fn main() {
|
|||||||
(("dcmi", "PSSI"), quote!(crate::dcmi::FrameDma)),
|
(("dcmi", "PSSI"), quote!(crate::dcmi::FrameDma)),
|
||||||
// SDMMCv1 uses the same channel for both directions, so just implement for RX
|
// SDMMCv1 uses the same channel for both directions, so just implement for RX
|
||||||
(("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)),
|
(("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)),
|
||||||
|
(("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)),
|
||||||
]
|
]
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
|
@ -48,6 +48,8 @@ pub mod crc;
|
|||||||
))]
|
))]
|
||||||
pub mod flash;
|
pub mod flash;
|
||||||
pub mod pwm;
|
pub mod pwm;
|
||||||
|
#[cfg(quadspi)]
|
||||||
|
pub mod qspi;
|
||||||
#[cfg(rng)]
|
#[cfg(rng)]
|
||||||
pub mod rng;
|
pub mod rng;
|
||||||
#[cfg(sdmmc)]
|
#[cfg(sdmmc)]
|
||||||
@ -60,7 +62,6 @@ pub mod usart;
|
|||||||
pub mod usb;
|
pub mod usb;
|
||||||
#[cfg(otg)]
|
#[cfg(otg)]
|
||||||
pub mod usb_otg;
|
pub mod usb_otg;
|
||||||
|
|
||||||
#[cfg(iwdg)]
|
#[cfg(iwdg)]
|
||||||
pub mod wdg;
|
pub mod wdg;
|
||||||
|
|
||||||
|
294
embassy-stm32/src/qspi/enums.rs
Normal file
294
embassy-stm32/src/qspi/enums.rs
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub(crate) enum QspiMode {
|
||||||
|
IndirectWrite,
|
||||||
|
IndirectRead,
|
||||||
|
AutoPolling,
|
||||||
|
MemoryMapped,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<u8> for QspiMode {
|
||||||
|
fn into(self) -> u8 {
|
||||||
|
match self {
|
||||||
|
QspiMode::IndirectWrite => 0b00,
|
||||||
|
QspiMode::IndirectRead => 0b01,
|
||||||
|
QspiMode::AutoPolling => 0b10,
|
||||||
|
QspiMode::MemoryMapped => 0b11,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub enum QspiWidth {
|
||||||
|
NONE,
|
||||||
|
SING,
|
||||||
|
DUAL,
|
||||||
|
QUAD,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<u8> for QspiWidth {
|
||||||
|
fn into(self) -> u8 {
|
||||||
|
match self {
|
||||||
|
QspiWidth::NONE => 0b00,
|
||||||
|
QspiWidth::SING => 0b01,
|
||||||
|
QspiWidth::DUAL => 0b10,
|
||||||
|
QspiWidth::QUAD => 0b11,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub enum MemorySize {
|
||||||
|
_1KiB,
|
||||||
|
_2KiB,
|
||||||
|
_4KiB,
|
||||||
|
_8KiB,
|
||||||
|
_16KiB,
|
||||||
|
_32KiB,
|
||||||
|
_64KiB,
|
||||||
|
_128KiB,
|
||||||
|
_256KiB,
|
||||||
|
_512KiB,
|
||||||
|
_1MiB,
|
||||||
|
_2MiB,
|
||||||
|
_4MiB,
|
||||||
|
_8MiB,
|
||||||
|
_16MiB,
|
||||||
|
_32MiB,
|
||||||
|
_64MiB,
|
||||||
|
_128MiB,
|
||||||
|
_256MiB,
|
||||||
|
_512MiB,
|
||||||
|
_1GiB,
|
||||||
|
_2GiB,
|
||||||
|
_4GiB,
|
||||||
|
Other(u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<u8> for MemorySize {
|
||||||
|
fn into(self) -> u8 {
|
||||||
|
match self {
|
||||||
|
MemorySize::_1KiB => 9,
|
||||||
|
MemorySize::_2KiB => 10,
|
||||||
|
MemorySize::_4KiB => 11,
|
||||||
|
MemorySize::_8KiB => 12,
|
||||||
|
MemorySize::_16KiB => 13,
|
||||||
|
MemorySize::_32KiB => 14,
|
||||||
|
MemorySize::_64KiB => 15,
|
||||||
|
MemorySize::_128KiB => 16,
|
||||||
|
MemorySize::_256KiB => 17,
|
||||||
|
MemorySize::_512KiB => 18,
|
||||||
|
MemorySize::_1MiB => 19,
|
||||||
|
MemorySize::_2MiB => 20,
|
||||||
|
MemorySize::_4MiB => 21,
|
||||||
|
MemorySize::_8MiB => 22,
|
||||||
|
MemorySize::_16MiB => 23,
|
||||||
|
MemorySize::_32MiB => 24,
|
||||||
|
MemorySize::_64MiB => 25,
|
||||||
|
MemorySize::_128MiB => 26,
|
||||||
|
MemorySize::_256MiB => 27,
|
||||||
|
MemorySize::_512MiB => 28,
|
||||||
|
MemorySize::_1GiB => 29,
|
||||||
|
MemorySize::_2GiB => 30,
|
||||||
|
MemorySize::_4GiB => 31,
|
||||||
|
MemorySize::Other(val) => val,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub enum AddressSize {
|
||||||
|
_8Bit,
|
||||||
|
_16Bit,
|
||||||
|
_24bit,
|
||||||
|
_32bit,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<u8> for AddressSize {
|
||||||
|
fn into(self) -> u8 {
|
||||||
|
match self {
|
||||||
|
AddressSize::_8Bit => 0b00,
|
||||||
|
AddressSize::_16Bit => 0b01,
|
||||||
|
AddressSize::_24bit => 0b10,
|
||||||
|
AddressSize::_32bit => 0b11,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub enum ChipSelectHightTime {
|
||||||
|
_1Cycle,
|
||||||
|
_2Cycle,
|
||||||
|
_3Cycle,
|
||||||
|
_4Cycle,
|
||||||
|
_5Cycle,
|
||||||
|
_6Cycle,
|
||||||
|
_7Cycle,
|
||||||
|
_8Cycle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<u8> for ChipSelectHightTime {
|
||||||
|
fn into(self) -> u8 {
|
||||||
|
match self {
|
||||||
|
ChipSelectHightTime::_1Cycle => 0,
|
||||||
|
ChipSelectHightTime::_2Cycle => 1,
|
||||||
|
ChipSelectHightTime::_3Cycle => 2,
|
||||||
|
ChipSelectHightTime::_4Cycle => 3,
|
||||||
|
ChipSelectHightTime::_5Cycle => 4,
|
||||||
|
ChipSelectHightTime::_6Cycle => 5,
|
||||||
|
ChipSelectHightTime::_7Cycle => 6,
|
||||||
|
ChipSelectHightTime::_8Cycle => 7,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub enum FIFOThresholdLevel {
|
||||||
|
_1Bytes,
|
||||||
|
_2Bytes,
|
||||||
|
_3Bytes,
|
||||||
|
_4Bytes,
|
||||||
|
_5Bytes,
|
||||||
|
_6Bytes,
|
||||||
|
_7Bytes,
|
||||||
|
_8Bytes,
|
||||||
|
_9Bytes,
|
||||||
|
_10Bytes,
|
||||||
|
_11Bytes,
|
||||||
|
_12Bytes,
|
||||||
|
_13Bytes,
|
||||||
|
_14Bytes,
|
||||||
|
_15Bytes,
|
||||||
|
_16Bytes,
|
||||||
|
_17Bytes,
|
||||||
|
_18Bytes,
|
||||||
|
_19Bytes,
|
||||||
|
_20Bytes,
|
||||||
|
_21Bytes,
|
||||||
|
_22Bytes,
|
||||||
|
_23Bytes,
|
||||||
|
_24Bytes,
|
||||||
|
_25Bytes,
|
||||||
|
_26Bytes,
|
||||||
|
_27Bytes,
|
||||||
|
_28Bytes,
|
||||||
|
_29Bytes,
|
||||||
|
_30Bytes,
|
||||||
|
_31Bytes,
|
||||||
|
_32Bytes,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<u8> for FIFOThresholdLevel {
|
||||||
|
fn into(self) -> u8 {
|
||||||
|
match self {
|
||||||
|
FIFOThresholdLevel::_1Bytes => 0,
|
||||||
|
FIFOThresholdLevel::_2Bytes => 1,
|
||||||
|
FIFOThresholdLevel::_3Bytes => 2,
|
||||||
|
FIFOThresholdLevel::_4Bytes => 3,
|
||||||
|
FIFOThresholdLevel::_5Bytes => 4,
|
||||||
|
FIFOThresholdLevel::_6Bytes => 5,
|
||||||
|
FIFOThresholdLevel::_7Bytes => 6,
|
||||||
|
FIFOThresholdLevel::_8Bytes => 7,
|
||||||
|
FIFOThresholdLevel::_9Bytes => 8,
|
||||||
|
FIFOThresholdLevel::_10Bytes => 9,
|
||||||
|
FIFOThresholdLevel::_11Bytes => 10,
|
||||||
|
FIFOThresholdLevel::_12Bytes => 11,
|
||||||
|
FIFOThresholdLevel::_13Bytes => 12,
|
||||||
|
FIFOThresholdLevel::_14Bytes => 13,
|
||||||
|
FIFOThresholdLevel::_15Bytes => 14,
|
||||||
|
FIFOThresholdLevel::_16Bytes => 15,
|
||||||
|
FIFOThresholdLevel::_17Bytes => 16,
|
||||||
|
FIFOThresholdLevel::_18Bytes => 17,
|
||||||
|
FIFOThresholdLevel::_19Bytes => 18,
|
||||||
|
FIFOThresholdLevel::_20Bytes => 19,
|
||||||
|
FIFOThresholdLevel::_21Bytes => 20,
|
||||||
|
FIFOThresholdLevel::_22Bytes => 21,
|
||||||
|
FIFOThresholdLevel::_23Bytes => 22,
|
||||||
|
FIFOThresholdLevel::_24Bytes => 23,
|
||||||
|
FIFOThresholdLevel::_25Bytes => 24,
|
||||||
|
FIFOThresholdLevel::_26Bytes => 25,
|
||||||
|
FIFOThresholdLevel::_27Bytes => 26,
|
||||||
|
FIFOThresholdLevel::_28Bytes => 27,
|
||||||
|
FIFOThresholdLevel::_29Bytes => 28,
|
||||||
|
FIFOThresholdLevel::_30Bytes => 29,
|
||||||
|
FIFOThresholdLevel::_31Bytes => 30,
|
||||||
|
FIFOThresholdLevel::_32Bytes => 31,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub enum DummyCycles {
|
||||||
|
_0,
|
||||||
|
_1,
|
||||||
|
_2,
|
||||||
|
_3,
|
||||||
|
_4,
|
||||||
|
_5,
|
||||||
|
_6,
|
||||||
|
_7,
|
||||||
|
_8,
|
||||||
|
_9,
|
||||||
|
_10,
|
||||||
|
_11,
|
||||||
|
_12,
|
||||||
|
_13,
|
||||||
|
_14,
|
||||||
|
_15,
|
||||||
|
_16,
|
||||||
|
_17,
|
||||||
|
_18,
|
||||||
|
_19,
|
||||||
|
_20,
|
||||||
|
_21,
|
||||||
|
_22,
|
||||||
|
_23,
|
||||||
|
_24,
|
||||||
|
_25,
|
||||||
|
_26,
|
||||||
|
_27,
|
||||||
|
_28,
|
||||||
|
_29,
|
||||||
|
_30,
|
||||||
|
_31,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<u8> for DummyCycles {
|
||||||
|
fn into(self) -> u8 {
|
||||||
|
match self {
|
||||||
|
DummyCycles::_0 => 0,
|
||||||
|
DummyCycles::_1 => 1,
|
||||||
|
DummyCycles::_2 => 2,
|
||||||
|
DummyCycles::_3 => 3,
|
||||||
|
DummyCycles::_4 => 4,
|
||||||
|
DummyCycles::_5 => 5,
|
||||||
|
DummyCycles::_6 => 6,
|
||||||
|
DummyCycles::_7 => 7,
|
||||||
|
DummyCycles::_8 => 8,
|
||||||
|
DummyCycles::_9 => 9,
|
||||||
|
DummyCycles::_10 => 10,
|
||||||
|
DummyCycles::_11 => 11,
|
||||||
|
DummyCycles::_12 => 12,
|
||||||
|
DummyCycles::_13 => 13,
|
||||||
|
DummyCycles::_14 => 14,
|
||||||
|
DummyCycles::_15 => 15,
|
||||||
|
DummyCycles::_16 => 16,
|
||||||
|
DummyCycles::_17 => 17,
|
||||||
|
DummyCycles::_18 => 18,
|
||||||
|
DummyCycles::_19 => 19,
|
||||||
|
DummyCycles::_20 => 20,
|
||||||
|
DummyCycles::_21 => 21,
|
||||||
|
DummyCycles::_22 => 22,
|
||||||
|
DummyCycles::_23 => 23,
|
||||||
|
DummyCycles::_24 => 24,
|
||||||
|
DummyCycles::_25 => 25,
|
||||||
|
DummyCycles::_26 => 26,
|
||||||
|
DummyCycles::_27 => 27,
|
||||||
|
DummyCycles::_28 => 28,
|
||||||
|
DummyCycles::_29 => 29,
|
||||||
|
DummyCycles::_30 => 30,
|
||||||
|
DummyCycles::_31 => 31,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
338
embassy-stm32/src/qspi/mod.rs
Normal file
338
embassy-stm32/src/qspi/mod.rs
Normal file
@ -0,0 +1,338 @@
|
|||||||
|
#![macro_use]
|
||||||
|
|
||||||
|
pub mod enums;
|
||||||
|
|
||||||
|
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||||
|
use enums::*;
|
||||||
|
|
||||||
|
use crate::dma::TransferOptions;
|
||||||
|
use crate::gpio::sealed::AFType;
|
||||||
|
use crate::gpio::AnyPin;
|
||||||
|
use crate::pac::quadspi::Quadspi as Regs;
|
||||||
|
use crate::rcc::RccPeripheral;
|
||||||
|
use crate::{peripherals, Peripheral};
|
||||||
|
|
||||||
|
pub struct TransferConfig {
|
||||||
|
/// Instraction width (IMODE)
|
||||||
|
pub iwidth: QspiWidth,
|
||||||
|
/// Address width (ADMODE)
|
||||||
|
pub awidth: QspiWidth,
|
||||||
|
/// Data width (DMODE)
|
||||||
|
pub dwidth: QspiWidth,
|
||||||
|
/// Instruction Id
|
||||||
|
pub instruction: u8,
|
||||||
|
/// Flash memory address
|
||||||
|
pub address: Option<u32>,
|
||||||
|
/// Number of dummy cycles (DCYC)
|
||||||
|
pub dummy: DummyCycles,
|
||||||
|
/// Length of data
|
||||||
|
pub data_len: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TransferConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
iwidth: QspiWidth::NONE,
|
||||||
|
awidth: QspiWidth::NONE,
|
||||||
|
dwidth: QspiWidth::NONE,
|
||||||
|
instruction: 0,
|
||||||
|
address: None,
|
||||||
|
dummy: DummyCycles::_0,
|
||||||
|
data_len: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Config {
|
||||||
|
/// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen.
|
||||||
|
/// If you need other value the whose predefined use `Other` variant.
|
||||||
|
pub memory_size: MemorySize,
|
||||||
|
/// Address size (8/16/24/32-bit)
|
||||||
|
pub address_size: AddressSize,
|
||||||
|
/// Scalar factor for generating CLK [0-255]
|
||||||
|
pub prescaler: u8,
|
||||||
|
/// Number of bytes to trigger FIFO threshold flag.
|
||||||
|
pub fifo_threshold: FIFOThresholdLevel,
|
||||||
|
/// Minimum number of cycles that chip select must be high between issued commands
|
||||||
|
pub cs_high_time: ChipSelectHightTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Config {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
memory_size: MemorySize::Other(0),
|
||||||
|
address_size: AddressSize::_24bit,
|
||||||
|
prescaler: 128,
|
||||||
|
fifo_threshold: FIFOThresholdLevel::_17Bytes,
|
||||||
|
cs_high_time: ChipSelectHightTime::_5Cycle,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub struct Qspi<'d, T: Instance, Dma> {
|
||||||
|
_peri: PeripheralRef<'d, T>,
|
||||||
|
sck: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
|
d0: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
|
d1: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
|
d2: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
|
d3: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
|
nss: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
|
dma: PeripheralRef<'d, Dma>,
|
||||||
|
config: Config,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
|
||||||
|
pub fn new(
|
||||||
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
|
d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
|
||||||
|
d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
|
||||||
|
d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
|
||||||
|
d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
|
||||||
|
sck: impl Peripheral<P = impl SckPin<T>> + 'd,
|
||||||
|
nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
|
||||||
|
dma: impl Peripheral<P = Dma> + 'd,
|
||||||
|
config: Config,
|
||||||
|
) -> Self {
|
||||||
|
into_ref!(peri, d0, d1, d2, d3, sck, nss);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
|
||||||
|
sck.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
|
nss.set_as_af(nss.af_num(), AFType::OutputPushPull);
|
||||||
|
nss.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
|
d0.set_as_af(d0.af_num(), AFType::OutputPushPull);
|
||||||
|
d0.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
|
d1.set_as_af(d1.af_num(), AFType::OutputPushPull);
|
||||||
|
d1.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
|
d2.set_as_af(d2.af_num(), AFType::OutputPushPull);
|
||||||
|
d2.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
|
d3.set_as_af(d3.af_num(), AFType::OutputPushPull);
|
||||||
|
d3.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::new_inner(
|
||||||
|
peri,
|
||||||
|
Some(d0.map_into()),
|
||||||
|
Some(d1.map_into()),
|
||||||
|
Some(d2.map_into()),
|
||||||
|
Some(d3.map_into()),
|
||||||
|
Some(sck.map_into()),
|
||||||
|
Some(nss.map_into()),
|
||||||
|
dma,
|
||||||
|
config,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_inner(
|
||||||
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
|
d0: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
|
d1: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
|
d2: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
|
d3: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
|
sck: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
|
nss: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
|
dma: impl Peripheral<P = Dma> + 'd,
|
||||||
|
config: Config,
|
||||||
|
) -> Self {
|
||||||
|
into_ref!(peri, dma);
|
||||||
|
|
||||||
|
T::enable();
|
||||||
|
unsafe {
|
||||||
|
T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into()));
|
||||||
|
|
||||||
|
while T::REGS.sr().read().busy() {}
|
||||||
|
|
||||||
|
T::REGS.cr().write(|w| {
|
||||||
|
w.set_prescaler(config.prescaler);
|
||||||
|
w.set_en(true);
|
||||||
|
});
|
||||||
|
T::REGS.dcr().write(|w| {
|
||||||
|
w.set_fsize(config.memory_size.into());
|
||||||
|
w.set_csht(config.cs_high_time.into());
|
||||||
|
w.set_ckmode(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
_peri: peri,
|
||||||
|
sck,
|
||||||
|
d0,
|
||||||
|
d1,
|
||||||
|
d2,
|
||||||
|
d3,
|
||||||
|
nss,
|
||||||
|
dma,
|
||||||
|
config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn command(&mut self, transaction: TransferConfig) {
|
||||||
|
unsafe {
|
||||||
|
T::REGS.cr().modify(|v| v.set_dmaen(false));
|
||||||
|
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
|
||||||
|
|
||||||
|
while !T::REGS.sr().read().tcf() {}
|
||||||
|
T::REGS.fcr().modify(|v| v.set_ctcf(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) {
|
||||||
|
unsafe {
|
||||||
|
T::REGS.cr().modify(|v| v.set_dmaen(false));
|
||||||
|
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
|
||||||
|
|
||||||
|
if let Some(len) = transaction.data_len {
|
||||||
|
let current_ar = T::REGS.ar().read().address();
|
||||||
|
T::REGS.ccr().modify(|v| {
|
||||||
|
v.set_fmode(QspiMode::IndirectRead.into());
|
||||||
|
});
|
||||||
|
T::REGS.ar().write(|v| {
|
||||||
|
v.set_address(current_ar);
|
||||||
|
});
|
||||||
|
|
||||||
|
for idx in 0..len {
|
||||||
|
while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {}
|
||||||
|
buf[idx] = *(T::REGS.dr().ptr() as *mut u8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while !T::REGS.sr().read().tcf() {}
|
||||||
|
T::REGS.fcr().modify(|v| v.set_ctcf(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) {
|
||||||
|
unsafe {
|
||||||
|
T::REGS.cr().modify(|v| v.set_dmaen(false));
|
||||||
|
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
|
||||||
|
|
||||||
|
if let Some(len) = transaction.data_len {
|
||||||
|
T::REGS.ccr().modify(|v| {
|
||||||
|
v.set_fmode(QspiMode::IndirectWrite.into());
|
||||||
|
});
|
||||||
|
|
||||||
|
for idx in 0..len {
|
||||||
|
while !T::REGS.sr().read().ftf() {}
|
||||||
|
*(T::REGS.dr().ptr() as *mut u8) = buf[idx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while !T::REGS.sr().read().tcf() {}
|
||||||
|
T::REGS.fcr().modify(|v| v.set_ctcf(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig)
|
||||||
|
where
|
||||||
|
Dma: QuadDma<T>,
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
|
||||||
|
|
||||||
|
let request = self.dma.request();
|
||||||
|
let options = TransferOptions::default();
|
||||||
|
|
||||||
|
T::REGS.ccr().modify(|v| {
|
||||||
|
v.set_fmode(QspiMode::IndirectRead.into());
|
||||||
|
});
|
||||||
|
let current_ar = T::REGS.ar().read().address();
|
||||||
|
T::REGS.ar().write(|v| {
|
||||||
|
v.set_address(current_ar);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.dma
|
||||||
|
.start_read(request, T::REGS.dr().ptr() as *mut u8, buf, options);
|
||||||
|
|
||||||
|
T::REGS.cr().modify(|v| v.set_dmaen(true));
|
||||||
|
|
||||||
|
while self.dma.is_running() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig)
|
||||||
|
where
|
||||||
|
Dma: QuadDma<T>,
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
|
||||||
|
|
||||||
|
let request = self.dma.request();
|
||||||
|
let options = TransferOptions::default();
|
||||||
|
|
||||||
|
T::REGS.ccr().modify(|v| {
|
||||||
|
v.set_fmode(QspiMode::IndirectWrite.into());
|
||||||
|
});
|
||||||
|
|
||||||
|
self.dma
|
||||||
|
.start_write(request, buf, T::REGS.dr().ptr() as *mut u8, options);
|
||||||
|
|
||||||
|
T::REGS.cr().modify(|v| v.set_dmaen(true));
|
||||||
|
|
||||||
|
while self.dma.is_running() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) {
|
||||||
|
unsafe {
|
||||||
|
T::REGS.fcr().modify(|v| {
|
||||||
|
v.set_csmf(true);
|
||||||
|
v.set_ctcf(true);
|
||||||
|
v.set_ctef(true);
|
||||||
|
v.set_ctof(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
while T::REGS.sr().read().busy() {}
|
||||||
|
|
||||||
|
if let Some(len) = transaction.data_len {
|
||||||
|
T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
T::REGS.ccr().write(|v| {
|
||||||
|
v.set_fmode(fmode.into());
|
||||||
|
v.set_imode(transaction.iwidth.into());
|
||||||
|
v.set_instruction(transaction.instruction);
|
||||||
|
v.set_admode(transaction.awidth.into());
|
||||||
|
v.set_adsize(self.config.address_size.into());
|
||||||
|
v.set_dmode(transaction.dwidth.into());
|
||||||
|
v.set_abmode(QspiWidth::NONE.into());
|
||||||
|
v.set_dcyc(transaction.dummy.into());
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(addr) = transaction.address {
|
||||||
|
T::REGS.ar().write(|v| {
|
||||||
|
v.set_address(addr);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) mod sealed {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub trait Instance {
|
||||||
|
const REGS: Regs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
|
||||||
|
|
||||||
|
pin_trait!(SckPin, Instance);
|
||||||
|
pin_trait!(D0Pin, Instance);
|
||||||
|
pin_trait!(D1Pin, Instance);
|
||||||
|
pin_trait!(D2Pin, Instance);
|
||||||
|
pin_trait!(D3Pin, Instance);
|
||||||
|
pin_trait!(NSSPin, Instance);
|
||||||
|
|
||||||
|
dma_trait!(QuadDma, Instance);
|
||||||
|
|
||||||
|
foreach_peripheral!(
|
||||||
|
(quadspi, $inst:ident) => {
|
||||||
|
impl sealed::Instance for peripherals::$inst {
|
||||||
|
const REGS: Regs = crate::pac::$inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Instance for peripherals::$inst {}
|
||||||
|
};
|
||||||
|
);
|
Loading…
Reference in New Issue
Block a user