stm32/spi: add support for all word sizes.

Co-Authored-By: anton smeenk <asmeenk@planet.nl>
This commit is contained in:
Dario Nieuwenhuis 2023-04-18 20:56:23 +02:00
parent a673b9aa29
commit 2080d8bb6d
6 changed files with 197 additions and 140 deletions

View File

@ -9,7 +9,8 @@ use embassy_cortex_m::interrupt::Priority;
use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use super::{Dir, Word, WordSize}; use super::word::{Word, WordSize};
use super::Dir;
use crate::_generated::BDMA_CHANNEL_COUNT; use crate::_generated::BDMA_CHANNEL_COUNT;
use crate::interrupt::{Interrupt, InterruptExt}; use crate::interrupt::{Interrupt, InterruptExt};
use crate::pac; use crate::pac;
@ -167,7 +168,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
ptr as *mut u32, ptr as *mut u32,
len, len,
true, true,
W::bits(), W::size(),
options, options,
) )
} }
@ -202,7 +203,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
ptr as *mut u32, ptr as *mut u32,
len, len,
true, true,
W::bits(), W::size(),
options, options,
) )
} }
@ -225,7 +226,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
repeated as *const W as *mut u32, repeated as *const W as *mut u32,
count, count,
false, false,
W::bits(), W::size(),
options, options,
) )
} }

View File

@ -9,7 +9,8 @@ use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use pac::dma::regs; use pac::dma::regs;
use super::{Dir, Word, WordSize}; use super::word::{Word, WordSize};
use super::Dir;
use crate::_generated::DMA_CHANNEL_COUNT; use crate::_generated::DMA_CHANNEL_COUNT;
use crate::interrupt::{Interrupt, InterruptExt}; use crate::interrupt::{Interrupt, InterruptExt};
use crate::pac::dma::vals; use crate::pac::dma::vals;
@ -246,7 +247,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
ptr as *mut u32, ptr as *mut u32,
len, len,
true, true,
W::bits(), W::size(),
options, options,
) )
} }
@ -281,7 +282,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
ptr as *mut u32, ptr as *mut u32,
len, len,
true, true,
W::bits(), W::size(),
options, options,
) )
} }
@ -304,7 +305,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
repeated as *const W as *mut u32, repeated as *const W as *mut u32,
count, count,
false, false,
W::bits(), W::size(),
options, options,
) )
} }
@ -464,7 +465,7 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
assert!(len > 0 && len <= 0xFFFF); assert!(len > 0 && len <= 0xFFFF);
let dir = Dir::PeripheralToMemory; let dir = Dir::PeripheralToMemory;
let data_size = W::bits(); let data_size = W::size();
let channel_number = channel.num(); let channel_number = channel.num();
let dma = channel.regs(); let dma = channel.regs();

View File

@ -9,7 +9,8 @@ use embassy_cortex_m::interrupt::Priority;
use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use super::{Dir, Word, WordSize}; use super::word::{Word, WordSize};
use super::Dir;
use crate::_generated::GPDMA_CHANNEL_COUNT; use crate::_generated::GPDMA_CHANNEL_COUNT;
use crate::interrupt::{Interrupt, InterruptExt}; use crate::interrupt::{Interrupt, InterruptExt};
use crate::pac; use crate::pac;
@ -165,7 +166,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
ptr as *mut u32, ptr as *mut u32,
len, len,
true, true,
W::bits(), W::size(),
options, options,
) )
} }
@ -200,7 +201,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
ptr as *mut u32, ptr as *mut u32,
len, len,
true, true,
W::bits(), W::size(),
options, options,
) )
} }
@ -223,7 +224,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
repeated as *const W as *mut u32, repeated as *const W as *mut u32,
count, count,
false, false,
W::bits(), W::size(),
options, options,
) )
} }

View File

@ -21,6 +21,8 @@ pub use gpdma::*;
#[cfg(dmamux)] #[cfg(dmamux)]
mod dmamux; mod dmamux;
pub mod word;
use core::mem; use core::mem;
use embassy_cortex_m::interrupt::Priority; use embassy_cortex_m::interrupt::Priority;
@ -36,53 +38,6 @@ enum Dir {
PeripheralToMemory, PeripheralToMemory,
} }
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum WordSize {
OneByte,
TwoBytes,
FourBytes,
}
impl WordSize {
pub fn bytes(&self) -> usize {
match self {
Self::OneByte => 1,
Self::TwoBytes => 2,
Self::FourBytes => 4,
}
}
}
mod word_sealed {
pub trait Word {}
}
pub trait Word: word_sealed::Word {
fn bits() -> WordSize;
}
impl word_sealed::Word for u8 {}
impl Word for u8 {
fn bits() -> WordSize {
WordSize::OneByte
}
}
impl word_sealed::Word for u16 {}
impl Word for u16 {
fn bits() -> WordSize {
WordSize::TwoBytes
}
}
impl word_sealed::Word for u32 {}
impl Word for u32 {
fn bits() -> WordSize {
WordSize::FourBytes
}
}
pub struct NoDma; pub struct NoDma;
impl_peripheral!(NoDma); impl_peripheral!(NoDma);

View File

@ -0,0 +1,79 @@
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum WordSize {
OneByte,
TwoBytes,
FourBytes,
}
impl WordSize {
pub fn bytes(&self) -> usize {
match self {
Self::OneByte => 1,
Self::TwoBytes => 2,
Self::FourBytes => 4,
}
}
}
mod sealed {
pub trait Word {}
}
pub trait Word: sealed::Word + Default + Copy + 'static {
fn size() -> WordSize;
fn bits() -> usize;
}
macro_rules! impl_word {
(_, $T:ident, $bits:literal, $size:ident) => {
impl sealed::Word for $T {}
impl Word for $T {
fn bits() -> usize {
$bits
}
fn size() -> WordSize {
WordSize::$size
}
}
};
($T:ident, $uX:ident, $bits:literal, $size:ident) => {
#[repr(transparent)]
#[derive(Copy, Clone, Default)]
pub struct $T(pub $uX);
impl_word!(_, $T, $bits, $size);
};
}
impl_word!(U1, u8, 1, OneByte);
impl_word!(U2, u8, 2, OneByte);
impl_word!(U3, u8, 3, OneByte);
impl_word!(U4, u8, 4, OneByte);
impl_word!(U5, u8, 5, OneByte);
impl_word!(U6, u8, 6, OneByte);
impl_word!(U7, u8, 7, OneByte);
impl_word!(_, u8, 8, OneByte);
impl_word!(U9, u16, 9, TwoBytes);
impl_word!(U10, u16, 10, TwoBytes);
impl_word!(U11, u16, 11, TwoBytes);
impl_word!(U12, u16, 12, TwoBytes);
impl_word!(U13, u16, 13, TwoBytes);
impl_word!(U14, u16, 14, TwoBytes);
impl_word!(U15, u16, 15, TwoBytes);
impl_word!(_, u16, 16, TwoBytes);
impl_word!(U17, u32, 17, FourBytes);
impl_word!(U18, u32, 18, FourBytes);
impl_word!(U19, u32, 19, FourBytes);
impl_word!(U20, u32, 20, FourBytes);
impl_word!(U21, u32, 21, FourBytes);
impl_word!(U22, u32, 22, FourBytes);
impl_word!(U23, u32, 23, FourBytes);
impl_word!(U24, u32, 24, FourBytes);
impl_word!(U25, u32, 25, FourBytes);
impl_word!(U26, u32, 26, FourBytes);
impl_word!(U27, u32, 27, FourBytes);
impl_word!(U28, u32, 28, FourBytes);
impl_word!(U29, u32, 29, FourBytes);
impl_word!(U30, u32, 30, FourBytes);
impl_word!(U31, u32, 31, FourBytes);
impl_word!(_, u32, 32, FourBytes);

View File

@ -7,8 +7,7 @@ use embassy_futures::join::join;
use embassy_hal_common::{into_ref, PeripheralRef}; use embassy_hal_common::{into_ref, PeripheralRef};
pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
use self::sealed::WordSize; use crate::dma::{slice_ptr_parts, word, Transfer};
use crate::dma::{slice_ptr_parts, Transfer};
use crate::gpio::sealed::{AFType, Pin as _}; use crate::gpio::sealed::{AFType, Pin as _};
use crate::gpio::{AnyPin, Pull}; use crate::gpio::{AnyPin, Pull};
use crate::pac::spi::{regs, vals, Spi as Regs}; use crate::pac::spi::{regs, vals, Spi as Regs};
@ -78,7 +77,7 @@ pub struct Spi<'d, T: Instance, Tx, Rx> {
miso: Option<PeripheralRef<'d, AnyPin>>, miso: Option<PeripheralRef<'d, AnyPin>>,
txdma: PeripheralRef<'d, Tx>, txdma: PeripheralRef<'d, Tx>,
rxdma: PeripheralRef<'d, Rx>, rxdma: PeripheralRef<'d, Rx>,
current_word_size: WordSize, current_word_size: word_impl::Config,
} }
impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
@ -234,14 +233,15 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
if mosi.is_none() { if mosi.is_none() {
w.set_rxonly(vals::Rxonly::OUTPUTDISABLED); w.set_rxonly(vals::Rxonly::OUTPUTDISABLED);
} }
w.set_dff(WordSize::EightBit.dff()) w.set_dff(<u8 as sealed::Word>::CONFIG)
}); });
} }
#[cfg(spi_v2)] #[cfg(spi_v2)]
unsafe { unsafe {
T::REGS.cr2().modify(|w| { T::REGS.cr2().modify(|w| {
w.set_frxth(WordSize::EightBit.frxth()); let (ds, frxth) = <u8 as sealed::Word>::CONFIG;
w.set_ds(WordSize::EightBit.ds()); w.set_frxth(frxth);
w.set_ds(ds);
w.set_ssoe(false); w.set_ssoe(false);
}); });
T::REGS.cr1().modify(|w| { T::REGS.cr1().modify(|w| {
@ -279,7 +279,8 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
T::REGS.cfg1().modify(|w| { T::REGS.cfg1().modify(|w| {
w.set_crcen(false); w.set_crcen(false);
w.set_mbr(br); w.set_mbr(br);
w.set_dsize(WordSize::EightBit.dsize()); w.set_dsize(<u8 as sealed::Word>::CONFIG);
w.set_fthlv(vals::Fthlv::ONEFRAME);
}); });
T::REGS.cr2().modify(|w| { T::REGS.cr2().modify(|w| {
w.set_tsize(0); w.set_tsize(0);
@ -297,7 +298,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
miso, miso,
txdma, txdma,
rxdma, rxdma,
current_word_size: WordSize::EightBit, current_word_size: <u8 as sealed::Word>::CONFIG,
} }
} }
@ -355,7 +356,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
} }
} }
fn set_word_size(&mut self, word_size: WordSize) { fn set_word_size(&mut self, word_size: word_impl::Config) {
if self.current_word_size == word_size { if self.current_word_size == word_size {
return; return;
} }
@ -364,7 +365,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
unsafe { unsafe {
T::REGS.cr1().modify(|reg| { T::REGS.cr1().modify(|reg| {
reg.set_spe(false); reg.set_spe(false);
reg.set_dff(word_size.dff()) reg.set_dff(word_size)
}); });
T::REGS.cr1().modify(|reg| { T::REGS.cr1().modify(|reg| {
reg.set_spe(true); reg.set_spe(true);
@ -376,8 +377,8 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
w.set_spe(false); w.set_spe(false);
}); });
T::REGS.cr2().modify(|w| { T::REGS.cr2().modify(|w| {
w.set_frxth(word_size.frxth()); w.set_frxth(word_size.1);
w.set_ds(word_size.ds()); w.set_ds(word_size.0);
}); });
T::REGS.cr1().modify(|w| { T::REGS.cr1().modify(|w| {
w.set_spe(true); w.set_spe(true);
@ -393,7 +394,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
w.set_spe(false); w.set_spe(false);
}); });
T::REGS.cfg1().modify(|w| { T::REGS.cfg1().modify(|w| {
w.set_dsize(word_size.dsize()); w.set_dsize(word_size);
}); });
T::REGS.cr1().modify(|w| { T::REGS.cr1().modify(|w| {
w.set_csusp(false); w.set_csusp(false);
@ -412,7 +413,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
return Ok(()); return Ok(());
} }
self.set_word_size(W::WORDSIZE); self.set_word_size(W::CONFIG);
unsafe { unsafe {
T::REGS.cr1().modify(|w| { T::REGS.cr1().modify(|w| {
w.set_spe(false); w.set_spe(false);
@ -450,7 +451,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
return Ok(()); return Ok(());
} }
self.set_word_size(W::WORDSIZE); self.set_word_size(W::CONFIG);
unsafe { unsafe {
T::REGS.cr1().modify(|w| { T::REGS.cr1().modify(|w| {
w.set_spe(false); w.set_spe(false);
@ -513,7 +514,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
return Ok(()); return Ok(());
} }
self.set_word_size(W::WORDSIZE); self.set_word_size(W::CONFIG);
unsafe { unsafe {
T::REGS.cr1().modify(|w| { T::REGS.cr1().modify(|w| {
w.set_spe(false); w.set_spe(false);
@ -571,7 +572,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> { pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) } unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) }
flush_rx_fifo(T::REGS); flush_rx_fifo(T::REGS);
self.set_word_size(W::WORDSIZE); self.set_word_size(W::CONFIG);
for word in words.iter() { for word in words.iter() {
let _ = transfer_word(T::REGS, *word)?; let _ = transfer_word(T::REGS, *word)?;
} }
@ -581,7 +582,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) } unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) }
flush_rx_fifo(T::REGS); flush_rx_fifo(T::REGS);
self.set_word_size(W::WORDSIZE); self.set_word_size(W::CONFIG);
for word in words.iter_mut() { for word in words.iter_mut() {
*word = transfer_word(T::REGS, W::default())?; *word = transfer_word(T::REGS, W::default())?;
} }
@ -591,7 +592,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) } unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) }
flush_rx_fifo(T::REGS); flush_rx_fifo(T::REGS);
self.set_word_size(W::WORDSIZE); self.set_word_size(W::CONFIG);
for word in words.iter_mut() { for word in words.iter_mut() {
*word = transfer_word(T::REGS, *word)?; *word = transfer_word(T::REGS, *word)?;
} }
@ -601,7 +602,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) } unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) }
flush_rx_fifo(T::REGS); flush_rx_fifo(T::REGS);
self.set_word_size(W::WORDSIZE); self.set_word_size(W::CONFIG);
let len = read.len().max(write.len()); let len = read.len().max(write.len());
for i in 0..len { for i in 0..len {
let wb = write.get(i).copied().unwrap_or_default(); let wb = write.get(i).copied().unwrap_or_default();
@ -933,70 +934,89 @@ pub(crate) mod sealed {
const REGS: Regs; const REGS: Regs;
} }
pub trait Word: Copy + 'static { pub trait Word {
const WORDSIZE: WordSize; const CONFIG: word_impl::Config;
}
} }
impl Word for u8 { pub trait Word: word::Word + sealed::Word {}
const WORDSIZE: WordSize = WordSize::EightBit;
macro_rules! impl_word {
($T:ty, $config:expr) => {
impl sealed::Word for $T {
const CONFIG: Config = $config;
} }
impl Word for u16 { impl Word for $T {}
const WORDSIZE: WordSize = WordSize::SixteenBit; };
} }
#[derive(Copy, Clone, PartialOrd, PartialEq)]
pub enum WordSize {
EightBit,
SixteenBit,
}
impl WordSize {
#[cfg(any(spi_v1, spi_f1))] #[cfg(any(spi_v1, spi_f1))]
pub fn dff(&self) -> vals::Dff { mod word_impl {
match self { use super::*;
WordSize::EightBit => vals::Dff::EIGHTBIT,
WordSize::SixteenBit => vals::Dff::SIXTEENBIT, pub type Config = vals::Dff;
}
impl_word!(u8, vals::Dff::EIGHTBIT);
impl_word!(u16, vals::Dff::SIXTEENBIT);
} }
#[cfg(spi_v2)] #[cfg(any(spi_v2))]
pub fn ds(&self) -> vals::Ds { mod word_impl {
match self { use super::*;
WordSize::EightBit => vals::Ds::EIGHTBIT,
WordSize::SixteenBit => vals::Ds::SIXTEENBIT,
}
}
#[cfg(spi_v2)] pub type Config = (vals::Ds, vals::Frxth);
pub fn frxth(&self) -> vals::Frxth {
match self { impl_word!(word::U4, (vals::Ds::FOURBIT, vals::Frxth::QUARTER));
WordSize::EightBit => vals::Frxth::QUARTER, impl_word!(word::U5, (vals::Ds::FIVEBIT, vals::Frxth::QUARTER));
WordSize::SixteenBit => vals::Frxth::HALF, impl_word!(word::U6, (vals::Ds::SIXBIT, vals::Frxth::QUARTER));
} impl_word!(word::U7, (vals::Ds::SEVENBIT, vals::Frxth::QUARTER));
impl_word!(u8, (vals::Ds::EIGHTBIT, vals::Frxth::QUARTER));
impl_word!(word::U9, (vals::Ds::NINEBIT, vals::Frxth::HALF));
impl_word!(word::U10, (vals::Ds::TENBIT, vals::Frxth::HALF));
impl_word!(word::U11, (vals::Ds::ELEVENBIT, vals::Frxth::HALF));
impl_word!(word::U12, (vals::Ds::TWELVEBIT, vals::Frxth::HALF));
impl_word!(word::U13, (vals::Ds::THIRTEENBIT, vals::Frxth::HALF));
impl_word!(word::U14, (vals::Ds::FOURTEENBIT, vals::Frxth::HALF));
impl_word!(word::U15, (vals::Ds::FIFTEENBIT, vals::Frxth::HALF));
impl_word!(u16, (vals::Ds::SIXTEENBIT, vals::Frxth::HALF));
} }
#[cfg(any(spi_v3, spi_v4, spi_v5))] #[cfg(any(spi_v3, spi_v4, spi_v5))]
pub fn dsize(&self) -> u8 { mod word_impl {
match self { use super::*;
WordSize::EightBit => 0b0111,
WordSize::SixteenBit => 0b1111,
}
}
#[cfg(any(spi_v3, spi_v4, spi_v5))] pub type Config = u8;
pub fn _frxth(&self) -> vals::Fthlv {
match self {
WordSize::EightBit => vals::Fthlv::ONEFRAME,
WordSize::SixteenBit => vals::Fthlv::ONEFRAME,
}
}
}
}
pub trait Word: Copy + 'static + sealed::Word + Default + crate::dma::Word {} impl_word!(word::U4, 4 - 1);
impl_word!(word::U5, 5 - 1);
impl Word for u8 {} impl_word!(word::U6, 6 - 1);
impl Word for u16 {} impl_word!(word::U7, 7 - 1);
impl_word!(u8, 8 - 1);
impl_word!(word::U9, 9 - 1);
impl_word!(word::U10, 10 - 1);
impl_word!(word::U11, 11 - 1);
impl_word!(word::U12, 12 - 1);
impl_word!(word::U13, 13 - 1);
impl_word!(word::U14, 14 - 1);
impl_word!(word::U15, 15 - 1);
impl_word!(u16, 16 - 1);
impl_word!(word::U17, 17 - 1);
impl_word!(word::U18, 18 - 1);
impl_word!(word::U19, 19 - 1);
impl_word!(word::U20, 20 - 1);
impl_word!(word::U21, 21 - 1);
impl_word!(word::U22, 22 - 1);
impl_word!(word::U23, 23 - 1);
impl_word!(word::U24, 24 - 1);
impl_word!(word::U25, 25 - 1);
impl_word!(word::U26, 26 - 1);
impl_word!(word::U27, 27 - 1);
impl_word!(word::U28, 28 - 1);
impl_word!(word::U29, 29 - 1);
impl_word!(word::U30, 30 - 1);
impl_word!(word::U31, 31 - 1);
impl_word!(u32, 32 - 1);
}
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);