From 6a802c47083e4f6bb7b7c6c06fd2ef3e291a5212 Mon Sep 17 00:00:00 2001
From: Mateusz Butkiewicz <mateusz@github.butkiewicz.dev>
Date: Wed, 22 Mar 2023 08:44:58 +0100
Subject: [PATCH 1/2] feat(stm32:qspi): add support for QSPI in stm32
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Implemented with help of Tomasz GrzeĊ› <tomasz.grzes@gmail.com>.
---
 embassy-stm32/build.rs        |   7 +
 embassy-stm32/src/lib.rs      |   3 +-
 embassy-stm32/src/qspi/mod.rs | 342 ++++++++++++++++++++++++++++++++++
 3 files changed, 351 insertions(+), 1 deletion(-)
 create mode 100644 embassy-stm32/src/qspi/mod.rs

diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index dbfc1370..3780c5a4 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -427,6 +427,12 @@ fn main() {
         (("sdmmc", "D6"), quote!(crate::sdmmc::D6Pin)),
         (("sdmmc", "D6"), quote!(crate::sdmmc::D7Pin)),
         (("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();
 
     for p in METADATA.peripherals {
@@ -507,6 +513,7 @@ fn main() {
         (("dcmi", "PSSI"), quote!(crate::dcmi::FrameDma)),
         // SDMMCv1 uses the same channel for both directions, so just implement for RX
         (("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)),
+        (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)),
     ]
     .into();
 
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index eeaa04f6..8dc4df2d 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -48,6 +48,8 @@ pub mod crc;
 ))]
 pub mod flash;
 pub mod pwm;
+#[cfg(quadspi)]
+pub mod qspi;
 #[cfg(rng)]
 pub mod rng;
 #[cfg(sdmmc)]
@@ -60,7 +62,6 @@ pub mod usart;
 pub mod usb;
 #[cfg(otg)]
 pub mod usb_otg;
-
 #[cfg(iwdg)]
 pub mod wdg;
 
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs
new file mode 100644
index 00000000..f375d1b4
--- /dev/null
+++ b/embassy-stm32/src/qspi/mod.rs
@@ -0,0 +1,342 @@
+#![macro_use]
+
+use embassy_hal_common::{into_ref, PeripheralRef};
+
+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 QspiWidth;
+
+#[allow(dead_code)]
+impl QspiWidth {
+    pub const NONE: u8 = 0b00;
+    pub const SING: u8 = 0b01;
+    pub const DUAL: u8 = 0b10;
+    pub const QUAD: u8 = 0b11;
+}
+
+struct QspiMode;
+
+#[allow(dead_code)]
+impl QspiMode {
+    pub const INDIRECT_WRITE: u8 = 0b00;
+    pub const INDIRECT_READ: u8 = 0b01;
+    pub const AUTO_POLLING: u8 = 0b10;
+    pub const MEMORY_MAPPED: u8 = 0b11;
+}
+
+pub struct QspiTransaction {
+    pub iwidth: u8,
+    pub awidth: u8,
+    pub dwidth: u8,
+    pub instruction: u8,
+    pub address: Option<u32>,
+    pub dummy: u8,
+    pub data_len: Option<usize>,
+}
+
+impl Default for QspiTransaction {
+    fn default() -> Self {
+        Self {
+            iwidth: QspiWidth::NONE,
+            awidth: QspiWidth::NONE,
+            dwidth: QspiWidth::NONE,
+            instruction: 0,
+            address: None,
+            dummy: 0,
+            data_len: None,
+        }
+    }
+}
+
+pub struct Config {
+    pub memory_size: u8,
+    pub address_size: u8,
+    pub prescaler: u8,
+    pub fifo_threshold: u8,
+    pub cs_high_time: u8,
+}
+
+impl Default for Config {
+    fn default() -> Self {
+        Self {
+            memory_size: 0,
+            address_size: 2,
+            prescaler: 128,
+            fifo_threshold: 16,
+            cs_high_time: 4,
+        }
+    }
+}
+
+#[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));
+
+            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);
+                w.set_csht(config.cs_high_time);
+                w.set_ckmode(false);
+            });
+        }
+
+        Self {
+            _peri: peri,
+            sck,
+            d0,
+            d1,
+            d2,
+            d3,
+            nss,
+            dma,
+            config,
+        }
+    }
+
+    pub fn command(&mut self, transaction: QspiTransaction) {
+        unsafe {
+            T::REGS.cr().modify(|v| v.set_dmaen(false));
+            self.setup_transaction(QspiMode::INDIRECT_WRITE, &transaction);
+
+            while !T::REGS.sr().read().tcf() {}
+            T::REGS.fcr().modify(|v| v.set_ctcf(true));
+        }
+    }
+
+    pub fn read(&mut self, buf: &mut [u8], transaction: QspiTransaction) {
+        unsafe {
+            T::REGS.cr().modify(|v| v.set_dmaen(false));
+            self.setup_transaction(QspiMode::INDIRECT_WRITE, &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::INDIRECT_READ);
+                });
+                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 write(&mut self, buf: &[u8], transaction: QspiTransaction) {
+        unsafe {
+            T::REGS.cr().modify(|v| v.set_dmaen(false));
+            self.setup_transaction(QspiMode::INDIRECT_WRITE, &transaction);
+
+            if let Some(len) = transaction.data_len {
+                T::REGS.ccr().modify(|v| {
+                    v.set_fmode(QspiMode::INDIRECT_WRITE);
+                });
+
+                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 read_dma(&mut self, buf: &mut [u8], transaction: QspiTransaction)
+    where
+        Dma: QuadDma<T>,
+    {
+        unsafe {
+            self.setup_transaction(QspiMode::INDIRECT_WRITE, &transaction);
+
+            let request = self.dma.request();
+            let options = TransferOptions::default();
+
+            T::REGS.ccr().modify(|v| {
+                v.set_fmode(QspiMode::INDIRECT_READ);
+            });
+            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 write_dma(&mut self, buf: &[u8], transaction: QspiTransaction)
+    where
+        Dma: QuadDma<T>,
+    {
+        unsafe {
+            self.setup_transaction(QspiMode::INDIRECT_WRITE, &transaction);
+
+            let request = self.dma.request();
+            let options = TransferOptions::default();
+
+            T::REGS.ccr().modify(|v| {
+                v.set_fmode(QspiMode::INDIRECT_WRITE);
+            });
+
+            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: u8, transaction: &QspiTransaction) {
+        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);
+                v.set_imode(transaction.iwidth);
+                v.set_instruction(transaction.instruction);
+                v.set_admode(transaction.awidth);
+                v.set_adsize(self.config.address_size);
+                v.set_dmode(transaction.dwidth);
+                v.set_abmode(QspiWidth::NONE);
+                v.set_dcyc(transaction.dummy);
+            });
+
+            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 {}
+    };
+);

From 87898501a2f66ee179562fa88bfc9a1b4a2ada9b Mon Sep 17 00:00:00 2001
From: Mateusz Butkiewicz <mateusz@github.butkiewicz.dev>
Date: Wed, 29 Mar 2023 13:27:20 +0200
Subject: [PATCH 2/2] feat(stm32:qspi): convert some u8 to enum variants

---
 embassy-stm32/src/qspi/enums.rs | 294 ++++++++++++++++++++++++++++++++
 embassy-stm32/src/qspi/mod.rs   | 116 ++++++-------
 2 files changed, 350 insertions(+), 60 deletions(-)
 create mode 100644 embassy-stm32/src/qspi/enums.rs

diff --git a/embassy-stm32/src/qspi/enums.rs b/embassy-stm32/src/qspi/enums.rs
new file mode 100644
index 00000000..2dbe2b06
--- /dev/null
+++ b/embassy-stm32/src/qspi/enums.rs
@@ -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,
+        }
+    }
+}
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs
index f375d1b4..f3331962 100644
--- a/embassy-stm32/src/qspi/mod.rs
+++ b/embassy-stm32/src/qspi/mod.rs
@@ -1,6 +1,9 @@
 #![macro_use]
 
+pub mod enums;
+
 use embassy_hal_common::{into_ref, PeripheralRef};
+use enums::*;
 
 use crate::dma::TransferOptions;
 use crate::gpio::sealed::AFType;
@@ -9,37 +12,24 @@ use crate::pac::quadspi::Quadspi as Regs;
 use crate::rcc::RccPeripheral;
 use crate::{peripherals, Peripheral};
 
-pub struct QspiWidth;
-
-#[allow(dead_code)]
-impl QspiWidth {
-    pub const NONE: u8 = 0b00;
-    pub const SING: u8 = 0b01;
-    pub const DUAL: u8 = 0b10;
-    pub const QUAD: u8 = 0b11;
-}
-
-struct QspiMode;
-
-#[allow(dead_code)]
-impl QspiMode {
-    pub const INDIRECT_WRITE: u8 = 0b00;
-    pub const INDIRECT_READ: u8 = 0b01;
-    pub const AUTO_POLLING: u8 = 0b10;
-    pub const MEMORY_MAPPED: u8 = 0b11;
-}
-
-pub struct QspiTransaction {
-    pub iwidth: u8,
-    pub awidth: u8,
-    pub dwidth: u8,
+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>,
-    pub dummy: u8,
+    /// Number of dummy cycles (DCYC)
+    pub dummy: DummyCycles,
+    /// Length of data
     pub data_len: Option<usize>,
 }
 
-impl Default for QspiTransaction {
+impl Default for TransferConfig {
     fn default() -> Self {
         Self {
             iwidth: QspiWidth::NONE,
@@ -47,28 +37,34 @@ impl Default for QspiTransaction {
             dwidth: QspiWidth::NONE,
             instruction: 0,
             address: None,
-            dummy: 0,
+            dummy: DummyCycles::_0,
             data_len: None,
         }
     }
 }
 
 pub struct Config {
-    pub memory_size: u8,
-    pub address_size: u8,
+    /// 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,
-    pub fifo_threshold: u8,
-    pub cs_high_time: 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: 0,
-            address_size: 2,
+            memory_size: MemorySize::Other(0),
+            address_size: AddressSize::_24bit,
             prescaler: 128,
-            fifo_threshold: 16,
-            cs_high_time: 4,
+            fifo_threshold: FIFOThresholdLevel::_17Bytes,
+            cs_high_time: ChipSelectHightTime::_5Cycle,
         }
     }
 }
@@ -143,7 +139,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
 
         T::enable();
         unsafe {
-            T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold));
+            T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into()));
 
             while T::REGS.sr().read().busy() {}
 
@@ -152,8 +148,8 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
                 w.set_en(true);
             });
             T::REGS.dcr().write(|w| {
-                w.set_fsize(config.memory_size);
-                w.set_csht(config.cs_high_time);
+                w.set_fsize(config.memory_size.into());
+                w.set_csht(config.cs_high_time.into());
                 w.set_ckmode(false);
             });
         }
@@ -171,25 +167,25 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
         }
     }
 
-    pub fn command(&mut self, transaction: QspiTransaction) {
+    pub fn command(&mut self, transaction: TransferConfig) {
         unsafe {
             T::REGS.cr().modify(|v| v.set_dmaen(false));
-            self.setup_transaction(QspiMode::INDIRECT_WRITE, &transaction);
+            self.setup_transaction(QspiMode::IndirectWrite, &transaction);
 
             while !T::REGS.sr().read().tcf() {}
             T::REGS.fcr().modify(|v| v.set_ctcf(true));
         }
     }
 
-    pub fn read(&mut self, buf: &mut [u8], transaction: QspiTransaction) {
+    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::INDIRECT_WRITE, &transaction);
+            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::INDIRECT_READ);
+                    v.set_fmode(QspiMode::IndirectRead.into());
                 });
                 T::REGS.ar().write(|v| {
                     v.set_address(current_ar);
@@ -206,14 +202,14 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
         }
     }
 
-    pub fn write(&mut self, buf: &[u8], transaction: QspiTransaction) {
+    pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) {
         unsafe {
             T::REGS.cr().modify(|v| v.set_dmaen(false));
-            self.setup_transaction(QspiMode::INDIRECT_WRITE, &transaction);
+            self.setup_transaction(QspiMode::IndirectWrite, &transaction);
 
             if let Some(len) = transaction.data_len {
                 T::REGS.ccr().modify(|v| {
-                    v.set_fmode(QspiMode::INDIRECT_WRITE);
+                    v.set_fmode(QspiMode::IndirectWrite.into());
                 });
 
                 for idx in 0..len {
@@ -227,18 +223,18 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
         }
     }
 
-    pub fn read_dma(&mut self, buf: &mut [u8], transaction: QspiTransaction)
+    pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig)
     where
         Dma: QuadDma<T>,
     {
         unsafe {
-            self.setup_transaction(QspiMode::INDIRECT_WRITE, &transaction);
+            self.setup_transaction(QspiMode::IndirectWrite, &transaction);
 
             let request = self.dma.request();
             let options = TransferOptions::default();
 
             T::REGS.ccr().modify(|v| {
-                v.set_fmode(QspiMode::INDIRECT_READ);
+                v.set_fmode(QspiMode::IndirectRead.into());
             });
             let current_ar = T::REGS.ar().read().address();
             T::REGS.ar().write(|v| {
@@ -254,18 +250,18 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
         }
     }
 
-    pub fn write_dma(&mut self, buf: &[u8], transaction: QspiTransaction)
+    pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig)
     where
         Dma: QuadDma<T>,
     {
         unsafe {
-            self.setup_transaction(QspiMode::INDIRECT_WRITE, &transaction);
+            self.setup_transaction(QspiMode::IndirectWrite, &transaction);
 
             let request = self.dma.request();
             let options = TransferOptions::default();
 
             T::REGS.ccr().modify(|v| {
-                v.set_fmode(QspiMode::INDIRECT_WRITE);
+                v.set_fmode(QspiMode::IndirectWrite.into());
             });
 
             self.dma
@@ -277,7 +273,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
         }
     }
 
-    fn setup_transaction(&mut self, fmode: u8, transaction: &QspiTransaction) {
+    fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) {
         unsafe {
             T::REGS.fcr().modify(|v| {
                 v.set_csmf(true);
@@ -293,14 +289,14 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
             }
 
             T::REGS.ccr().write(|v| {
-                v.set_fmode(fmode);
-                v.set_imode(transaction.iwidth);
+                v.set_fmode(fmode.into());
+                v.set_imode(transaction.iwidth.into());
                 v.set_instruction(transaction.instruction);
-                v.set_admode(transaction.awidth);
-                v.set_adsize(self.config.address_size);
-                v.set_dmode(transaction.dwidth);
-                v.set_abmode(QspiWidth::NONE);
-                v.set_dcyc(transaction.dummy);
+                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 {