SPI improvements / Clock passing update

1. Using `impl Into<Hertz>` instead of Hertz now to increase
   usability for users
2. Update for SPI API to increase usability
This commit is contained in:
Robin Müller 2021-11-21 20:14:56 +01:00
parent e5dba61d6c
commit 4feb74e4a6
5 changed files with 71 additions and 26 deletions

View File

@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- DelayUs and DelayMs trait implementations for timer
- SPI implementation for blocking API, supports blockmode as well
### Changed
- API which expects values in Hertz now uses `impl Into<Hertz>` as input parameter
## [0.2.1]
### Added

View File

@ -62,10 +62,10 @@ fn main() -> ! {
pinsa.pa29.into_funsel_1(),
);
spia_ref.borrow_mut().replace(
Spi::spia::<NoneT>(
Spi::spia(
dp.SPIA,
(sck, miso, mosi),
50.mhz().into(),
50.mhz(),
spi_cfg,
Some(&mut dp.SYSCONFIG),
None,
@ -80,10 +80,10 @@ fn main() -> ! {
pinsb.pb7.into_funsel_2(),
);
spia_ref.borrow_mut().replace(
Spi::spia::<NoneT>(
Spi::spia(
dp.SPIA,
(sck, miso, mosi),
50.mhz().into(),
50.mhz(),
spi_cfg,
Some(&mut dp.SYSCONFIG),
None,
@ -98,10 +98,10 @@ fn main() -> ! {
pinsb.pb3.into_funsel_1(),
);
spib_ref.borrow_mut().replace(
Spi::spib::<NoneT>(
Spi::spib(
dp.SPIB,
(sck, miso, mosi),
50.mhz().into(),
50.mhz(),
spi_cfg,
Some(&mut dp.SYSCONFIG),
None,
@ -114,10 +114,9 @@ fn main() -> ! {
match SPI_BUS_SEL {
SpiBusSelect::SpiAPortA | SpiBusSelect::SpiAPortB => {
if let Some(ref mut spi) = *spia_ref.borrow_mut() {
let transfer_cfg = TransferConfig::<NoneT>::new(
let transfer_cfg = TransferConfig::new_no_hw_cs(
SPI_SPEED_KHZ.khz().into(),
SPI_MODE,
None,
BLOCKMODE,
false,
);

View File

@ -40,9 +40,9 @@ pub enum FilterClkSel {
/// The Vorago in powered by an external clock which might have different frequencies.
/// The clock can be set here so it can be used by other software components as well.
/// The clock can be set exactly once
pub fn set_sys_clock(freq: Hertz) {
pub fn set_sys_clock(freq: impl Into<Hertz>) {
interrupt::free(|cs| {
SYS_CLOCK.borrow(cs).set(freq).ok();
SYS_CLOCK.borrow(cs).set(freq.into()).ok();
})
}

View File

@ -54,26 +54,28 @@ pub trait PinSck<SPI>: Sealed {}
pub trait PinMosi<SPI>: Sealed {}
pub trait PinMiso<SPI>: Sealed {}
pub trait OptionalHwCs<SPI>: Sealed {
pub trait HwCs: Sealed {
const CS_ID: HwChipSelectId;
}
pub trait OptionalHwCs<SPI>: HwCs + Sealed {}
macro_rules! hw_cs_pin {
($SPIx:ident, $PXx:ident, $AFx:ident, $HwCsIdent:path, $typedef:ident) => {
impl OptionalHwCs<$SPIx> for Pin<$PXx, $AFx> {
impl HwCs for Pin<$PXx, $AFx> {
const CS_ID: HwChipSelectId = $HwCsIdent;
}
impl OptionalHwCs<$SPIx> for Pin<$PXx, $AFx> {}
pub type $typedef = Pin<$PXx, $AFx>;
};
}
impl OptionalHwCs<SPIA> for NoneT {
const CS_ID: HwChipSelectId = HwChipSelectId::Invalid;
}
impl OptionalHwCs<SPIB> for NoneT {
impl HwCs for NoneT {
const CS_ID: HwChipSelectId = HwChipSelectId::Invalid;
}
impl OptionalHwCs<SPIA> for NoneT {}
impl OptionalHwCs<SPIB> for NoneT {}
// SPIA
impl PinSck<SPIA> for Pin<PA31, AltFunc1> {}
@ -183,6 +185,7 @@ pub trait GenericTransferConfig {
fn blockmode(&mut self, blockmode: bool);
fn mode(&mut self, mode: Mode);
fn frequency(&mut self, spi_clk: Hertz);
fn hw_cs_id(&self) -> u8;
}
/// This struct contains all configuration parameter which are transfer specific
@ -201,7 +204,32 @@ pub struct TransferConfig<HWCS> {
pub blockmode: bool,
}
impl<HWCS> TransferConfig<HWCS> {
/// Type erased variant of the transfer configuration. This is required to avoid generics in
/// the SPI constructor.
pub struct ReducedTransferConfig {
pub spi_clk: Hertz,
pub mode: Mode,
pub sod: bool,
/// If this is enabled, all data in the FIFO is transmitted in a single frame unless
/// the BMSTOP bit is set on a dataword. A frame is defined as CSn being active for the
/// duration of multiple data words
pub blockmode: bool,
pub hw_cs: HwChipSelectId,
}
impl TransferConfig<NoneT> {
pub fn new_no_hw_cs(spi_clk: Hertz, mode: Mode, blockmode: bool, sod: bool) -> Self {
TransferConfig {
spi_clk,
mode,
hw_cs: None,
sod,
blockmode,
}
}
}
impl<HWCS: HwCs> TransferConfig<HWCS> {
pub fn new(
spi_clk: Hertz,
mode: Mode,
@ -217,9 +245,19 @@ impl<HWCS> TransferConfig<HWCS> {
blockmode,
}
}
pub fn downgrade(self) -> ReducedTransferConfig {
ReducedTransferConfig {
spi_clk: self.spi_clk,
mode: self.mode,
sod: self.sod,
blockmode: self.blockmode,
hw_cs: HWCS::CS_ID,
}
}
}
impl<HWCS> GenericTransferConfig for TransferConfig<HWCS> {
impl<HWCS: HwCs> GenericTransferConfig for TransferConfig<HWCS> {
/// Slave Output Disable
fn sod(&mut self, sod: bool) {
self.sod = sod;
@ -236,6 +274,10 @@ impl<HWCS> GenericTransferConfig for TransferConfig<HWCS> {
fn frequency(&mut self, spi_clk: Hertz) {
self.spi_clk = spi_clk;
}
fn hw_cs_id(&self) -> u8 {
HWCS::CS_ID as u8
}
}
#[derive(Default)]
@ -341,13 +383,13 @@ macro_rules! spi {
/// If only one device is connected, this configuration only needs to be done
/// once.
/// * `syscfg` - Can be passed optionally to enable the peripheral clock
pub fn $spix<HwCs: OptionalHwCs<$SPIX>>(
pub fn $spix(
spi: $SPIX,
pins: (Sck, Miso, Mosi),
sys_clk: Hertz,
sys_clk: impl Into<Hertz> + Copy,
spi_cfg: SpiConfig,
syscfg: Option<&mut SYSCONFIG>,
transfer_cfg: Option<&TransferConfig<HwCs>>,
transfer_cfg: Option<&ReducedTransferConfig>,
) -> Self {
if let Some(syscfg) = syscfg {
enable_peripheral_clock(syscfg, $clk_enb);
@ -365,9 +407,9 @@ macro_rules! spi {
let mut init_blockmode = false;
if let Some(transfer_cfg) = transfer_cfg {
mode = transfer_cfg.mode;
clk_prescale = sys_clk.0 / (transfer_cfg.spi_clk.0 * (scrdv as u32 + 1));
if transfer_cfg.hw_cs.is_some() {
ss = HwCs::CS_ID as u8;
clk_prescale = sys_clk.into().0 / (transfer_cfg.spi_clk.0 * (scrdv as u32 + 1));
if transfer_cfg.hw_cs != HwChipSelectId::Invalid {
ss = transfer_cfg.hw_cs as u8;
}
init_blockmode = transfer_cfg.blockmode;
}
@ -408,7 +450,7 @@ macro_rules! spi {
spi_base: SpiBase {
spi,
cfg: spi_cfg,
sys_clk,
sys_clk: sys_clk.into(),
blockmode: init_blockmode,
_word: PhantomData,
},

View File

@ -46,7 +46,7 @@ pub enum Error {
BreakCondition,
}
#[derive(Copy, Clone, PartialEq)]
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Event {
// Receiver FIFO interrupt enable. Generates interrupt
// when FIFO is at least half full. Half full is defined as FIFO