atsamd_hal::clock::v2

Module xosc

Source
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§

  • An external multipurpose crystal oscillator controller
  • Singleton token that can be exchanged for an Xosc

Enums§

Traits§

  • Type-level enum for the Xosc operating mode
  • Type-level enum identifying one of two possible Xoscs

Type Aliases§