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