From 7c3958b5bf5fac6a7bf710ba353693cb55331c39 Mon Sep 17 00:00:00 2001 From: Kaizen Wolf Date: Tue, 28 Dec 2021 00:17:52 +0100 Subject: [PATCH] Implement is_reg_synced on sercom registers --- hal/src/sercom/v2.rs | 8 +++ hal/src/sercom/v2/spi/reg.rs | 51 ++++++++--------- hal/src/sercom/v2/uart/reg.rs | 90 ++++++++++++++---------------- hal/src/spi_common.rs | 19 ++++--- hal/src/thumbv6m/clock.rs | 3 +- hal/src/thumbv6m/sercom/v1/i2c.rs | 68 +++++++++++----------- hal/src/thumbv6m/sercom/v1/uart.rs | 2 +- 7 files changed, 118 insertions(+), 123 deletions(-) diff --git a/hal/src/sercom/v2.rs b/hal/src/sercom/v2.rs index b3e7f1ba439..e8875ee5fe8 100644 --- a/hal/src/sercom/v2.rs +++ b/hal/src/sercom/v2.rs @@ -40,6 +40,14 @@ pub mod uart; #[cfg(feature = "dma")] pub mod dma; +/// Register synchronization flags +pub enum reg_sync { + CtrlB, + Length, + Enable, + SwRst, +} + //============================================================================== // Sercom //============================================================================== diff --git a/hal/src/sercom/v2/spi/reg.rs b/hal/src/sercom/v2/spi/reg.rs index 5a778a79c55..4cba68f9fe1 100644 --- a/hal/src/sercom/v2/spi/reg.rs +++ b/hal/src/sercom/v2/spi/reg.rs @@ -12,7 +12,7 @@ use crate::pac::sercom0::spi::ctrla::MODE_A; #[cfg(feature = "min-samd51g")] use crate::pac::sercom0::spim::ctrla::MODE_A; -use crate::sercom::v2::Sercom; +use crate::sercom::v2::{reg_sync, Sercom}; use crate::time::Hertz; use super::{BitOrder, DataWidth, Error, Flags, Phase, Polarity, Status}; @@ -52,10 +52,7 @@ impl Registers { #[inline] pub fn reset(&mut self) { self.spi().ctrla.write(|w| w.swrst().set_bit()); - #[cfg(feature = "samd20")] - while self.spi().status.read().syncbusy().bit_is_set() {} - #[cfg(not(feature = "samd20"))] - while self.spi().syncbusy.read().swrst().bit_is_set() {} + while !self.is_register_synced(reg_sync::SwRst) {} } #[cfg(feature = "dma")] @@ -74,6 +71,20 @@ impl Registers { }); } + /// Wait for the registers synchronization + #[inline] + fn is_register_synced(&mut self, synced_reg: reg_sync) -> bool { + #[cfg(feature = "samd20")] + return !self.spi().status.read().syncbusy().bit_is_set(); + #[cfg(not(feature = "samd20"))] + match synced_reg { + reg_sync::CtrlB => !self.spi().syncbusy.read().ctrlb().bit_is_set(), + reg_sync::Length => !self.spi().syncbusy.read().length().bit_is_set(), + reg_sync::Enable => !self.spi().syncbusy.read().enable().bit_is_set(), + reg_sync::SwRst => !self.spi().syncbusy.read().swrst().bit_is_set(), + } + } + /// Configure the SPI operating mode /// /// For maximum flexibility, this module chooses to always operate in 32-bit @@ -90,10 +101,7 @@ impl Registers { w.data32b().data_trans_32bit(); w.icspace().bits(1) }); - #[cfg(feature = "samd20")] - while self.spi().status.read().syncbusy().bit_is_set() {} - #[cfg(not(feature = "samd20"))] - while self.spi().syncbusy.read().ctrlb().bit_is_set() {} + while !self.is_register_synced(reg_sync::CtrlB) {} } /// Return the current transaction length @@ -112,10 +120,7 @@ impl Registers { w.len().bits(length); w.lenen().set_bit() }); - #[cfg(feature = "samd20")] - while self.spi().status.read().syncbusy().bit_is_set() {} - #[cfg(not(feature = "samd20"))] - while self.spi().syncbusy.read().length().bit_is_set() {} + while !self.is_register_synced(reg_sync::Length) {} } /// Set the character size @@ -284,40 +289,28 @@ impl Registers { #[inline] pub fn rx_enable(&mut self) { self.spi().ctrlb.modify(|_, w| w.rxen().set_bit()); - #[cfg(feature = "samd20")] - while self.spi().status.read().syncbusy().bit_is_set() {} - #[cfg(not(feature = "samd20"))] - while self.spi().syncbusy.read().ctrlb().bit_is_set() {} + while !self.is_register_synced(reg_sync::CtrlB) {} } /// Disable the receiver #[inline] pub fn rx_disable(&mut self) { self.spi().ctrlb.modify(|_, w| w.rxen().clear_bit()); - #[cfg(feature = "samd20")] - while self.spi().status.read().syncbusy().bit_is_set() {} - #[cfg(not(feature = "samd20"))] - while self.spi().syncbusy.read().ctrlb().bit_is_set() {} + while !self.is_register_synced(reg_sync::CtrlB) {} } /// Enable the peripheral #[inline] pub fn enable(&mut self) { self.spi().ctrla.modify(|_, w| w.enable().set_bit()); - #[cfg(feature = "samd20")] - while self.spi().status.read().syncbusy().bit_is_set() {} - #[cfg(not(feature = "samd20"))] - while self.spi().syncbusy.read().enable().bit_is_set() {} + while !self.is_register_synced(reg_sync::Enable) {} } /// Disable the peripheral #[inline] pub fn disable(&mut self) { self.spi().ctrla.modify(|_, w| w.enable().clear_bit()); - #[cfg(feature = "samd20")] - while self.spi().status.read().syncbusy().bit_is_set() {} - #[cfg(not(feature = "samd20"))] - while self.spi().syncbusy.read().enable().bit_is_set() {} + while !self.is_register_synced(reg_sync::Enable) {} } /// Read from the `DATA` register diff --git a/hal/src/sercom/v2/uart/reg.rs b/hal/src/sercom/v2/uart/reg.rs index 730fd4cc49b..f307c30786d 100644 --- a/hal/src/sercom/v2/uart/reg.rs +++ b/hal/src/sercom/v2/uart/reg.rs @@ -55,15 +55,26 @@ impl Registers { self.sercom } + /// Wait for the registers synchronization + #[inline] + pub fn is_register_synced(&mut self, synced_reg: reg_sync) -> bool { + #[cfg(feature = "samd20")] + return !self.usart().status.read().syncbusy().bit_is_set(); + #[cfg(not(feature = "samd20"))] + match synced_reg { + reg_sync::CtrlB => !self.usart().syncbusy.read().ctrlb().bit_is_set(), + reg_sync::Length => !self.usart().syncbusy.read().length().bit_is_set(), + reg_sync::Enable => !self.usart().syncbusy.read().enable().bit_is_set(), + reg_sync::SwRst => !self.usart().syncbusy.read().swrst().bit_is_set(), + } + } + /// Reset the SERCOM peripheral #[inline] pub(super) fn swrst(&mut self) { self.usart().ctrla.write(|w| w.swrst().set_bit()); - #[cfg(feature = "samd20")] - while self.usart().status.read().syncbusy().bit_is_set() {} - #[cfg(not(feature = "samd20"))] - while self.usart().syncbusy.read().swrst().bit_is_set() {} + while !self.is_register_synced(reg_sync::SwRst) {} } /// Configure the SERCOM to use internal clock mode @@ -291,24 +302,24 @@ impl Registers { use Oversampling::*; #[cfg(feature = "samd20")] - let baud = self.usart().baud.read().bits(); - #[cfg(feature = "samd20")] - let mode = Arithmetic(Bits16); - - #[cfg(not(feature = "samd20"))] - let baud = self.usart().baud_usartfp_mode().read().bits(); - #[cfg(not(feature = "samd20"))] - let sampr = self.usart().ctrla.read().sampr().bits(); + { + let baud = self.usart().baud.read().bits(); + let mode = Arithmetic(Bits16); + return (baud, mode); + } #[cfg(not(feature = "samd20"))] - let mode = match sampr { - 0 => Arithmetic(Bits16), - 1 => Fractional(Bits16), - 2 => Arithmetic(Bits8), - 3 => Fractional(Bits8), - _ => unreachable!(), - }; - - (baud, mode) + { + let baud = self.usart().baud_usartfp_mode().read().bits(); + let sampr = self.usart().ctrla.read().sampr().bits(); + let mode = match sampr { + 0 => Arithmetic(Bits16), + 1 => Fractional(Bits16), + 2 => Arithmetic(Bits8), + 3 => Fractional(Bits8), + _ => unreachable!(), + }; + (baud, mode) + } } /// Control the buffer overflow notification @@ -433,24 +444,16 @@ impl Registers { /// UART transactions are not possible until the peripheral is enabled. #[inline] pub(super) fn enable(&mut self, rxen: bool, txen: bool) { - let usart = self.usart(); - // Enable RX if rxen { - usart.ctrlb.modify(|_, w| w.rxen().set_bit()); - #[cfg(feature = "samd20")] - while usart.status.read().syncbusy().bit_is_set() {} - #[cfg(not(feature = "samd20"))] - while usart.syncbusy.read().ctrlb().bit_is_set() {} + self.usart().ctrlb.modify(|_, w| w.rxen().set_bit()); + while !self.is_register_synced(reg_sync::CtrlB) {} } // Enable TX if txen { - usart.ctrlb.modify(|_, w| w.txen().set_bit()); - #[cfg(feature = "samd20")] - while usart.status.read().syncbusy().bit_is_set() {} - #[cfg(not(feature = "samd20"))] - while usart.syncbusy.read().ctrlb().bit_is_set() {} + self.usart().ctrlb.modify(|_, w| w.txen().set_bit()); + while !self.is_register_synced(reg_sync::CtrlB) {} } // Globally enable peripheral @@ -459,21 +462,13 @@ impl Registers { #[inline] pub(super) fn disable(&mut self) { - let usart = self.usart(); - // Disable RX - usart.ctrlb.modify(|_, w| w.rxen().clear_bit()); - #[cfg(feature = "samd20")] - while usart.status.read().syncbusy().bit_is_set() {} - #[cfg(not(feature = "samd20"))] - while usart.syncbusy.read().ctrlb().bit_is_set() {} + self.usart().ctrlb.modify(|_, w| w.rxen().clear_bit()); + while !self.is_register_synced(reg_sync::CtrlB) {} // Disable TX - usart.ctrlb.modify(|_, w| w.txen().clear_bit()); - #[cfg(feature = "samd20")] - while usart.status.read().syncbusy().bit_is_set() {} - #[cfg(not(feature = "samd20"))] - while usart.syncbusy.read().ctrlb().bit_is_set() {} + self.usart().ctrlb.modify(|_, w| w.txen().clear_bit()); + while !self.is_register_synced(reg_sync::CtrlB) {} self.enable_peripheral(false); } @@ -482,10 +477,7 @@ impl Registers { /// synchronize. pub(super) fn enable_peripheral(&mut self, enable: bool) { self.usart().ctrla.modify(|_, w| w.enable().bit(enable)); - #[cfg(feature = "samd20")] - while self.usart().status.read().syncbusy().bit_is_set() {} - #[cfg(not(feature = "samd20"))] - while self.usart().syncbusy.read().enable().bit_is_set() {} + while !self.is_register_synced(reg_sync::Enable) {} } } diff --git a/hal/src/spi_common.rs b/hal/src/spi_common.rs index d9994a0e6fa..75cca7e728e 100644 --- a/hal/src/spi_common.rs +++ b/hal/src/spi_common.rs @@ -26,24 +26,27 @@ pub trait CommonSpi { /// Helper for accessing the spi member of the sercom instance fn spi_mut(&mut self) -> &SPI; + /// Wait for the registers synchronization + #[inline] + fn is_register_synced(&mut self) -> bool { + #[cfg(feature = "samd20")] + return !self.spi().status.read().syncbusy().bit_is_set(); + #[cfg(not(feature = "samd20"))] + !self.spi().syncbusy.read().enable().bit_is_set() + } + /// Disable the SPI fn disable(&mut self) { self.spi_mut().ctrla.modify(|_, w| w.enable().clear_bit()); // wait for configuration to take effect - #[cfg(feature = "samd20")] - while self.spi().status.read().syncbusy().bit_is_set() {} - #[cfg(not(feature = "samd20"))] - while self.spi().syncbusy.read().enable().bit_is_set() {} + while !self.is_register_synced() {} } /// Enable the SPI fn enable(&mut self) { self.spi_mut().ctrla.modify(|_, w| w.enable().set_bit()); // wait for configuration to take effect - #[cfg(feature = "samd20")] - while self.spi().status.read().syncbusy().bit_is_set() {} - #[cfg(not(feature = "samd20"))] - while self.spi().syncbusy.read().enable().bit_is_set() {} + while !self.is_register_synced() {} } /// Set the polarity (CPOL) and phase (CPHA) of the SPI diff --git a/hal/src/thumbv6m/clock.rs b/hal/src/thumbv6m/clock.rs index 0c98be84b11..8088ac0381f 100644 --- a/hal/src/thumbv6m/clock.rs +++ b/hal/src/thumbv6m/clock.rs @@ -202,7 +202,6 @@ impl GenericClockController { pm.apbbsel.write(|w| w.apbbdiv().div1()); pm.apbcsel.write(|w| w.apbcdiv().div1()); - let used_clocks = 1u64 << u8::from(ClockId::DFLL48); Self { state, gclks: [ @@ -215,7 +214,7 @@ impl GenericClockController { Hertz(0), Hertz(0), ], - used_clocks, + used_clocks: 1u64 << u8::from(ClockId::DFLL48), } } diff --git a/hal/src/thumbv6m/sercom/v1/i2c.rs b/hal/src/thumbv6m/sercom/v1/i2c.rs index 01318f6db2e..b465769646c 100644 --- a/hal/src/thumbv6m/sercom/v1/i2c.rs +++ b/hal/src/thumbv6m/sercom/v1/i2c.rs @@ -19,6 +19,12 @@ const BUS_STATE_BUSY: u8 = 3; const MASTER_ACT_READ: u8 = 2; const MASTER_ACT_STOP: u8 = 3; +enum i2c_reg_sync { + SwRst, + Enable, + SysOp, +} + /// Define an I2C master type for the given SERCOM and pad pair. macro_rules! i2c { ([ @@ -85,52 +91,53 @@ where // safe because we're exclusively owning SERCOM pm.apbcmask.modify(|_, w| w.$powermask().set_bit()); + let mut s = Self { sda, scl, sercom }; + unsafe { // reset the sercom instance - sercom.i2cm().ctrla.modify(|_, w| w.swrst().set_bit()); + s.sercom.i2cm().ctrla.modify(|_, w| w.swrst().set_bit()); // wait for reset to complete - #[cfg(feature = "samd20")] - while sercom.i2cm().status.read().syncbusy().bit_is_set() - || sercom.i2cm().ctrla.read().swrst().bit_is_set() - {} - #[cfg(not(feature = "samd20"))] - while sercom.i2cm().syncbusy.read().swrst().bit_is_set() - || sercom.i2cm().ctrla.read().swrst().bit_is_set() + while !s.is_register_synced(i2c_reg_sync::SwRst) + || s.sercom.i2cm().ctrla.read().swrst().bit_is_set() {} // Put the hardware into i2c master mode - sercom.i2cm().ctrla.modify(|_, w| w.mode().i2c_master()); + s.sercom.i2cm().ctrla.modify(|_, w| w.mode().i2c_master()); // wait for configuration to take effect - #[cfg(feature = "samd20")] - while sercom.i2cm().status.read().syncbusy().bit_is_set() {} - #[cfg(not(feature = "samd20"))] - while sercom.i2cm().syncbusy.read().enable().bit_is_set() {} + while !s.is_register_synced(i2c_reg_sync::Enable) {} // set the baud rate let gclk = clock.freq(); let baud = (gclk.0 / (2 * freq.into().0) - 1) as u8; - sercom.i2cm().baud.modify(|_, w| w.baud().bits(baud)); + s.sercom.i2cm().baud.modify(|_, w| w.baud().bits(baud)); - sercom.i2cm().ctrla.modify(|_, w| w.enable().set_bit()); + s.sercom.i2cm().ctrla.modify(|_, w| w.enable().set_bit()); // wait for configuration to take effect - #[cfg(feature = "samd20")] - while sercom.i2cm().status.read().syncbusy().bit_is_set() {} - #[cfg(not(feature = "samd20"))] - while sercom.i2cm().syncbusy.read().enable().bit_is_set() {} + while s.is_register_synced(i2c_reg_sync::Enable) {} // set the bus idle - sercom + s.sercom .i2cm() .status .modify(|_, w| w.busstate().bits(BUS_STATE_IDLE)); // wait for it to take effect - #[cfg(feature = "samd20")] - while sercom.i2cm().status.read().syncbusy().bit_is_set() {} - #[cfg(not(feature = "samd20"))] - while sercom.i2cm().syncbusy.read().sysop().bit_is_set() {} + while !s.is_register_synced(i2c_reg_sync::SysOp) {} } - Self { sda, scl, sercom } + s + } + + /// Wait for the registers synchronization + #[inline] + fn is_register_synced(&mut self, synced_reg: i2c_reg_sync) -> bool { + #[cfg(feature = "samd20")] + return !self.i2cm().status.read().syncbusy().bit_is_set(); + #[cfg(not(feature = "samd20"))] + match synced_reg { + reg_sync::Enable => !self.i2cm().syncbusy.read().enable().bit_is_set(), + reg_sync::SwRst => !self.i2cm().syncbusy.read().swrst().bit_is_set(), + reg_sync::SysOp=> !self.i2cm().syncbusy.read().sysop().bit_is_set(), + } } /// Breaks the sercom device up into its constituent pins and the SERCOM @@ -238,18 +245,11 @@ where self.status_to_err() } - fn wait_sync(&mut self) { - #[cfg(feature = "samd20")] - while self.i2cm().status.read().syncbusy().bit_is_set() {} - #[cfg(not(feature = "samd20"))] - while self.i2cm().syncbusy.read().sysop().bit_is_set() {} - } - fn cmd(&mut self, cmd: u8) { unsafe { self.i2cm().ctrlb.modify(|_, w| w.cmd().bits(cmd)); } - self.wait_sync(); + while !self.is_register_synced(i2c_reg_sync::SysOp) {} } fn cmd_stop(&mut self) { @@ -264,7 +264,7 @@ where w.cmd().bits(MASTER_ACT_READ) }); } - self.wait_sync(); + while !self.is_register_synced(i2c_reg_sync::SysOp) {} } fn i2cm(&mut self) -> &I2CM { diff --git a/hal/src/thumbv6m/sercom/v1/uart.rs b/hal/src/thumbv6m/sercom/v1/uart.rs index 4f01c547b2a..e7484b71c33 100644 --- a/hal/src/thumbv6m/sercom/v1/uart.rs +++ b/hal/src/thumbv6m/sercom/v1/uart.rs @@ -11,7 +11,7 @@ use crate::pac::sercom0::USART; use crate::pac::{PM, SERCOM0, SERCOM1}; #[cfg(feature = "samd2x")] use crate::pac::{SERCOM2, SERCOM3}; -#[cfg(any(feature = "samd20", feature = "min-samd21g"))] +#[cfg(feature = "min-samd2x")] use crate::pac::{SERCOM4, SERCOM5}; use crate::sercom::v1::pads::CompatiblePad; use crate::sercom::v2::*;