Expand description
External multipurpose crystal oscillator controller
Overview
The xosc module provides access to the two external crystal oscillator
controllers (XOSCs) within the OSCCTRL peripheral.
Each XOSC peripheral can operate in two Modes. It can accept an external
clock or can interface with an crystal oscillator. In both cases, the clock
must be in the 8-48 MHz range.
When used with an external clock, only one GPIO Pin is required, but
when used with a crystal oscillator, two GPIO Pins are required. The
XIn Pin is used in both Modes, while the XOut Pin is only
used in CrystalMode.
When operating in CrystalMode, the XOSC peripheral provides several
configuration options to increase stability or reduce power consumption of
the crystal.
The XOSC peripheral can also detect failure of the clock or crystal; and if failure occurs, it can automatically switch to a safe, backup clock derived from the DFLL.
Creating and configuring an Xosc proceeds according to the principles
outlined in the clock module documentation. It is best shown with an
example.
Example
Let’s start by using clock_system_at_reset to access the HAL clocking
structs. We’ll also need access to the GPIO Pins.
use atsamd_hal::{
    clock::v2::{
        clock_system_at_reset,
        xosc::{CrystalCurrent, SafeClockDiv, StartUpDelay, Xosc},
    },
    gpio::Pins,
    pac::Peripherals,
    time::U32Ext,
};
let mut pac = Peripherals::take().unwrap();
let pins = Pins::new(pac.PORT);
let (buses, clocks, tokens) = clock_system_at_reset(
    pac.OSCCTRL,
    pac.OSC32KCTRL,
    pac.GCLK,
    pac.MCLK,
    &mut pac.NVMCTRL,
);Next, we can create and configure the Xosc in one long chain of methods,
using the provided builder API. The final call to Xosc::enable yields an
EnabledXosc that can act as a clock Source for other clocks in the
tree.
let mut xosc = Xosc::from_crystal(tokens.xosc0, pins.pa14, pins.pa15, 20.mhz())
    .current(CrystalCurrent::Medium)
    .loop_control(true)
    .low_buf_gain(true)
    .start_up_delay(StartUpDelay::Delay488us)
    .enable();We start by calling Xosc::from_crystal, and we provide the corresponding
XIn and XOut Pins, as well as the nominal crystal frequency. We
then set the CrystalCurrent level to Medium. The default current level
for a 20 MHz signal is actually High, but we opt for a lower current under
the assumption that our crystal’s capacitive load is small. Next, we turn on
automatic loop control, which should save power, but we also set
LOWBUFGAIN to 1. Counterintuitively, this actually increases the
crystal amplitude, which increases power consumption, but it also improves
stability. We then apply a 488 μs start up delay, to allow the clock to
stabilize before it is applied to any logic. Finally, we enable the Xosc.
Next, we wait until the Xosc is stable and ready to be used as a clock
Source.
while !xosc.is_ready() {}Once the clock is stable, we can also enable failure detection. To do so, we
must provide the EnabledDfll to act as the backup safe clock. We can
also select a divider for the safe clock, so that it loosely matches the
Xosc frequency. In thise case, we divide the 48 MHz Dfll down to
24 MHz, which is the closest option to 20 MHz.
xosc.enable_failure_detection(clocks.dfll, SafeClockDiv::Div2);In the event of a clock failure, the Xosc would be automatically
switched to the safe clock, and EnabledXosc::has_failed would return
true. If the problem were later resolved, the Xosc could be switched back
to the crystal with EnabledXosc::switch_back.
The complete example is provided below.
use atsamd_hal::{
    clock::v2::{
        clock_system_at_reset,
        xosc::{CrystalCurrent, SafeClockDiv, StartUpDelay, Xosc},
    },
    gpio::Pins,
    pac::Peripherals,
    time::U32Ext,
};
let mut pac = Peripherals::take().unwrap();
let pins = Pins::new(pac.PORT);
let (buses, clocks, tokens) = clock_system_at_reset(
    pac.OSCCTRL,
    pac.OSC32KCTRL,
    pac.GCLK,
    pac.MCLK,
    &mut pac.NVMCTRL,
);
let mut xosc = Xosc::from_crystal(tokens.xosc0, pins.pa14, pins.pa15, 20.mhz())
    .current(CrystalCurrent::Medium)
    .loop_control(true)
    .low_buf_gain(true)
    .start_up_delay(StartUpDelay::Delay488us)
    .enable();
while !xosc.is_ready() {}
xosc.enable_failure_detection(clocks.dfll, SafeClockDiv::Div2);Structs
Enums
Xosc monitoring takes effectTraits
Type Definitions
EnabledXoscEnabledXosc