Merge pull request #1669 from embassy-rs/nocrlf

ci: add check for no CRLF line endings.
This commit is contained in:
Dario Nieuwenhuis 2023-07-18 12:33:14 +00:00 committed by GitHub
commit 27a3d2cd0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 684 additions and 626 deletions

41
.gitattributes vendored Normal file
View File

@ -0,0 +1,41 @@
* text=auto
*.adoc text
*.html text
*.in text
*.json text
*.md text
*.proto text
*.py text
*.rs text
*.service text
*.sh text
*.toml text
*.txt text
*.x text
*.yml text
*.raw binary
*.bin binary
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.mov binary
*.mp4 binary
*.mp3 binary
*.flv binary
*.fla binary
*.swf binary
*.gz binary
*.zip binary
*.7z binary
*.ttf binary
*.eot binary
*.woff binary
*.pyc binary
*.pdf binary
*.ez binary
*.bz2 binary
*.swp binary

17
.github/ci/crlf.sh vendored Executable file
View File

@ -0,0 +1,17 @@
#!/bin/bash
## on push branch~=gh-readonly-queue/main/.*
## on pull_request
set -euo pipefail
FILES_WITH_CRLF=$(find ! -path "./.git/*" -not -type d | xargs file -N | (grep " CRLF " || true))
if [ -z "$FILES_WITH_CRLF" ]; then
echo -e "No files with CRLF endings found."
exit 0
else
NR_FILES=$(echo "$FILES_WITH_CRLF" | wc -l)
echo -e "ERROR: Found ${NR_FILES} files with CRLF endings."
echo "$FILES_WITH_CRLF"
exit "$NR_FILES"
fi

View File

@ -1,294 +1,294 @@
//! Pulse Density Modulation (PDM) mirophone driver. //! Pulse Density Modulation (PDM) mirophone driver.
#![macro_use] #![macro_use]
use core::marker::PhantomData; use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, Ordering}; use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll; use core::task::Poll;
use embassy_hal_common::drop::OnDrop; use embassy_hal_common::drop::OnDrop;
use embassy_hal_common::{into_ref, PeripheralRef}; use embassy_hal_common::{into_ref, PeripheralRef};
use futures::future::poll_fn; use futures::future::poll_fn;
use crate::chip::EASY_DMA_SIZE; use crate::chip::EASY_DMA_SIZE;
use crate::gpio::sealed::Pin; use crate::gpio::sealed::Pin;
use crate::gpio::{AnyPin, Pin as GpioPin}; use crate::gpio::{AnyPin, Pin as GpioPin};
use crate::interrupt::typelevel::Interrupt; use crate::interrupt::typelevel::Interrupt;
use crate::{interrupt, Peripheral}; use crate::{interrupt, Peripheral};
/// Interrupt handler. /// Interrupt handler.
pub struct InterruptHandler<T: Instance> { pub struct InterruptHandler<T: Instance> {
_phantom: PhantomData<T>, _phantom: PhantomData<T>,
} }
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() { unsafe fn on_interrupt() {
T::regs().intenclr.write(|w| w.end().clear()); T::regs().intenclr.write(|w| w.end().clear());
T::state().waker.wake(); T::state().waker.wake();
} }
} }
/// PDM microphone interface /// PDM microphone interface
pub struct Pdm<'d, T: Instance> { pub struct Pdm<'d, T: Instance> {
_peri: PeripheralRef<'d, T>, _peri: PeripheralRef<'d, T>,
} }
/// PDM error. /// PDM error.
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive] #[non_exhaustive]
pub enum Error { pub enum Error {
/// Buffer is too long. /// Buffer is too long.
BufferTooLong, BufferTooLong,
/// Buffer is empty /// Buffer is empty
BufferZeroLength, BufferZeroLength,
/// PDM is not running /// PDM is not running
NotRunning, NotRunning,
} }
static DUMMY_BUFFER: [i16; 1] = [0; 1]; static DUMMY_BUFFER: [i16; 1] = [0; 1];
impl<'d, T: Instance> Pdm<'d, T> { impl<'d, T: Instance> Pdm<'d, T> {
/// Create PDM driver /// Create PDM driver
pub fn new( pub fn new(
pdm: impl Peripheral<P = T> + 'd, pdm: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
clk: impl Peripheral<P = impl GpioPin> + 'd, clk: impl Peripheral<P = impl GpioPin> + 'd,
din: impl Peripheral<P = impl GpioPin> + 'd, din: impl Peripheral<P = impl GpioPin> + 'd,
config: Config, config: Config,
) -> Self { ) -> Self {
into_ref!(pdm, clk, din); into_ref!(pdm, clk, din);
Self::new_inner(pdm, clk.map_into(), din.map_into(), config) Self::new_inner(pdm, clk.map_into(), din.map_into(), config)
} }
fn new_inner( fn new_inner(
pdm: PeripheralRef<'d, T>, pdm: PeripheralRef<'d, T>,
clk: PeripheralRef<'d, AnyPin>, clk: PeripheralRef<'d, AnyPin>,
din: PeripheralRef<'d, AnyPin>, din: PeripheralRef<'d, AnyPin>,
config: Config, config: Config,
) -> Self { ) -> Self {
into_ref!(pdm); into_ref!(pdm);
let r = T::regs(); let r = T::regs();
// setup gpio pins // setup gpio pins
din.conf().write(|w| w.input().set_bit()); din.conf().write(|w| w.input().set_bit());
r.psel.din.write(|w| unsafe { w.bits(din.psel_bits()) }); r.psel.din.write(|w| unsafe { w.bits(din.psel_bits()) });
clk.set_low(); clk.set_low();
clk.conf().write(|w| w.dir().output()); clk.conf().write(|w| w.dir().output());
r.psel.clk.write(|w| unsafe { w.bits(clk.psel_bits()) }); r.psel.clk.write(|w| unsafe { w.bits(clk.psel_bits()) });
// configure // configure
// use default for // use default for
// - gain right // - gain right
// - gain left // - gain left
// - clk // - clk
// - ratio // - ratio
r.mode.write(|w| { r.mode.write(|w| {
w.edge().bit(config.edge == Edge::LeftRising); w.edge().bit(config.edge == Edge::LeftRising);
w.operation().bit(config.operation_mode == OperationMode::Mono); w.operation().bit(config.operation_mode == OperationMode::Mono);
w w
}); });
r.gainl.write(|w| w.gainl().default_gain()); r.gainl.write(|w| w.gainl().default_gain());
r.gainr.write(|w| w.gainr().default_gain()); r.gainr.write(|w| w.gainr().default_gain());
// IRQ // IRQ
T::Interrupt::unpend(); T::Interrupt::unpend();
unsafe { T::Interrupt::enable() }; unsafe { T::Interrupt::enable() };
r.enable.write(|w| w.enable().set_bit()); r.enable.write(|w| w.enable().set_bit());
Self { _peri: pdm } Self { _peri: pdm }
} }
/// Start sampling microphon data into a dummy buffer /// Start sampling microphon data into a dummy buffer
/// Usefull to start the microphon and keep it active between recording samples /// Usefull to start the microphon and keep it active between recording samples
pub async fn start(&mut self) { pub async fn start(&mut self) {
let r = T::regs(); let r = T::regs();
// start dummy sampling because microphon needs some setup time // start dummy sampling because microphon needs some setup time
r.sample r.sample
.ptr .ptr
.write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) });
r.sample r.sample
.maxcnt .maxcnt
.write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) });
r.tasks_start.write(|w| unsafe { w.bits(1) }); r.tasks_start.write(|w| unsafe { w.bits(1) });
} }
/// Stop sampling microphon data inta a dummy buffer /// Stop sampling microphon data inta a dummy buffer
pub async fn stop(&mut self) { pub async fn stop(&mut self) {
let r = T::regs(); let r = T::regs();
r.tasks_stop.write(|w| unsafe { w.bits(1) }); r.tasks_stop.write(|w| unsafe { w.bits(1) });
r.events_started.reset(); r.events_started.reset();
} }
/// Sample data into the given buffer. /// Sample data into the given buffer.
pub async fn sample(&mut self, buffer: &mut [i16]) -> Result<(), Error> { pub async fn sample(&mut self, buffer: &mut [i16]) -> Result<(), Error> {
if buffer.len() == 0 { if buffer.len() == 0 {
return Err(Error::BufferZeroLength); return Err(Error::BufferZeroLength);
} }
if buffer.len() > EASY_DMA_SIZE { if buffer.len() > EASY_DMA_SIZE {
return Err(Error::BufferTooLong); return Err(Error::BufferTooLong);
} }
let r = T::regs(); let r = T::regs();
if r.events_started.read().bits() == 0 { if r.events_started.read().bits() == 0 {
return Err(Error::NotRunning); return Err(Error::NotRunning);
} }
let drop = OnDrop::new(move || { let drop = OnDrop::new(move || {
r.intenclr.write(|w| w.end().clear()); r.intenclr.write(|w| w.end().clear());
r.events_stopped.reset(); r.events_stopped.reset();
// reset to dummy buffer // reset to dummy buffer
r.sample r.sample
.ptr .ptr
.write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) });
r.sample r.sample
.maxcnt .maxcnt
.write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) });
while r.events_stopped.read().bits() == 0 {} while r.events_stopped.read().bits() == 0 {}
}); });
// setup user buffer // setup user buffer
let ptr = buffer.as_ptr(); let ptr = buffer.as_ptr();
let len = buffer.len(); let len = buffer.len();
r.sample.ptr.write(|w| unsafe { w.sampleptr().bits(ptr as u32) }); r.sample.ptr.write(|w| unsafe { w.sampleptr().bits(ptr as u32) });
r.sample.maxcnt.write(|w| unsafe { w.buffsize().bits(len as _) }); r.sample.maxcnt.write(|w| unsafe { w.buffsize().bits(len as _) });
// wait till the current sample is finished and the user buffer sample is started // wait till the current sample is finished and the user buffer sample is started
Self::wait_for_sample().await; Self::wait_for_sample().await;
// reset the buffer back to the dummy buffer // reset the buffer back to the dummy buffer
r.sample r.sample
.ptr .ptr
.write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) });
r.sample r.sample
.maxcnt .maxcnt
.write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) });
// wait till the user buffer is sampled // wait till the user buffer is sampled
Self::wait_for_sample().await; Self::wait_for_sample().await;
drop.defuse(); drop.defuse();
Ok(()) Ok(())
} }
async fn wait_for_sample() { async fn wait_for_sample() {
let r = T::regs(); let r = T::regs();
r.events_end.reset(); r.events_end.reset();
r.intenset.write(|w| w.end().set()); r.intenset.write(|w| w.end().set());
compiler_fence(Ordering::SeqCst); compiler_fence(Ordering::SeqCst);
poll_fn(|cx| { poll_fn(|cx| {
T::state().waker.register(cx.waker()); T::state().waker.register(cx.waker());
if r.events_end.read().bits() != 0 { if r.events_end.read().bits() != 0 {
return Poll::Ready(()); return Poll::Ready(());
} }
Poll::Pending Poll::Pending
}) })
.await; .await;
compiler_fence(Ordering::SeqCst); compiler_fence(Ordering::SeqCst);
} }
} }
/// PDM microphone driver Config /// PDM microphone driver Config
pub struct Config { pub struct Config {
/// Use stero or mono operation /// Use stero or mono operation
pub operation_mode: OperationMode, pub operation_mode: OperationMode,
/// On which edge the left channel should be samples /// On which edge the left channel should be samples
pub edge: Edge, pub edge: Edge,
} }
impl Default for Config { impl Default for Config {
fn default() -> Self { fn default() -> Self {
Self { Self {
operation_mode: OperationMode::Mono, operation_mode: OperationMode::Mono,
edge: Edge::LeftFalling, edge: Edge::LeftFalling,
} }
} }
} }
/// PDM operation mode. /// PDM operation mode.
#[derive(PartialEq)] #[derive(PartialEq)]
pub enum OperationMode { pub enum OperationMode {
/// Mono (1 channel) /// Mono (1 channel)
Mono, Mono,
/// Stereo (2 channels) /// Stereo (2 channels)
Stereo, Stereo,
} }
/// PDM edge polarity /// PDM edge polarity
#[derive(PartialEq)] #[derive(PartialEq)]
pub enum Edge { pub enum Edge {
/// Left edge is rising /// Left edge is rising
LeftRising, LeftRising,
/// Left edge is falling /// Left edge is falling
LeftFalling, LeftFalling,
} }
impl<'d, T: Instance> Drop for Pdm<'d, T> { impl<'d, T: Instance> Drop for Pdm<'d, T> {
fn drop(&mut self) { fn drop(&mut self) {
let r = T::regs(); let r = T::regs();
r.tasks_stop.write(|w| unsafe { w.bits(1) }); r.tasks_stop.write(|w| unsafe { w.bits(1) });
r.enable.write(|w| w.enable().disabled()); r.enable.write(|w| w.enable().disabled());
r.psel.din.reset(); r.psel.din.reset();
r.psel.clk.reset(); r.psel.clk.reset();
} }
} }
pub(crate) mod sealed { pub(crate) mod sealed {
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
/// Peripheral static state /// Peripheral static state
pub struct State { pub struct State {
pub waker: AtomicWaker, pub waker: AtomicWaker,
} }
impl State { impl State {
pub const fn new() -> Self { pub const fn new() -> Self {
Self { Self {
waker: AtomicWaker::new(), waker: AtomicWaker::new(),
} }
} }
} }
pub trait Instance { pub trait Instance {
fn regs() -> &'static crate::pac::pdm::RegisterBlock; fn regs() -> &'static crate::pac::pdm::RegisterBlock;
fn state() -> &'static State; fn state() -> &'static State;
} }
} }
/// PDM peripheral instance. /// PDM peripheral instance.
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
/// Interrupt for this peripheral. /// Interrupt for this peripheral.
type Interrupt: interrupt::typelevel::Interrupt; type Interrupt: interrupt::typelevel::Interrupt;
} }
macro_rules! impl_pdm { macro_rules! impl_pdm {
($type:ident, $pac_type:ident, $irq:ident) => { ($type:ident, $pac_type:ident, $irq:ident) => {
impl crate::pdm::sealed::Instance for peripherals::$type { impl crate::pdm::sealed::Instance for peripherals::$type {
fn regs() -> &'static crate::pac::pdm::RegisterBlock { fn regs() -> &'static crate::pac::pdm::RegisterBlock {
unsafe { &*pac::$pac_type::ptr() } unsafe { &*pac::$pac_type::ptr() }
} }
fn state() -> &'static crate::pdm::sealed::State { fn state() -> &'static crate::pdm::sealed::State {
static STATE: crate::pdm::sealed::State = crate::pdm::sealed::State::new(); static STATE: crate::pdm::sealed::State = crate::pdm::sealed::State::new();
&STATE &STATE
} }
} }
impl crate::pdm::Instance for peripherals::$type { impl crate::pdm::Instance for peripherals::$type {
type Interrupt = crate::interrupt::typelevel::$irq; type Interrupt = crate::interrupt::typelevel::$irq;
} }
}; };
} }

View File

@ -1,332 +1,332 @@
#![macro_use] #![macro_use]
pub mod enums; pub mod enums;
use embassy_hal_common::{into_ref, PeripheralRef}; use embassy_hal_common::{into_ref, PeripheralRef};
use enums::*; use enums::*;
use crate::dma::Transfer; use crate::dma::Transfer;
use crate::gpio::sealed::AFType; use crate::gpio::sealed::AFType;
use crate::gpio::AnyPin; use crate::gpio::AnyPin;
use crate::pac::quadspi::Quadspi as Regs; use crate::pac::quadspi::Quadspi as Regs;
use crate::rcc::RccPeripheral; use crate::rcc::RccPeripheral;
use crate::{peripherals, Peripheral}; use crate::{peripherals, Peripheral};
pub struct TransferConfig { pub struct TransferConfig {
/// Instraction width (IMODE) /// Instraction width (IMODE)
pub iwidth: QspiWidth, pub iwidth: QspiWidth,
/// Address width (ADMODE) /// Address width (ADMODE)
pub awidth: QspiWidth, pub awidth: QspiWidth,
/// Data width (DMODE) /// Data width (DMODE)
pub dwidth: QspiWidth, pub dwidth: QspiWidth,
/// Instruction Id /// Instruction Id
pub instruction: u8, pub instruction: u8,
/// Flash memory address /// Flash memory address
pub address: Option<u32>, pub address: Option<u32>,
/// Number of dummy cycles (DCYC) /// Number of dummy cycles (DCYC)
pub dummy: DummyCycles, pub dummy: DummyCycles,
/// Length of data /// Length of data
pub data_len: Option<usize>, pub data_len: Option<usize>,
} }
impl Default for TransferConfig { impl Default for TransferConfig {
fn default() -> Self { fn default() -> Self {
Self { Self {
iwidth: QspiWidth::NONE, iwidth: QspiWidth::NONE,
awidth: QspiWidth::NONE, awidth: QspiWidth::NONE,
dwidth: QspiWidth::NONE, dwidth: QspiWidth::NONE,
instruction: 0, instruction: 0,
address: None, address: None,
dummy: DummyCycles::_0, dummy: DummyCycles::_0,
data_len: None, data_len: None,
} }
} }
} }
pub struct Config { pub struct Config {
/// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen. /// 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. /// If you need other value the whose predefined use `Other` variant.
pub memory_size: MemorySize, pub memory_size: MemorySize,
/// Address size (8/16/24/32-bit) /// Address size (8/16/24/32-bit)
pub address_size: AddressSize, pub address_size: AddressSize,
/// Scalar factor for generating CLK [0-255] /// Scalar factor for generating CLK [0-255]
pub prescaler: u8, pub prescaler: u8,
/// Number of bytes to trigger FIFO threshold flag. /// Number of bytes to trigger FIFO threshold flag.
pub fifo_threshold: FIFOThresholdLevel, pub fifo_threshold: FIFOThresholdLevel,
/// Minimum number of cycles that chip select must be high between issued commands /// Minimum number of cycles that chip select must be high between issued commands
pub cs_high_time: ChipSelectHightTime, pub cs_high_time: ChipSelectHightTime,
} }
impl Default for Config { impl Default for Config {
fn default() -> Self { fn default() -> Self {
Self { Self {
memory_size: MemorySize::Other(0), memory_size: MemorySize::Other(0),
address_size: AddressSize::_24bit, address_size: AddressSize::_24bit,
prescaler: 128, prescaler: 128,
fifo_threshold: FIFOThresholdLevel::_17Bytes, fifo_threshold: FIFOThresholdLevel::_17Bytes,
cs_high_time: ChipSelectHightTime::_5Cycle, cs_high_time: ChipSelectHightTime::_5Cycle,
} }
} }
} }
#[allow(dead_code)] #[allow(dead_code)]
pub struct Qspi<'d, T: Instance, Dma> { pub struct Qspi<'d, T: Instance, Dma> {
_peri: PeripheralRef<'d, T>, _peri: PeripheralRef<'d, T>,
sck: Option<PeripheralRef<'d, AnyPin>>, sck: Option<PeripheralRef<'d, AnyPin>>,
d0: Option<PeripheralRef<'d, AnyPin>>, d0: Option<PeripheralRef<'d, AnyPin>>,
d1: Option<PeripheralRef<'d, AnyPin>>, d1: Option<PeripheralRef<'d, AnyPin>>,
d2: Option<PeripheralRef<'d, AnyPin>>, d2: Option<PeripheralRef<'d, AnyPin>>,
d3: Option<PeripheralRef<'d, AnyPin>>, d3: Option<PeripheralRef<'d, AnyPin>>,
nss: Option<PeripheralRef<'d, AnyPin>>, nss: Option<PeripheralRef<'d, AnyPin>>,
dma: PeripheralRef<'d, Dma>, dma: PeripheralRef<'d, Dma>,
config: Config, config: Config,
} }
impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
pub fn new( pub fn new(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
d0: impl Peripheral<P = impl D0Pin<T>> + 'd, d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
d1: impl Peripheral<P = impl D1Pin<T>> + 'd, d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
d2: impl Peripheral<P = impl D2Pin<T>> + 'd, d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
d3: impl Peripheral<P = impl D3Pin<T>> + 'd, d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
sck: impl Peripheral<P = impl SckPin<T>> + 'd, sck: impl Peripheral<P = impl SckPin<T>> + 'd,
nss: impl Peripheral<P = impl NSSPin<T>> + 'd, nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
dma: impl Peripheral<P = Dma> + 'd, dma: impl Peripheral<P = Dma> + 'd,
config: Config, config: Config,
) -> Self { ) -> Self {
into_ref!(peri, d0, d1, d2, d3, sck, nss); into_ref!(peri, d0, d1, d2, d3, sck, nss);
sck.set_as_af(sck.af_num(), AFType::OutputPushPull); sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
sck.set_speed(crate::gpio::Speed::VeryHigh); sck.set_speed(crate::gpio::Speed::VeryHigh);
nss.set_as_af(nss.af_num(), AFType::OutputPushPull); nss.set_as_af(nss.af_num(), AFType::OutputPushPull);
nss.set_speed(crate::gpio::Speed::VeryHigh); nss.set_speed(crate::gpio::Speed::VeryHigh);
d0.set_as_af(d0.af_num(), AFType::OutputPushPull); d0.set_as_af(d0.af_num(), AFType::OutputPushPull);
d0.set_speed(crate::gpio::Speed::VeryHigh); d0.set_speed(crate::gpio::Speed::VeryHigh);
d1.set_as_af(d1.af_num(), AFType::OutputPushPull); d1.set_as_af(d1.af_num(), AFType::OutputPushPull);
d1.set_speed(crate::gpio::Speed::VeryHigh); d1.set_speed(crate::gpio::Speed::VeryHigh);
d2.set_as_af(d2.af_num(), AFType::OutputPushPull); d2.set_as_af(d2.af_num(), AFType::OutputPushPull);
d2.set_speed(crate::gpio::Speed::VeryHigh); d2.set_speed(crate::gpio::Speed::VeryHigh);
d3.set_as_af(d3.af_num(), AFType::OutputPushPull); d3.set_as_af(d3.af_num(), AFType::OutputPushPull);
d3.set_speed(crate::gpio::Speed::VeryHigh); d3.set_speed(crate::gpio::Speed::VeryHigh);
Self::new_inner( Self::new_inner(
peri, peri,
Some(d0.map_into()), Some(d0.map_into()),
Some(d1.map_into()), Some(d1.map_into()),
Some(d2.map_into()), Some(d2.map_into()),
Some(d3.map_into()), Some(d3.map_into()),
Some(sck.map_into()), Some(sck.map_into()),
Some(nss.map_into()), Some(nss.map_into()),
dma, dma,
config, config,
) )
} }
fn new_inner( fn new_inner(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
d0: Option<PeripheralRef<'d, AnyPin>>, d0: Option<PeripheralRef<'d, AnyPin>>,
d1: Option<PeripheralRef<'d, AnyPin>>, d1: Option<PeripheralRef<'d, AnyPin>>,
d2: Option<PeripheralRef<'d, AnyPin>>, d2: Option<PeripheralRef<'d, AnyPin>>,
d3: Option<PeripheralRef<'d, AnyPin>>, d3: Option<PeripheralRef<'d, AnyPin>>,
sck: Option<PeripheralRef<'d, AnyPin>>, sck: Option<PeripheralRef<'d, AnyPin>>,
nss: Option<PeripheralRef<'d, AnyPin>>, nss: Option<PeripheralRef<'d, AnyPin>>,
dma: impl Peripheral<P = Dma> + 'd, dma: impl Peripheral<P = Dma> + 'd,
config: Config, config: Config,
) -> Self { ) -> Self {
into_ref!(peri, dma); into_ref!(peri, dma);
T::enable(); T::enable();
T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into())); T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into()));
while T::REGS.sr().read().busy() {} while T::REGS.sr().read().busy() {}
T::REGS.cr().write(|w| { T::REGS.cr().write(|w| {
w.set_prescaler(config.prescaler); w.set_prescaler(config.prescaler);
w.set_en(true); w.set_en(true);
}); });
T::REGS.dcr().write(|w| { T::REGS.dcr().write(|w| {
w.set_fsize(config.memory_size.into()); w.set_fsize(config.memory_size.into());
w.set_csht(config.cs_high_time.into()); w.set_csht(config.cs_high_time.into());
w.set_ckmode(false); w.set_ckmode(false);
}); });
Self { Self {
_peri: peri, _peri: peri,
sck, sck,
d0, d0,
d1, d1,
d2, d2,
d3, d3,
nss, nss,
dma, dma,
config, config,
} }
} }
pub fn command(&mut self, transaction: TransferConfig) { pub fn command(&mut self, transaction: TransferConfig) {
T::REGS.cr().modify(|v| v.set_dmaen(false)); T::REGS.cr().modify(|v| v.set_dmaen(false));
self.setup_transaction(QspiMode::IndirectWrite, &transaction); self.setup_transaction(QspiMode::IndirectWrite, &transaction);
while !T::REGS.sr().read().tcf() {} while !T::REGS.sr().read().tcf() {}
T::REGS.fcr().modify(|v| v.set_ctcf(true)); T::REGS.fcr().modify(|v| v.set_ctcf(true));
} }
pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) { pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) {
T::REGS.cr().modify(|v| v.set_dmaen(false)); T::REGS.cr().modify(|v| v.set_dmaen(false));
self.setup_transaction(QspiMode::IndirectWrite, &transaction); self.setup_transaction(QspiMode::IndirectWrite, &transaction);
if let Some(len) = transaction.data_len { if let Some(len) = transaction.data_len {
let current_ar = T::REGS.ar().read().address(); let current_ar = T::REGS.ar().read().address();
T::REGS.ccr().modify(|v| { T::REGS.ccr().modify(|v| {
v.set_fmode(QspiMode::IndirectRead.into()); v.set_fmode(QspiMode::IndirectRead.into());
}); });
T::REGS.ar().write(|v| { T::REGS.ar().write(|v| {
v.set_address(current_ar); v.set_address(current_ar);
}); });
for idx in 0..len { for idx in 0..len {
while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {} while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {}
buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut u8).read_volatile() }; buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut u8).read_volatile() };
} }
} }
while !T::REGS.sr().read().tcf() {} while !T::REGS.sr().read().tcf() {}
T::REGS.fcr().modify(|v| v.set_ctcf(true)); T::REGS.fcr().modify(|v| v.set_ctcf(true));
} }
pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) { pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) {
T::REGS.cr().modify(|v| v.set_dmaen(false)); T::REGS.cr().modify(|v| v.set_dmaen(false));
self.setup_transaction(QspiMode::IndirectWrite, &transaction); self.setup_transaction(QspiMode::IndirectWrite, &transaction);
if let Some(len) = transaction.data_len { if let Some(len) = transaction.data_len {
T::REGS.ccr().modify(|v| { T::REGS.ccr().modify(|v| {
v.set_fmode(QspiMode::IndirectWrite.into()); v.set_fmode(QspiMode::IndirectWrite.into());
}); });
for idx in 0..len { for idx in 0..len {
while !T::REGS.sr().read().ftf() {} while !T::REGS.sr().read().ftf() {}
unsafe { (T::REGS.dr().as_ptr() as *mut u8).write_volatile(buf[idx]) }; unsafe { (T::REGS.dr().as_ptr() as *mut u8).write_volatile(buf[idx]) };
} }
} }
while !T::REGS.sr().read().tcf() {} while !T::REGS.sr().read().tcf() {}
T::REGS.fcr().modify(|v| v.set_ctcf(true)); T::REGS.fcr().modify(|v| v.set_ctcf(true));
} }
pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig)
where where
Dma: QuadDma<T>, Dma: QuadDma<T>,
{ {
self.setup_transaction(QspiMode::IndirectWrite, &transaction); self.setup_transaction(QspiMode::IndirectWrite, &transaction);
T::REGS.ccr().modify(|v| { T::REGS.ccr().modify(|v| {
v.set_fmode(QspiMode::IndirectRead.into()); v.set_fmode(QspiMode::IndirectRead.into());
}); });
let current_ar = T::REGS.ar().read().address(); let current_ar = T::REGS.ar().read().address();
T::REGS.ar().write(|v| { T::REGS.ar().write(|v| {
v.set_address(current_ar); v.set_address(current_ar);
}); });
let request = self.dma.request(); let request = self.dma.request();
let transfer = unsafe { let transfer = unsafe {
Transfer::new_read( Transfer::new_read(
&mut self.dma, &mut self.dma,
request, request,
T::REGS.dr().as_ptr() as *mut u8, T::REGS.dr().as_ptr() as *mut u8,
buf, buf,
Default::default(), Default::default(),
) )
}; };
T::REGS.cr().modify(|v| v.set_dmaen(true)); T::REGS.cr().modify(|v| v.set_dmaen(true));
transfer.blocking_wait(); transfer.blocking_wait();
} }
pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig)
where where
Dma: QuadDma<T>, Dma: QuadDma<T>,
{ {
self.setup_transaction(QspiMode::IndirectWrite, &transaction); self.setup_transaction(QspiMode::IndirectWrite, &transaction);
T::REGS.ccr().modify(|v| { T::REGS.ccr().modify(|v| {
v.set_fmode(QspiMode::IndirectWrite.into()); v.set_fmode(QspiMode::IndirectWrite.into());
}); });
let request = self.dma.request(); let request = self.dma.request();
let transfer = unsafe { let transfer = unsafe {
Transfer::new_write( Transfer::new_write(
&mut self.dma, &mut self.dma,
request, request,
buf, buf,
T::REGS.dr().as_ptr() as *mut u8, T::REGS.dr().as_ptr() as *mut u8,
Default::default(), Default::default(),
) )
}; };
T::REGS.cr().modify(|v| v.set_dmaen(true)); T::REGS.cr().modify(|v| v.set_dmaen(true));
transfer.blocking_wait(); transfer.blocking_wait();
} }
fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) { fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) {
T::REGS.fcr().modify(|v| { T::REGS.fcr().modify(|v| {
v.set_csmf(true); v.set_csmf(true);
v.set_ctcf(true); v.set_ctcf(true);
v.set_ctef(true); v.set_ctef(true);
v.set_ctof(true); v.set_ctof(true);
}); });
while T::REGS.sr().read().busy() {} while T::REGS.sr().read().busy() {}
if let Some(len) = transaction.data_len { if let Some(len) = transaction.data_len {
T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1)); T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1));
} }
T::REGS.ccr().write(|v| { T::REGS.ccr().write(|v| {
v.set_fmode(fmode.into()); v.set_fmode(fmode.into());
v.set_imode(transaction.iwidth.into()); v.set_imode(transaction.iwidth.into());
v.set_instruction(transaction.instruction); v.set_instruction(transaction.instruction);
v.set_admode(transaction.awidth.into()); v.set_admode(transaction.awidth.into());
v.set_adsize(self.config.address_size.into()); v.set_adsize(self.config.address_size.into());
v.set_dmode(transaction.dwidth.into()); v.set_dmode(transaction.dwidth.into());
v.set_abmode(QspiWidth::NONE.into()); v.set_abmode(QspiWidth::NONE.into());
v.set_dcyc(transaction.dummy.into()); v.set_dcyc(transaction.dummy.into());
}); });
if let Some(addr) = transaction.address { if let Some(addr) = transaction.address {
T::REGS.ar().write(|v| { T::REGS.ar().write(|v| {
v.set_address(addr); v.set_address(addr);
}); });
} }
} }
} }
pub(crate) mod sealed { pub(crate) mod sealed {
use super::*; use super::*;
pub trait Instance { pub trait Instance {
const REGS: Regs; const REGS: Regs;
} }
} }
pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
pin_trait!(SckPin, Instance); pin_trait!(SckPin, Instance);
pin_trait!(D0Pin, Instance); pin_trait!(D0Pin, Instance);
pin_trait!(D1Pin, Instance); pin_trait!(D1Pin, Instance);
pin_trait!(D2Pin, Instance); pin_trait!(D2Pin, Instance);
pin_trait!(D3Pin, Instance); pin_trait!(D3Pin, Instance);
pin_trait!(NSSPin, Instance); pin_trait!(NSSPin, Instance);
dma_trait!(QuadDma, Instance); dma_trait!(QuadDma, Instance);
foreach_peripheral!( foreach_peripheral!(
(quadspi, $inst:ident) => { (quadspi, $inst:ident) => {
impl sealed::Instance for peripherals::$inst { impl sealed::Instance for peripherals::$inst {
const REGS: Regs = crate::pac::$inst; const REGS: Regs = crate::pac::$inst;
} }
impl Instance for peripherals::$inst {} impl Instance for peripherals::$inst {}
}; };
); );