Merge pull request #18 from robamu-org/mueller/doc-fixes
Doc fixes and SPI block mode support
This commit is contained in:
commit
e5dba61d6c
@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
### Added
|
### Added
|
||||||
|
|
||||||
- DelayUs and DelayMs trait implementations for timer
|
- DelayUs and DelayMs trait implementations for timer
|
||||||
- SPI implementation for blocking API
|
- SPI implementation for blocking API, supports blockmode as well
|
||||||
|
|
||||||
## [0.2.1]
|
## [0.2.1]
|
||||||
|
|
||||||
|
@ -31,11 +31,11 @@ pub enum SpiBusSelect {
|
|||||||
SpiBPortB,
|
SpiBPortB,
|
||||||
}
|
}
|
||||||
|
|
||||||
const EXAMPLE_SEL: ExampleSelect = ExampleSelect::Loopback;
|
const EXAMPLE_SEL: ExampleSelect = ExampleSelect::TestBuffer;
|
||||||
const SPI_BUS_SEL: SpiBusSelect = SpiBusSelect::SpiBPortB;
|
const SPI_BUS_SEL: SpiBusSelect = SpiBusSelect::SpiBPortB;
|
||||||
const SPI_SPEED_KHZ: u32 = 1000;
|
const SPI_SPEED_KHZ: u32 = 1000;
|
||||||
const SPI_MODE: Mode = MODE_0;
|
const SPI_MODE: Mode = MODE_0;
|
||||||
const BLOCKMODE: bool = false;
|
const BLOCKMODE: bool = true;
|
||||||
|
|
||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
@ -45,14 +45,17 @@ fn main() -> ! {
|
|||||||
|
|
||||||
let spia_ref: RefCell<Option<SpiBase<SPIA, u8>>> = RefCell::new(None);
|
let spia_ref: RefCell<Option<SpiBase<SPIA, u8>>> = RefCell::new(None);
|
||||||
let spib_ref: RefCell<Option<SpiBase<SPIB, u8>>> = RefCell::new(None);
|
let spib_ref: RefCell<Option<SpiBase<SPIB, u8>>> = RefCell::new(None);
|
||||||
|
let pinsa = PinsA::new(&mut dp.SYSCONFIG, None, dp.PORTA);
|
||||||
|
let pinsb = PinsB::new(&mut dp.SYSCONFIG, Some(dp.IOCONFIG), dp.PORTB);
|
||||||
|
|
||||||
let mut spi_cfg = spi::SpiConfig::default();
|
let mut spi_cfg = spi::SpiConfig::default();
|
||||||
if EXAMPLE_SEL == ExampleSelect::Loopback {
|
if EXAMPLE_SEL == ExampleSelect::Loopback {
|
||||||
spi_cfg = spi_cfg.loopback(true)
|
spi_cfg = spi_cfg.loopback(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up the SPI peripheral
|
||||||
match SPI_BUS_SEL {
|
match SPI_BUS_SEL {
|
||||||
SpiBusSelect::SpiAPortA => {
|
SpiBusSelect::SpiAPortA => {
|
||||||
let pinsa = PinsA::new(&mut dp.SYSCONFIG, None, dp.PORTA);
|
|
||||||
let (sck, mosi, miso) = (
|
let (sck, mosi, miso) = (
|
||||||
pinsa.pa31.into_funsel_1(),
|
pinsa.pa31.into_funsel_1(),
|
||||||
pinsa.pa30.into_funsel_1(),
|
pinsa.pa30.into_funsel_1(),
|
||||||
@ -71,7 +74,6 @@ fn main() -> ! {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
SpiBusSelect::SpiAPortB => {
|
SpiBusSelect::SpiAPortB => {
|
||||||
let pinsb = PinsB::new(&mut dp.SYSCONFIG, Some(dp.IOCONFIG), dp.PORTB);
|
|
||||||
let (sck, mosi, miso) = (
|
let (sck, mosi, miso) = (
|
||||||
pinsb.pb9.into_funsel_2(),
|
pinsb.pb9.into_funsel_2(),
|
||||||
pinsb.pb8.into_funsel_2(),
|
pinsb.pb8.into_funsel_2(),
|
||||||
@ -90,7 +92,6 @@ fn main() -> ! {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
SpiBusSelect::SpiBPortB => {
|
SpiBusSelect::SpiBPortB => {
|
||||||
let pinsb = PinsB::new(&mut dp.SYSCONFIG, Some(dp.IOCONFIG), dp.PORTB);
|
|
||||||
let (sck, mosi, miso) = (
|
let (sck, mosi, miso) = (
|
||||||
pinsb.pb5.into_funsel_1(),
|
pinsb.pb5.into_funsel_1(),
|
||||||
pinsb.pb4.into_funsel_1(),
|
pinsb.pb4.into_funsel_1(),
|
||||||
@ -109,19 +110,41 @@ fn main() -> ! {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Configure transfer specific properties here
|
||||||
|
match SPI_BUS_SEL {
|
||||||
|
SpiBusSelect::SpiAPortA | SpiBusSelect::SpiAPortB => {
|
||||||
|
if let Some(ref mut spi) = *spia_ref.borrow_mut() {
|
||||||
|
let transfer_cfg = TransferConfig::<NoneT>::new(
|
||||||
|
SPI_SPEED_KHZ.khz().into(),
|
||||||
|
SPI_MODE,
|
||||||
|
None,
|
||||||
|
BLOCKMODE,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
spi.cfg_transfer(&transfer_cfg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SpiBusSelect::SpiBPortB => {
|
||||||
|
if let Some(ref mut spi) = *spib_ref.borrow_mut() {
|
||||||
|
let hw_cs_pin = pinsb.pb2.into_funsel_1();
|
||||||
|
let transfer_cfg = TransferConfig::new(
|
||||||
|
SPI_SPEED_KHZ.khz().into(),
|
||||||
|
SPI_MODE,
|
||||||
|
Some(hw_cs_pin),
|
||||||
|
BLOCKMODE,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
spi.cfg_transfer(&transfer_cfg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Application logic
|
||||||
let mut delay_tim = CountDownTimer::tim1(&mut dp.SYSCONFIG, 50.mhz().into(), dp.TIM1);
|
let mut delay_tim = CountDownTimer::tim1(&mut dp.SYSCONFIG, 50.mhz().into(), dp.TIM1);
|
||||||
loop {
|
loop {
|
||||||
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> = TransferConfig {
|
|
||||||
spi_clk: SPI_SPEED_KHZ.khz().into(),
|
|
||||||
blockmode: BLOCKMODE,
|
|
||||||
hw_cs: None,
|
|
||||||
mode: SPI_MODE,
|
|
||||||
sod: false,
|
|
||||||
};
|
|
||||||
spi.cfg_transfer(&transfer_cfg);
|
|
||||||
if EXAMPLE_SEL == ExampleSelect::Loopback {
|
if EXAMPLE_SEL == ExampleSelect::Loopback {
|
||||||
nb::block!(spi.send(0x42_u8)).unwrap();
|
nb::block!(spi.send(0x42_u8)).unwrap();
|
||||||
let word = nb::block!(spi.read()).unwrap();
|
let word = nb::block!(spi.read()).unwrap();
|
||||||
@ -134,7 +157,7 @@ fn main() -> ! {
|
|||||||
assert_eq!(reply, &[0x03, 0x02, 0x01]);
|
assert_eq!(reply, &[0x03, 0x02, 0x01]);
|
||||||
delay_tim.delay_ms(500_u32);
|
delay_tim.delay_ms(500_u32);
|
||||||
} else {
|
} else {
|
||||||
let mut send_buf: [u8; 3] = [0x00, 0x01, 0x02];
|
let mut send_buf: [u8; 3] = [0x01, 0x02, 0x03];
|
||||||
let reply = spi.transfer(&mut send_buf).unwrap();
|
let reply = spi.transfer(&mut send_buf).unwrap();
|
||||||
rprintln!("Received reply: {}, {}, {}", reply[0], reply[1], reply[2]);
|
rprintln!("Received reply: {}, {}, {}", reply[0], reply[1], reply[2]);
|
||||||
delay_tim.delay_ms(1000_u32);
|
delay_tim.delay_ms(1000_u32);
|
||||||
@ -143,14 +166,6 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
SpiBusSelect::SpiBPortB => {
|
SpiBusSelect::SpiBPortB => {
|
||||||
if let Some(ref mut spi) = *spib_ref.borrow_mut() {
|
if let Some(ref mut spi) = *spib_ref.borrow_mut() {
|
||||||
let transfer_cfg: TransferConfig<NoneT> = TransferConfig {
|
|
||||||
spi_clk: SPI_SPEED_KHZ.khz().into(),
|
|
||||||
blockmode: BLOCKMODE,
|
|
||||||
hw_cs: None,
|
|
||||||
mode: SPI_MODE,
|
|
||||||
sod: false,
|
|
||||||
};
|
|
||||||
spi.cfg_transfer(&transfer_cfg);
|
|
||||||
if EXAMPLE_SEL == ExampleSelect::Loopback {
|
if EXAMPLE_SEL == ExampleSelect::Loopback {
|
||||||
nb::block!(spi.send(0x42_u8)).unwrap();
|
nb::block!(spi.send(0x42_u8)).unwrap();
|
||||||
let word = nb::block!(spi.read()).unwrap();
|
let word = nb::block!(spi.read()).unwrap();
|
||||||
@ -163,7 +178,7 @@ fn main() -> ! {
|
|||||||
assert_eq!(reply, &[0x03, 0x02, 0x01]);
|
assert_eq!(reply, &[0x03, 0x02, 0x01]);
|
||||||
delay_tim.delay_ms(500_u32);
|
delay_tim.delay_ms(500_u32);
|
||||||
} else {
|
} else {
|
||||||
let mut send_buf: [u8; 3] = [0x00, 0x01, 0x02];
|
let mut send_buf: [u8; 3] = [0x01, 0x02, 0x03];
|
||||||
let reply = spi.transfer(&mut send_buf).unwrap();
|
let reply = spi.transfer(&mut send_buf).unwrap();
|
||||||
rprintln!("Received reply: {}, {}, {}", reply[0], reply[1], reply[2]);
|
rprintln!("Received reply: {}, {}, {}", reply[0], reply[1], reply[2]);
|
||||||
delay_tim.delay_ms(1000_u32);
|
delay_tim.delay_ms(1000_u32);
|
||||||
|
@ -55,7 +55,7 @@
|
|||||||
//! `Error = core::convert::Infallible`, the value-level API can return a real
|
//! `Error = core::convert::Infallible`, the value-level API can return a real
|
||||||
//! error. If the [`DynPin`] is not in the correct [`DynPinMode`] for the
|
//! error. If the [`DynPin`] is not in the correct [`DynPinMode`] for the
|
||||||
//! operation, the trait functions will return
|
//! operation, the trait functions will return
|
||||||
//! [`InvalidPinType`](Error::InvalidPinType).
|
//! [`InvalidPinType`](PinError::InvalidPinType).
|
||||||
|
|
||||||
use super::pins::{
|
use super::pins::{
|
||||||
common_reg_if_functions, FilterType, InterruptEdge, InterruptLevel, Pin, PinError, PinId,
|
common_reg_if_functions, FilterType, InterruptEdge, InterruptLevel, Pin, PinError, PinId,
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
//! The implementation of this GPIO module is heavily based on the
|
//! The implementation of this GPIO module is heavily based on the
|
||||||
//! [ATSAMD HAL implementation](https://docs.rs/atsamd-hal/0.13.0/atsamd_hal/gpio/v2/index.html).
|
//! [ATSAMD HAL implementation](https://docs.rs/atsamd-hal/0.13.0/atsamd_hal/gpio/v2/index.html).
|
||||||
//!
|
//!
|
||||||
//! This API provides two different submodules, [`pins`] and [`dynpins`],
|
//! This API provides two different submodules, [`mod@pins`] and [`dynpins`],
|
||||||
//! representing two different ways to handle GPIO pins. The default, [`pins`],
|
//! representing two different ways to handle GPIO pins. The default, [`mod@pins`],
|
||||||
//! is a type-level API that tracks the state of each pin at compile-time. The
|
//! is a type-level API that tracks the state of each pin at compile-time. The
|
||||||
//! alternative, [`dynpins`] is a type-erased, value-level API that tracks the
|
//! alternative, [`dynpins`] is a type-erased, value-level API that tracks the
|
||||||
//! state of each pin at run-time.
|
//! state of each pin at run-time.
|
||||||
|
@ -26,16 +26,17 @@
|
|||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! A `PinId` identifies a pin by it's group (A, B) and pin number. Each
|
//! A [`PinId`] identifies a pin by it's group (A, B) and pin number. Each
|
||||||
//! `PinId` instance is named according to its datasheet identifier, e.g.
|
//! [`PinId`] instance is named according to its datasheet identifier, e.g.
|
||||||
//! [`PA02`].
|
//! PA02.
|
||||||
//!
|
//!
|
||||||
//! A `PinMode` represents the various pin modes. The available `PinMode`
|
//! A `PinMode` represents the various pin modes. The available `PinMode`
|
||||||
//! variants are [`Input`], [`Output`] and [`Alternate`], each with its own corresponding
|
//! variants are [`Input`], [`Output`] and [`Alternate`], each with its own corresponding
|
||||||
//! configurations.
|
//! configurations.
|
||||||
//!
|
//!
|
||||||
//! It is not possible for users to create new instances of a [`Pin`]. Singleton
|
//! It is not possible for users to create new instances of a [`Pin`]. Singleton
|
||||||
//! instances of each pin are made available to users through the [`Pins`]
|
//! instances of each pin are made available to users through the [`PinsA`] and
|
||||||
|
//! [`PinsB`]
|
||||||
//! struct.
|
//! struct.
|
||||||
//!
|
//!
|
||||||
//! To create the [`PinsA`] or [`PinsB`] struct, users must supply the PAC
|
//! To create the [`PinsA`] or [`PinsB`] struct, users must supply the PAC
|
||||||
@ -84,7 +85,8 @@
|
|||||||
//! This module also provides additional, type-level tools to work with GPIO
|
//! This module also provides additional, type-level tools to work with GPIO
|
||||||
//! pins.
|
//! pins.
|
||||||
//!
|
//!
|
||||||
//! The [`AnyPin`] trait defines an [`AnyKind`] type class
|
//! The [`AnyPin`] trait defines an
|
||||||
|
//! [`AnyKind`](https://docs.rs/atsamd-hal/0.13.0/atsamd_hal/typelevel/index.html) type class
|
||||||
//! for all `Pin` types.
|
//! for all `Pin` types.
|
||||||
|
|
||||||
use super::dynpins::{DynAlternate, DynGroup, DynInput, DynOutput, DynPinId, DynPinMode};
|
use super::dynpins::{DynAlternate, DynGroup, DynInput, DynOutput, DynPinId, DynPinMode};
|
||||||
@ -229,7 +231,8 @@ impl OutputConfig for ReadableOpenDrain {
|
|||||||
|
|
||||||
/// Type-level variant of [`PinMode`] for output modes
|
/// Type-level variant of [`PinMode`] for output modes
|
||||||
///
|
///
|
||||||
/// Type `C` is one of two output configurations: [`PushPull`] or [`Readable`]
|
/// Type `C` is one of four output configurations: [`PushPull`], [`OpenDrain`] or
|
||||||
|
/// their respective readable versions
|
||||||
pub struct Output<C: OutputConfig> {
|
pub struct Output<C: OutputConfig> {
|
||||||
cfg: PhantomData<C>,
|
cfg: PhantomData<C>,
|
||||||
}
|
}
|
||||||
@ -543,7 +546,8 @@ pub type SpecificPin<P> = Pin<<P as AnyPin>::Id, <P as AnyPin>::Mode>;
|
|||||||
|
|
||||||
/// Type class for [`Pin`] types
|
/// Type class for [`Pin`] types
|
||||||
///
|
///
|
||||||
/// This trait uses the [`AnyKind`] trait pattern to create a [type class] for
|
/// This trait uses the [`AnyKind`](https://docs.rs/atsamd-hal/0.13.0/atsamd_hal/typelevel/index.html)
|
||||||
|
/// trait pattern to create a [type class] for
|
||||||
/// [`Pin`] types. See the `AnyKind` documentation for more details on the
|
/// [`Pin`] types. See the `AnyKind` documentation for more details on the
|
||||||
/// pattern.
|
/// pattern.
|
||||||
pub trait AnyPin: Is<Type = SpecificPin<Self>> {
|
pub trait AnyPin: Is<Type = SpecificPin<Self>> {
|
||||||
|
99
src/spi.rs
99
src/spi.rs
@ -1,4 +1,8 @@
|
|||||||
//! API for the SPI peripheral
|
//! API for the SPI peripheral
|
||||||
|
//!
|
||||||
|
//! ## Examples
|
||||||
|
//!
|
||||||
|
//! - [Blocking SPI example](https://github.com/robamu-org/va108xx-hal-rs/blob/main/examples/spi.rs)
|
||||||
use crate::Sealed;
|
use crate::Sealed;
|
||||||
use crate::{
|
use crate::{
|
||||||
clock::{enable_peripheral_clock, PeripheralClocks},
|
clock::{enable_peripheral_clock, PeripheralClocks},
|
||||||
@ -181,6 +185,8 @@ pub trait GenericTransferConfig {
|
|||||||
fn frequency(&mut self, spi_clk: Hertz);
|
fn frequency(&mut self, spi_clk: Hertz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This struct contains all configuration parameter which are transfer specific
|
||||||
|
/// and might change for transfers to different SPI slaves
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct TransferConfig<HWCS> {
|
pub struct TransferConfig<HWCS> {
|
||||||
pub spi_clk: Hertz,
|
pub spi_clk: Hertz,
|
||||||
@ -189,9 +195,30 @@ pub struct TransferConfig<HWCS> {
|
|||||||
/// false
|
/// false
|
||||||
pub hw_cs: Option<HWCS>,
|
pub hw_cs: Option<HWCS>,
|
||||||
pub sod: bool,
|
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 blockmode: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<HWCS> TransferConfig<HWCS> {
|
||||||
|
pub fn new(
|
||||||
|
spi_clk: Hertz,
|
||||||
|
mode: Mode,
|
||||||
|
hw_cs: Option<HWCS>,
|
||||||
|
blockmode: bool,
|
||||||
|
sod: bool,
|
||||||
|
) -> Self {
|
||||||
|
TransferConfig {
|
||||||
|
spi_clk,
|
||||||
|
mode,
|
||||||
|
hw_cs,
|
||||||
|
sod,
|
||||||
|
blockmode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<HWCS> GenericTransferConfig for TransferConfig<HWCS> {
|
impl<HWCS> GenericTransferConfig for TransferConfig<HWCS> {
|
||||||
/// Slave Output Disable
|
/// Slave Output Disable
|
||||||
fn sod(&mut self, sod: bool) {
|
fn sod(&mut self, sod: bool) {
|
||||||
@ -211,32 +238,6 @@ impl<HWCS> GenericTransferConfig for TransferConfig<HWCS> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configuration options for a single transfer. These can be used to reconfigure the SPI bus
|
|
||||||
/// for transaction to different devices
|
|
||||||
impl<HWCS: OptionalHwCs<SPIA>> TransferConfig<HWCS> {
|
|
||||||
pub fn cfg_spia(spi_clk: Hertz, mode: Mode, hw_cs: Option<HWCS>) -> Self {
|
|
||||||
TransferConfig {
|
|
||||||
spi_clk,
|
|
||||||
mode,
|
|
||||||
hw_cs,
|
|
||||||
sod: false,
|
|
||||||
blockmode: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<HWCS: OptionalHwCs<SPIB>> TransferConfig<HWCS> {
|
|
||||||
pub fn cfg_spib(spi_clk: Hertz, mode: Mode, hw_cs: Option<HWCS>) -> Self {
|
|
||||||
TransferConfig {
|
|
||||||
spi_clk,
|
|
||||||
mode,
|
|
||||||
hw_cs,
|
|
||||||
sod: false,
|
|
||||||
blockmode: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
/// Configuration options for the whole SPI bus. See Programmer Guide p.92 for more details
|
/// Configuration options for the whole SPI bus. See Programmer Guide p.92 for more details
|
||||||
pub struct SpiConfig {
|
pub struct SpiConfig {
|
||||||
@ -301,6 +302,7 @@ pub struct SpiBase<SPI, Word = u8> {
|
|||||||
spi: SPI,
|
spi: SPI,
|
||||||
cfg: SpiConfig,
|
cfg: SpiConfig,
|
||||||
sys_clk: Hertz,
|
sys_clk: Hertz,
|
||||||
|
blockmode: bool,
|
||||||
_word: PhantomData<Word>,
|
_word: PhantomData<Word>,
|
||||||
}
|
}
|
||||||
pub struct Spi<SPI, PINS, Word = u8> {
|
pub struct Spi<SPI, PINS, Word = u8> {
|
||||||
@ -330,7 +332,8 @@ macro_rules! spi {
|
|||||||
/// )
|
/// )
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// in the function call
|
/// in the function call. You can delete the pin type information by calling
|
||||||
|
/// the [`downgrade`](Self::downgrade) function
|
||||||
///
|
///
|
||||||
/// ## Arguments
|
/// ## Arguments
|
||||||
/// * `transfer_cfg` - Transfer configuration which includes configuration
|
/// * `transfer_cfg` - Transfer configuration which includes configuration
|
||||||
@ -359,12 +362,14 @@ macro_rules! spi {
|
|||||||
let mut mode = MODE_0;
|
let mut mode = MODE_0;
|
||||||
let mut clk_prescale = 0x02;
|
let mut clk_prescale = 0x02;
|
||||||
let mut ss = 0;
|
let mut ss = 0;
|
||||||
|
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.0 / (transfer_cfg.spi_clk.0 * (scrdv as u32 + 1));
|
||||||
if transfer_cfg.hw_cs.is_some() {
|
if transfer_cfg.hw_cs.is_some() {
|
||||||
ss = HwCs::CS_ID as u8;
|
ss = HwCs::CS_ID as u8;
|
||||||
}
|
}
|
||||||
|
init_blockmode = transfer_cfg.blockmode;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (cpo_bit, cph_bit) = match mode {
|
let (cpo_bit, cph_bit) = match mode {
|
||||||
@ -404,6 +409,7 @@ macro_rules! spi {
|
|||||||
spi,
|
spi,
|
||||||
cfg: spi_cfg,
|
cfg: spi_cfg,
|
||||||
sys_clk,
|
sys_clk,
|
||||||
|
blockmode: init_blockmode,
|
||||||
_word: PhantomData,
|
_word: PhantomData,
|
||||||
},
|
},
|
||||||
pins,
|
pins,
|
||||||
@ -470,6 +476,7 @@ macro_rules! spi {
|
|||||||
pub fn cfg_transfer<HwCs: OptionalHwCs<$SPIX>>(&mut self, transfer_cfg: &TransferConfig<HwCs>) {
|
pub fn cfg_transfer<HwCs: OptionalHwCs<$SPIX>>(&mut self, transfer_cfg: &TransferConfig<HwCs>) {
|
||||||
self.cfg_clock(transfer_cfg.spi_clk);
|
self.cfg_clock(transfer_cfg.spi_clk);
|
||||||
self.cfg_mode(transfer_cfg.mode);
|
self.cfg_mode(transfer_cfg.mode);
|
||||||
|
self.blockmode = transfer_cfg.blockmode;
|
||||||
self.spi.ctrl1.modify(|_, w| {
|
self.spi.ctrl1.modify(|_, w| {
|
||||||
if transfer_cfg.sod {
|
if transfer_cfg.sod {
|
||||||
w.sod().set_bit();
|
w.sod().set_bit();
|
||||||
@ -491,7 +498,7 @@ macro_rules! spi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Changing the word size also requires a type conversion
|
/// Changing the word size also requires a type conversion
|
||||||
impl <Sck: PinSck<$SPIX>, Miso: PinMiso<$SPIX>, Mosi: PinMosi<$SPIX>>
|
impl <Sck: PinSck<$SPIX>, Miso: PinMiso<$SPIX>, Mosi: PinMosi<$SPIX>>
|
||||||
From<Spi<$SPIX, (Sck, Miso, Mosi), u8>> for Spi<$SPIX, (Sck, Miso, Mosi), u16>
|
From<Spi<$SPIX, (Sck, Miso, Mosi), u8>> for Spi<$SPIX, (Sck, Miso, Mosi), u16>
|
||||||
{
|
{
|
||||||
@ -507,6 +514,7 @@ macro_rules! spi {
|
|||||||
spi_base: SpiBase {
|
spi_base: SpiBase {
|
||||||
spi: old_spi.spi_base.spi,
|
spi: old_spi.spi_base.spi,
|
||||||
cfg: old_spi.spi_base.cfg,
|
cfg: old_spi.spi_base.cfg,
|
||||||
|
blockmode: old_spi.spi_base.blockmode,
|
||||||
sys_clk: old_spi.spi_base.sys_clk,
|
sys_clk: old_spi.spi_base.sys_clk,
|
||||||
_word: PhantomData,
|
_word: PhantomData,
|
||||||
},
|
},
|
||||||
@ -515,7 +523,7 @@ macro_rules! spi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Changing the word size also requires a type conversion
|
/// Changing the word size also requires a type conversion
|
||||||
impl <Sck: PinSck<$SPIX>, Miso: PinMiso<$SPIX>, Mosi: PinMosi<$SPIX>>
|
impl <Sck: PinSck<$SPIX>, Miso: PinMiso<$SPIX>, Mosi: PinMosi<$SPIX>>
|
||||||
From<Spi<$SPIX, (Sck, Miso, Mosi), u16>> for
|
From<Spi<$SPIX, (Sck, Miso, Mosi), u16>> for
|
||||||
Spi<$SPIX, (Sck, Miso, Mosi), u8>
|
Spi<$SPIX, (Sck, Miso, Mosi), u8>
|
||||||
@ -532,6 +540,7 @@ macro_rules! spi {
|
|||||||
spi_base: SpiBase {
|
spi_base: SpiBase {
|
||||||
spi: old_spi.spi_base.spi,
|
spi: old_spi.spi_base.spi,
|
||||||
cfg: old_spi.spi_base.cfg,
|
cfg: old_spi.spi_base.cfg,
|
||||||
|
blockmode: old_spi.spi_base.blockmode,
|
||||||
sys_clk: old_spi.spi_base.sys_clk,
|
sys_clk: old_spi.spi_base.sys_clk,
|
||||||
_word: PhantomData,
|
_word: PhantomData,
|
||||||
},
|
},
|
||||||
@ -546,15 +555,6 @@ macro_rules! spi {
|
|||||||
{
|
{
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
|
|
||||||
/// Read a word from the slave. Must be preceeded by a [`send`] call
|
|
||||||
#[inline(always)]
|
|
||||||
fn read(&mut self) -> nb::Result<$WORD, Self::Error> {
|
|
||||||
if self.spi.status.read().rne().bit_is_clear() {
|
|
||||||
return Err(nb::Error::WouldBlock);
|
|
||||||
}
|
|
||||||
Ok((self.spi.data.read().bits() & 0xffff) as $WORD)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends a word to the slave
|
/// Sends a word to the slave
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn send(&mut self, word: $WORD) -> nb::Result<(), Self::Error> {
|
fn send(&mut self, word: $WORD) -> nb::Result<(), Self::Error> {
|
||||||
@ -564,6 +564,15 @@ macro_rules! spi {
|
|||||||
self.spi.data.write(|w| unsafe { w.bits(word as u32) });
|
self.spi.data.write(|w| unsafe { w.bits(word as u32) });
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read a word from the slave. Must be preceeded by a [`send`](Self::send) call
|
||||||
|
#[inline(always)]
|
||||||
|
fn read(&mut self) -> nb::Result<$WORD, Self::Error> {
|
||||||
|
if self.spi.status.read().rne().bit_is_clear() {
|
||||||
|
return Err(nb::Error::WouldBlock);
|
||||||
|
}
|
||||||
|
Ok((self.spi.data.read().bits() & 0xffff) as $WORD)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Sck: PinSck<$SPIX>, Miso: PinMiso<$SPIX>, Mosi: PinMosi<$SPIX>>
|
impl<Sck: PinSck<$SPIX>, Miso: PinMiso<$SPIX>, Mosi: PinMosi<$SPIX>>
|
||||||
@ -592,15 +601,25 @@ macro_rules! spi {
|
|||||||
write_words: &'w [$WORD],
|
write_words: &'w [$WORD],
|
||||||
read_words: Option<&'w mut [$WORD]>,
|
read_words: Option<&'w mut [$WORD]>,
|
||||||
) -> Result<(), Infallible> {
|
) -> Result<(), Infallible> {
|
||||||
// FIFO has a depth of 16. Only fill the first half for now
|
// FIFO has a depth of 16.
|
||||||
const FIFO_WORDS: usize = 8;
|
const FIFO_WORDS: usize = 12;
|
||||||
|
|
||||||
|
if self.blockmode {
|
||||||
|
self.spi.ctrl1.modify(|_, w| {
|
||||||
|
w.mtxpause().set_bit()
|
||||||
|
})
|
||||||
|
}
|
||||||
// Fill the first half of the write FIFO
|
// Fill the first half of the write FIFO
|
||||||
let len = write_words.len();
|
let len = write_words.len();
|
||||||
let mut write = write_words.iter();
|
let mut write = write_words.iter();
|
||||||
for _ in 0..core::cmp::min(FIFO_WORDS, len) {
|
for _ in 0..core::cmp::min(FIFO_WORDS, len) {
|
||||||
nb::block!(self.send(*write.next().unwrap())).ok().unwrap();
|
nb::block!(self.send(*write.next().unwrap())).ok().unwrap();
|
||||||
}
|
}
|
||||||
|
if self.blockmode {
|
||||||
|
self.spi.ctrl1.modify(|_, w| {
|
||||||
|
w.mtxpause().clear_bit()
|
||||||
|
})
|
||||||
|
}
|
||||||
if let Some(read) = read_words {
|
if let Some(read) = read_words {
|
||||||
let mut read = read.iter_mut();
|
let mut read = read.iter_mut();
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@ impl Sealed for NoneT {}
|
|||||||
|
|
||||||
/// Marker trait for type identity
|
/// Marker trait for type identity
|
||||||
///
|
///
|
||||||
/// This trait is used as part of the [`AnyKind`] trait pattern. It represents
|
/// This trait is used as part of the [`AnyKind`](https://docs.rs/atsamd-hal/0.13.0/atsamd_hal/typelevel/index.html)
|
||||||
/// the concept of type identity, because all implementors have
|
/// trait pattern. It represents the concept of type identity, because all implementors have
|
||||||
/// `<Self as Is>::Type == Self`. When used as a trait bound with a specific
|
/// `<Self as Is>::Type == Self`. When used as a trait bound with a specific
|
||||||
/// type, it guarantees that the corresponding type parameter is exactly the
|
/// type, it guarantees that the corresponding type parameter is exactly the
|
||||||
/// specific type. Stated differently, it guarantees that `T == Specific` in
|
/// specific type. Stated differently, it guarantees that `T == Specific` in
|
||||||
|
Reference in New Issue
Block a user