diff --git a/.ci/Dockerfile b/.ci/Dockerfile new file mode 100644 index 00000000..38424f13 --- /dev/null +++ b/.ci/Dockerfile @@ -0,0 +1,10 @@ +FROM rust:1.61.0-slim + +RUN apt-get update && apt-get install -y \ + binutils-arm-none-eabi \ + git \ + && rm -rf /var/lib/apt/lists/* + +RUN rustup target add thumbv7em-none-eabihf && \ + rustup component add rustfmt && \ + rustup component add clippy diff --git a/.ci/README.md b/.ci/README.md new file mode 100644 index 00000000..0479a062 --- /dev/null +++ b/.ci/README.md @@ -0,0 +1 @@ +This directory contains the `Dockerfile` used in the CI of the HAL. See [GitLab Container Registry documentation](https://git.grepit.se/embedded-rust/atsamx7x-hal/container_registry) for update instructions. diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..ad24e118 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,57 @@ +image: "registry.git.grepit.se/embedded-rust/atsamx7x-hal" + +stages: + - HAL + - examples + - lint + +default: + before_script: + - rustup show + +samv71q21b: + stage: HAL + script: + - cd hal + - cargo check --features samv71q21b,unproven + +same70n21b: + stage: HAL + script: + - cd hal + - cargo check --features same70n21b,unproven + +e70: + stage: examples + script: + - cd boards/atsame70_xpro + - cargo check --examples + +v71: + stage: examples + script: + - cd boards/atsamv71_xult + - cargo check --examples + +fmt: + stage: lint + needs: [] + script: + - cd hal + - cargo fmt -- --check + - cd ../boards/atsame70_xpro + - cargo fmt -- --check + - cd ../atsamv71_xult + - cargo fmt -- --check + +clippy: + stage: lint + allow_failure: true + needs: ["samv71q21b"] + script: + - cd hal + - cargo clippy --no-deps --features samv71q21b,unproven + - cd ../boards/atsame70_xpro + - cargo clippy --examples --no-deps + - cd ../atsamv71_xult + - cargo clippy --examples --no-deps diff --git a/hal/build.rs b/hal/build.rs index f8f900c8..a0428af9 100644 --- a/hal/build.rs +++ b/hal/build.rs @@ -6,7 +6,7 @@ fn main() -> Result<(), &'static str> { fn feat(f: &str) -> bool { env::var(format!( "CARGO_FEATURE_{}", - f.to_ascii_uppercase().replace("-", "_") + f.to_ascii_uppercase().replace('-', "_") )) .is_ok() } diff --git a/hal/src/efc.rs b/hal/src/efc.rs index be75ef14..e914e585 100644 --- a/hal/src/efc.rs +++ b/hal/src/efc.rs @@ -6,7 +6,7 @@ use crate::target_device::EFC; /// The voltage which drives the MCU. /// /// Refer to §58 and §59. -#[derive(PartialEq)] +#[derive(Eq, PartialEq)] pub enum VddioLevel { /// VDDIO = 3.3V, typical V3, @@ -49,7 +49,7 @@ impl Efc { /// The number of flash wait states for a read operation. /// /// Note: The number of cycles a read takes is 1 + FWS. -#[derive(Debug, PartialEq, Copy, Clone)] +#[derive(Debug, Eq, PartialEq, Copy, Clone)] #[repr(u8)] enum FlashWaitStates { Zero, diff --git a/hal/src/pio/bank.rs b/hal/src/pio/bank.rs index 8faa7877..6368afc8 100644 --- a/hal/src/pio/bank.rs +++ b/hal/src/pio/bank.rs @@ -97,18 +97,18 @@ impl Iterator for BankInterruptsIter { match self.idx { 32.. => { // We have iterated over all pins: nothing more to do. - return None; + None } idx if self.irq & (1 << idx) != 0 => { // Pin number `idx` had a pending interrupt. let pin = self.idx; - self.idx = self.idx + 1; + self.idx += 1; Some(pin) } _ => { // Pin number `idx` did not have a pending interrupt: // advance to the next pin. - self.idx = self.idx + 1; + self.idx += 1; self.next() } } @@ -253,28 +253,41 @@ macro_rules! bank { macro_rules! banks { ( $( + $( #[$cfg1:meta] )? $Bank:ident { $( - $( #[$cfg:meta] )? + $( #[$cfg2:meta] )? ($Id:ident, $NUM:literal), )+ } )+ ) => { $( - $( - $( #[$cfg] )? - pin_id!($Bank, $Id, $NUM); - )+ - bank!( - $Bank, - $( - $( #[$cfg] )? - $Id, - )+ - ); - impl PinBank for $Bank { - const DYN: DynBank = DynBank::$Bank; + paste! { + $( #[$cfg1] )? + mod [<$Bank:lower _impl>] { + use super::*; + + $( + $( #[$cfg2] )? + pin_id!($Bank, $Id, $NUM); + )+ + + bank!( + $Bank, + $( + $( #[$cfg2] )? + $Id, + )+ + ); + + impl PinBank for $Bank { + const DYN: DynBank = DynBank::$Bank; + } + + } + $( #[$cfg1] )? + pub use [<$Bank:lower _impl>]::*; } )+ }; @@ -288,6 +301,7 @@ banks!( (PA3, 3), (PA4, 4), (PA5, 5), + #[cfg(feature = "pins-144")] (PA6, 6), (PA7, 7), (PA8, 8), @@ -311,6 +325,7 @@ banks!( (PA26, 26), (PA27, 27), (PA28, 28), + #[cfg(feature = "pins-144")] (PA29, 29), (PA30, 30), (PA31, 31), @@ -331,6 +346,7 @@ banks!( (PB13, 13), } + #[cfg(feature = "pins-144")] C { (PC0, 0), (PC1, 1), @@ -390,17 +406,20 @@ banks!( (PD20, 20), (PD21, 21), (PD22, 22), + #[cfg(feature = "pins-144")] (PD23, 23), (PD24, 24), (PD25, 25), (PD26, 26), (PD27, 27), (PD28, 28), + #[cfg(feature = "pins-144")] (PD29, 29), (PD30, 30), (PD31, 31), } + #[cfg(feature = "pins-144")] E { (PE0, 0), (PE1, 1), diff --git a/hal/src/pio/dynpin.rs b/hal/src/pio/dynpin.rs index 1b669b6e..1d2bc15a 100644 --- a/hal/src/pio/dynpin.rs +++ b/hal/src/pio/dynpin.rs @@ -82,12 +82,14 @@ pub enum DynPinMode { /// Value-level `enum` regresenting [`Pin`] banks #[doc(hidden)] -#[derive(PartialEq, Clone, Copy)] +#[derive(Eq, PartialEq, Clone, Copy)] pub enum DynBank { A, B, + #[cfg(feature = "pins-144")] C, D, + #[cfg(feature = "pins-144")] E, } @@ -96,8 +98,10 @@ impl DynBank { match self { Self::A => PIOA::ptr(), Self::B => PIOB::ptr(), + #[cfg(feature = "pins-144")] Self::C => PIOC::ptr(), Self::D => PIOD::ptr(), + #[cfg(feature = "pins-144")] Self::E => PIOE::ptr(), } } @@ -105,7 +109,7 @@ impl DynBank { /// Value-level `struct` representing [`Pin`] IDs #[doc(hidden)] -#[derive(PartialEq, Clone, Copy)] +#[derive(Eq, PartialEq, Clone, Copy)] pub struct DynPinId { pub bank: DynBank, pub num: u8, diff --git a/hal/src/pio/mod.rs b/hal/src/pio/mod.rs index 6794cf2c..770a12cc 100644 --- a/hal/src/pio/mod.rs +++ b/hal/src/pio/mod.rs @@ -102,12 +102,13 @@ use crate::target_device::{ // All PIO banks below use the same register block definition. pioa::RegisterBlock, + // Banks common to all chip sizes. PIOA, PIOB, - PIOC, PIOD, - PIOE, }; +#[cfg(feature = "pins-144")] +use crate::target_device::{PIOC, PIOE}; pub mod pin; pub use pin::*; diff --git a/hal/src/pio/pin.rs b/hal/src/pio/pin.rs index 5387b43f..969bc0e1 100644 --- a/hal/src/pio/pin.rs +++ b/hal/src/pio/pin.rs @@ -20,7 +20,7 @@ pub(in crate::pio) struct Registers { id: PhantomData, } -unsafe impl RegisterInterface for Registers { +impl RegisterInterface for Registers { #[inline] fn id(&self) -> DynPinId { I::DYN @@ -226,21 +226,25 @@ where } #[inline] + #[allow(clippy::bool_comparison)] pub(in crate::pio) fn _is_written_high(&self) -> bool { self.regs.read_out_pin() == true } #[inline] + #[allow(clippy::bool_comparison)] pub(in crate::pio) fn _is_written_low(&self) -> bool { self.regs.read_out_pin() == false } #[inline] + #[allow(clippy::bool_comparison)] pub(in crate::pio) fn _is_read_high(&self) -> bool { self.regs.read_in_pin() == true } #[inline] + #[allow(clippy::bool_comparison)] pub(in crate::pio) fn _is_read_low(&self) -> bool { self.regs.read_in_pin() == false } diff --git a/hal/src/pio/reg.rs b/hal/src/pio/reg.rs index 4f92a12f..7a262bfd 100644 --- a/hal/src/pio/reg.rs +++ b/hal/src/pio/reg.rs @@ -2,7 +2,7 @@ use crate::target_device::pioa::RegisterBlock; use super::dynpin::*; -pub(in crate::pio) unsafe trait RegisterInterface { +pub(in crate::pio) trait RegisterInterface { fn id(&self) -> DynPinId; /// Return the `u32` mask to set/clear a bit for this @@ -21,14 +21,14 @@ pub(in crate::pio) unsafe trait RegisterInterface { fn change_mode(&mut self, mode: DynPinMode) { match mode { DynPinMode::Reset => unimplemented!(), - DynPinMode::Peripheral(a) => self.into_peripheral(a), - DynPinMode::Output => self.into_output(), - DynPinMode::Input => self.into_input(), + DynPinMode::Peripheral(a) => self.as_peripheral(a), + DynPinMode::Output => self.as_output(), + DynPinMode::Input => self.as_input(), } } #[inline] - fn into_peripheral(&mut self, cfg: DynPeripheral) { + fn as_peripheral(&mut self, cfg: DynPeripheral) { use DynPeripheral::*; let (sr0, sr1) = match cfg { A => (false, false), @@ -58,7 +58,7 @@ pub(in crate::pio) unsafe trait RegisterInterface { } #[inline] - fn into_output(&mut self) { + fn as_output(&mut self) { // set initial output state as low (0) self.write_pin(false); @@ -75,7 +75,7 @@ pub(in crate::pio) unsafe trait RegisterInterface { } #[inline] - fn into_input(&mut self) { + fn as_input(&mut self) { // take pin from peripheral self.reg().pio_per.write(|w| unsafe { w.bits(self.mask()) }); diff --git a/hal/src/pmc.rs b/hal/src/pmc.rs index fadeb054..08a08bf9 100644 --- a/hal/src/pmc.rs +++ b/hal/src/pmc.rs @@ -67,7 +67,7 @@ pub use crate::target_device::pmc::pmc_mckr::PRES_A as MckPrescaler; pub use crate::target_device::pmc::pmc_pck::CSS_A as PCK_CSS; /// Output divider for UPLLCK. -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, Eq, PartialEq, Clone)] pub enum UpllDivider { /// UPLLCK is divided by 1: input and output frequencies are /// equal. @@ -83,7 +83,7 @@ pub struct Pmc { } /// Possible errors that can occur on PMC configuration. -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, Eq, PartialEq, Clone)] pub enum PmcError { ClockingError(PeripheralIdentifier), InvalidConfiguration, @@ -500,7 +500,7 @@ impl Pmc { PllaConfig { div, mult }: PllaConfig, source: &SRC, ) -> Result { - if mult > 63 || mult < 2 { + if !(2..=63).contains(&mult) { return Err(PmcError::InvalidConfiguration); } if div == 0 || div > 127 { @@ -667,8 +667,9 @@ impl Pmc { for pid in pids { // Check if this supports PMC clocking - pid.supports_pmc_clocking() - .map_err(|_| PmcError::ClockingError(*pid))?; + if !pid.supports_pmc_clocking() { + return Err(PmcError::ClockingError(*pid)); + } let pid_val: u32 = (*pid) as u32; @@ -874,33 +875,32 @@ pub enum PeripheralIdentifier { } impl PeripheralIdentifier { - pub fn supports_pmc_clocking(&self) -> Result<(), ()> { + pub(crate) fn supports_pmc_clocking(&self) -> bool { use PeripheralIdentifier::*; // These pids don't support PMC clocking - match self { - SUPC => Err(()), - RSTC => Err(()), - RTC => Err(()), - RTT => Err(()), - WDT => Err(()), - PMC => Err(()), - EFC => Err(()), - MCAN0INT1 => Err(()), - MCAN1INT1 => Err(()), - MLB_IRQ1 => Err(()), - _RESERVED => Err(()), - ARM => Err(()), - SDRAMC => Err(()), - RSWDT => Err(()), - ARM_CACHE_ECC_WARNING => Err(()), - ARM_CACHE_ECC_FAULT => Err(()), - GMAC_Q1 => Err(()), - GMAC_Q2 => Err(()), - ARM_FPU_IXC_FPU => Err(()), - GMAC_Q3 => Err(()), - GMAC_Q4 => Err(()), - GMAC_Q5 => Err(()), - _ => Ok(()), - } + !matches!( + self, + SUPC | RSTC + | RTC + | RTT + | WDT + | PMC + | EFC + | MCAN0INT1 + | MCAN1INT1 + | MLB_IRQ1 + | _RESERVED + | ARM + | SDRAMC + | RSWDT + | ARM_CACHE_ECC_WARNING + | ARM_CACHE_ECC_FAULT + | GMAC_Q1 + | GMAC_Q2 + | ARM_FPU_IXC_FPU + | GMAC_Q3 + | GMAC_Q4 + | GMAC_Q5 + ) } } diff --git a/hal/src/serial/mod.rs b/hal/src/serial/mod.rs index a35aeaad..e3afce1b 100644 --- a/hal/src/serial/mod.rs +++ b/hal/src/serial/mod.rs @@ -3,7 +3,7 @@ use crate::fugit::{HertzU32 as Hertz, RateExtU32}; /// Bits per second -#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)] +#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Debug)] pub struct Bps(pub(crate) Hertz); /// [`u32`] type extension that adds convenience methods diff --git a/hal/src/serial/spi.rs b/hal/src/serial/spi.rs index f7032e6d..b79a5952 100644 --- a/hal/src/serial/spi.rs +++ b/hal/src/serial/spi.rs @@ -73,7 +73,9 @@ use crate::ehal::blocking; use crate::fugit::{ExtU32, NanosDurationU32 as NanosDuration}; use crate::pio::*; use crate::pmc::{HostClock, PeripheralIdentifier, Pmc}; -use crate::target_device::{spi0::RegisterBlock, SPI0, SPI1}; +#[cfg(feature = "pins-144")] +use crate::target_device::SPI1; +use crate::target_device::{spi0::RegisterBlock, SPI0}; use crate::{ehal, nb}; use ehal::spi::Mode; @@ -522,6 +524,7 @@ macro_rules! impl_spi { } } } + $( #[$cfg] )? pub use [<$Spi:lower _impl>]::*; )+ } @@ -612,7 +615,7 @@ impl<'spi, M: SpiMeta> blocking::spi::Transactional for Client<'spi, M> { use blocking::spi::Operation; let len = operations.len(); - for (i, o) in operations.into_iter().enumerate() { + for (i, o) in operations.iter_mut().enumerate() { let last_op = i == len - 1; if let Some(e) = match o { diff --git a/hal/src/serial/twi.rs b/hal/src/serial/twi.rs index e341c2cd..a63d61e3 100644 --- a/hal/src/serial/twi.rs +++ b/hal/src/serial/twi.rs @@ -80,7 +80,7 @@ pub struct Twi { meta: PhantomData, } -#[derive(PartialEq)] +#[derive(Eq, PartialEq)] enum TwiAction { Read, Write, @@ -113,15 +113,15 @@ impl Twi { let calc_div = |ckdiv| { (clk.freq() / conf.freq) .checked_sub(3) - .and_then(|v| Some(v / 2u32.pow(ckdiv))) + .map(|v| v / 2u32.pow(ckdiv)) }; let (ckdiv, div) = (0..0b11u8) .find_map(|ckdiv| { let div: u8 = calc_div(ckdiv as u32)?.try_into().ok()?; if div > 0 { - return Some((ckdiv, div)); + Some((ckdiv, div)) } else { - return None; + None } }) .ok_or(TwiError::ImpossibleFreq)?; diff --git a/hal/src/serial/uart.rs b/hal/src/serial/uart.rs index cf72f8f0..55f4b4b4 100644 --- a/hal/src/serial/uart.rs +++ b/hal/src/serial/uart.rs @@ -168,7 +168,7 @@ impl UartConfiguration { } } -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, Eq, PartialEq, Clone)] /// Possible [`Uart`] errors pub enum UartError { /// An impossible baud rate was requested. @@ -387,16 +387,19 @@ impl Uart { macro_rules! impl_uart { ( $( - $( #[$cfg:meta] )? + $( #[$cfg1:meta] )? $Uart:ident: { RX: [ $RxPin:ty ], - TX: [ $( $TxPin:ty, )+ ], + TX: [$( + $( #[$cfg2:meta] )? + $TxPin:ty, + )+], }, )+ ) => { paste! { $( - $( #[$cfg] )? + $( #[$cfg1] )? mod [<$Uart:lower _impl>] { use super::*; @@ -409,6 +412,7 @@ macro_rules! impl_uart { pub trait [<$Uart RxPin>] {} $( + $( #[$cfg2] )? impl [<$Uart TxPin>] for $TxPin {} )+ impl [<$Uart RxPin>] for $RxPin {} @@ -430,6 +434,7 @@ macro_rules! impl_uart { } } } + $( #[$cfg1] )? pub use [<$Uart:lower _impl>]::*; )+ } @@ -443,7 +448,12 @@ impl_uart!( }, Uart1: { RX: [ Pin ], - TX: [ Pin, Pin, Pin, ], + TX: [ + Pin, + #[cfg(feature = "pins-144")] + Pin, + Pin, + ], }, Uart2: { RX: [ Pin ], diff --git a/hal/src/usb.rs b/hal/src/usb.rs index f10ab8f4..dcc897d7 100644 --- a/hal/src/usb.rs +++ b/hal/src/usb.rs @@ -89,7 +89,7 @@ pub use usb_device; const NUM_ENDPOINTS: usize = 10; /// Endpoint configuration. -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, Eq, PartialEq)] struct EPConfig { ep_type: EndpointType, ep_dir: UsbDirection, @@ -106,7 +106,7 @@ impl EPConfig { } } -#[derive(Debug, PartialEq)] +#[derive(Debug, Eq, PartialEq)] struct Endpoints { ep_config: [Option; NUM_ENDPOINTS], } @@ -474,13 +474,13 @@ impl Inner { } if ep_out == 0 && ep_in_complete == 0 && ep_setup == 0 { - return PollResult::None; + PollResult::None } else { - return PollResult::Data { + PollResult::Data { ep_out, ep_in_complete, ep_setup, - }; + } } }