diff --git a/boards/arduino_mkr1000/src/lib.rs b/boards/arduino_mkr1000/src/lib.rs index 064a49aac82f..35b0cd4c45e4 100644 --- a/boards/arduino_mkr1000/src/lib.rs +++ b/boards/arduino_mkr1000/src/lib.rs @@ -16,7 +16,7 @@ use hal::time::Hertz; use hal::sercom::{PadPin, UART5}; pub use hal::common::*; -pub use hal::samd21::*; + pub use hal::target_device as pac; use gpio::{Floating, Input, PfD, Port}; diff --git a/boards/arduino_mkrvidor4000/src/lib.rs b/boards/arduino_mkrvidor4000/src/lib.rs index 41beec19a2dd..0f07f6b4bf77 100644 --- a/boards/arduino_mkrvidor4000/src/lib.rs +++ b/boards/arduino_mkrvidor4000/src/lib.rs @@ -14,7 +14,7 @@ use hal::prelude::*; use hal::*; pub use hal::common::*; -pub use hal::samd21::*; + pub use hal::target_device as pac; use gpio::{Floating, Input, Port}; diff --git a/boards/arduino_mkrzero/src/lib.rs b/boards/arduino_mkrzero/src/lib.rs index 94e23349c741..57ba9ed971c9 100644 --- a/boards/arduino_mkrzero/src/lib.rs +++ b/boards/arduino_mkrzero/src/lib.rs @@ -23,7 +23,7 @@ use hal::prelude::*; use hal::*; pub use hal::common::*; -pub use hal::samd21::*; + pub use hal::target_device as pac; use gpio::{Floating, Input, Port}; diff --git a/boards/arduino_nano33iot/src/lib.rs b/boards/arduino_nano33iot/src/lib.rs index c20d493c43e5..bafdc2c9fe2f 100644 --- a/boards/arduino_nano33iot/src/lib.rs +++ b/boards/arduino_nano33iot/src/lib.rs @@ -19,7 +19,7 @@ use hal::sercom::{I2CMaster4, PadPin, SPIMaster1, UART5}; use hal::time::Hertz; pub use hal::common::*; -pub use hal::samd21::*; + pub use hal::target_device as pac; #[cfg(feature = "usb")] diff --git a/boards/circuit_playground_express/src/lib.rs b/boards/circuit_playground_express/src/lib.rs index 880d2c5f1081..2a2f29bf645f 100644 --- a/boards/circuit_playground_express/src/lib.rs +++ b/boards/circuit_playground_express/src/lib.rs @@ -6,7 +6,7 @@ use hal::prelude::*; use hal::*; pub use hal::common::*; -pub use hal::samd21::*; + pub use hal::target_device as pac; use gpio::{Floating, Input, Output, Port, PushPull}; diff --git a/boards/feather_m0/src/lib.rs b/boards/feather_m0/src/lib.rs index bf75287dd8dd..3080b0b9656b 100644 --- a/boards/feather_m0/src/lib.rs +++ b/boards/feather_m0/src/lib.rs @@ -11,7 +11,7 @@ use hal::prelude::*; use hal::*; pub use hal::common::*; -pub use hal::samd21::*; + pub use hal::target_device as pac; use gpio::{Floating, Input, PfC, Port}; diff --git a/boards/gemma_m0/src/lib.rs b/boards/gemma_m0/src/lib.rs index 454220833a5e..b647ec5e5c73 100644 --- a/boards/gemma_m0/src/lib.rs +++ b/boards/gemma_m0/src/lib.rs @@ -11,7 +11,7 @@ use hal::prelude::*; use hal::*; pub use hal::common::*; -pub use hal::samd21::*; + pub use hal::target_device as pac; use gpio::{Floating, Input, PfD, Port}; diff --git a/boards/itsybitsy_m0/src/lib.rs b/boards/itsybitsy_m0/src/lib.rs index 62f9535826b0..db04eb25d7f5 100644 --- a/boards/itsybitsy_m0/src/lib.rs +++ b/boards/itsybitsy_m0/src/lib.rs @@ -14,7 +14,7 @@ use hal::prelude::*; use hal::*; pub use hal::common::*; -pub use hal::samd21::*; + pub use hal::target_device as pac; use gpio::{Floating, Input, PfC, Port}; diff --git a/boards/metro_m0/src/lib.rs b/boards/metro_m0/src/lib.rs index 5d4e2426f86b..e569a6aae52d 100644 --- a/boards/metro_m0/src/lib.rs +++ b/boards/metro_m0/src/lib.rs @@ -9,7 +9,7 @@ use hal::prelude::*; use hal::*; pub use hal::common::*; -pub use hal::samd21::*; + pub use hal::target_device as pac; use hal::clock::GenericClockController; diff --git a/boards/samd11_bare/src/lib.rs b/boards/samd11_bare/src/lib.rs index c81827fdaaa6..f4883f07677c 100644 --- a/boards/samd11_bare/src/lib.rs +++ b/boards/samd11_bare/src/lib.rs @@ -11,7 +11,7 @@ use hal::prelude::*; use hal::*; pub use hal::common::*; -pub use hal::samd11::*; + pub use hal::target_device as pac; use gpio::{Floating, Input, PfC, Port}; diff --git a/boards/samd21_mini/src/lib.rs b/boards/samd21_mini/src/lib.rs index 9eb101b746e9..8fa37ba59a00 100644 --- a/boards/samd21_mini/src/lib.rs +++ b/boards/samd21_mini/src/lib.rs @@ -8,7 +8,7 @@ pub use cortex_m_rt::entry; extern crate atsamd_hal as hal; pub use hal::common::*; -pub use hal::samd21::*; + pub use hal::target_device as pac; use hal::prelude::*; diff --git a/boards/serpente/src/lib.rs b/boards/serpente/src/lib.rs index f5cc261aa952..ccdaad95792c 100644 --- a/boards/serpente/src/lib.rs +++ b/boards/serpente/src/lib.rs @@ -11,7 +11,7 @@ use hal::prelude::*; use hal::*; pub use hal::common::*; -pub use hal::samd21::*; + pub use hal::target_device as pac; use gpio::{Floating, Input, PfC, Port}; diff --git a/boards/sodaq_one/src/lib.rs b/boards/sodaq_one/src/lib.rs index 375d04114b8c..b946f55ef80c 100644 --- a/boards/sodaq_one/src/lib.rs +++ b/boards/sodaq_one/src/lib.rs @@ -11,7 +11,7 @@ use hal::prelude::*; use hal::*; pub use hal::common::*; -pub use hal::samd21::*; + pub use hal::target_device as pac; use gpio::{Floating, Input, Port}; diff --git a/boards/sodaq_sara_aff/src/lib.rs b/boards/sodaq_sara_aff/src/lib.rs index edacba9f2632..fb4d731ea710 100644 --- a/boards/sodaq_sara_aff/src/lib.rs +++ b/boards/sodaq_sara_aff/src/lib.rs @@ -11,7 +11,7 @@ use hal::prelude::*; use hal::*; pub use hal::common::*; -pub use hal::samd21::*; + pub use hal::target_device as pac; use gpio::{Floating, Input, PfD, Port}; diff --git a/boards/trinket_m0/src/lib.rs b/boards/trinket_m0/src/lib.rs index 2c3885ab70e0..93a3a64b64d4 100644 --- a/boards/trinket_m0/src/lib.rs +++ b/boards/trinket_m0/src/lib.rs @@ -9,7 +9,7 @@ use hal::prelude::*; use hal::*; pub use hal::common::*; -pub use hal::samd21::*; + pub use hal::target_device as pac; use gpio::{self, *}; diff --git a/boards/wio_lite_mg126/src/lib.rs b/boards/wio_lite_mg126/src/lib.rs index 3a06b000b33b..8b9160ddf926 100644 --- a/boards/wio_lite_mg126/src/lib.rs +++ b/boards/wio_lite_mg126/src/lib.rs @@ -14,7 +14,7 @@ use hal::prelude::*; use hal::*; pub use hal::common::*; -pub use hal::samd21::*; + pub use hal::target_device as pac; use gpio::{self, *}; diff --git a/boards/xiao_m0/src/lib.rs b/boards/xiao_m0/src/lib.rs index 553a8d1a8bb2..32e9498f215b 100644 --- a/boards/xiao_m0/src/lib.rs +++ b/boards/xiao_m0/src/lib.rs @@ -6,7 +6,7 @@ pub extern crate atsamd_hal as hal; pub use cortex_m_rt::entry; pub use hal::common::*; -pub use hal::samd21::*; + pub use hal::target_device as pac; use hal::prelude::*; diff --git a/hal/src/samd21/calibration.rs b/hal/src/common/thumbv6m/calibration.rs similarity index 82% rename from hal/src/samd21/calibration.rs rename to hal/src/common/thumbv6m/calibration.rs index 25b7d90c62e2..fb4228206c42 100644 --- a/hal/src/samd21/calibration.rs +++ b/hal/src/common/thumbv6m/calibration.rs @@ -1,5 +1,6 @@ //! NVM Software Calibration Area Mapping -// See 10.3.2 NVM Software Calibration Area Mapping, page 46 +// For samd11, see 9.5 NVM Software Calibration Area Mapping, page 24 +// For samd21, see 10.3.2 NVM Software Calibration Area Mapping, page 46 use core::ptr; @@ -53,5 +54,8 @@ pub fn usb_transp_cal() -> u8 { /// USB TRIM calibration value. Should be written to USB PADCAL register. pub fn usb_trim_cal() -> u8 { - cal_with_errata(4, 23, 7, 7, 3) as u8 + #[cfg(feature = "samd11")] + return cal_with_errata(4, 23, 7, 7, 5) as u8; + #[cfg(feature = "samd21")] + return cal_with_errata(4, 23, 7, 7, 3) as u8; } diff --git a/hal/src/samd21/clock.rs b/hal/src/common/thumbv6m/clock.rs similarity index 94% rename from hal/src/samd21/clock.rs rename to hal/src/common/thumbv6m/clock.rs index 2da566646ab3..4c45b8c6d11c 100644 --- a/hal/src/samd21/clock.rs +++ b/hal/src/common/thumbv6m/clock.rs @@ -53,7 +53,8 @@ impl State { src: ClockSource, improve_duty_cycle: bool, ) { - // validate the divisor factor based on gclk ID (see 15.8.5) + // validate the divisor factor based on gclk ID (samd21 see 15.8.5, for samd11 + // see 14.8.5) let mut divisor_invalid = false; if gclk == GCLK1 { if divider as u32 >= 2_u32.pow(16) { @@ -160,6 +161,7 @@ impl GenericClockController { let mut state = State { gclk }; set_flash_to_half_auto_wait_state(nvmctrl); + #[cfg(feature = "samd21")] set_flash_manual_write(nvmctrl); enable_gclk_apb(pm); if use_external_crystal { @@ -222,6 +224,7 @@ impl GenericClockController { let mut state = State { gclk }; // No wait states needed <= 24 MHz @ 3.3v (ref. 37.12 NVM characteristics) + #[cfg(feature = "samd21")] set_flash_manual_write(nvmctrl); enable_gclk_apb(pm); @@ -386,6 +389,30 @@ impl GenericClockController { } } +// samd11 +#[cfg(feature = "samd11")] +clock_generator!( + (tcc0, Tcc0Clock, TCC0), + (tc1_tc2, Tc1Tc2Clock, TC1_TC2), + (sercom0_core, Sercom0CoreClock, SERCOM0_CORE), + (sercom1_core, Sercom1CoreClock, SERCOM1_CORE), + (sercom2_core, Sercom2CoreClock, SERCOM2_CORE), + (rtc, RtcClock, RTC), + (adc, AdcClock, ADC), + (wdt, WdtClock, WDT), + (eic, EicClock, EIC), + (evsys0, Evsys0Clock, EVSYS_0), + (evsys1, Evsys1Clock, EVSYS_1), + (evsys2, Evsys2Clock, EVSYS_2), + (evsys3, Evsys3Clock, EVSYS_3), + (evsys4, Evsys4Clock, EVSYS_4), + (evsys5, Evsys5Clock, EVSYS_5), + (ac_ana, AcAnaClock, AC_ANA), + (ac_dig, AcDigClock, AC_DIG), + (dac, DacClock, DAC), +); +// samd21 +#[cfg(feature = "samd21")] clock_generator!( (tcc0_tcc1, Tcc0Tcc1Clock, TCC0_TCC1), (tcc2_tc3, Tcc2Tc3Clock, TCC2_TC3), @@ -433,6 +460,7 @@ fn set_flash_to_half_auto_wait_state(nvmctrl: &mut NVMCTRL) { } /// Prevent automatic writes to flash by pointers to flash area +#[cfg(feature = "samd21")] fn set_flash_manual_write(nvmctrl: &mut NVMCTRL) { nvmctrl.ctrlb.modify(|_, w| w.manw().set_bit()); } @@ -544,6 +572,10 @@ fn configure_and_enable_dfll48m(sysctrl: &mut SYSCTRL, use_external_crystal: boo // usb correction is not set due to instability issues around // USB bus resets. TODO(twitchyliquid64): Maybe switch to OSC8M? + // + // TODO usb correction (still active for samd11??) + #[cfg(feature = "samd11")] + w.usbcrm().set_bit(); // bypass coarse lock (have calibration data) w.bplckc().set_bit() @@ -555,6 +587,7 @@ fn configure_and_enable_dfll48m(sysctrl: &mut SYSCTRL, use_external_crystal: boo // and finally enable it! sysctrl.dfllctrl.modify(|_, w| w.enable().set_bit()); + #[cfg(feature = "samd21")] if use_external_crystal { // wait for lock while sysctrl.pclksr.read().dflllckc().bit_is_clear() diff --git a/hal/src/common/thumbv6m/mod.rs b/hal/src/common/thumbv6m/mod.rs index 7001c6c46eb6..42f1820bd1a4 100644 --- a/hal/src/common/thumbv6m/mod.rs +++ b/hal/src/common/thumbv6m/mod.rs @@ -6,6 +6,10 @@ pub use reset_cause::*; mod serial_number; pub use serial_number::*; +pub mod calibration; +pub mod clock; +pub mod timer; + #[cfg(feature = "unproven")] pub mod adc; @@ -15,4 +19,8 @@ pub mod pwm; #[cfg(feature = "unproven")] pub mod watchdog; +#[cfg(feature = "usb")] +#[cfg(feature = "samd21")] +pub mod usb; + pub(crate) mod sercom; diff --git a/hal/src/samd21/timer.rs b/hal/src/common/thumbv6m/timer.rs similarity index 94% rename from hal/src/samd21/timer.rs rename to hal/src/common/thumbv6m/timer.rs index 2aa81c8e344b..7cc6557b8032 100644 --- a/hal/src/samd21/timer.rs +++ b/hal/src/common/thumbv6m/timer.rs @@ -1,6 +1,13 @@ //! Working with timer counter hardware +#[cfg(feature = "samd11")] +use crate::target_device::tc1::COUNT16; +#[cfg(feature = "samd21")] use crate::target_device::tc3::COUNT16; #[allow(unused)] +#[cfg(feature = "samd11")] +use crate::target_device::{PM, TC1}; +#[allow(unused)] +#[cfg(feature = "samd21")] use crate::target_device::{PM, TC3, TC4, TC5}; use crate::timer_params::TimerParams; use hal::timer::{CountDown, Periodic}; @@ -168,6 +175,13 @@ impl TimerCounter<$TC> } } +// samd11 +#[cfg(feature = "samd11")] +tc! { + TimerCounter1: (TC1, tc1_, Tc1Tc2Clock), +} +// samd21 +#[cfg(feature = "samd21")] tc! { TimerCounter3: (TC3, tc3_, Tcc2Tc3Clock), TimerCounter4: (TC4, tc4_, Tc4Tc5Clock), diff --git a/hal/src/samd21/usb/bus.rs b/hal/src/common/thumbv6m/usb/bus.rs similarity index 100% rename from hal/src/samd21/usb/bus.rs rename to hal/src/common/thumbv6m/usb/bus.rs diff --git a/hal/src/samd21/usb/devicedesc.rs b/hal/src/common/thumbv6m/usb/devicedesc.rs similarity index 100% rename from hal/src/samd21/usb/devicedesc.rs rename to hal/src/common/thumbv6m/usb/devicedesc.rs diff --git a/hal/src/samd21/usb/mod.rs b/hal/src/common/thumbv6m/usb/mod.rs similarity index 100% rename from hal/src/samd21/usb/mod.rs rename to hal/src/common/thumbv6m/usb/mod.rs diff --git a/hal/src/lib.rs b/hal/src/lib.rs index f5bd2884ac65..29c13c1485ac 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -76,16 +76,6 @@ macro_rules! dbgprint { pub mod common; pub use self::common::*; -#[cfg(feature = "samd11")] -pub mod samd11; -#[cfg(feature = "samd11")] -pub use self::samd11::*; - -#[cfg(feature = "samd21")] -pub mod samd21; -#[cfg(feature = "samd21")] -pub use self::samd21::*; - // The following modules are included purely for backward compatibility reasons. // Whenever major breaking changes are made to the HAL next, these modules // should be removed. diff --git a/hal/src/samd11/calibration.rs b/hal/src/samd11/calibration.rs deleted file mode 100644 index 0d207aa73771..000000000000 --- a/hal/src/samd11/calibration.rs +++ /dev/null @@ -1,57 +0,0 @@ -//! NVM Software Calibration Row Mapping -// See 9.5 NVM Software Calibration Area Mapping, page 24 - -use core::ptr; - -const ADDR: u32 = 0x806020u32; - -fn cal(addr_offset: u32, bit_shift: u32, bit_mask: u32) -> u32 { - unsafe { - let addr: *const u32 = (ADDR + addr_offset) as *const _; - let value = ptr::read(addr); - - (value >> bit_shift) & bit_mask - } -} - -fn cal_with_errata( - addr_offset: u32, - bit_shift: u32, - bit_mask: u32, - bad_val: u32, - def_val: u32, -) -> u32 { - let val = cal(addr_offset, bit_shift, bit_mask); - // if the value matches the bad value, use an alternative value - // specified in the the errata section of the datasheet - if val == bad_val { - def_val - } else { - val - } -} - -/// Returns the osc32k calibration value from the NVM calibration area -pub fn osc32k_cal() -> u8 { - cal(4, 6, 0x7f) as u8 -} - -/// Returns the dfll48m coarse calibration value -pub fn dfll48m_coarse_cal() -> u8 { - cal_with_errata(4, 26, 0x3f, 0x3f, 0x1f) as u8 -} - -/// USB TRANSN calibration value. Should be written to USB PADCAL register. -pub fn usb_transn_cal() -> u8 { - cal_with_errata(4, 13, 0x1f, 0x1f, 5) as u8 -} - -/// USB TRANSP calibration value. Should be written to USB PADCAL register. -pub fn usb_transp_cal() -> u8 { - cal_with_errata(4, 18, 0x1f, 0x1f, 29) as u8 -} - -/// USB TRIM calibration value. Should be written to USB PADCAL register. -pub fn usb_trim_cal() -> u8 { - cal_with_errata(4, 23, 7, 7, 5) as u8 -} diff --git a/hal/src/samd11/clock.rs b/hal/src/samd11/clock.rs deleted file mode 100644 index fc2d2db771f3..000000000000 --- a/hal/src/samd11/clock.rs +++ /dev/null @@ -1,539 +0,0 @@ -//! Configuring the system clock sources. -//! You will typically need to create an instance of `GenericClockController` -//! before you can set up most of the peripherals on the atsamd21 device. -//! The other types in this module are used to enforce at compile time -//! that the peripherals have been correctly configured. -use crate::target_device::gclk::clkctrl::GEN_A::*; -use crate::target_device::gclk::clkctrl::ID_A::*; -use crate::target_device::gclk::genctrl::SRC_A::*; -use crate::target_device::{self, GCLK, NVMCTRL, PM, SYSCTRL}; -use crate::time::{Hertz, U32Ext}; - -pub type ClockId = target_device::gclk::clkctrl::ID_A; -pub type ClockGenId = target_device::gclk::clkctrl::GEN_A; -pub type ClockSource = target_device::gclk::genctrl::SRC_A; - -/// Represents a configured clock generator. -/// Can be converted into the effective clock frequency. -/// Its primary purpose is to be passed in to methods -/// such as `GenericClockController::tcc2_tc3` to configure -/// the clock for a peripheral. -#[derive(Clone, Copy)] -pub struct GClock { - gclk: ClockGenId, - freq: Hertz, -} - -impl Into for GClock { - fn into(self) -> Hertz { - self.freq - } -} - -struct State { - gclk: GCLK, -} - -impl State { - fn reset_gclk(&mut self) { - self.gclk.ctrl.write(|w| w.swrst().set_bit()); - while self.gclk.ctrl.read().swrst().bit_is_set() - || self.gclk.status.read().syncbusy().bit_is_set() - {} - } - - fn wait_for_sync(&mut self) { - while self.gclk.status.read().syncbusy().bit_is_set() {} - } - - fn set_gclk_divider_and_source( - &mut self, - gclk: ClockGenId, - divider: u16, - src: ClockSource, - improve_duty_cycle: bool, - ) { - // validate the divisor factor based on gclk ID (see 14.8.5) - let mut divisor_invalid = false; - if gclk == GCLK1 { - if divider as u32 >= 2_u32.pow(16) { - divisor_invalid = true; - } - } else if gclk == GCLK2 { - if divider >= 2_u16.pow(5) { - divisor_invalid = true; - } - } else { - if divider >= 2_u16.pow(8) { - divisor_invalid = true; - } - } - if divisor_invalid { - panic!("invalid divisor {} for GCLK {}", divider, gclk as u8); - } - - self.gclk.gendiv.write(|w| unsafe { - w.id().bits(u8::from(gclk)); - w.div().bits(divider) - }); - self.wait_for_sync(); - - self.gclk.genctrl.write(|w| unsafe { - w.id().bits(u8::from(gclk)); - w.src().bits(u8::from(src)); - // divide directly by divider, rather than exponential - w.divsel().clear_bit(); - w.idc().bit(improve_duty_cycle); - w.genen().set_bit(); - w.oe().set_bit() - }); - self.wait_for_sync(); - } - - fn enable_clock_generator(&mut self, clock: ClockId, generator: ClockGenId) { - self.gclk.clkctrl.write(|w| unsafe { - w.id().bits(u8::from(clock)); - w.gen().bits(u8::from(generator)); - w.clken().set_bit() - }); - self.wait_for_sync(); - } - - fn configure_standby(&mut self, gclk: ClockGenId, enable: bool) { - // We must first read out the configuration of genctrl to read/modify/write it. - // To do so, we must do an 8-bit write to GENCTRL.ID (ref 15.6.4.1 Indirect - // Access). 32-bit write did not work. - unsafe { - let genctrl_ptr_u8: *mut u8 = self.gclk.genctrl.as_ptr() as *mut u8; - *genctrl_ptr_u8 = u8::from(gclk); - } - self.wait_for_sync(); - - // Now that the configuration is loaded, modify it - self.gclk.genctrl.modify(|_, w| w.runstdby().bit(enable)); - self.wait_for_sync(); - } -} - -/// `GenericClockController` encapsulates the GCLK hardware. -/// It provides a type safe way to configure the system clocks. -/// Initializing the `GenericClockController` instance configures -/// the system to run at 48Mhz by setting gclk1 as a 32khz source -/// and feeding it into the DFLL48 hardware which in turn drives -/// gclk0 at 48Mhz. -pub struct GenericClockController { - state: State, - gclks: [Hertz; 8], - used_clocks: u64, -} - -impl GenericClockController { - /// Reset the clock controller, configure the system to run - /// at 48Mhz and reset various clock dividers. - pub fn with_internal_32kosc( - gclk: GCLK, - pm: &mut PM, - sysctrl: &mut SYSCTRL, - nvmctrl: &mut NVMCTRL, - ) -> Self { - Self::new_48mhz_from_32khz(gclk, pm, sysctrl, nvmctrl, false) - } - - /// Reset the clock controller, configure the system to run - /// at 48Mhz and reset various clock dividers. - pub fn with_external_32kosc( - gclk: GCLK, - pm: &mut PM, - sysctrl: &mut SYSCTRL, - nvmctrl: &mut NVMCTRL, - ) -> Self { - Self::new_48mhz_from_32khz(gclk, pm, sysctrl, nvmctrl, true) - } - - fn new_48mhz_from_32khz( - gclk: GCLK, - pm: &mut PM, - sysctrl: &mut SYSCTRL, - nvmctrl: &mut NVMCTRL, - use_external_crystal: bool, - ) -> Self { - let mut state = State { gclk }; - - set_flash_to_half_auto_wait_state(nvmctrl); - enable_gclk_apb(pm); - if use_external_crystal { - enable_external_32kosc(sysctrl); - } else { - enable_internal_32kosc(sysctrl); - } - - state.reset_gclk(); - - // Enable a 32khz source -> GCLK1 - if use_external_crystal { - state.set_gclk_divider_and_source(GCLK1, 1, XOSC32K, false); - } else { - state.set_gclk_divider_and_source(GCLK1, 1, OSC32K, false); - } - - // Feed 32khz into the DFLL48 - state.enable_clock_generator(DFLL48, GCLK1); - // Enable the DFLL48 - configure_and_enable_dfll48m(sysctrl, use_external_crystal); - // Feed DFLL48 into the main clock - state.set_gclk_divider_and_source(GCLK0, 1, DFLL48M, true); - // We are now running at 48Mhz - - // Reset various dividers back to 1 - sysctrl.osc8m.modify(|_, w| { - w.presc()._0(); - w.ondemand().clear_bit() - }); - pm.cpusel.write(|w| w.cpudiv().div1()); - pm.apbasel.write(|w| w.apbadiv().div1()); - pm.apbbsel.write(|w| w.apbbdiv().div1()); - pm.apbcsel.write(|w| w.apbcdiv().div1()); - - Self { - state, - gclks: [ - OSC48M_FREQ, - OSC32K_FREQ, - Hertz(0), - Hertz(0), - Hertz(0), - Hertz(0), - Hertz(0), - Hertz(0), - ], - used_clocks: 1u64 << u8::from(ClockId::DFLL48), - } - } - - /// Reset the clock controller, configure the system to run at 8Mhz from - /// internal 8 MHz RC clock (no PLL) and reset various clock dividers. - pub fn with_internal_8mhz( - gclk: GCLK, - pm: &mut PM, - sysctrl: &mut SYSCTRL, - _nvmctrl: &mut NVMCTRL, - ) -> Self { - let mut state = State { gclk }; - - // No wait states needed <= 24 MHz @ 3.3v (ref. 35.11 NVM characteristics) - enable_gclk_apb(pm); - - state.reset_gclk(); - - // Enable 8 MHz source -> GCLK0 - state.set_gclk_divider_and_source(GCLK0, 1, OSC8M, false); - - // Reset various dividers back to 1 - sysctrl.osc8m.modify(|_, w| { - w.presc()._0(); - w.ondemand().clear_bit() - }); - pm.cpusel.write(|w| w.cpudiv().div1()); - pm.apbasel.write(|w| w.apbadiv().div1()); - pm.apbbsel.write(|w| w.apbbdiv().div1()); - pm.apbcsel.write(|w| w.apbcdiv().div1()); - - Self { - state, - gclks: [ - OSC8M_FREQ, - Hertz(0), - Hertz(0), - Hertz(0), - Hertz(0), - Hertz(0), - Hertz(0), - Hertz(0), - ], - used_clocks: 0, - } - } - - /// Returns a `GClock` for gclk0, the system clock generator at 48Mhz - pub fn gclk0(&mut self) -> GClock { - GClock { - gclk: GCLK0, - freq: self.gclks[0], - } - } - - /// Returns a `GClock` for gclk1, the 32Khz oscillator. - pub fn gclk1(&mut self) -> GClock { - GClock { - gclk: GCLK1, - freq: self.gclks[1], - } - } - - /// Returns the `GClock` for the specified clock generator. - /// If that clock generator has not yet been configured, - /// returns None. - pub fn get_gclk(&mut self, gclk: ClockGenId) -> Option { - let idx = u8::from(gclk) as usize; - if self.gclks[idx].0 == 0 { - None - } else { - Some(GClock { - gclk, - freq: self.gclks[idx], - }) - } - } - - /// Configures a clock generator with the specified divider and - /// source. - /// `divider` is a linear divider to be applied to the clock - /// source. While the hardware also supports an exponential divider, - /// this function doesn't expose that functionality at this time. - /// `improve_duty_cycle` is a boolean that, when set to true, enables - /// a 5o/50 duty cycle for odd divider values. - /// Returns a `GClock` for the configured clock generator. - /// Returns `None` if the clock generator has already been configured. - pub fn configure_gclk_divider_and_source( - &mut self, - gclk: ClockGenId, - divider: u16, - src: ClockSource, - improve_duty_cycle: bool, - ) -> Option { - let idx = u8::from(gclk) as usize; - if self.gclks[idx].0 != 0 { - return None; - } - self.state - .set_gclk_divider_and_source(gclk, divider, src, improve_duty_cycle); - let freq: Hertz = match src { - XOSC32K | OSC32K | OSCULP32K => OSC32K_FREQ, - GCLKGEN1 => self.gclks[1], - OSC8M => OSC8M_FREQ, - DFLL48M => OSC48M_FREQ, - DPLL96M => 96.mhz().into(), - GCLKIN | XOSC => unimplemented!(), - }; - self.gclks[idx] = Hertz(freq.0 / divider as u32); - Some(GClock { gclk, freq }) - } - - /// Enables or disables the given GClk from operation in standby. - pub fn configure_standby(&mut self, gclk: ClockGenId, enable: bool) { - self.state.configure_standby(gclk, enable) - } -} - -macro_rules! clock_generator { - ($(($id:ident, $Type:ident, $clock:ident),)+) => { - -$( -/// A typed token that indicates that the clock for the peripheral(s) -/// with the matching name has been configured. -/// The effective clock frequency is available via the `freq` method, -/// or by converting the object into a `Hertz` instance. -/// The peripheral initialization code will typically require passing -/// in this object to prove at compile time that the clock has been -/// correctly initialized. -#[derive(Debug)] -pub struct $Type { - freq: Hertz, -} - -impl $Type { - /// Returns the frequency of the configured clock - pub fn freq(&self) -> Hertz { - self.freq - } -} -impl Into for $Type { - fn into(self) -> Hertz { - self.freq - } -} -)+ - -impl GenericClockController { - $( - /// Configure the clock for peripheral(s) that match the name - /// of this function to use the specific clock generator. - /// The `GClock` parameter may be one of default clocks - /// return from `gclk0()`, `gclk1()` or a clock configured - /// by the host application using the `configure_gclk_divider_and_source` - /// method. - /// Returns a typed token that proves that the clock has been configured; - /// the peripheral initialization code will typically require that this - /// clock token be passed in to ensure that the clock has been initialized - /// appropriately. - /// Returns `None` is the specified generic clock has already been - /// configured. - pub fn $id(&mut self, generator: &GClock) -> Option<$Type> { - let bits : u64 = 1< { - freq: Hertz, - tc: TC, -} - -/// This is a helper trait to make it easier to make most of the -/// TimerCounter impl generic. It doesn't make too much sense to -/// to try to implement this trait outside of this module. -pub trait Count16 { - fn count_16(&self) -> &COUNT16; -} - -impl Periodic for TimerCounter {} -impl CountDown for TimerCounter -where - TC: Count16, -{ - type Time = Nanoseconds; - - fn start(&mut self, timeout: T) - where - T: Into, - { - let params = TimerParams::new_us(timeout, self.freq.0); - let divider = params.divider; - let cycles = params.cycles; - - let count = self.tc.count_16(); - - // Disable the timer while we reconfigure it - count.ctrla.modify(|_, w| w.enable().clear_bit()); - while count.status.read().syncbusy().bit_is_set() {} - - // Now that we have a clock routed to the peripheral, we - // can ask it to perform a reset. - count.ctrla.write(|w| w.swrst().set_bit()); - while count.status.read().syncbusy().bit_is_set() {} - // the SVD erroneously marks swrst as write-only, so we - // need to manually read the bit here - while count.ctrla.read().bits() & 1 != 0 {} - - count.ctrlbset.write(|w| { - // Count up when the direction bit is zero - w.dir().clear_bit(); - // Periodic - w.oneshot().clear_bit() - }); - - // Set TOP value for mfrq mode - count.cc[0].write(|w| unsafe { w.cc().bits(cycles as u16) }); - - count.ctrla.modify(|_, w| { - match divider { - 1 => w.prescaler().div1(), - 2 => w.prescaler().div2(), - 4 => w.prescaler().div4(), - 8 => w.prescaler().div8(), - 16 => w.prescaler().div16(), - 64 => w.prescaler().div64(), - 256 => w.prescaler().div256(), - 1024 => w.prescaler().div1024(), - _ => unreachable!(), - }; - // Enable Match Frequency Waveform generation - w.wavegen().mfrq(); - w.enable().set_bit(); - w.runstdby().set_bit() - }); - } - - fn wait(&mut self) -> nb::Result<(), Void> { - let count = self.tc.count_16(); - if count.intflag.read().ovf().bit_is_set() { - // Writing a 1 clears the flag - count.intflag.modify(|_, w| w.ovf().set_bit()); - Ok(()) - } else { - Err(nb::Error::WouldBlock) - } - } -} - -impl InterruptDrivenTimer for TimerCounter -where - TC: Count16, -{ - /// Enable the interrupt generation for this hardware timer. - /// This method only sets the clock configuration to trigger - /// the interrupt; it does not configure the interrupt controller - /// or define an interrupt handler. - fn enable_interrupt(&mut self) { - self.tc.count_16().intenset.write(|w| w.ovf().set_bit()); - } - - /// Disables interrupt generation for this hardware timer. - /// This method only sets the clock configuration to prevent - /// triggering the interrupt; it does not configure the interrupt - /// controller. - fn disable_interrupt(&mut self) { - self.tc.count_16().intenclr.write(|w| w.ovf().set_bit()); - } -} - -macro_rules! tc { - ($($TYPE:ident: ($TC:ident, $pm:ident, $clock:ident),)+) => { - $( -pub type $TYPE = TimerCounter<$TC>; - -impl Count16 for $TC { - fn count_16(&self) -> &COUNT16 { - self.count16() - } -} - -impl TimerCounter<$TC> -{ - /// Configure this timer counter instance. - /// The clock is obtained from the `GenericClockController` instance - /// and its frequency impacts the resolution and maximum range of - /// the timeout values that can be passed to the `start` method. - /// Note that some hardware timer instances share the same clock - /// generator instance and thus will be clocked at the same rate. - pub fn $pm(clock: &clock::$clock, tc: $TC, pm: &mut PM) -> Self { - // this is safe because we're constrained to just the tc3 bit - pm.apbcmask.modify(|_, w| w.$pm().set_bit()); - { - let count = tc.count_16(); - - // Disable the timer while we reconfigure it - count.ctrla.modify(|_, w| w.enable().clear_bit()); - while count.status.read().syncbusy().bit_is_set() {} - } - Self { - freq: clock.freq(), - tc, - } - } -} - )+ - } -} - -tc! { - TimerCounter1: (TC1, tc1_, Tc1Tc2Clock), -} diff --git a/hal/src/samd21/mod.rs b/hal/src/samd21/mod.rs deleted file mode 100644 index f6cf0f4d47bb..000000000000 --- a/hal/src/samd21/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod calibration; -pub mod clock; -pub mod timer; - -#[cfg(feature = "usb")] -pub mod usb;