diff --git a/examples/simple/Cargo.toml b/examples/simple/Cargo.toml index be52905..0458b1b 100644 --- a/examples/simple/Cargo.toml +++ b/examples/simple/Cargo.toml @@ -30,4 +30,4 @@ features = ["cortex-m-systick"] [dependencies.va108xx-hal] version = "0.6" path = "../../va108xx-hal" -features = ["rt", "defmt"] +features = ["rt", "defmt"] \ No newline at end of file diff --git a/examples/simple/examples/rtt-log.rs b/examples/simple/examples/rtt-log.rs index 55a63db..cbd4187 100644 --- a/examples/simple/examples/rtt-log.rs +++ b/examples/simple/examples/rtt-log.rs @@ -3,12 +3,14 @@ #![no_std] use cortex_m_rt::entry; -use panic_halt as _; +use panic_rtt_target as _; use rtt_target::{rprintln, rtt_init_print}; +use va108xx_hal as _; #[entry] fn main() -> ! { rtt_init_print!(); + rprintln!("-- VA108XX RTT example --"); let mut counter = 0; loop { rprintln!("{}: Hello, world!", counter); diff --git a/examples/simple/examples/spi.rs b/examples/simple/examples/spi.rs index 27037ad..f776b1e 100644 --- a/examples/simple/examples/spi.rs +++ b/examples/simple/examples/spi.rs @@ -73,12 +73,12 @@ fn main() -> ! { pinsa.pa30.into_funsel_1(), pinsa.pa29.into_funsel_1(), ); - let mut spia = Spi::spia( + let mut spia = Spi::new( + &mut dp.sysconfig, + 50.MHz(), dp.spia, (sck, miso, mosi), - 50.MHz(), spi_cfg, - Some(&mut dp.sysconfig), None, ); spia.set_fill_word(FILL_WORD); @@ -90,12 +90,12 @@ fn main() -> ! { pinsb.pb8.into_funsel_2(), pinsb.pb7.into_funsel_2(), ); - let mut spia = Spi::spia( + let mut spia = Spi::new( + &mut dp.sysconfig, + 50.MHz(), dp.spia, (sck, miso, mosi), - 50.MHz(), spi_cfg, - Some(&mut dp.sysconfig), None, ); spia.set_fill_word(FILL_WORD); @@ -107,12 +107,12 @@ fn main() -> ! { pinsb.pb4.into_funsel_1(), pinsb.pb3.into_funsel_1(), ); - let mut spib = Spi::spib( + let mut spib = Spi::new( + &mut dp.sysconfig, + 50.MHz(), dp.spib, (sck, miso, mosi), - 50.MHz(), spi_cfg, - Some(&mut dp.sysconfig), None, ); spib.set_fill_word(FILL_WORD); @@ -195,6 +195,10 @@ fn main() -> ! { if EXAMPLE_SEL == ExampleSelect::Loopback { // Can't really verify correct reply here. spi.write(&[0x42]).expect("write failed"); + // Need small delay.. otherwise we will read back the sent byte (which we don't want here). + // The write function will return as soon as all bytes were shifted out, ignoring the + // reply bytes. + delay.delay_us(50); // Because of the loopback mode, we should get back the fill word here. spi.read(&mut reply_buf[0..1]).unwrap(); assert_eq!(reply_buf[0], FILL_WORD); diff --git a/examples/simple/examples/uart-irq-rtic.rs b/examples/simple/examples/uart-irq-rtic.rs index 1ff01e5..94781bd 100644 --- a/examples/simple/examples/uart-irq-rtic.rs +++ b/examples/simple/examples/uart-irq-rtic.rs @@ -65,7 +65,7 @@ mod app { let irq_cfg = IrqCfg::new(pac::interrupt::OC3, true, true); let (mut irq_uart, _) = - uart::Uart::uartb(dp.uartb, (tx, rx), 115200.Hz(), &mut dp.sysconfig, 50.MHz()) + uart::Uart::new(&mut dp.sysconfig, 50.MHz(), dp.uartb, (tx, rx), 115200.Hz()) .into_uart_with_irq(irq_cfg, Some(&mut dp.sysconfig), Some(&mut dp.irqsel)) .downgrade(); irq_uart diff --git a/examples/simple/examples/uart.rs b/examples/simple/examples/uart.rs index beff171..de94bed 100644 --- a/examples/simple/examples/uart.rs +++ b/examples/simple/examples/uart.rs @@ -28,7 +28,7 @@ fn main() -> ! { let tx = gpioa.pa9.into_funsel_2(); let rx = gpioa.pa8.into_funsel_2(); - let uarta = uart::Uart::uarta(dp.uarta, (tx, rx), 115200.Hz(), &mut dp.sysconfig, 50.MHz()); + let uarta = uart::Uart::new(&mut dp.sysconfig, 50.MHz(), dp.uarta, (tx, rx), 115200.Hz()); let (mut tx, mut rx) = uarta.split(); writeln!(tx, "Hello World\r").unwrap(); loop { diff --git a/va108xx-hal/CHANGELOG.md b/va108xx-hal/CHANGELOG.md index a66e4c4..c8cc308 100644 --- a/va108xx-hal/CHANGELOG.md +++ b/va108xx-hal/CHANGELOG.md @@ -6,6 +6,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [v0.7.0] 2024-07-04 + +- Replace `uarta` and `uartb` `Uart` constructors by `new` method. + ## [v0.6.0] 2024-06-16 - Updated `embedded-hal` to v1 diff --git a/va108xx-hal/src/spi.rs b/va108xx-hal/src/spi.rs index 0a87d32..c0254d0 100644 --- a/va108xx-hal/src/spi.rs +++ b/va108xx-hal/src/spi.rs @@ -4,7 +4,7 @@ //! //! - [Blocking SPI example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/spi.rs) use crate::{ - clock::{enable_peripheral_clock, PeripheralClocks}, + clock::enable_peripheral_clock, gpio::pins::{ AltFunc1, AltFunc2, AltFunc3, Pin, PA10, PA11, PA12, PA13, PA14, PA15, PA16, PA17, PA18, PA19, PA20, PA21, PA22, PA23, PA24, PA25, PA26, PA27, PA28, PA29, PA30, PA31, PB0, PB1, @@ -14,9 +14,10 @@ use crate::{ pac, time::Hertz, typelevel::Sealed, + PeripheralSelect, }; -use core::{convert::Infallible, fmt::Debug, marker::PhantomData}; -use embedded_hal::spi::{Mode, SpiBus, MODE_0, MODE_1, MODE_2, MODE_3}; +use core::{convert::Infallible, fmt::Debug, marker::PhantomData, ops::Deref}; +use embedded_hal::spi::{Mode, MODE_0, MODE_1, MODE_2, MODE_3}; //================================================================================================== // Defintions @@ -54,6 +55,47 @@ pub enum WordSize { SixteenBits = 0x0f, } +pub type SpiRegBlock = pac::spia::RegisterBlock; + +/// Common trait implemented by all PAC peripheral access structures. The register block +/// format is the same for all SPI blocks. +pub trait Instance: Deref { + const IDX: u8; + const PERIPH_SEL: PeripheralSelect; + + fn ptr() -> *const SpiRegBlock; +} + +impl Instance for pac::Spia { + const IDX: u8 = 0; + const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi0; + + #[inline(always)] + fn ptr() -> *const SpiRegBlock { + Self::ptr() + } +} + +impl Instance for pac::Spib { + const IDX: u8 = 1; + const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi1; + + #[inline(always)] + fn ptr() -> *const SpiRegBlock { + Self::ptr() + } +} + +impl Instance for pac::Spic { + const IDX: u8 = 2; + const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi2; + + #[inline(always)] + fn ptr() -> *const SpiRegBlock { + Self::ptr() + } +} + //================================================================================================== // Pin type definitions //================================================================================================== @@ -69,14 +111,20 @@ pub trait HwCsProvider: Sealed { pub trait OptionalHwCs: HwCsProvider + Sealed {} -macro_rules! hw_cs_pin { - ($SPIx:path, $portId: path, $PXx:ident, $AFx:ident, $HwCsIdent:path, $typedef:ident) => { - impl HwCsProvider for Pin<$PXx, $AFx> { - const CS_ID: HwChipSelectId = $HwCsIdent; - const SPI_PORT: SpiPort = $portId; - } - impl OptionalHwCs<$SPIx> for Pin<$PXx, $AFx> {} - pub type $typedef = Pin<$PXx, $AFx>; +macro_rules! hw_cs_pins { + ($SPIx:path, $portId: path: + $( + ($PXx:ident, $AFx:ident, $HwCsIdent:path, $typedef:ident), + )+ + ) => { + $( + impl HwCsProvider for Pin<$PXx, $AFx> { + const CS_ID: HwChipSelectId = $HwCsIdent; + const SPI_PORT: SpiPort = $portId; + } + impl OptionalHwCs<$SPIx> for Pin<$PXx, $AFx> {} + pub type $typedef = Pin<$PXx, $AFx>; + )+ }; } @@ -106,126 +154,23 @@ pub type SpiAPortBSck = Pin; pub type SpiAPortBMosi = Pin; pub type SpiAPortBMiso = Pin; -hw_cs_pin!( - pac::Spia, - SpiPort::Porta, - PA28, - AltFunc1, - HwChipSelectId::Id0, - HwCs0SpiAPortA -); -hw_cs_pin!( - pac::Spia, - SpiPort::Porta, - PA27, - AltFunc1, - HwChipSelectId::Id1, - HwCs1SpiAPortA -); -hw_cs_pin!( - pac::Spia, - SpiPort::Porta, - PA26, - AltFunc1, - HwChipSelectId::Id2, - HwCs2SpiAPortA -); -hw_cs_pin!( - pac::Spia, - SpiPort::Porta, - PA25, - AltFunc1, - HwChipSelectId::Id3, - HwCs3SpiAPortA -); -hw_cs_pin!( - pac::Spia, - SpiPort::Porta, - PA24, - AltFunc1, - HwChipSelectId::Id4, - HwCs4SpiAPortA -); -hw_cs_pin!( - pac::Spia, - SpiPort::Porta, - PA23, - AltFunc1, - HwChipSelectId::Id5, - HwCs5SpiAPortA -); -hw_cs_pin!( - pac::Spia, - SpiPort::Porta, - PA22, - AltFunc1, - HwChipSelectId::Id6, - HwCs6SpiAPortA -); -hw_cs_pin!( - pac::Spia, - SpiPort::Porta, - PA21, - AltFunc1, - HwChipSelectId::Id7, - HwCs7SpiAPortA -); - -hw_cs_pin!( - pac::Spia, - SpiPort::Porta, - PB6, - AltFunc2, - HwChipSelectId::Id0, - HwCs0SpiAPortB -); -hw_cs_pin!( - pac::Spia, - SpiPort::Porta, - PB5, - AltFunc2, - HwChipSelectId::Id6, - HwCs6SpiAPortB -); -hw_cs_pin!( - pac::Spia, - SpiPort::Porta, - PB4, - AltFunc2, - HwChipSelectId::Id5, - HwCs5SpiAPortB -); -hw_cs_pin!( - pac::Spia, - SpiPort::Porta, - PB3, - AltFunc2, - HwChipSelectId::Id4, - HwCs4SpiAPortB -); -hw_cs_pin!( - pac::Spia, - SpiPort::Porta, - PB2, - AltFunc2, - HwChipSelectId::Id3, - HwCs3SpiAPortB -); -hw_cs_pin!( - pac::Spia, - SpiPort::Porta, - PB1, - AltFunc2, - HwChipSelectId::Id2, - HwCs2SpiAPortB -); -hw_cs_pin!( - pac::Spia, - SpiPort::Porta, - PB0, - AltFunc2, - HwChipSelectId::Id1, - HwCs1SpiAPortB +hw_cs_pins!( + pac::Spia, SpiPort::Porta: + (PA28, AltFunc1, HwChipSelectId::Id0, HwCs0SpiAPortA), + (PA27, AltFunc1, HwChipSelectId::Id1, HwCs1SpiAPortA), + (PA26, AltFunc1, HwChipSelectId::Id2, HwCs2SpiAPortA), + (PA25, AltFunc1, HwChipSelectId::Id3, HwCs3SpiAPortA), + (PA24, AltFunc1, HwChipSelectId::Id4, HwCs4SpiAPortA), + (PA23, AltFunc1, HwChipSelectId::Id5, HwCs5SpiAPortA), + (PA22, AltFunc1, HwChipSelectId::Id6, HwCs6SpiAPortA), + (PA21, AltFunc1, HwChipSelectId::Id7, HwCs7SpiAPortA), + (PB6, AltFunc2, HwChipSelectId::Id0, HwCs0SpiAPortB), + (PB5, AltFunc2, HwChipSelectId::Id6, HwCs6SpiAPortB), + (PB4, AltFunc2, HwChipSelectId::Id5, HwCs5SpiAPortB), + (PB3, AltFunc2, HwChipSelectId::Id4, HwCs4SpiAPortB), + (PB2, AltFunc2, HwChipSelectId::Id3, HwCs3SpiAPortB), + (PB1, AltFunc2, HwChipSelectId::Id2, HwCs2SpiAPortB), + (PB0, AltFunc2, HwChipSelectId::Id1, HwCs1SpiAPortB), ); // SPIB @@ -246,303 +191,50 @@ impl PinSck for Pin {} impl PinMosi for Pin {} impl PinMiso for Pin {} -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PB16, - AltFunc1, - HwChipSelectId::Id0, - HwCs0SpiBPortB0 -); -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PB15, - AltFunc1, - HwChipSelectId::Id1, - HwCs1SpiBPortB0 -); -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PB14, - AltFunc1, - HwChipSelectId::Id2, - HwCs2SpiBPortB0 -); -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PB13, - AltFunc1, - HwChipSelectId::Id3, - HwCs3SpiBPortB -); -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PB12, - AltFunc1, - HwChipSelectId::Id4, - HwCs4SpiBPortB -); -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PB11, - AltFunc1, - HwChipSelectId::Id5, - HwCs5SpiBPortB -); -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PB10, - AltFunc1, - HwChipSelectId::Id6, - HwCs6SpiBPortB -); - -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PB2, - AltFunc1, - HwChipSelectId::Id0, - HwCs0SpiBPortB1 -); -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PB1, - AltFunc1, - HwChipSelectId::Id1, - HwCs1SpiBPortB1 -); -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PB0, - AltFunc1, - HwChipSelectId::Id2, - HwCs2SpiBPortB1 -); - -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PB12, - AltFunc2, - HwChipSelectId::Id0, - HwCs0SpiBPortB2 -); -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PB11, - AltFunc2, - HwChipSelectId::Id1, - HwCs1SpiBPortB2 -); -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PB10, - AltFunc2, - HwChipSelectId::Id2, - HwCs2SpiBPortB2 -); - -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PA17, - AltFunc2, - HwChipSelectId::Id0, - HwCs0SpiBPortA -); -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PA16, - AltFunc2, - HwChipSelectId::Id1, - HwCs1SpiBPortA -); -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PA15, - AltFunc2, - HwChipSelectId::Id2, - HwCs2SpiBPortA -); -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PA14, - AltFunc2, - HwChipSelectId::Id3, - HwCs3SpiBPortA -); -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PA13, - AltFunc2, - HwChipSelectId::Id4, - HwCs4SpiBPortA -); -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PA12, - AltFunc2, - HwChipSelectId::Id5, - HwCs5SpiBPortA0 -); -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PA11, - AltFunc2, - HwChipSelectId::Id6, - HwCs6SpiBPortA0 -); -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PA10, - AltFunc2, - HwChipSelectId::Id7, - HwCs7SpiBPortA0 -); - -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PA23, - AltFunc2, - HwChipSelectId::Id5, - HwCs5SpiBPortA1 -); -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PA22, - AltFunc2, - HwChipSelectId::Id6, - HwCs6SpiBPortA1 -); -hw_cs_pin!( - pac::Spib, - SpiPort::Portb, - PA21, - AltFunc2, - HwChipSelectId::Id7, - HwCs7SpiBPortA1 +hw_cs_pins!( + pac::Spib, SpiPort::Portb: + (PB16, AltFunc1, HwChipSelectId::Id0, HwCs0SpiBPortB0), + (PB15, AltFunc1, HwChipSelectId::Id1, HwCs1SpiBPortB0), + (PB14, AltFunc1, HwChipSelectId::Id2, HwCs2SpiBPortB0), + (PB13, AltFunc1, HwChipSelectId::Id3, HwCs3SpiBPortB), + (PB12, AltFunc1, HwChipSelectId::Id4, HwCs4SpiBPortB), + (PB11, AltFunc1, HwChipSelectId::Id5, HwCs5SpiBPortB), + (PB12, AltFunc2, HwChipSelectId::Id0, HwCs0SpiBPortB2), + (PB11, AltFunc2, HwChipSelectId::Id1, HwCs1SpiBPortB2), + (PB10, AltFunc1, HwChipSelectId::Id6, HwCs6SpiBPortB), + (PB10, AltFunc2, HwChipSelectId::Id2, HwCs2SpiBPortB2), + (PB2, AltFunc1, HwChipSelectId::Id0, HwCs0SpiBPortB1), + (PB1, AltFunc1, HwChipSelectId::Id1, HwCs1SpiBPortB1), + (PB0, AltFunc1, HwChipSelectId::Id2, HwCs2SpiBPortB1), + (PA17, AltFunc2, HwChipSelectId::Id0, HwCs0SpiBPortA), + (PA16, AltFunc2, HwChipSelectId::Id1, HwCs1SpiBPortA), + (PA15, AltFunc2, HwChipSelectId::Id2, HwCs2SpiBPortA), + (PA14, AltFunc2, HwChipSelectId::Id3, HwCs3SpiBPortA), + (PA13, AltFunc2, HwChipSelectId::Id4, HwCs4SpiBPortA), + (PA12, AltFunc2, HwChipSelectId::Id5, HwCs5SpiBPortA0), + (PA11, AltFunc2, HwChipSelectId::Id6, HwCs6SpiBPortA0), + (PA10, AltFunc2, HwChipSelectId::Id7, HwCs7SpiBPortA0), + (PA23, AltFunc2, HwChipSelectId::Id5, HwCs5SpiBPortA1), + (PA22, AltFunc2, HwChipSelectId::Id6, HwCs6SpiBPortA1), + (PA21, AltFunc2, HwChipSelectId::Id7, HwCs7SpiBPortA1), ); // SPIC -hw_cs_pin!( - pac::Spic, - SpiPort::Portc, - PB9, - AltFunc3, - HwChipSelectId::Id1, - HwCs1SpiCPortB0 -); -hw_cs_pin!( - pac::Spic, - SpiPort::Portc, - PB8, - AltFunc3, - HwChipSelectId::Id2, - HwCs2SpiCPortB0 -); -hw_cs_pin!( - pac::Spic, - SpiPort::Portc, - PB7, - AltFunc3, - HwChipSelectId::Id3, - HwCs3SpiCPortB -); - -hw_cs_pin!( - pac::Spic, - SpiPort::Portc, - PB22, - AltFunc3, - HwChipSelectId::Id1, - HwCs1SpiCPortB1 -); -hw_cs_pin!( - pac::Spic, - SpiPort::Portc, - PB23, - AltFunc3, - HwChipSelectId::Id2, - HwCs2SpiCPortB1 -); - -hw_cs_pin!( - pac::Spic, - SpiPort::Portc, - PA20, - AltFunc1, - HwChipSelectId::Id1, - HwCs1SpiCPortA0 -); -hw_cs_pin!( - pac::Spic, - SpiPort::Portc, - PA19, - AltFunc1, - HwChipSelectId::Id2, - HwCs2SpiCPortA0 -); -hw_cs_pin!( - pac::Spic, - SpiPort::Portc, - PB18, - AltFunc1, - HwChipSelectId::Id3, - HwCs3SpiCPortA0 -); - -hw_cs_pin!( - pac::Spic, - SpiPort::Portc, - PA23, - AltFunc3, - HwChipSelectId::Id1, - HwCs1SpiCPortA1 -); -hw_cs_pin!( - pac::Spic, - SpiPort::Portc, - PA22, - AltFunc3, - HwChipSelectId::Id2, - HwCs2SpiCPortA1 -); -hw_cs_pin!( - pac::Spic, - SpiPort::Portc, - PA21, - AltFunc3, - HwChipSelectId::Id3, - HwCs3SpiCPortA1 -); -hw_cs_pin!( - pac::Spic, - SpiPort::Portc, - PA20, - AltFunc3, - HwChipSelectId::Id4, - HwCs4SpiCPortA +hw_cs_pins!( + pac::Spic, SpiPort::Portc: + (PB9, AltFunc3, HwChipSelectId::Id1, HwCs1SpiCPortB0), + (PB8, AltFunc3, HwChipSelectId::Id2, HwCs2SpiCPortB0), + (PB7, AltFunc3, HwChipSelectId::Id3, HwCs3SpiCPortB), + (PB23, AltFunc3, HwChipSelectId::Id2, HwCs2SpiCPortB1), + (PB22, AltFunc3, HwChipSelectId::Id1, HwCs1SpiCPortB1), + (PA20, AltFunc1, HwChipSelectId::Id1, HwCs1SpiCPortA0), + (PA19, AltFunc1, HwChipSelectId::Id2, HwCs2SpiCPortA0), + (PB18, AltFunc1, HwChipSelectId::Id3, HwCs3SpiCPortA0), + (PA23, AltFunc3, HwChipSelectId::Id1, HwCs1SpiCPortA1), + (PA22, AltFunc3, HwChipSelectId::Id2, HwCs2SpiCPortA1), + (PA21, AltFunc3, HwChipSelectId::Id3, HwCs3SpiCPortA1), + (PA20, AltFunc3, HwChipSelectId::Id4, HwCs4SpiCPortA), ); //================================================================================================== @@ -689,17 +381,20 @@ impl SpiConfig { /// Configuration trait for the Word Size /// used by the SPI peripheral -pub trait Word: Copy + Default { +pub trait WordProvider: Copy + Default + Into + TryFrom + 'static { + const MASK: u32; fn word_reg() -> u8; } -impl Word for u8 { +impl WordProvider for u8 { + const MASK: u32 = 0xff; fn word_reg() -> u8 { 0x07 } } -impl Word for u16 { +impl WordProvider for u16 { + const MASK: u32 = 0xffff; fn word_reg() -> u8 { 0x0f } @@ -716,7 +411,7 @@ pub struct SpiBase { /// Fill word for read-only SPI transactions. pub fill_word: Word, blockmode: bool, - _word: PhantomData, + word: PhantomData, } pub struct Spi { @@ -724,491 +419,481 @@ pub struct Spi { pins: Pins, } -// Not sure if implementing SpiDevice is a good idea here.. -/* -pub struct SpiWithHwCs { - inner: SpiBase, - pins: Pins, - hw_cs: HwCs, -} - -pub struct SpiWithHwCsErased { - inner: SpiBase, -} -*/ - // Re-export this so it can be used for the constructor pub use crate::typelevel::NoneT; -macro_rules! spi { - ($($SPIX:path: ($spix:ident, $clk_enb:path) => ($($WORD:ident),+),)+) => { - $( - impl, Miso: PinMiso<$SPIX>, Mosi: PinMosi<$SPIX>, - WORD: Word> Spi<$SPIX, (Sck, Miso, Mosi), WORD> - { - /// Create a new SPI struct - /// - /// You can delete the pin type information by calling the - /// [`downgrade`](Self::downgrade) function - /// - /// ## Arguments - /// * `spi` - SPI bus to use - /// * `pins` - Pins to be used for SPI transactions. These pins are consumed - /// to ensure the pins can not be used for other purposes anymore - /// * `spi_cfg` - Configuration specific to the SPI bus - /// * `transfer_cfg` - Optional initial transfer configuration which includes - /// configuration which can change across individual SPI transfers like SPI mode - /// or SPI clock. 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( - spi: $SPIX, - pins: (Sck, Miso, Mosi), - sys_clk: impl Into + Copy, - spi_cfg: SpiConfig, - syscfg: Option<&mut pac::Sysconfig>, - transfer_cfg: Option<&ReducedTransferConfig>, - ) -> Self { - if let Some(syscfg) = syscfg { - enable_peripheral_clock(syscfg, $clk_enb); - } - let SpiConfig { - scrdv, - ms, - sod, - lbm, - mdlycap, - } = spi_cfg; - let mut mode = MODE_0; - let mut clk_prescale = 0x02; - let mut ss = 0; - let mut init_blockmode = false; - if let Some(transfer_cfg) = transfer_cfg { - mode = transfer_cfg.mode; - clk_prescale = sys_clk.into().raw() / (transfer_cfg.spi_clk.raw() * (scrdv as u32 + 1)); - if transfer_cfg.hw_cs != HwChipSelectId::Invalid { - ss = transfer_cfg.hw_cs as u8; - } - init_blockmode = transfer_cfg.blockmode; - } - - let (cpo_bit, cph_bit) = match mode { - MODE_0 => (false, false), - MODE_1 => (false, true), - MODE_2 => (true, false), - MODE_3 => (true, true), - }; - spi.ctrl0().write(|w| { - unsafe { - w.size().bits(WORD::word_reg()); - w.scrdv().bits(scrdv); - // Clear clock phase and polarity. Will be set to correct value for each - // transfer - w.spo().bit(cpo_bit); - w.sph().bit(cph_bit) - } - }); - spi.ctrl1().write(|w| { - w.lbm().bit(lbm); - w.sod().bit(sod); - w.ms().bit(ms); - w.mdlycap().bit(mdlycap); - w.blockmode().bit(init_blockmode); - unsafe { w.ss().bits(ss) } - }); - - spi.fifo_clr().write(|w| { - w.rxfifo().set_bit(); - w.txfifo().set_bit() - }); - spi.clkprescale().write(|w| unsafe { w.bits(clk_prescale) }); - // Enable the peripheral as the last step as recommended in the - // programmers guide - spi.ctrl1().modify(|_, w| w.enable().set_bit()); - Spi { - inner: SpiBase { - spi, - cfg: spi_cfg, - sys_clk: sys_clk.into(), - fill_word: Default::default(), - blockmode: init_blockmode, - _word: PhantomData, - }, - pins, - } - } - - #[inline] - pub fn cfg_clock(&mut self, spi_clk: impl Into) { - self.inner.cfg_clock(spi_clk); - } - - #[inline] - pub fn cfg_mode(&mut self, mode: Mode) { - self.inner.cfg_mode(mode); - } - - pub fn set_fill_word(&mut self, fill_word: WORD) { - self.inner.fill_word = fill_word; - } - - pub fn fill_word(&self) -> WORD { - self.inner.fill_word - } - - #[inline] - pub fn perid(&self) -> u32 { - self.inner.perid() - } - - pub fn cfg_transfer>(&mut self, transfer_cfg: &TransferConfig) { - self.inner.cfg_transfer(transfer_cfg); - } - - /// Releases the SPI peripheral and associated pins - pub fn release(self) -> ($SPIX, (Sck, Miso, Mosi), SpiConfig) { - (self.inner.spi, self.pins, self.inner.cfg) - } - - pub fn downgrade(self) -> SpiBase<$SPIX, WORD> { - self.inner - } +impl< + SpiI: Instance, + Sck: PinSck, + Miso: PinMiso, + Mosi: PinMosi, + Word: WordProvider, + > Spi +where + >::Error: core::fmt::Debug, +{ + /// Create a new SPI struct + /// + /// You can delete the pin type information by calling the + /// [`downgrade`](Self::downgrade) function + /// + /// ## Arguments + /// * `spi` - SPI bus to use + /// * `pins` - Pins to be used for SPI transactions. These pins are consumed + /// to ensure the pins can not be used for other purposes anymore + /// * `spi_cfg` - Configuration specific to the SPI bus + /// * `transfer_cfg` - Optional initial transfer configuration which includes + /// configuration which can change across individual SPI transfers like SPI mode + /// or SPI clock. 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 new( + syscfg: &mut pac::Sysconfig, + sys_clk: impl Into + Copy, + spi: SpiI, + pins: (Sck, Miso, Mosi), + spi_cfg: SpiConfig, + transfer_cfg: Option<&ReducedTransferConfig>, + ) -> Self { + enable_peripheral_clock(syscfg, SpiI::PERIPH_SEL); + let SpiConfig { + scrdv, + ms, + sod, + lbm, + mdlycap, + } = spi_cfg; + let mut mode = MODE_0; + let mut clk_prescale = 0x02; + let mut ss = 0; + let mut init_blockmode = false; + if let Some(transfer_cfg) = transfer_cfg { + mode = transfer_cfg.mode; + clk_prescale = sys_clk.into().raw() / (transfer_cfg.spi_clk.raw() * (scrdv as u32 + 1)); + if transfer_cfg.hw_cs != HwChipSelectId::Invalid { + ss = transfer_cfg.hw_cs as u8; } + init_blockmode = transfer_cfg.blockmode; + } - impl SpiBase<$SPIX, WORD> { - #[inline] - pub fn cfg_clock(&mut self, spi_clk: impl Into) { - let clk_prescale = self.sys_clk.raw() / (spi_clk.into().raw() * (self.cfg.scrdv as u32 + 1)); - self.spi - .clkprescale() - .write(|w| unsafe { w.bits(clk_prescale) }); - } - - #[inline] - pub fn cfg_mode(&mut self, mode: Mode) { - let (cpo_bit, cph_bit) = match mode { - MODE_0 => (false, false), - MODE_1 => (false, true), - MODE_2 => (true, false), - MODE_3 => (true, true), - }; - self.spi.ctrl0().modify(|_, w| { - w.spo().bit(cpo_bit); - w.sph().bit(cph_bit) - }); - } - - #[inline] - pub fn clear_tx_fifo(&self) { - self.spi.fifo_clr().write(|w| w.txfifo().set_bit()); - } - - #[inline] - pub fn clear_rx_fifo(&self) { - self.spi.fifo_clr().write(|w| w.rxfifo().set_bit()); - } - - #[inline] - pub fn perid(&self) -> u32 { - self.spi.perid().read().bits() - } - - #[inline] - pub fn cfg_hw_cs(&mut self, hw_cs: HwChipSelectId) { - if hw_cs == HwChipSelectId::Invalid { - return; - } - self.spi.ctrl1().modify(|_, w| { - w.sod().clear_bit(); - unsafe { - w.ss().bits(hw_cs as u8); - } - w - }); - } - - #[inline] - pub fn cfg_hw_cs_with_pin>(&mut self, _: &HwCs) { - self.cfg_hw_cs(HwCs::CS_ID); - } - - pub fn cfg_hw_cs_disable(&mut self) { - self.spi.ctrl1().modify(|_, w| { - w.sod().set_bit(); - w - }); - } - - pub fn cfg_transfer>(&mut self, transfer_cfg: &TransferConfig) { - self.cfg_clock(transfer_cfg.spi_clk); - self.cfg_mode(transfer_cfg.mode); - self.blockmode = transfer_cfg.blockmode; - self.spi.ctrl1().modify(|_, w| { - if transfer_cfg.sod { - w.sod().set_bit(); - } else if transfer_cfg.hw_cs.is_some() { - w.sod().clear_bit(); - unsafe { - w.ss().bits(HwCs::CS_ID as u8); - } - } else { - w.sod().clear_bit(); - } - if transfer_cfg.blockmode { - w.blockmode().set_bit(); - } else { - w.blockmode().clear_bit(); - } - w - }); - } + let (cpo_bit, cph_bit) = match mode { + MODE_0 => (false, false), + MODE_1 => (false, true), + MODE_2 => (true, false), + MODE_3 => (true, true), + }; + spi.ctrl0().write(|w| { + unsafe { + w.size().bits(Word::word_reg()); + w.scrdv().bits(scrdv); + // Clear clock phase and polarity. Will be set to correct value for each + // transfer + w.spo().bit(cpo_bit); + w.sph().bit(cph_bit) } + }); + spi.ctrl1().write(|w| { + w.lbm().bit(lbm); + w.sod().bit(sod); + w.ms().bit(ms); + w.mdlycap().bit(mdlycap); + w.blockmode().bit(init_blockmode); + unsafe { w.ss().bits(ss) } + }); - /// Changing the word size also requires a type conversion - impl , Miso: PinMiso<$SPIX>, Mosi: PinMosi<$SPIX>> - From> for Spi<$SPIX, (Sck, Miso, Mosi), u16> - { - fn from( - old_spi: Spi<$SPIX, (Sck, Miso, Mosi), u8> - ) -> Self { - old_spi.inner.spi.ctrl0().modify(|_, w| { - unsafe { - w.size().bits(WordSize::SixteenBits as u8) - } - }); - Spi { - inner: SpiBase { - spi: old_spi.inner.spi, - cfg: old_spi.inner.cfg, - blockmode: old_spi.inner.blockmode, - fill_word: Default::default(), - sys_clk: old_spi.inner.sys_clk, - _word: PhantomData, - }, - pins: old_spi.pins, - } - } - } + spi.fifo_clr().write(|w| { + w.rxfifo().set_bit(); + w.txfifo().set_bit() + }); + spi.clkprescale().write(|w| unsafe { w.bits(clk_prescale) }); + // Enable the peripheral as the last step as recommended in the + // programmers guide + spi.ctrl1().modify(|_, w| w.enable().set_bit()); + Spi { + inner: SpiBase { + spi, + cfg: spi_cfg, + sys_clk: sys_clk.into(), + fill_word: Default::default(), + blockmode: init_blockmode, + word: PhantomData, + }, + pins, + } + } - /// Changing the word size also requires a type conversion - impl , Miso: PinMiso<$SPIX>, Mosi: PinMosi<$SPIX>> - From> for - Spi<$SPIX, (Sck, Miso, Mosi), u8> - { - fn from( - old_spi: Spi<$SPIX, (Sck, Miso, Mosi), u16> - ) -> Self { - old_spi.inner.spi.ctrl0().modify(|_, w| { - unsafe { - w.size().bits(WordSize::EightBits as u8) - } - }); - Spi { - inner: SpiBase { - spi: old_spi.inner.spi, - cfg: old_spi.inner.cfg, - blockmode: old_spi.inner.blockmode, - sys_clk: old_spi.inner.sys_clk, - fill_word: Default::default(), - _word: PhantomData, - }, - pins: old_spi.pins, - } - } - } + #[inline] + pub fn cfg_clock(&mut self, spi_clk: impl Into) { + self.inner.cfg_clock(spi_clk); + } - $( + #[inline] + pub fn cfg_mode(&mut self, mode: Mode) { + self.inner.cfg_mode(mode); + } - impl SpiBase<$SPIX, $WORD> { - /// Sends a word to the slave - #[inline(always)] - fn send_blocking(&self, word: $WORD) { - // TODO: Upper limit for wait cycles to avoid complete hangups? - while self.spi.status().read().tnf().bit_is_clear() {} - self.send(word) - } + pub fn set_fill_word(&mut self, fill_word: Word) { + self.inner.fill_word = fill_word; + } - #[inline(always)] - fn send(&self, word: $WORD) { - self.spi.data().write(|w| unsafe { w.bits(word as u32) }); - } + pub fn fill_word(&self) -> Word { + self.inner.fill_word + } - /// Read a word from the slave. Must be preceeded by a [`send`](Self::send) call - #[inline(always)] - fn read_blocking(&self) -> $WORD { - // TODO: Upper limit for wait cycles to avoid complete hangups? - while self.spi.status().read().rne().bit_is_clear() {} - self.read_single_word() - } + #[inline] + pub fn perid(&self) -> u32 { + self.inner.perid() + } - #[inline(always)] - fn read_single_word(&self) -> $WORD { - (self.spi.data().read().bits() & 0xffff) as $WORD - } + pub fn cfg_transfer>(&mut self, transfer_cfg: &TransferConfig) { + self.inner.cfg_transfer(transfer_cfg); + } - fn transfer_preparation(&self, words: &[$WORD]) -> Result<(), Infallible> { - if words.len() == 0 { - return Ok(()); - } - let mut status_reg = self.spi.status().read(); - loop { - // Wait until all bytes have been transferred. - while status_reg.tfe().bit_is_clear() { - // Ignore all received read words. - if status_reg.rne().bit_is_set() { - self.clear_rx_fifo(); - } - status_reg = self.spi.status().read(); - continue; - } - break; - } - // Ignore all received read words. - if status_reg.rne().bit_is_set() { - self.clear_rx_fifo(); - } - Ok(()) - } + /// Releases the SPI peripheral and associated pins + pub fn release(self) -> (SpiI, (Sck, Miso, Mosi), SpiConfig) { + (self.inner.spi, self.pins, self.inner.cfg) + } - fn initial_send_fifo_pumping(&self, words: Option<&[$WORD]>) -> usize { - if self.blockmode { - self.spi.ctrl1().modify(|_, w| w.mtxpause().set_bit()) - } - // Fill the first half of the write FIFO - let mut current_write_idx = 0; - for _ in 0..core::cmp::min(FILL_DEPTH, words.map_or(0, |words| words.len())) { - self.send_blocking(words.map_or(self.fill_word, |words| words[current_write_idx])); - current_write_idx += 1; - } - if self.blockmode { - self.spi.ctrl1().modify(|_, w| w.mtxpause().clear_bit()) - } - current_write_idx - } - } - - impl embedded_hal::spi::ErrorType for SpiBase<$SPIX, $WORD> { - type Error = Infallible; - } - - impl SpiBus<$WORD> for SpiBase<$SPIX, $WORD> { - fn read(&mut self, words: &mut [$WORD]) -> Result<(), Self::Error> { - self.transfer_preparation(words)?; - let mut current_read_idx = 0; - let mut current_write_idx = self.initial_send_fifo_pumping(None); - loop { - if current_write_idx < words.len() { - self.send_blocking(self.fill_word); - current_write_idx += 1; - } - if current_read_idx < words.len() { - words[current_read_idx] = self.read_blocking(); - current_read_idx += 1; - } - if current_read_idx >= words.len() && current_write_idx >= words.len() { - break; - } - } - Ok(()) - } - - fn write(&mut self, words: &[$WORD]) -> Result<(), Self::Error> { - self.transfer_preparation(words)?; - let mut current_write_idx = self.initial_send_fifo_pumping(Some(words)); - while current_write_idx < words.len() { - self.send_blocking(words[current_write_idx]); - current_write_idx += 1; - // Ignore received words. - if self.spi.status().read().rne().bit_is_set() { - self.clear_rx_fifo(); - } - } - Ok(()) - } - - fn transfer(&mut self, read: &mut [$WORD], write: &[$WORD]) -> Result<(), Self::Error> { - self.transfer_preparation(write)?; - let mut current_read_idx = 0; - let mut current_write_idx = self.initial_send_fifo_pumping(Some(write)); - while current_read_idx < read.len() || current_write_idx < write.len() { - if current_write_idx < write.len() { - self.send_blocking(write[current_write_idx]); - current_write_idx += 1; - } - if current_read_idx < read.len() { - read[current_read_idx] = self.read_blocking(); - current_read_idx += 1; - } - } - - Ok(()) - } - - fn transfer_in_place(&mut self, words: &mut [$WORD]) -> Result<(), Self::Error> { - self.transfer_preparation(words)?; - let mut current_read_idx = 0; - let mut current_write_idx = self.initial_send_fifo_pumping(Some(words)); - - while current_read_idx < words.len() || current_write_idx < words.len() { - if current_write_idx < words.len() { - self.send_blocking(words[current_write_idx]); - current_write_idx += 1; - } - if current_read_idx < words.len() && current_read_idx < current_write_idx { - words[current_read_idx] = self.read_blocking(); - current_read_idx += 1; - } - } - Ok(()) - } - - fn flush(&mut self) -> Result<(), Self::Error> { - let status_reg = self.spi.status().read(); - while status_reg.tfe().bit_is_clear() || status_reg.rne().bit_is_set() { - if status_reg.rne().bit_is_set() { - self.read_single_word(); - } - } - Ok(()) - } - } - - impl, Miso: PinMiso<$SPIX>, Mosi: PinMosi<$SPIX>> - embedded_hal::spi::ErrorType for Spi<$SPIX, (Sck, Miso, Mosi), $WORD> - { - type Error = Infallible; - } - - impl, Miso: PinMiso<$SPIX>, Mosi: PinMosi<$SPIX>> SpiBus<$WORD> - for Spi<$SPIX, (Sck, Miso, Mosi), $WORD> - { - fn read(&mut self, words: &mut [$WORD]) -> Result<(), Self::Error> { - self.inner.read(words) - } - - fn write(&mut self, words: &[$WORD]) -> Result<(), Self::Error> { - self.inner.write(words) - } - - fn transfer(&mut self, read: &mut [$WORD], write: &[$WORD]) -> Result<(), Self::Error> { - self.inner.transfer(read, write) - } - - fn transfer_in_place(&mut self, words: &mut [$WORD]) -> Result<(), Self::Error> { - self.inner.transfer_in_place(words) - } - - fn flush(&mut self) -> Result<(), Self::Error> { - self.inner.flush() - } - } - )+ - )+ + pub fn downgrade(self) -> SpiBase { + self.inner } } -spi!( - pac::Spia: (spia, PeripheralClocks::Spi0) => (u8, u16), - pac::Spib: (spib, PeripheralClocks::Spi1) => (u8, u16), - pac::Spic: (spic, PeripheralClocks::Spi2) => (u8, u16), -); +impl SpiBase +where + >::Error: core::fmt::Debug, +{ + #[inline] + pub fn cfg_clock(&mut self, spi_clk: impl Into) { + let clk_prescale = + self.sys_clk.raw() / (spi_clk.into().raw() * (self.cfg.scrdv as u32 + 1)); + self.spi + .clkprescale() + .write(|w| unsafe { w.bits(clk_prescale) }); + } + + #[inline] + pub fn cfg_mode(&mut self, mode: Mode) { + let (cpo_bit, cph_bit) = match mode { + MODE_0 => (false, false), + MODE_1 => (false, true), + MODE_2 => (true, false), + MODE_3 => (true, true), + }; + self.spi.ctrl0().modify(|_, w| { + w.spo().bit(cpo_bit); + w.sph().bit(cph_bit) + }); + } + + #[inline] + pub fn clear_tx_fifo(&self) { + self.spi.fifo_clr().write(|w| w.txfifo().set_bit()); + } + + #[inline] + pub fn clear_rx_fifo(&self) { + self.spi.fifo_clr().write(|w| w.rxfifo().set_bit()); + } + + #[inline] + pub fn perid(&self) -> u32 { + self.spi.perid().read().bits() + } + + #[inline] + pub fn cfg_hw_cs(&mut self, hw_cs: HwChipSelectId) { + if hw_cs == HwChipSelectId::Invalid { + return; + } + self.spi.ctrl1().modify(|_, w| { + w.sod().clear_bit(); + unsafe { + w.ss().bits(hw_cs as u8); + } + w + }); + } + + #[inline] + pub fn cfg_hw_cs_with_pin>(&mut self, _: &HwCs) { + self.cfg_hw_cs(HwCs::CS_ID); + } + + pub fn cfg_hw_cs_disable(&mut self) { + self.spi.ctrl1().modify(|_, w| { + w.sod().set_bit(); + w + }); + } + + pub fn cfg_transfer>( + &mut self, + transfer_cfg: &TransferConfig, + ) { + self.cfg_clock(transfer_cfg.spi_clk); + self.cfg_mode(transfer_cfg.mode); + self.blockmode = transfer_cfg.blockmode; + self.spi.ctrl1().modify(|_, w| { + if transfer_cfg.sod { + w.sod().set_bit(); + } else if transfer_cfg.hw_cs.is_some() { + w.sod().clear_bit(); + unsafe { + w.ss().bits(HwCs::CS_ID as u8); + } + } else { + w.sod().clear_bit(); + } + if transfer_cfg.blockmode { + w.blockmode().set_bit(); + } else { + w.blockmode().clear_bit(); + } + w + }); + } + + /// Sends a word to the slave + #[inline(always)] + fn send_blocking(&self, word: Word) { + // TODO: Upper limit for wait cycles to avoid complete hangups? + while self.spi.status().read().tnf().bit_is_clear() {} + self.send(word) + } + + #[inline(always)] + fn send(&self, word: Word) { + self.spi.data().write(|w| unsafe { w.bits(word.into()) }); + } + + /// Read a word from the slave. Must be preceeded by a [`send`](Self::send) call + #[inline(always)] + fn read_blocking(&self) -> Word { + // TODO: Upper limit for wait cycles to avoid complete hangups? + while self.spi.status().read().rne().bit_is_clear() {} + self.read_single_word() + } + + #[inline(always)] + fn read_single_word(&self) -> Word { + (self.spi.data().read().bits() & Word::MASK) + .try_into() + .unwrap() + } + + fn transfer_preparation(&self, words: &[Word]) -> Result<(), Infallible> { + if words.is_empty() { + return Ok(()); + } + let mut status_reg = self.spi.status().read(); + // Wait until all bytes have been transferred. + while status_reg.tfe().bit_is_clear() { + // Ignore all received read words. + if status_reg.rne().bit_is_set() { + self.clear_rx_fifo(); + } + status_reg = self.spi.status().read(); + } + // Ignore all received read words. + if status_reg.rne().bit_is_set() { + self.clear_rx_fifo(); + } + Ok(()) + } + + fn initial_send_fifo_pumping(&self, words: Option<&[Word]>) -> usize { + if self.blockmode { + self.spi.ctrl1().modify(|_, w| w.mtxpause().set_bit()) + } + // Fill the first half of the write FIFO + let mut current_write_idx = 0; + for _ in 0..core::cmp::min(FILL_DEPTH, words.map_or(0, |words| words.len())) { + self.send_blocking(words.map_or(self.fill_word, |words| words[current_write_idx])); + current_write_idx += 1; + } + if self.blockmode { + self.spi.ctrl1().modify(|_, w| w.mtxpause().clear_bit()) + } + current_write_idx + } +} + +/// Changing the word size also requires a type conversion +impl, Miso: PinMiso, Mosi: PinMosi> + From> for Spi +{ + fn from(old_spi: Spi) -> Self { + old_spi + .inner + .spi + .ctrl0() + .modify(|_, w| unsafe { w.size().bits(WordSize::SixteenBits as u8) }); + Spi { + inner: SpiBase { + spi: old_spi.inner.spi, + cfg: old_spi.inner.cfg, + blockmode: old_spi.inner.blockmode, + fill_word: Default::default(), + sys_clk: old_spi.inner.sys_clk, + word: PhantomData, + }, + pins: old_spi.pins, + } + } +} + +/// Changing the word size also requires a type conversion +impl, Miso: PinMiso, Mosi: PinMosi> + From> for Spi +{ + fn from(old_spi: Spi) -> Self { + old_spi + .inner + .spi + .ctrl0() + .modify(|_, w| unsafe { w.size().bits(WordSize::EightBits as u8) }); + Spi { + inner: SpiBase { + spi: old_spi.inner.spi, + cfg: old_spi.inner.cfg, + blockmode: old_spi.inner.blockmode, + sys_clk: old_spi.inner.sys_clk, + fill_word: Default::default(), + word: PhantomData, + }, + pins: old_spi.pins, + } + } +} + +impl embedded_hal::spi::ErrorType for SpiBase { + type Error = Infallible; +} + +impl embedded_hal::spi::SpiBus for SpiBase +where + >::Error: core::fmt::Debug, +{ + fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error> { + self.transfer_preparation(words)?; + let mut current_read_idx = 0; + let mut current_write_idx = self.initial_send_fifo_pumping(None); + loop { + if current_write_idx < words.len() { + self.send_blocking(self.fill_word); + current_write_idx += 1; + } + if current_read_idx < words.len() { + words[current_read_idx] = self.read_blocking(); + current_read_idx += 1; + } + if current_read_idx >= words.len() && current_write_idx >= words.len() { + break; + } + } + Ok(()) + } + + fn write(&mut self, words: &[Word]) -> Result<(), Self::Error> { + self.transfer_preparation(words)?; + let mut current_write_idx = self.initial_send_fifo_pumping(Some(words)); + while current_write_idx < words.len() { + self.send_blocking(words[current_write_idx]); + current_write_idx += 1; + // Ignore received words. + if self.spi.status().read().rne().bit_is_set() { + self.clear_rx_fifo(); + } + } + Ok(()) + } + + fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> { + self.transfer_preparation(write)?; + let mut current_read_idx = 0; + let mut current_write_idx = self.initial_send_fifo_pumping(Some(write)); + while current_read_idx < read.len() || current_write_idx < write.len() { + if current_write_idx < write.len() { + self.send_blocking(write[current_write_idx]); + current_write_idx += 1; + } + if current_read_idx < read.len() { + read[current_read_idx] = self.read_blocking(); + current_read_idx += 1; + } + } + + Ok(()) + } + + fn transfer_in_place(&mut self, words: &mut [Word]) -> Result<(), Self::Error> { + self.transfer_preparation(words)?; + let mut current_read_idx = 0; + let mut current_write_idx = self.initial_send_fifo_pumping(Some(words)); + + while current_read_idx < words.len() || current_write_idx < words.len() { + if current_write_idx < words.len() { + self.send_blocking(words[current_write_idx]); + current_write_idx += 1; + } + if current_read_idx < words.len() && current_read_idx < current_write_idx { + words[current_read_idx] = self.read_blocking(); + current_read_idx += 1; + } + } + Ok(()) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + let status_reg = self.spi.status().read(); + while status_reg.tfe().bit_is_clear() || status_reg.rne().bit_is_set() { + if status_reg.rne().bit_is_set() { + self.read_single_word(); + } + } + Ok(()) + } +} + +impl< + SpiI: Instance, + Word: WordProvider, + Sck: PinSck, + Miso: PinMiso, + Mosi: PinMosi, + > embedded_hal::spi::ErrorType for Spi +{ + type Error = Infallible; +} + +impl< + SpiI: Instance, + Word: WordProvider, + Sck: PinSck, + Miso: PinMiso, + Mosi: PinMosi, + > embedded_hal::spi::SpiBus for Spi +where + >::Error: core::fmt::Debug, +{ + fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error> { + self.inner.read(words) + } + + fn write(&mut self, words: &[Word]) -> Result<(), Self::Error> { + self.inner.write(words) + } + + fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> { + self.inner.transfer(read, write) + } + + fn transfer_in_place(&mut self, words: &mut [Word]) -> Result<(), Self::Error> { + self.inner.transfer_in_place(words) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + self.inner.flush() + } +} diff --git a/va108xx-hal/src/uart.rs b/va108xx-hal/src/uart.rs index 136bacd..f0deb7f 100644 --- a/va108xx-hal/src/uart.rs +++ b/va108xx-hal/src/uart.rs @@ -11,7 +11,7 @@ use libm::floorf; pub use crate::IrqCfg; use crate::{ - clock::{self, enable_peripheral_clock, PeripheralClocks}, + clock::{enable_peripheral_clock, PeripheralClocks}, gpio::pins::{ AltFunc1, AltFunc2, AltFunc3, Pin, PA16, PA17, PA18, PA19, PA2, PA26, PA27, PA3, PA30, PA31, PA8, PA9, PB18, PB19, PB20, PB21, PB22, PB23, PB6, PB7, PB8, PB9, @@ -19,6 +19,7 @@ use crate::{ pac::{self, uarta as uart_base}, time::Hertz, utility::unmask_irq, + PeripheralSelect, }; //================================================================================================== @@ -306,7 +307,7 @@ pub struct UartBase { } /// Serial abstraction. Entry point to create a new UART pub struct Uart { - uart_base: UartBase, + inner: UartBase, pins: Pins, } @@ -353,6 +354,7 @@ impl Tx { pub trait Instance: Deref { fn ptr() -> *const uart_base::RegisterBlock; const IDX: u8; + const PERIPH_SEL: PeripheralSelect; } impl UartBase { @@ -483,14 +485,34 @@ impl UartBase { } } -impl Uart +impl Uart where - UART: Instance, + UartInstance: Instance, + PinsInstance: Pins, { + pub fn new( + syscfg: &mut va108xx::Sysconfig, + sys_clk: impl Into, + uart: UartInstance, + pins: PinsInstance, + config: impl Into, + ) -> Self { + crate::clock::enable_peripheral_clock(syscfg, UartInstance::PERIPH_SEL); + Uart { + inner: UartBase { + uart, + tx: Tx::new(), + rx: Rx::new(), + }, + pins, + } + .init(config.into(), sys_clk.into()) + } + /// This function assumes that the peripheral clock was alredy enabled /// in the SYSCONFIG register fn init(mut self, config: Config, sys_clk: Hertz) -> Self { - self.uart_base = self.uart_base.init(config, sys_clk); + self.inner = self.inner.init(config, sys_clk); self } @@ -501,7 +523,7 @@ where irq_cfg: IrqCfg, sys_cfg: Option<&mut pac::Sysconfig>, irq_sel: Option<&mut pac::Irqsel>, - ) -> UartWithIrq { + ) -> UartWithIrq { let (uart, pins) = self.downgrade_internal(); UartWithIrq { pins, @@ -520,75 +542,75 @@ where #[inline] pub fn enable_rx(&mut self) { - self.uart_base.enable_rx(); + self.inner.enable_rx(); } #[inline] pub fn disable_rx(&mut self) { - self.uart_base.enable_rx(); + self.inner.enable_rx(); } #[inline] pub fn enable_tx(&mut self) { - self.uart_base.enable_tx(); + self.inner.enable_tx(); } #[inline] pub fn disable_tx(&mut self) { - self.uart_base.disable_tx(); + self.inner.disable_tx(); } #[inline] pub fn clear_rx_fifo(&mut self) { - self.uart_base.clear_rx_fifo(); + self.inner.clear_rx_fifo(); } #[inline] pub fn clear_tx_fifo(&mut self) { - self.uart_base.clear_tx_fifo(); + self.inner.clear_tx_fifo(); } #[inline] pub fn clear_rx_status(&mut self) { - self.uart_base.clear_rx_status(); + self.inner.clear_rx_status(); } #[inline] pub fn clear_tx_status(&mut self) { - self.uart_base.clear_tx_status(); + self.inner.clear_tx_status(); } pub fn listen(&self, event: Event) { - self.uart_base.listen(event); + self.inner.listen(event); } pub fn unlisten(&self, event: Event) { - self.uart_base.unlisten(event); + self.inner.unlisten(event); } - pub fn release(self) -> (UART, PINS) { - (self.uart_base.release(), self.pins) + pub fn release(self) -> (UartInstance, PinsInstance) { + (self.inner.release(), self.pins) } - fn downgrade_internal(self) -> (UartBase, PINS) { + fn downgrade_internal(self) -> (UartBase, PinsInstance) { let base = UartBase { - uart: self.uart_base.uart, - tx: self.uart_base.tx, - rx: self.uart_base.rx, + uart: self.inner.uart, + tx: self.inner.tx, + rx: self.inner.rx, }; (base, self.pins) } - pub fn downgrade(self) -> UartBase { + pub fn downgrade(self) -> UartBase { UartBase { - uart: self.uart_base.uart, - tx: self.uart_base.tx, - rx: self.uart_base.rx, + uart: self.inner.uart, + tx: self.inner.tx, + rx: self.inner.rx, } } - pub fn split(self) -> (Tx, Rx) { - self.uart_base.split() + pub fn split(self) -> (Tx, Rx) { + self.inner.split() } } @@ -597,6 +619,8 @@ impl Instance for pac::Uarta { pac::Uarta::ptr() as *const _ } const IDX: u8 = 0; + + const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Uart0; } impl Instance for pac::Uartb { @@ -604,36 +628,8 @@ impl Instance for pac::Uartb { pac::Uartb::ptr() as *const _ } const IDX: u8 = 1; -} -macro_rules! uart_impl { - ($($UARTX:path: ($uartx:ident, $clk_enb_enum:path),)+) => { - $( - - impl> Uart<$UARTX, PINS> { - pub fn $uartx( - uart: $UARTX, - pins: PINS, - config: impl Into, - syscfg: &mut pac::Sysconfig, - sys_clk: impl Into - ) -> Self - { - enable_peripheral_clock(syscfg, $clk_enb_enum); - Uart { - uart_base: UartBase { - uart, - tx: Tx::new(), - rx: Rx::new(), - }, - pins, - } - .init(config.into(), sys_clk.into()) - } - } - - )+ - } + const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Uart1; } impl UartWithIrqBase { @@ -871,10 +867,12 @@ impl UartWithIrq { } } +/* uart_impl! { pac::Uarta: (uarta, clock::PeripheralClocks::Uart0), pac::Uartb: (uartb, clock::PeripheralClocks::Uart1), } +*/ impl Tx where Uart: Instance {} diff --git a/vscode/launch.json b/vscode/launch.json index 0498f52..356536c 100644 --- a/vscode/launch.json +++ b/vscode/launch.json @@ -18,6 +18,17 @@ "executable": "${workspaceFolder}/target/thumbv6m-none-eabi/debug/examples/blinky-leds", "interface": "jtag", "runToEntryPoint": "main", + "rttConfig": { + "enabled": true, + "address": "0x10000000", + "decoders": [ + { + "port": 0, + "timestamp": true, + "type": "console" + } + ] + } }, { "type": "cortex-debug", @@ -28,9 +39,20 @@ "device": "Cortex-M0", "svdFile": "./va108xx/svd/va108xx.svd.patched", "preLaunchTask": "rust: cargo build hal tests", - "executable": "${workspaceFolder}/target/thumbv6m-none-eabi/debug/examples/tests", + "executable": "${workspaceFolder}/target/thumbv6m-none-eabi/debug/board-tests", "interface": "jtag", "runToEntryPoint": "main", + "rttConfig": { + "enabled": true, + "address": "0x10000000", + "decoders": [ + { + "port": 0, + "timestamp": true, + "type": "console" + } + ] + } }, { "type": "cortex-debug", @@ -44,6 +66,17 @@ "executable": "${workspaceFolder}/target/thumbv6m-none-eabi/debug/examples/rtt-log", "interface": "jtag", "runToEntryPoint": "main", + "rttConfig": { + "enabled": true, + "address": "0x10000000", + "decoders": [ + { + "port": 0, + "timestamp": true, + "type": "console" + } + ] + } }, { "type": "cortex-debug", @@ -57,6 +90,17 @@ "executable": "${workspaceFolder}/target/thumbv6m-none-eabi/debug/examples/blinky-button-irq", "interface": "jtag", "runToEntryPoint": "main", + "rttConfig": { + "enabled": true, + "address": "0x10000000", + "decoders": [ + { + "port": 0, + "timestamp": true, + "type": "console" + } + ] + } }, { "type": "cortex-debug", @@ -70,6 +114,17 @@ "executable": "${workspaceFolder}/target/thumbv6m-none-eabi/debug/examples/timer-ticks", "interface": "jtag", "runToEntryPoint": "main", + "rttConfig": { + "enabled": true, + "address": "0x10000000", + "decoders": [ + { + "port": 0, + "timestamp": true, + "type": "console" + } + ] + } }, { "type": "cortex-debug", @@ -83,6 +138,17 @@ "executable": "${workspaceFolder}/target/thumbv6m-none-eabi/debug/examples/uart", "interface": "jtag", "runToEntryPoint": "main", + "rttConfig": { + "enabled": true, + "address": "0x10000000", + "decoders": [ + { + "port": 0, + "timestamp": true, + "type": "console" + } + ] + } }, { "type": "cortex-debug", @@ -96,6 +162,17 @@ "executable": "${workspaceFolder}/target/thumbv6m-none-eabi/debug/examples/spi", "interface": "jtag", "runToEntryPoint": "main", + "rttConfig": { + "enabled": true, + "address": "0x10000000", + "decoders": [ + { + "port": 0, + "timestamp": true, + "type": "console" + } + ] + } }, { "type": "cortex-debug", @@ -109,11 +186,22 @@ "executable": "${workspaceFolder}/target/thumbv6m-none-eabi/debug/examples/adt75-temp-sensor", "interface": "jtag", "runToEntryPoint": "main", + "rttConfig": { + "enabled": true, + "address": "0x10000000", + "decoders": [ + { + "port": 0, + "timestamp": true, + "type": "console" + } + ] + } }, { "type": "cortex-debug", "request": "launch", - "name": "Debug Button Blinky RTIC", + "name": "Button Blinky RTIC Example", "servertype": "jlink", "cwd": "${workspaceRoot}", "device": "Cortex-M0", @@ -122,11 +210,22 @@ "executable": "${workspaceFolder}/target/thumbv6m-none-eabi/debug/examples/blinky-button-rtic", "interface": "jtag", "runToEntryPoint": "main", + "rttConfig": { + "enabled": true, + "address": "0x10000000", + "decoders": [ + { + "port": 0, + "timestamp": true, + "type": "console" + } + ] + } }, { "type": "cortex-debug", "request": "launch", - "name": "Debug PWM", + "name": "PWM Example", "servertype": "jlink", "cwd": "${workspaceRoot}", "device": "Cortex-M0", @@ -135,11 +234,22 @@ "executable": "${workspaceFolder}/target/thumbv6m-none-eabi/debug/examples/pwm", "interface": "jtag", "runToEntryPoint": "main", + "rttConfig": { + "enabled": true, + "address": "0x10000000", + "decoders": [ + { + "port": 0, + "timestamp": true, + "type": "console" + } + ] + } }, { "type": "cortex-debug", "request": "launch", - "name": "Debug Cascade", + "name": "Cascade Example", "servertype": "jlink", "cwd": "${workspaceRoot}", "device": "Cortex-M0", @@ -148,11 +258,22 @@ "executable": "${workspaceFolder}/target/thumbv6m-none-eabi/debug/examples/cascade", "interface": "jtag", "runToEntryPoint": "main", + "rttConfig": { + "enabled": true, + "address": "0x10000000", + "decoders": [ + { + "port": 0, + "timestamp": true, + "type": "console" + } + ] + } }, { "type": "cortex-debug", "request": "launch", - "name": "Debug Accelerometer", + "name": "Accelerometer Example", "servertype": "jlink", "cwd": "${workspaceRoot}", "device": "Cortex-M0", @@ -161,6 +282,17 @@ "executable": "${workspaceFolder}/target/thumbv6m-none-eabi/debug/examples/adxl343-accelerometer", "interface": "jtag", "runToEntryPoint": "main", + "rttConfig": { + "enabled": true, + "address": "0x10000000", + "decoders": [ + { + "port": 0, + "timestamp": true, + "type": "console" + } + ] + } }, { "type": "cortex-debug", @@ -178,7 +310,7 @@ { "type": "cortex-debug", "request": "launch", - "name": "Debug ADC", + "name": "ADC Example", "servertype": "jlink", "cwd": "${workspaceRoot}", "device": "Cortex-M0", @@ -187,11 +319,22 @@ "executable": "${workspaceFolder}/target/thumbv6m-none-eabi/debug/examples/max11619-adc", "interface": "jtag", "runToEntryPoint": "main", + "rttConfig": { + "enabled": true, + "address": "0x10000000", + "decoders": [ + { + "port": 0, + "timestamp": true, + "type": "console" + } + ] + } }, { "type": "cortex-debug", "request": "launch", - "name": "Debug UART IRQ", + "name": "UART IRQ Example", "servertype": "jlink", "cwd": "${workspaceRoot}", "device": "Cortex-M0", @@ -200,6 +343,17 @@ "executable": "${workspaceFolder}/target/thumbv6m-none-eabi/debug/examples/uart-irq-rtic", "interface": "jtag", "runToEntryPoint": "main", + "rttConfig": { + "enabled": true, + "address": "0x10000000", + "decoders": [ + { + "port": 0, + "timestamp": true, + "type": "console" + } + ] + } }, ] } \ No newline at end of file diff --git a/vscode/tasks.json b/vscode/tasks.json index ae76f96..c8eb183 100644 --- a/vscode/tasks.json +++ b/vscode/tasks.json @@ -21,10 +21,8 @@ "command": "~/.cargo/bin/cargo", // note: full path to the cargo "args": [ "build", - "-p", - "va108xx-hal", "--bin", - "tests", + "board-tests", "--features", "rt" ], @@ -39,8 +37,6 @@ "command": "~/.cargo/bin/cargo", // note: full path to the cargo "args": [ "build", - "-p", - "va108xx-hal", "--example", "rtt-log", ], @@ -55,8 +51,6 @@ "command": "~/.cargo/bin/cargo", // note: full path to the cargo "args": [ "build", - "-p", - "va108xx-hal", "--example", "timer-ticks", "--features", @@ -89,8 +83,6 @@ "command": "~/.cargo/bin/cargo", // note: full path to the cargo "args": [ "build", - "-p", - "va108xx-hal", "--example", "spi", ], @@ -105,8 +97,6 @@ "command": "~/.cargo/bin/cargo", // note: full path to the cargo "args": [ "build", - "-p", - "va108xx-hal", "--example", "pwm", "--features", @@ -123,8 +113,6 @@ "command": "~/.cargo/bin/cargo", // note: full path to the cargo "args": [ "build", - "-p", - "va108xx-hal", "--example", "cascade", "--features", @@ -141,8 +129,6 @@ "command": "~/.cargo/bin/cargo", // note: full path to the cargo "args": [ "build", - "-p", - "va108xx-hal", "--example", "uart-irq-rtic", "--features",