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 Mode
s. 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 Pin
s are required. The
XIn
Pin
is used in both Mode
s, 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
Pin
s, 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
EnabledXosc
EnabledXosc