diff --git a/.cargo/def-config.toml b/.cargo/def-config.toml index 1887082..26a3517 100644 --- a/.cargo/def-config.toml +++ b/.cargo/def-config.toml @@ -24,8 +24,7 @@ rustflags = [ # "-C", "link-arg=-Tdefmt.x", # Can be useful for debugging. - "-Clink-args=-Map=app.map" - + # "-Clink-args=-Map=app.map" ] [build] diff --git a/README.md b/README.md index 7be1942..94838bb 100644 --- a/README.md +++ b/README.md @@ -106,3 +106,6 @@ configuration variables in your `settings.json`: - `"cortex-debug.gdbPath.linux"` - `"cortex-debug.gdbPath.windows"` - `"cortex-debug.gdbPath.osx"` + +The provided VS Code configurations also provide an integrated RTT logger, which you can access +via the terminal at `RTT Ch:0 console`. diff --git a/board-tests/Cargo.toml b/board-tests/Cargo.toml index 36b34c9..01b7901 100644 --- a/board-tests/Cargo.toml +++ b/board-tests/Cargo.toml @@ -15,7 +15,7 @@ embedded-hal-nb = "1" embedded-io = "0.6" [dependencies.va108xx-hal] -version = "0.6" +version = "0.7" path = "../va108xx-hal" features = ["rt"] diff --git a/examples/simple/Cargo.toml b/examples/simple/Cargo.toml index be52905..746aedb 100644 --- a/examples/simple/Cargo.toml +++ b/examples/simple/Cargo.toml @@ -28,6 +28,6 @@ version = "1" features = ["cortex-m-systick"] [dependencies.va108xx-hal] -version = "0.6" +version = "0.7" path = "../../va108xx-hal" features = ["rt", "defmt"] diff --git a/examples/simple/examples/pwm.rs b/examples/simple/examples/pwm.rs index db3fe1c..e51b5b0 100644 --- a/examples/simple/examples/pwm.rs +++ b/examples/simple/examples/pwm.rs @@ -21,9 +21,9 @@ fn main() -> ! { let mut dp = pac::Peripherals::take().unwrap(); let pinsa = PinsA::new(&mut dp.sysconfig, None, dp.porta); let mut pwm = pwm::PwmPin::new( - (pinsa.pa3.into_funsel_1(), dp.tim3), - 50.MHz(), &mut dp.sysconfig, + 50.MHz(), + (pinsa.pa3.into_funsel_1(), dp.tim3), 10.Hz(), ); let mut delay = set_up_ms_delay_provider(&mut dp.sysconfig, 50.MHz(), dp.tim0); 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/Cargo.toml b/va108xx-hal/Cargo.toml index 17b286d..2a10125 100644 --- a/va108xx-hal/Cargo.toml +++ b/va108xx-hal/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "va108xx-hal" -version = "0.6.0" +version = "0.7.0" authors = ["Robin Mueller "] edition = "2021" description = "HAL for the Vorago VA108xx family of microcontrollers" diff --git a/va108xx-hal/README.md b/va108xx-hal/README.md index 1cae452..74c2a79 100644 --- a/va108xx-hal/README.md +++ b/va108xx-hal/README.md @@ -4,7 +4,7 @@ # HAL for the Vorago VA108xx MCU family This repository contains the **H**ardware **A**bstraction **L**ayer (HAL), which is an additional -hardware abstraction on top of the [peripheral access API](https://egit.irs.uni-stuttgart.de/rust/va108xx). +hardware abstraction on top of the [peripheral access API](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/va108xx). It is the result of reading the datasheet for the device and encoding a type-safe layer over the raw PAC. This crate also implements traits specified by the diff --git a/va108xx-hal/src/gpio/dynpins.rs b/va108xx-hal/src/gpio/dynpin.rs similarity index 99% rename from va108xx-hal/src/gpio/dynpins.rs rename to va108xx-hal/src/gpio/dynpin.rs index 45c06d6..4c96e77 100644 --- a/va108xx-hal/src/gpio/dynpins.rs +++ b/va108xx-hal/src/gpio/dynpin.rs @@ -57,7 +57,7 @@ //! [InvalidPinTypeError]. use super::{ - pins::{FilterType, InterruptEdge, InterruptLevel, Pin, PinId, PinMode, PinState}, + pin::{FilterType, InterruptEdge, InterruptLevel, Pin, PinId, PinMode, PinState}, reg::RegisterInterface, }; use crate::{clock::FilterClkSel, pac, FunSel, IrqCfg}; diff --git a/va108xx-hal/src/gpio/mod.rs b/va108xx-hal/src/gpio/mod.rs index c79a81b..0d2a726 100644 --- a/va108xx-hal/src/gpio/mod.rs +++ b/va108xx-hal/src/gpio/mod.rs @@ -3,10 +3,10 @@ //! The implementation of this GPIO module is heavily based on the //! [ATSAMD HAL implementation](https://docs.rs/atsamd-hal/latest/atsamd_hal/gpio/index.html). //! -//! This API provides two different submodules, [`mod@pins`] and [`dynpins`], -//! representing two different ways to handle GPIO pins. The default, [`mod@pins`], +//! This API provides two different submodules, [pin] and [dynpin], +//! representing two different ways to handle GPIO pins. The default, [pin], //! 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, [dynpin] is a type-erased, value-level API that tracks the //! state of each pin at run-time. //! //! The type-level API is strongly preferred. By representing the state of each @@ -14,7 +14,7 @@ //! compile-time. Furthermore, the type-level API has absolutely zero run-time //! cost. //! -//! If needed, [`dynpins`] can be used to erase the type-level differences +//! If needed, [dynpin] can be used to erase the type-level differences //! between pins. However, by doing so, pins must now be tracked at run-time, //! and each pin has a non-zero memory footprint. //! @@ -101,10 +101,10 @@ macro_rules! common_reg_if_functions { }; } -pub mod dynpins; -pub use dynpins::*; +pub mod dynpin; +pub use dynpin::*; -pub mod pins; -pub use pins::*; +pub mod pin; +pub use pin::*; mod reg; diff --git a/va108xx-hal/src/gpio/pins.rs b/va108xx-hal/src/gpio/pin.rs similarity index 99% rename from va108xx-hal/src/gpio/pins.rs rename to va108xx-hal/src/gpio/pin.rs index dda846b..ad91f85 100644 --- a/va108xx-hal/src/gpio/pins.rs +++ b/va108xx-hal/src/gpio/pin.rs @@ -70,7 +70,7 @@ //! This module implements all of the embedded HAL GPIO traits for each [`Pin`] //! in the corresponding [`PinMode`]s, namely: [`InputPin`], [`OutputPin`], //! and [`StatefulOutputPin`]. -use super::dynpins::{DynAlternate, DynGroup, DynInput, DynOutput, DynPinId, DynPinMode}; +use super::dynpin::{DynAlternate, DynGroup, DynInput, DynOutput, DynPinId, DynPinMode}; use super::reg::RegisterInterface; use crate::{ pac::{Irqsel, Porta, Portb, Sysconfig}, diff --git a/va108xx-hal/src/gpio/reg.rs b/va108xx-hal/src/gpio/reg.rs index 9e2abff..afc83a2 100644 --- a/va108xx-hal/src/gpio/reg.rs +++ b/va108xx-hal/src/gpio/reg.rs @@ -1,5 +1,5 @@ -use super::dynpins::{self, DynGroup, DynPinId, DynPinMode}; -use super::pins::{FilterType, InterruptEdge, InterruptLevel, PinState}; +use super::dynpin::{self, DynGroup, DynPinId, DynPinMode}; +use super::pin::{FilterType, InterruptEdge, InterruptLevel, PinState}; use super::IsMaskedError; use crate::clock::FilterClkSel; use va108xx::{ioconfig, porta}; @@ -30,7 +30,7 @@ impl From for ModeFields { use DynPinMode::*; match mode { Input(config) => { - use dynpins::DynInput::*; + use dynpin::DynInput::*; fields.dir = false; match config { Floating => (), @@ -44,7 +44,7 @@ impl From for ModeFields { } } Output(config) => { - use dynpins::DynOutput::*; + use dynpin::DynOutput::*; fields.dir = true; match config { PushPull => (), diff --git a/va108xx-hal/src/i2c.rs b/va108xx-hal/src/i2c.rs index 88d1d6d..569c323 100644 --- a/va108xx-hal/src/i2c.rs +++ b/va108xx-hal/src/i2c.rs @@ -2,26 +2,31 @@ //! //! ## Examples //! -//! - [REB1 I2C temperature sensor example](https://egit.irs.uni-stuttgart.de/rust/vorago-reb1/src/branch/main/examples/adt75-temp-sensor.rs) +//! - [REB1 I2C temperature sensor example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/adt75-temp-sensor.rs use crate::{ - clock::{enable_peripheral_clock, PeripheralClocks}, - pac, - time::Hertz, - typelevel::Sealed, + clock::enable_peripheral_clock, pac, time::Hertz, typelevel::Sealed, PeripheralSelect, }; -use core::marker::PhantomData; +use core::{marker::PhantomData, ops::Deref}; use embedded_hal::i2c::{self, Operation, SevenBitAddress, TenBitAddress}; //================================================================================================== // Defintions //================================================================================================== +const CLK_100K: Hertz = Hertz::from_raw(100_000); +const CLK_400K: Hertz = Hertz::from_raw(400_000); +const MIN_CLK_400K: Hertz = Hertz::from_raw(8_000_000); + #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum FifoEmptyMode { Stall = 0, EndTransaction = 1, } +#[derive(Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ClockTooSlowForFastI2c; + #[derive(Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { @@ -34,7 +39,21 @@ pub enum Error { InsufficientDataReceived, /// Number of bytes in transfer too large (larger than 0x7fe) DataTooLarge, +} + +#[derive(Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum InitError { + /// Wrong address used in constructor WrongAddrMode, + /// APB1 clock is too slow for fast I2C mode. + ClkTooSlow(ClockTooSlowForFastI2c), +} + +impl From for InitError { + fn from(value: ClockTooSlowForFastI2c) -> Self { + Self::ClkTooSlow(value) + } } impl embedded_hal::i2c::Error for Error { @@ -47,10 +66,9 @@ impl embedded_hal::i2c::Error for Error { Error::NackData => { embedded_hal::i2c::ErrorKind::NoAcknowledge(i2c::NoAcknowledgeSource::Data) } - Error::DataTooLarge - | Error::WrongAddrMode - | Error::InsufficientDataReceived - | Error::InvalidTimingParams => embedded_hal::i2c::ErrorKind::Other, + Error::DataTooLarge | Error::InsufficientDataReceived | Error::InvalidTimingParams => { + embedded_hal::i2c::ErrorKind::Other + } } } } @@ -81,6 +99,37 @@ pub enum I2cAddress { TenBit(u16), } +pub type I2cRegBlock = pac::i2ca::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 I2cRegBlock; +} + +impl Instance for pac::I2ca { + const IDX: u8 = 0; + const PERIPH_SEL: PeripheralSelect = PeripheralSelect::I2c0; + + #[inline(always)] + fn ptr() -> *const I2cRegBlock { + Self::ptr() + } +} + +impl Instance for pac::I2cb { + const IDX: u8 = 1; + const PERIPH_SEL: PeripheralSelect = PeripheralSelect::I2c1; + + #[inline(always)] + fn ptr() -> *const I2cRegBlock { + Self::ptr() + } +} + //================================================================================================== // Config //================================================================================================== @@ -242,149 +291,149 @@ impl I2cBase { } } -macro_rules! i2c_base { - ($($I2CX:path: ($i2cx:ident, $clk_enb:path),)+) => { - $( - impl I2cBase<$I2CX> { - pub fn $i2cx( - i2c: $I2CX, - sys_clk: impl Into, - speed_mode: I2cSpeed, - ms_cfg: Option<&MasterConfig>, - sl_cfg: Option<&SlaveConfig>, - sys_cfg: Option<&mut va108xx::Sysconfig>, - ) -> Self { - if let Some(sys_cfg) = sys_cfg { - enable_peripheral_clock(sys_cfg, $clk_enb); - } - let mut i2c_base = I2cBase { - i2c, - sys_clk: sys_clk.into(), - }; - if let Some(ms_cfg) = ms_cfg { - i2c_base.cfg_master(ms_cfg); - } +impl I2cBase { + pub fn new( + syscfg: &mut pac::Sysconfig, + sysclk: impl Into, + i2c: I2c, + speed_mode: I2cSpeed, + ms_cfg: Option<&MasterConfig>, + sl_cfg: Option<&SlaveConfig>, + ) -> Result { + enable_peripheral_clock(syscfg, I2c::PERIPH_SEL); - if let Some(sl_cfg) = sl_cfg { - i2c_base.cfg_slave(sl_cfg); - } - i2c_base.cfg_clk_scale(speed_mode); - i2c_base - } + let mut i2c_base = I2cBase { + i2c, + sys_clk: sysclk.into(), + }; + if let Some(ms_cfg) = ms_cfg { + i2c_base.cfg_master(ms_cfg); + } - fn cfg_master(&mut self, ms_cfg: &MasterConfig) { - let (txfemd, rxfemd) = match (ms_cfg.tx_fe_mode, ms_cfg.rx_fe_mode) { - (FifoEmptyMode::Stall, FifoEmptyMode::Stall) => (false, false), - (FifoEmptyMode::Stall, FifoEmptyMode::EndTransaction) => (false, true), - (FifoEmptyMode::EndTransaction, FifoEmptyMode::Stall) => (true, false), - (FifoEmptyMode::EndTransaction, FifoEmptyMode::EndTransaction) => (true, true), - }; - self.i2c.ctrl().modify(|_, w| { - w.txfemd().bit(txfemd); - w.rxffmd().bit(rxfemd); - w.dlgfilter().bit(ms_cfg.dlg_filt); - w.algfilter().bit(ms_cfg.alg_filt) - }); - if let Some(ref tm_cfg) = ms_cfg.tm_cfg { - self.i2c.tmconfig().write(|w| unsafe { w.bits(tm_cfg.reg()) }); - } - self.i2c.fifo_clr().write(|w| { - w.rxfifo().set_bit(); - w.txfifo().set_bit() - }); - } + if let Some(sl_cfg) = sl_cfg { + i2c_base.cfg_slave(sl_cfg); + } + i2c_base.cfg_clk_scale(speed_mode)?; + Ok(i2c_base) + } - fn cfg_slave(&mut self, sl_cfg: &SlaveConfig) { - let (txfemd, rxfemd) = match (sl_cfg.tx_fe_mode, sl_cfg.rx_fe_mode) { - (FifoEmptyMode::Stall, FifoEmptyMode::Stall) => (false, false), - (FifoEmptyMode::Stall, FifoEmptyMode::EndTransaction) => (false, true), - (FifoEmptyMode::EndTransaction, FifoEmptyMode::Stall) => (true, false), - (FifoEmptyMode::EndTransaction, FifoEmptyMode::EndTransaction) => (true, true), - }; - self.i2c.s0_ctrl().modify(|_, w| { - w.txfemd().bit(txfemd); - w.rxffmd().bit(rxfemd) - }); - self.i2c.s0_fifo_clr().write(|w| { - w.rxfifo().set_bit(); - w.txfifo().set_bit() - }); - let max_words = sl_cfg.max_words; - if let Some(max_words) = max_words { - self.i2c - .s0_maxwords() - .write(|w| unsafe { w.bits(1 << 31 | max_words as u32) }); - } - let (addr, addr_mode_mask) = Self::unwrap_addr(sl_cfg.addr); - // The first bit is the read/write value. Normally, both read and write are matched - // using the RWMASK bit of the address mask register - self.i2c - .s0_address() - .write(|w| unsafe { w.bits((addr << 1) as u32 | addr_mode_mask) }); - if let Some(addr_mask) = sl_cfg.addr_mask { - self.i2c - .s0_addressmask() - .write(|w| unsafe { w.bits((addr_mask << 1) as u32) }); - } - if let Some(addr_b) = sl_cfg.addr_b { - let (addr, addr_mode_mask) = Self::unwrap_addr(addr_b); - self.i2c - .s0_addressb() - .write(|w| unsafe { w.bits((addr << 1) as u32 | addr_mode_mask) }) - } - if let Some(addr_b_mask) = sl_cfg.addr_b_mask { - self.i2c - .s0_addressmaskb() - .write(|w| unsafe { w.bits((addr_b_mask << 1) as u32) }) - } - } + fn cfg_master(&mut self, ms_cfg: &MasterConfig) { + let (txfemd, rxfemd) = match (ms_cfg.tx_fe_mode, ms_cfg.rx_fe_mode) { + (FifoEmptyMode::Stall, FifoEmptyMode::Stall) => (false, false), + (FifoEmptyMode::Stall, FifoEmptyMode::EndTransaction) => (false, true), + (FifoEmptyMode::EndTransaction, FifoEmptyMode::Stall) => (true, false), + (FifoEmptyMode::EndTransaction, FifoEmptyMode::EndTransaction) => (true, true), + }; + self.i2c.ctrl().modify(|_, w| { + w.txfemd().bit(txfemd); + w.rxffmd().bit(rxfemd); + w.dlgfilter().bit(ms_cfg.dlg_filt); + w.algfilter().bit(ms_cfg.alg_filt) + }); + if let Some(ref tm_cfg) = ms_cfg.tm_cfg { + self.i2c + .tmconfig() + .write(|w| unsafe { w.bits(tm_cfg.reg()) }); + } + self.i2c.fifo_clr().write(|w| { + w.rxfifo().set_bit(); + w.txfifo().set_bit() + }); + } - #[inline] - pub fn filters(&mut self, digital_filt: bool, analog_filt: bool) { - self.i2c.ctrl().modify(|_, w| { - w.dlgfilter().bit(digital_filt); - w.algfilter().bit(analog_filt) - }); - } + fn cfg_slave(&mut self, sl_cfg: &SlaveConfig) { + let (txfemd, rxfemd) = match (sl_cfg.tx_fe_mode, sl_cfg.rx_fe_mode) { + (FifoEmptyMode::Stall, FifoEmptyMode::Stall) => (false, false), + (FifoEmptyMode::Stall, FifoEmptyMode::EndTransaction) => (false, true), + (FifoEmptyMode::EndTransaction, FifoEmptyMode::Stall) => (true, false), + (FifoEmptyMode::EndTransaction, FifoEmptyMode::EndTransaction) => (true, true), + }; + self.i2c.s0_ctrl().modify(|_, w| { + w.txfemd().bit(txfemd); + w.rxffmd().bit(rxfemd) + }); + self.i2c.s0_fifo_clr().write(|w| { + w.rxfifo().set_bit(); + w.txfifo().set_bit() + }); + let max_words = sl_cfg.max_words; + if let Some(max_words) = max_words { + self.i2c + .s0_maxwords() + .write(|w| unsafe { w.bits(1 << 31 | max_words as u32) }); + } + let (addr, addr_mode_mask) = Self::unwrap_addr(sl_cfg.addr); + // The first bit is the read/write value. Normally, both read and write are matched + // using the RWMASK bit of the address mask register + self.i2c + .s0_address() + .write(|w| unsafe { w.bits((addr << 1) as u32 | addr_mode_mask) }); + if let Some(addr_mask) = sl_cfg.addr_mask { + self.i2c + .s0_addressmask() + .write(|w| unsafe { w.bits((addr_mask << 1) as u32) }); + } + if let Some(addr_b) = sl_cfg.addr_b { + let (addr, addr_mode_mask) = Self::unwrap_addr(addr_b); + self.i2c + .s0_addressb() + .write(|w| unsafe { w.bits((addr << 1) as u32 | addr_mode_mask) }) + } + if let Some(addr_b_mask) = sl_cfg.addr_b_mask { + self.i2c + .s0_addressmaskb() + .write(|w| unsafe { w.bits((addr_b_mask << 1) as u32) }) + } + } - #[inline] - pub fn fifo_empty_mode(&mut self, rx: FifoEmptyMode, tx: FifoEmptyMode) { - self.i2c.ctrl().modify(|_, w| { - w.txfemd().bit(tx as u8 != 0); - w.rxffmd().bit(rx as u8 != 0) - }); - } + #[inline] + pub fn filters(&mut self, digital_filt: bool, analog_filt: bool) { + self.i2c.ctrl().modify(|_, w| { + w.dlgfilter().bit(digital_filt); + w.algfilter().bit(analog_filt) + }); + } - fn calc_clk_div(&self, speed_mode: I2cSpeed) -> u8 { - if speed_mode == I2cSpeed::Regular100khz { - ((self.sys_clk.raw() / (u32::pow(10, 5) * 20)) - 1) as u8 - } else { - (((10 * self.sys_clk.raw()) / u32::pow(10, 8)) - 1) as u8 - } - } + #[inline] + pub fn fifo_empty_mode(&mut self, rx: FifoEmptyMode, tx: FifoEmptyMode) { + self.i2c.ctrl().modify(|_, w| { + w.txfemd().bit(tx as u8 != 0); + w.rxffmd().bit(rx as u8 != 0) + }); + } - /// Configures the clock scale for a given speed mode setting - pub fn cfg_clk_scale(&mut self, speed_mode: I2cSpeed) { - self.i2c.clkscale().write(|w| unsafe { - w.bits((speed_mode as u32) << 31 | self.calc_clk_div(speed_mode) as u32) - }); - } - - pub fn load_address(&mut self, addr: u16) { - // Load address - self.i2c - .address() - .write(|w| unsafe { w.bits((addr << 1) as u32) }); - } - - #[inline] - fn stop_cmd(&mut self) { - self.i2c - .cmd() - .write(|w| unsafe { w.bits(I2cCmd::Stop as u32) }); - } + fn calc_clk_div(&self, speed_mode: I2cSpeed) -> Result { + if speed_mode == I2cSpeed::Regular100khz { + Ok(((self.sys_clk.raw() / CLK_100K.raw() / 20) - 1) as u8) + } else { + if self.sys_clk.raw() < MIN_CLK_400K.raw() { + return Err(ClockTooSlowForFastI2c); } - )+ + Ok(((self.sys_clk.raw() / CLK_400K.raw() / 25) - 1) as u8) + } + } + + /// Configures the clock scale for a given speed mode setting + pub fn cfg_clk_scale(&mut self, speed_mode: I2cSpeed) -> Result<(), ClockTooSlowForFastI2c> { + let clk_div = self.calc_clk_div(speed_mode)?; + self.i2c + .clkscale() + .write(|w| unsafe { w.bits((speed_mode as u32) << 31 | clk_div as u32) }); + Ok(()) + } + + pub fn load_address(&mut self, addr: u16) { + // Load address + self.i2c + .address() + .write(|w| unsafe { w.bits((addr << 1) as u32) }); + } + + #[inline] + fn stop_cmd(&mut self) { + self.i2c + .cmd() + .write(|w| unsafe { w.bits(I2cCmd::Stop as u32) }); } } @@ -395,20 +444,218 @@ macro_rules! i2c_base { // slave_cfg: SlaveConfig, // } -i2c_base!( - pac::I2ca: (i2ca, PeripheralClocks::I2c0), - pac::I2cb: (i2cb, PeripheralClocks::I2c1), -); - //================================================================================================== // I2C Master //================================================================================================== -pub struct I2cMaster { - i2c_base: I2cBase, - _addr: PhantomData, +pub struct I2cMaster { + i2c_base: I2cBase, + addr: PhantomData, } +impl I2cMaster { + pub fn new( + syscfg: &mut pac::Sysconfig, + sysclk: impl Into, + i2c: I2c, + cfg: MasterConfig, + speed_mode: I2cSpeed, + ) -> Result { + Ok(I2cMaster { + i2c_base: I2cBase::new(syscfg, sysclk, i2c, speed_mode, Some(&cfg), None)?, + addr: PhantomData, + } + .enable_master()) + } + + #[inline] + pub fn cancel_transfer(&self) { + self.i2c_base + .i2c + .cmd() + .write(|w| unsafe { w.bits(I2cCmd::Cancel as u32) }); + } + + #[inline] + pub fn clear_tx_fifo(&self) { + self.i2c_base.i2c.fifo_clr().write(|w| w.txfifo().set_bit()); + } + + #[inline] + pub fn clear_rx_fifo(&self) { + self.i2c_base.i2c.fifo_clr().write(|w| w.rxfifo().set_bit()); + } + + #[inline] + pub fn enable_master(self) -> Self { + self.i2c_base.i2c.ctrl().modify(|_, w| w.enable().set_bit()); + self + } + + #[inline] + pub fn disable_master(self) -> Self { + self.i2c_base + .i2c + .ctrl() + .modify(|_, w| w.enable().clear_bit()); + self + } + + #[inline(always)] + fn load_fifo(&self, word: u8) { + self.i2c_base + .i2c + .data() + .write(|w| unsafe { w.bits(word as u32) }); + } + + #[inline(always)] + fn read_fifo(&self) -> u8 { + self.i2c_base.i2c.data().read().bits() as u8 + } + + fn error_handler_write(&mut self, init_cmd: &I2cCmd) { + self.clear_tx_fifo(); + if *init_cmd == I2cCmd::Start { + self.i2c_base.stop_cmd() + } + } + + fn write_base( + &mut self, + addr: I2cAddress, + init_cmd: I2cCmd, + bytes: impl IntoIterator, + ) -> Result<(), Error> { + let mut iter = bytes.into_iter(); + // Load address + let (addr, addr_mode_bit) = I2cBase::::unwrap_addr(addr); + self.i2c_base.i2c.address().write(|w| unsafe { + w.bits(I2cDirection::Send as u32 | (addr << 1) as u32 | addr_mode_bit) + }); + + self.i2c_base + .i2c + .cmd() + .write(|w| unsafe { w.bits(init_cmd as u32) }); + let mut load_if_next_available = || { + if let Some(next_byte) = iter.next() { + self.load_fifo(next_byte); + } + }; + loop { + let status_reader = self.i2c_base.i2c.status().read(); + if status_reader.arblost().bit_is_set() { + self.error_handler_write(&init_cmd); + return Err(Error::ArbitrationLost); + } else if status_reader.nackaddr().bit_is_set() { + self.error_handler_write(&init_cmd); + return Err(Error::NackAddr); + } else if status_reader.nackdata().bit_is_set() { + self.error_handler_write(&init_cmd); + return Err(Error::NackData); + } else if status_reader.idle().bit_is_set() { + return Ok(()); + } else { + while !status_reader.txnfull().bit_is_set() { + load_if_next_available(); + } + } + } + } + + fn write_from_buffer( + &mut self, + init_cmd: I2cCmd, + addr: I2cAddress, + output: &[u8], + ) -> Result<(), Error> { + let len = output.len(); + // It should theoretically possible to transfer larger data sizes by tracking + // the number of sent words and setting it to 0x7fe as soon as only that many + // bytes are remaining. However, large transfer like this are not common. This + // feature will therefore not be supported for now. + if len > 0x7fe { + return Err(Error::DataTooLarge); + } + // Load number of words + self.i2c_base + .i2c + .words() + .write(|w| unsafe { w.bits(len as u32) }); + let mut bytes = output.iter(); + // FIFO has a depth of 16. We load slightly above the trigger level + // but not all of it because the transaction might fail immediately + const FILL_DEPTH: usize = 12; + + // load the FIFO + for _ in 0..core::cmp::min(FILL_DEPTH, len) { + self.load_fifo(*bytes.next().unwrap()); + } + + self.write_base(addr, init_cmd, output.iter().cloned()) + } + + fn read_internal(&mut self, addr: I2cAddress, buffer: &mut [u8]) -> Result<(), Error> { + let len = buffer.len(); + // It should theoretically possible to transfer larger data sizes by tracking + // the number of sent words and setting it to 0x7fe as soon as only that many + // bytes are remaining. However, large transfer like this are not common. This + // feature will therefore not be supported for now. + if len > 0x7fe { + return Err(Error::DataTooLarge); + } + // Clear the receive FIFO + self.clear_rx_fifo(); + + // Load number of words + self.i2c_base + .i2c + .words() + .write(|w| unsafe { w.bits(len as u32) }); + let (addr, addr_mode_bit) = match addr { + I2cAddress::Regular(addr) => (addr as u16, 0 << 15), + I2cAddress::TenBit(addr) => (addr, 1 << 15), + }; + // Load address + self.i2c_base.i2c.address().write(|w| unsafe { + w.bits(I2cDirection::Read as u32 | (addr << 1) as u32 | addr_mode_bit) + }); + + let mut buf_iter = buffer.iter_mut(); + let mut read_bytes = 0; + // Start receive transfer + self.i2c_base + .i2c + .cmd() + .write(|w| unsafe { w.bits(I2cCmd::StartWithStop as u32) }); + let mut read_if_next_available = || { + if let Some(next_byte) = buf_iter.next() { + *next_byte = self.read_fifo(); + } + }; + loop { + let status_reader = self.i2c_base.i2c.status().read(); + if status_reader.arblost().bit_is_set() { + self.clear_rx_fifo(); + return Err(Error::ArbitrationLost); + } else if status_reader.nackaddr().bit_is_set() { + self.clear_rx_fifo(); + return Err(Error::NackAddr); + } else if status_reader.idle().bit_is_set() { + if read_bytes != len { + return Err(Error::InsufficientDataReceived); + } + return Ok(()); + } else if status_reader.rxnempty().bit_is_set() { + read_if_next_available(); + read_bytes += 1; + } + } + } +} + +/* macro_rules! i2c_master { ($($I2CX:path: ($i2cx:ident, $clk_enb:path),)+) => { $( @@ -675,204 +922,237 @@ i2c_master!( pac::I2ca: (i2ca, PeripheralClocks::I2c0), pac::I2cb: (i2cb, PeripheralClocks::I2c1), ); +*/ + +//====================================================================================== +// Embedded HAL I2C implementations +//====================================================================================== + +impl embedded_hal::i2c::ErrorType for I2cMaster { + type Error = Error; +} + +impl embedded_hal::i2c::I2c for I2cMaster { + fn transaction( + &mut self, + address: SevenBitAddress, + operations: &mut [Operation<'_>], + ) -> Result<(), Self::Error> { + for operation in operations { + match operation { + Operation::Read(buf) => self.read_internal(I2cAddress::Regular(address), buf)?, + Operation::Write(buf) => self.write_from_buffer( + I2cCmd::StartWithStop, + I2cAddress::Regular(address), + buf, + )?, + } + } + Ok(()) + } +} + +impl embedded_hal::i2c::ErrorType for I2cMaster { + type Error = Error; +} + +impl embedded_hal::i2c::I2c for I2cMaster { + fn transaction( + &mut self, + address: TenBitAddress, + operations: &mut [Operation<'_>], + ) -> Result<(), Self::Error> { + for operation in operations { + match operation { + Operation::Read(buf) => self.read_internal(I2cAddress::TenBit(address), buf)?, + Operation::Write(buf) => { + self.write_from_buffer(I2cCmd::StartWithStop, I2cAddress::TenBit(address), buf)? + } + } + } + Ok(()) + } +} //================================================================================================== // I2C Slave //================================================================================================== -pub struct I2cSlave { - i2c_base: I2cBase, - _addr: PhantomData, +pub struct I2cSlave { + i2c_base: I2cBase, + addr: PhantomData, } -macro_rules! i2c_slave { - ($($I2CX:path: ($i2cx:ident, $i2cx_slave:ident),)+) => { - $( - impl I2cSlave<$I2CX, ADDR> { - fn $i2cx_slave( - i2c: $I2CX, - cfg: SlaveConfig, - sys_clk: impl Into, - speed_mode: I2cSpeed, - sys_cfg: Option<&mut pac::Sysconfig>, - ) -> Self { - I2cSlave { - i2c_base: I2cBase::$i2cx( - i2c, - sys_clk, - speed_mode, - None, - Some(&cfg), - sys_cfg - ), - _addr: PhantomData, - } - .enable_slave() - } +impl I2cSlave { + fn new_generic( + sys_cfg: &mut pac::Sysconfig, + sys_clk: impl Into, + i2c: I2c, + cfg: SlaveConfig, + speed_mode: I2cSpeed, + ) -> Result { + Ok(I2cSlave { + i2c_base: I2cBase::new(sys_cfg, sys_clk, i2c, speed_mode, None, Some(&cfg))?, + addr: PhantomData, + } + .enable_slave()) + } - #[inline] - pub fn enable_slave(self) -> Self { - self.i2c_base - .i2c - .s0_ctrl() - .modify(|_, w| w.enable().set_bit()); - self - } + #[inline] + pub fn enable_slave(self) -> Self { + self.i2c_base + .i2c + .s0_ctrl() + .modify(|_, w| w.enable().set_bit()); + self + } - #[inline] - pub fn disable_slave(self) -> Self { - self.i2c_base - .i2c - .s0_ctrl() - .modify(|_, w| w.enable().clear_bit()); - self - } + #[inline] + pub fn disable_slave(self) -> Self { + self.i2c_base + .i2c + .s0_ctrl() + .modify(|_, w| w.enable().clear_bit()); + self + } - #[inline(always)] - fn load_fifo(&self, word: u8) { - self.i2c_base - .i2c - .s0_data() - .write(|w| unsafe { w.bits(word as u32) }); - } + #[inline(always)] + fn load_fifo(&self, word: u8) { + self.i2c_base + .i2c + .s0_data() + .write(|w| unsafe { w.bits(word as u32) }); + } - #[inline(always)] - fn read_fifo(&self) -> u8 { - self.i2c_base.i2c.s0_data().read().bits() as u8 - } + #[inline(always)] + fn read_fifo(&self) -> u8 { + self.i2c_base.i2c.s0_data().read().bits() as u8 + } - #[inline] - fn clear_tx_fifo(&self) { - self.i2c_base - .i2c - .s0_fifo_clr() - .write(|w| w.txfifo().set_bit()); - } + #[inline] + fn clear_tx_fifo(&self) { + self.i2c_base + .i2c + .s0_fifo_clr() + .write(|w| w.txfifo().set_bit()); + } - #[inline] - fn clear_rx_fifo(&self) { - self.i2c_base - .i2c - .s0_fifo_clr() - .write(|w| w.rxfifo().set_bit()); - } + #[inline] + fn clear_rx_fifo(&self) { + self.i2c_base + .i2c + .s0_fifo_clr() + .write(|w| w.rxfifo().set_bit()); + } - /// Get the last address that was matched by the slave control and the corresponding - /// master direction - pub fn last_address(&self) -> (I2cDirection, u32) { - let bits = self.i2c_base.i2c.s0_lastaddress().read().bits(); - match bits & 0x01 { - 0 => (I2cDirection::Send, bits >> 1), - 1 => (I2cDirection::Read, bits >> 1), - _ => (I2cDirection::Send, bits >> 1), - } - } + /// Get the last address that was matched by the slave control and the corresponding + /// master direction + pub fn last_address(&self) -> (I2cDirection, u32) { + let bits = self.i2c_base.i2c.s0_lastaddress().read().bits(); + match bits & 0x01 { + 0 => (I2cDirection::Send, bits >> 1), + 1 => (I2cDirection::Read, bits >> 1), + _ => (I2cDirection::Send, bits >> 1), + } + } - pub fn write(&mut self, output: &[u8]) -> Result<(), Error> { - let len = output.len(); - // It should theoretically possible to transfer larger data sizes by tracking - // the number of sent words and setting it to 0x7fe as soon as only that many - // bytes are remaining. However, large transfer like this are not common. This - // feature will therefore not be supported for now. - if len > 0x7fe { - return Err(Error::DataTooLarge); - } - let mut bytes = output.iter(); - // FIFO has a depth of 16. We load slightly above the trigger level - // but not all of it because the transaction might fail immediately - const FILL_DEPTH: usize = 12; + pub fn write(&mut self, output: &[u8]) -> Result<(), Error> { + let len = output.len(); + // It should theoretically possible to transfer larger data sizes by tracking + // the number of sent words and setting it to 0x7fe as soon as only that many + // bytes are remaining. However, large transfer like this are not common. This + // feature will therefore not be supported for now. + if len > 0x7fe { + return Err(Error::DataTooLarge); + } + let mut bytes = output.iter(); + // FIFO has a depth of 16. We load slightly above the trigger level + // but not all of it because the transaction might fail immediately + const FILL_DEPTH: usize = 12; - // load the FIFO - for _ in 0..core::cmp::min(FILL_DEPTH, len) { - self.load_fifo(*bytes.next().unwrap()); - } + // load the FIFO + for _ in 0..core::cmp::min(FILL_DEPTH, len) { + self.load_fifo(*bytes.next().unwrap()); + } - let status_reader = self.i2c_base.i2c.s0_status().read(); - let mut load_if_next_available = || { - if let Some(next_byte) = bytes.next() { - self.load_fifo(*next_byte); - } - }; - loop { - if status_reader.nackdata().bit_is_set() { - self.clear_tx_fifo(); - return Err(Error::NackData); - } else if status_reader.idle().bit_is_set() { - return Ok(()); - } else { - while !status_reader.txnfull().bit_is_set() { - load_if_next_available(); - } - } - } - } - - pub fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { - let len = buffer.len(); - // It should theoretically possible to transfer larger data sizes by tracking - // the number of sent words and setting it to 0x7fe as soon as only that many - // bytes are remaining. However, large transfer like this are not common. This - // feature will therefore not be supported for now. - if len > 0x7fe { - return Err(Error::DataTooLarge); - } - // Clear the receive FIFO - self.clear_rx_fifo(); - - let mut buf_iter = buffer.iter_mut(); - let mut read_bytes = 0; - let mut read_if_next_available = || { - if let Some(next_byte) = buf_iter.next() { - *next_byte = self.read_fifo(); - } - }; - loop { - let status_reader = self.i2c_base.i2c.s0_status().read(); - if status_reader.idle().bit_is_set() { - if read_bytes != len { - return Err(Error::InsufficientDataReceived); - } - return Ok(()); - } else if status_reader.rxnempty().bit_is_set() { - read_bytes += 1; - read_if_next_available(); - } - } + let status_reader = self.i2c_base.i2c.s0_status().read(); + let mut load_if_next_available = || { + if let Some(next_byte) = bytes.next() { + self.load_fifo(*next_byte); + } + }; + loop { + if status_reader.nackdata().bit_is_set() { + self.clear_tx_fifo(); + return Err(Error::NackData); + } else if status_reader.idle().bit_is_set() { + return Ok(()); + } else { + while !status_reader.txnfull().bit_is_set() { + load_if_next_available(); } } + } + } + pub fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { + let len = buffer.len(); + // It should theoretically possible to transfer larger data sizes by tracking + // the number of sent words and setting it to 0x7fe as soon as only that many + // bytes are remaining. However, large transfer like this are not common. This + // feature will therefore not be supported for now. + if len > 0x7fe { + return Err(Error::DataTooLarge); + } + // Clear the receive FIFO + self.clear_rx_fifo(); - impl I2cSlave<$I2CX, SevenBitAddress> { - /// Create a new I2C slave for seven bit addresses - /// - /// Returns a [`Error::WrongAddrMode`] error if a ten bit address is passed - pub fn i2ca( - i2c: $I2CX, - cfg: SlaveConfig, - sys_clk: impl Into, - speed_mode: I2cSpeed, - sys_cfg: Option<&mut pac::Sysconfig>, - ) -> Result { - if let I2cAddress::TenBit(_) = cfg.addr { - return Err(Error::WrongAddrMode); - } - Ok(Self::$i2cx_slave(i2c, cfg, sys_clk, speed_mode, sys_cfg)) - } + let mut buf_iter = buffer.iter_mut(); + let mut read_bytes = 0; + let mut read_if_next_available = || { + if let Some(next_byte) = buf_iter.next() { + *next_byte = self.read_fifo(); } - - impl I2cSlave<$I2CX, TenBitAddress> { - pub fn $i2cx( - i2c: $I2CX, - cfg: SlaveConfig, - sys_clk: impl Into, - speed_mode: I2cSpeed, - sys_cfg: Option<&mut pac::Sysconfig>, - ) -> Self { - Self::$i2cx_slave(i2c, cfg, sys_clk, speed_mode, sys_cfg) + }; + loop { + let status_reader = self.i2c_base.i2c.s0_status().read(); + if status_reader.idle().bit_is_set() { + if read_bytes != len { + return Err(Error::InsufficientDataReceived); } + return Ok(()); + } else if status_reader.rxnempty().bit_is_set() { + read_bytes += 1; + read_if_next_available(); } - )+ + } } } -i2c_slave!(pac::I2ca: (i2ca, i2ca_slave), pac::I2cb: (i2cb, i2cb_slave),); +impl I2cSlave { + /// Create a new I2C slave for seven bit addresses + pub fn new( + sys_cfg: &mut pac::Sysconfig, + sys_clk: impl Into, + i2c: I2c, + cfg: SlaveConfig, + speed_mode: I2cSpeed, + ) -> Result { + if let I2cAddress::TenBit(_) = cfg.addr { + return Err(InitError::WrongAddrMode); + } + Ok(Self::new_generic(sys_cfg, sys_clk, i2c, cfg, speed_mode)?) + } +} + +impl I2cSlave { + pub fn new_ten_bit_addr( + sys_cfg: &mut pac::Sysconfig, + sys_clk: impl Into, + i2c: I2c, + cfg: SlaveConfig, + speed_mode: I2cSpeed, + ) -> Result { + Self::new_generic(sys_cfg, sys_clk, i2c, cfg, speed_mode) + } +} diff --git a/va108xx-hal/src/prelude.rs b/va108xx-hal/src/prelude.rs index 435a2f7..516618f 100644 --- a/va108xx-hal/src/prelude.rs +++ b/va108xx-hal/src/prelude.rs @@ -1,3 +1,5 @@ //! Prelude pub use fugit::ExtU32 as _; pub use fugit::RateExtU32 as _; + +pub use crate::time::*; diff --git a/va108xx-hal/src/pwm.rs b/va108xx-hal/src/pwm.rs index 1232666..01f3ffc 100644 --- a/va108xx-hal/src/pwm.rs +++ b/va108xx-hal/src/pwm.rs @@ -4,7 +4,7 @@ //! //! ## Examples //! -//! - [PWM example](https://egit.irs.uni-stuttgart.de/rust/va108xx-hal/src/branch/main/examples/pwm.rs) +//! - [PWM example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/pwm.rs) use core::convert::Infallible; use core::marker::PhantomData; @@ -158,9 +158,9 @@ where { /// Create a new stronlgy typed PWM pin pub fn new( - vtp: (Pin, Tim), - sys_clk: impl Into + Copy, sys_cfg: &mut pac::Sysconfig, + sys_clk: impl Into + Copy, + tim_and_pin: (Pin, Tim), initial_period: impl Into + Copy, ) -> Self { let mut pin = PwmPin { @@ -171,7 +171,7 @@ where current_rst_val: 0, sys_clk: sys_clk.into(), }, - reg: unsafe { TimAndPinRegister::new(vtp.0, vtp.1) }, + reg: unsafe { TimAndPinRegister::new(tim_and_pin.0, tim_and_pin.1) }, mode: PhantomData, }; enable_peripheral_clock(sys_cfg, crate::clock::PeripheralClocks::Gpio); @@ -225,12 +225,13 @@ where (Pin, Tim): ValidTimAndPin, { pub fn pwma( - vtp: (Pin, Tim), - sys_clk: impl Into + Copy, sys_cfg: &mut pac::Sysconfig, + sys_clk: impl Into + Copy, + pin_and_tim: (Pin, Tim), initial_period: impl Into + Copy, ) -> Self { - let mut pin: PwmPin = Self::new(vtp, sys_clk, sys_cfg, initial_period); + let mut pin: PwmPin = + Self::new(sys_cfg, sys_clk, pin_and_tim, initial_period); pin.enable_pwm_a(); pin } @@ -241,12 +242,13 @@ where (Pin, Tim): ValidTimAndPin, { pub fn pwmb( - vtp: (Pin, Tim), - sys_clk: impl Into + Copy, sys_cfg: &mut pac::Sysconfig, + sys_clk: impl Into + Copy, + pin_and_tim: (Pin, Tim), initial_period: impl Into + Copy, ) -> Self { - let mut pin: PwmPin = Self::new(vtp, sys_clk, sys_cfg, initial_period); + let mut pin: PwmPin = + Self::new(sys_cfg, sys_clk, pin_and_tim, initial_period); pin.enable_pwm_b(); pin } diff --git a/va108xx-hal/src/spi.rs b/va108xx-hal/src/spi.rs index 0a87d32..e05a3a7 100644 --- a/va108xx-hal/src/spi.rs +++ b/va108xx-hal/src/spi.rs @@ -4,8 +4,8 @@ //! //! - [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}, - gpio::pins::{ + clock::enable_peripheral_clock, + gpio::pin::{ 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, PB10, PB11, PB12, PB13, PB14, PB15, PB16, PB17, PB18, PB19, PB2, PB22, PB23, PB3, PB4, PB5, @@ -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 db1e081..167b8ec 100644 --- a/va108xx-hal/src/uart.rs +++ b/va108xx-hal/src/uart.rs @@ -10,14 +10,15 @@ use fugit::RateExtU32; pub use crate::IrqCfg; use crate::{ - clock::{self, enable_peripheral_clock, PeripheralClocks}, - gpio::pins::{ + clock::{enable_peripheral_clock, PeripheralClocks}, + gpio::pin::{ 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, }, pac::{self, uarta as uart_base}, time::Hertz, utility::unmask_irq, + PeripheralSelect, }; //================================================================================================== @@ -305,7 +306,7 @@ pub struct UartBase { } /// Serial abstraction. Entry point to create a new UART pub struct Uart { - uart_base: UartBase, + inner: UartBase, pins: Pins, } @@ -352,6 +353,7 @@ impl Tx { pub trait Instance: Deref { fn ptr() -> *const uart_base::RegisterBlock; const IDX: u8; + const PERIPH_SEL: PeripheralSelect; } impl UartBase { @@ -489,14 +491,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 } @@ -507,7 +529,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, @@ -526,75 +548,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() } } @@ -603,6 +625,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 { @@ -610,36 +634,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 { @@ -877,10 +873,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/vorago-reb1/Cargo.toml b/vorago-reb1/Cargo.toml index 4a833f6..7e9e9bd 100644 --- a/vorago-reb1/Cargo.toml +++ b/vorago-reb1/Cargo.toml @@ -19,14 +19,14 @@ embedded-hal = "1" version = "0.3" [dependencies.va108xx-hal] -version = "0.6" +path = "../va108xx-hal" +version = "0.7" features = ["rt"] [features] rt = ["va108xx-hal/rt"] [dev-dependencies] -cortex-m-rtic = "1.1" panic-halt = "0.2" nb = "1" @@ -36,6 +36,14 @@ version = "0.5" [dev-dependencies.panic-rtt-target] version = "0.1" +[dev-dependencies.rtic] +version = "2" +features = ["thumbv6-backend"] + +[dev-dependencies.rtic-monotonics] +version = "1" +features = ["cortex-m-systick"] + [package.metadata.docs.rs] all-features = true rustdoc-args = ["--generate-link-to-definition"] diff --git a/vorago-reb1/examples/adt75-temp-sensor.rs b/vorago-reb1/examples/adt75-temp-sensor.rs index 9326643..40187bd 100644 --- a/vorago-reb1/examples/adt75-temp-sensor.rs +++ b/vorago-reb1/examples/adt75-temp-sensor.rs @@ -13,7 +13,7 @@ fn main() -> ! { rprintln!("-- Vorago Temperature Sensor and I2C Example --"); let mut dp = pac::Peripherals::take().unwrap(); let mut delay = set_up_ms_delay_provider(&mut dp.sysconfig, 50.MHz(), dp.tim0); - let mut temp_sensor = Adt75TempSensor::new(dp.i2ca, 50.MHz(), Some(&mut dp.sysconfig)) + let mut temp_sensor = Adt75TempSensor::new(&mut dp.sysconfig, 50.MHz(), dp.i2ca) .expect("Creating temperature sensor struct failed"); loop { let temp = temp_sensor diff --git a/vorago-reb1/examples/adxl343-accelerometer.rs b/vorago-reb1/examples/adxl343-accelerometer.rs index 5bd6a9a..483d4dc 100644 --- a/vorago-reb1/examples/adxl343-accelerometer.rs +++ b/vorago-reb1/examples/adxl343-accelerometer.rs @@ -52,12 +52,12 @@ fn main() -> ! { false, true, ); - let mut spi = Spi::spib( + let mut spi = Spi::new( + &mut dp.sysconfig, + 50.MHz(), dp.spib, (sck, miso, mosi), - 50.MHz(), spi_cfg, - Some(&mut dp.sysconfig), Some(&transfer_cfg.downgrade()), ); diff --git a/vorago-reb1/examples/blinky-button-rtic.rs b/vorago-reb1/examples/blinky-button-rtic.rs index ecfa587..c869cb7 100644 --- a/vorago-reb1/examples/blinky-button-rtic.rs +++ b/vorago-reb1/examples/blinky-button-rtic.rs @@ -5,6 +5,7 @@ #[rtic::app(device = pac)] mod app { use panic_rtt_target as _; + use rtic_monotonics::systick::Systick; use rtt_target::{rprintln, rtt_init_default, set_print_channel}; use va108xx_hal::{ clock::{set_clk_div_register, FilterClkSel}, @@ -43,10 +44,18 @@ mod app { struct Shared {} #[init] - fn init(ctx: init::Context) -> (Shared, Local, init::Monotonics) { + fn init(ctx: init::Context) -> (Shared, Local) { let channels = rtt_init_default!(); set_print_channel(channels.up.0); rprintln!("-- Vorago Button IRQ Example --"); + // Initialize the systick interrupt & obtain the token to prove that we did + let systick_mono_token = rtic_monotonics::create_systick_token!(); + Systick::start( + ctx.core.SYST, + Hertz::from(50.MHz()).raw(), + systick_mono_token, + ); + let mode = match CFG_MODE { // Ask mode from user via RTT CfgMode::Prompt => prompt_mode(channels.down.0), @@ -90,7 +99,7 @@ mod app { 50.MHz(), dp.tim0, ); - (Shared {}, Local { leds, button, mode }, init::Monotonics()) + (Shared {}, Local { leds, button, mode }) } // `shared` cannot be accessed from this context diff --git a/vorago-reb1/examples/blinky-leds.rs b/vorago-reb1/examples/blinky-leds.rs index 4e28871..0e0e0cf 100644 --- a/vorago-reb1/examples/blinky-leds.rs +++ b/vorago-reb1/examples/blinky-leds.rs @@ -10,7 +10,7 @@ use cortex_m_rt::entry; use embedded_hal::delay::DelayNs; use embedded_hal::digital::{OutputPin, StatefulOutputPin}; use panic_halt as _; -use va108xx_hal::{gpio::pins::PinsA, pac, prelude::*, timer::set_up_ms_delay_provider}; +use va108xx_hal::{gpio::PinsA, pac, prelude::*, timer::set_up_ms_delay_provider}; use vorago_reb1::leds::Leds; // REB LED pin definitions. All on port A diff --git a/vorago-reb1/examples/max11619-adc.rs b/vorago-reb1/examples/max11619-adc.rs index 73eda4e..8b76259 100644 --- a/vorago-reb1/examples/max11619-adc.rs +++ b/vorago-reb1/examples/max11619-adc.rs @@ -1,4 +1,7 @@ -//! MAX11619 ADC example applikcation +//! MAX11619 ADC example application. +//! +//! You can turn the potentiometer knob of the REB1 board to measure +//! different ADC values. #![no_main] #![no_std] @@ -139,12 +142,12 @@ fn main() -> ! { .expect("Setting accelerometer chip select high failed"); let transfer_cfg = TransferConfig::::new(3.MHz(), spi::MODE_0, None, true, false); - let spi = Spi::spib( + let spi = Spi::new( + &mut dp.sysconfig, + 50.MHz(), dp.spib, (sck, miso, mosi), - 50.MHz(), spi_cfg, - Some(&mut dp.sysconfig), Some(&transfer_cfg.downgrade()), ) .downgrade(); diff --git a/vorago-reb1/src/button.rs b/vorago-reb1/src/button.rs index b191829..4c7a03d 100644 --- a/vorago-reb1/src/button.rs +++ b/vorago-reb1/src/button.rs @@ -2,8 +2,8 @@ //! //! ## Examples //! -//! - [Button Blinky with IRQs](https://egit.irs.uni-stuttgart.de/rust/vorago-reb1/src/branch/main/examples/blinky-button-irq.rs) -//! - [Button Blinky with IRQs and RTIC](https://egit.irs.uni-stuttgart.de/rust/vorago-reb1/src/branch/main/examples/blinky-button-rtic.rs) +//! - [Button Blinky with IRQs](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/blinky-button-irq.rs) +//! - [Button Blinky with IRQs and RTIC](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/blinky-button-rtic.rs) use embedded_hal::digital::InputPin; use va108xx_hal::{ gpio::{FilterClkSel, FilterType, InputFloating, InterruptEdge, InterruptLevel, Pin, PA11}, diff --git a/vorago-reb1/src/leds.rs b/vorago-reb1/src/leds.rs index 36e2246..304cddd 100644 --- a/vorago-reb1/src/leds.rs +++ b/vorago-reb1/src/leds.rs @@ -2,13 +2,13 @@ //! //! ## Examples //! -//! - [LED example](https://egit.irs.uni-stuttgart.de/rust/vorago-reb1/src/branch/main/examples/blinky-leds.rs) -//! - [Button Blinky using IRQs](https://egit.irs.uni-stuttgart.de/rust/vorago-reb1/src/branch/main/examples/blinky-button-irq.rs) -//! - [Button Blinky using IRQs and RTIC](https://egit.irs.uni-stuttgart.de/rust/vorago-reb1/src/branch/main/examples/blinky-button-rtic.rs) +//! - [LED example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/blinky-leds.rs) +//! - [Button Blinky using IRQs](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/blinky-button-irq.rs) +//! - [Button Blinky using IRQs and RTIC](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/blinky-button-rtic.rs) use embedded_hal::digital::OutputPin; use va108xx_hal::{ - gpio::dynpins::DynPin, - gpio::pins::{Pin, PushPullOutput, PA10, PA6, PA7}, + gpio::dynpin::DynPin, + gpio::pin::{Pin, PushPullOutput, PA10, PA6, PA7}, }; pub type LD2 = Pin; diff --git a/vorago-reb1/src/max11619.rs b/vorago-reb1/src/max11619.rs index ff2f9ee..c4805ed 100644 --- a/vorago-reb1/src/max11619.rs +++ b/vorago-reb1/src/max11619.rs @@ -2,7 +2,7 @@ //! //! ## Examples //! -//! - [ADC example](https://egit.irs.uni-stuttgart.de/rust/vorago-reb1/src/branch/main/examples/max11619-adc.rs) +//! - [ADC example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/max11619-adc.rs) use core::convert::Infallible; use embedded_hal::spi::SpiDevice; use max116xx_10bit::{ diff --git a/vorago-reb1/src/temp_sensor.rs b/vorago-reb1/src/temp_sensor.rs index 3cffe55..a3266d0 100644 --- a/vorago-reb1/src/temp_sensor.rs +++ b/vorago-reb1/src/temp_sensor.rs @@ -4,10 +4,10 @@ //! //! ## Examples //! -//! - [Temperature Sensor example](https://egit.irs.uni-stuttgart.de/rust/vorago-reb1/src/branch/main/examples/adt75-temp-sensor.rs) +//! - [Temperature Sensor example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/adt75-temp-sensor.rs use embedded_hal::i2c::{I2c, SevenBitAddress}; use va108xx_hal::{ - i2c::{Error, I2cMaster, I2cSpeed, MasterConfig}, + i2c::{Error, I2cMaster, I2cSpeed, InitError, MasterConfig}, pac, time::Hertz, }; @@ -29,20 +29,40 @@ pub enum RegAddresses { OneShot = 0x04, } +#[derive(Debug)] +pub enum AdtInitError { + Init(InitError), + I2c(Error), +} + +impl From for AdtInitError { + fn from(value: InitError) -> Self { + Self::Init(value) + } +} + +impl From for AdtInitError { + fn from(value: Error) -> Self { + Self::I2c(value) + } +} + impl Adt75TempSensor { pub fn new( - i2ca: pac::I2ca, + sys_cfg: &mut pac::Sysconfig, sys_clk: impl Into + Copy, - sys_cfg: Option<&mut pac::Sysconfig>, + i2ca: pac::I2ca, ) -> Result { let mut sensor = Adt75TempSensor { - sensor_if: I2cMaster::i2ca( + // The master construction can not fail for regular I2C speed. + sensor_if: I2cMaster::new( + sys_cfg, + sys_clk, i2ca, MasterConfig::default(), - sys_clk, I2cSpeed::Regular100khz, - sys_cfg, - ), + ) + .unwrap(), cmd_buf: [RegAddresses::Temperature as u8], current_reg: RegAddresses::Temperature, }; 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",