Merge #19
19: Clock passing and SPI Updates r=robamu a=robamu 1. Using `impl Into<Hertz>` instead of Hertz now to increase usability for users 2. Update for SPI API to increase usability Co-authored-by: Robin Mueller <robin.mueller.m@gmail.com>
This commit is contained in:
commit
8f4add54d9
@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- DelayUs and DelayMs trait implementations for timer
|
- DelayUs and DelayMs trait implementations for timer
|
||||||
- SPI implementation for blocking API, supports blockmode as well
|
- 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]
|
## [0.2.1]
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
@ -62,10 +62,10 @@ fn main() -> ! {
|
|||||||
pinsa.pa29.into_funsel_1(),
|
pinsa.pa29.into_funsel_1(),
|
||||||
);
|
);
|
||||||
spia_ref.borrow_mut().replace(
|
spia_ref.borrow_mut().replace(
|
||||||
Spi::spia::<NoneT>(
|
Spi::spia(
|
||||||
dp.SPIA,
|
dp.SPIA,
|
||||||
(sck, miso, mosi),
|
(sck, miso, mosi),
|
||||||
50.mhz().into(),
|
50.mhz(),
|
||||||
spi_cfg,
|
spi_cfg,
|
||||||
Some(&mut dp.SYSCONFIG),
|
Some(&mut dp.SYSCONFIG),
|
||||||
None,
|
None,
|
||||||
@ -80,10 +80,10 @@ fn main() -> ! {
|
|||||||
pinsb.pb7.into_funsel_2(),
|
pinsb.pb7.into_funsel_2(),
|
||||||
);
|
);
|
||||||
spia_ref.borrow_mut().replace(
|
spia_ref.borrow_mut().replace(
|
||||||
Spi::spia::<NoneT>(
|
Spi::spia(
|
||||||
dp.SPIA,
|
dp.SPIA,
|
||||||
(sck, miso, mosi),
|
(sck, miso, mosi),
|
||||||
50.mhz().into(),
|
50.mhz(),
|
||||||
spi_cfg,
|
spi_cfg,
|
||||||
Some(&mut dp.SYSCONFIG),
|
Some(&mut dp.SYSCONFIG),
|
||||||
None,
|
None,
|
||||||
@ -98,10 +98,10 @@ fn main() -> ! {
|
|||||||
pinsb.pb3.into_funsel_1(),
|
pinsb.pb3.into_funsel_1(),
|
||||||
);
|
);
|
||||||
spib_ref.borrow_mut().replace(
|
spib_ref.borrow_mut().replace(
|
||||||
Spi::spib::<NoneT>(
|
Spi::spib(
|
||||||
dp.SPIB,
|
dp.SPIB,
|
||||||
(sck, miso, mosi),
|
(sck, miso, mosi),
|
||||||
50.mhz().into(),
|
50.mhz(),
|
||||||
spi_cfg,
|
spi_cfg,
|
||||||
Some(&mut dp.SYSCONFIG),
|
Some(&mut dp.SYSCONFIG),
|
||||||
None,
|
None,
|
||||||
@ -114,10 +114,9 @@ fn main() -> ! {
|
|||||||
match SPI_BUS_SEL {
|
match SPI_BUS_SEL {
|
||||||
SpiBusSelect::SpiAPortA | SpiBusSelect::SpiAPortB => {
|
SpiBusSelect::SpiAPortA | SpiBusSelect::SpiAPortB => {
|
||||||
if let Some(ref mut spi) = *spia_ref.borrow_mut() {
|
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_SPEED_KHZ.khz().into(),
|
||||||
SPI_MODE,
|
SPI_MODE,
|
||||||
None,
|
|
||||||
BLOCKMODE,
|
BLOCKMODE,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
@ -40,9 +40,9 @@ pub enum FilterClkSel {
|
|||||||
/// The Vorago in powered by an external clock which might have different frequencies.
|
/// 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 here so it can be used by other software components as well.
|
||||||
/// The clock can be set exactly once
|
/// 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| {
|
interrupt::free(|cs| {
|
||||||
SYS_CLOCK.borrow(cs).set(freq).ok();
|
SYS_CLOCK.borrow(cs).set(freq.into()).ok();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
72
src/spi.rs
72
src/spi.rs
@ -54,26 +54,28 @@ pub trait PinSck<SPI>: Sealed {}
|
|||||||
pub trait PinMosi<SPI>: Sealed {}
|
pub trait PinMosi<SPI>: Sealed {}
|
||||||
pub trait PinMiso<SPI>: Sealed {}
|
pub trait PinMiso<SPI>: Sealed {}
|
||||||
|
|
||||||
pub trait OptionalHwCs<SPI>: Sealed {
|
pub trait HwCs: Sealed {
|
||||||
const CS_ID: HwChipSelectId;
|
const CS_ID: HwChipSelectId;
|
||||||
}
|
}
|
||||||
|
pub trait OptionalHwCs<SPI>: HwCs + Sealed {}
|
||||||
|
|
||||||
macro_rules! hw_cs_pin {
|
macro_rules! hw_cs_pin {
|
||||||
($SPIx:ident, $PXx:ident, $AFx:ident, $HwCsIdent:path, $typedef:ident) => {
|
($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;
|
const CS_ID: HwChipSelectId = $HwCsIdent;
|
||||||
}
|
}
|
||||||
|
impl OptionalHwCs<$SPIx> for Pin<$PXx, $AFx> {}
|
||||||
pub type $typedef = Pin<$PXx, $AFx>;
|
pub type $typedef = Pin<$PXx, $AFx>;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OptionalHwCs<SPIA> for NoneT {
|
impl HwCs for NoneT {
|
||||||
const CS_ID: HwChipSelectId = HwChipSelectId::Invalid;
|
|
||||||
}
|
|
||||||
impl OptionalHwCs<SPIB> for NoneT {
|
|
||||||
const CS_ID: HwChipSelectId = HwChipSelectId::Invalid;
|
const CS_ID: HwChipSelectId = HwChipSelectId::Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl OptionalHwCs<SPIA> for NoneT {}
|
||||||
|
impl OptionalHwCs<SPIB> for NoneT {}
|
||||||
|
|
||||||
// SPIA
|
// SPIA
|
||||||
|
|
||||||
impl PinSck<SPIA> for Pin<PA31, AltFunc1> {}
|
impl PinSck<SPIA> for Pin<PA31, AltFunc1> {}
|
||||||
@ -183,6 +185,7 @@ pub trait GenericTransferConfig {
|
|||||||
fn blockmode(&mut self, blockmode: bool);
|
fn blockmode(&mut self, blockmode: bool);
|
||||||
fn mode(&mut self, mode: Mode);
|
fn mode(&mut self, mode: Mode);
|
||||||
fn frequency(&mut self, spi_clk: Hertz);
|
fn frequency(&mut self, spi_clk: Hertz);
|
||||||
|
fn hw_cs_id(&self) -> u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This struct contains all configuration parameter which are transfer specific
|
/// This struct contains all configuration parameter which are transfer specific
|
||||||
@ -201,7 +204,32 @@ pub struct TransferConfig<HWCS> {
|
|||||||
pub blockmode: bool,
|
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(
|
pub fn new(
|
||||||
spi_clk: Hertz,
|
spi_clk: Hertz,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
@ -217,9 +245,19 @@ impl<HWCS> TransferConfig<HWCS> {
|
|||||||
blockmode,
|
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
|
/// Slave Output Disable
|
||||||
fn sod(&mut self, sod: bool) {
|
fn sod(&mut self, sod: bool) {
|
||||||
self.sod = sod;
|
self.sod = sod;
|
||||||
@ -236,6 +274,10 @@ impl<HWCS> GenericTransferConfig for TransferConfig<HWCS> {
|
|||||||
fn frequency(&mut self, spi_clk: Hertz) {
|
fn frequency(&mut self, spi_clk: Hertz) {
|
||||||
self.spi_clk = spi_clk;
|
self.spi_clk = spi_clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn hw_cs_id(&self) -> u8 {
|
||||||
|
HWCS::CS_ID as u8
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@ -341,13 +383,13 @@ macro_rules! spi {
|
|||||||
/// If only one device is connected, this configuration only needs to be done
|
/// If only one device is connected, this configuration only needs to be done
|
||||||
/// once.
|
/// once.
|
||||||
/// * `syscfg` - Can be passed optionally to enable the peripheral clock
|
/// * `syscfg` - Can be passed optionally to enable the peripheral clock
|
||||||
pub fn $spix<HwCs: OptionalHwCs<$SPIX>>(
|
pub fn $spix(
|
||||||
spi: $SPIX,
|
spi: $SPIX,
|
||||||
pins: (Sck, Miso, Mosi),
|
pins: (Sck, Miso, Mosi),
|
||||||
sys_clk: Hertz,
|
sys_clk: impl Into<Hertz> + Copy,
|
||||||
spi_cfg: SpiConfig,
|
spi_cfg: SpiConfig,
|
||||||
syscfg: Option<&mut SYSCONFIG>,
|
syscfg: Option<&mut SYSCONFIG>,
|
||||||
transfer_cfg: Option<&TransferConfig<HwCs>>,
|
transfer_cfg: Option<&ReducedTransferConfig>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
if let Some(syscfg) = syscfg {
|
if let Some(syscfg) = syscfg {
|
||||||
enable_peripheral_clock(syscfg, $clk_enb);
|
enable_peripheral_clock(syscfg, $clk_enb);
|
||||||
@ -365,9 +407,9 @@ macro_rules! spi {
|
|||||||
let mut init_blockmode = false;
|
let mut init_blockmode = false;
|
||||||
if let Some(transfer_cfg) = transfer_cfg {
|
if let Some(transfer_cfg) = transfer_cfg {
|
||||||
mode = transfer_cfg.mode;
|
mode = transfer_cfg.mode;
|
||||||
clk_prescale = sys_clk.0 / (transfer_cfg.spi_clk.0 * (scrdv as u32 + 1));
|
clk_prescale = sys_clk.into().0 / (transfer_cfg.spi_clk.0 * (scrdv as u32 + 1));
|
||||||
if transfer_cfg.hw_cs.is_some() {
|
if transfer_cfg.hw_cs != HwChipSelectId::Invalid {
|
||||||
ss = HwCs::CS_ID as u8;
|
ss = transfer_cfg.hw_cs as u8;
|
||||||
}
|
}
|
||||||
init_blockmode = transfer_cfg.blockmode;
|
init_blockmode = transfer_cfg.blockmode;
|
||||||
}
|
}
|
||||||
@ -408,7 +450,7 @@ macro_rules! spi {
|
|||||||
spi_base: SpiBase {
|
spi_base: SpiBase {
|
||||||
spi,
|
spi,
|
||||||
cfg: spi_cfg,
|
cfg: spi_cfg,
|
||||||
sys_clk,
|
sys_clk: sys_clk.into(),
|
||||||
blockmode: init_blockmode,
|
blockmode: init_blockmode,
|
||||||
_word: PhantomData,
|
_word: PhantomData,
|
||||||
},
|
},
|
||||||
|
@ -46,7 +46,7 @@ pub enum Error {
|
|||||||
BreakCondition,
|
BreakCondition,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
// Receiver FIFO interrupt enable. Generates interrupt
|
// Receiver FIFO interrupt enable. Generates interrupt
|
||||||
// when FIFO is at least half full. Half full is defined as FIFO
|
// when FIFO is at least half full. Half full is defined as FIFO
|
||||||
|
Reference in New Issue
Block a user