Expand description
Internal, ultra low power, 32 kHz oscillator
Overview
The osculp32k module provides access to the 32 kHz ultra low power
internal oscillator (OSCULP32K) within the OSC32KCTRL peripheral.
The OSCULP32K clock is unlike most other clocks. First, it is an internal
clock that is always enabled and can’t be disabled. And second, it has two
separate outputs, one at 32 kHz and another divided down to 1 kHz. Moreover,
none, either or both of these outputs can be enabled at any given time.
We can see, then, that the OSCULP32K peripheral forms its own, miniature
clock tree. There is a 1:N producer clock that is always enabled; and there
are two possible consumer clocks that can be independently and optionally
enabled. In fact, this structure is illustrated by the OSCULP32K
register, which has no regular ENABLE bit and two different enable bits
for clock output, EN32K and EN1K.
To represent this structure in the type system, we divide the OSCULP32K
peripheral into these three clocks. Users get access to the 1:N
EnabledOscUlp32kBase clock Source at power-on reset, which can be
consumed by both the OscUlp32k and OscUlp1k clocks. Note that
OscUlp32k and OscUlp1k are themselves 1:N clocks as well.
Write lock
Rhe OSCULP32K register has a dedicated write lock bit that will freeze its
configuration until the next power-on reset. We implement this by simply
dropping the OscUlp32kBase clock, which prevents any further access to
the OSCULP32K register.
Example
Creating and configuring the OSCULP32K clocks proceeds according to the
principles outlined in the clock module documentation. It is best shown
with an example.
Let’s start by using clock_system_at_reset to access the HAL clocking
structs.
use atsamd_hal::{
    clock::v2::{
        clock_system_at_reset,
        osculp32k::{OscUlp1k, OscUlp32k},
    },
    pac::Peripherals,
};
let mut pac = Peripherals::take().unwrap();
let (buses, clocks, tokens) = clock_system_at_reset(
    pac.OSCCTRL,
    pac.OSC32KCTRL,
    pac.GCLK,
    pac.MCLK,
    &mut pac.NVMCTRL,
);Next, we can extract the EnabledOscUlp32kBase clock from the Clocks
struct and use it to enable the OscUlp1k and OscUlp32k clocks.
let base = clocks.osculp32k_base;
let (osculp1k, base) = OscUlp1k::enable(tokens.osculp32k.osculp1k, base);
let (osculp32k, base) = OscUlp32k::enable(tokens.osculp32k.osculp32k, base);We can then override the calibration value read from flash at start up.
base.set_calibration(128);And finally, we can set the write lock bit to freeze the configuation until
the next power-on reset. Doing so also drops the EnabledOscUlp32kBase
clock.
base.write_lock();The complete example is shown below.
use atsamd_hal::{
    clock::v2::{
        clock_system_at_reset,
        osculp32k::{OscUlp1k, OscUlp32k},
    },
    pac::Peripherals,
};
let mut pac = Peripherals::take().unwrap();
let (buses, clocks, tokens) = clock_system_at_reset(
    pac.OSCCTRL,
    pac.OSC32KCTRL,
    pac.GCLK,
    pac.MCLK,
    &mut pac.NVMCTRL,
);
let base = clocks.osculp32k_base;
let (osculp1k, base) = OscUlp1k::enable(tokens.osculp32k.osculp1k, base);
let (osculp32k, mut base) = OscUlp32k::enable(tokens.osculp32k.osculp32k, base);
base.set_calibration(128);
base.write_lock();Structs
OscUlp32kBase clockOscUlp1kOscUlp32kBase clockOscUlp32kEnums
OscUlp1k clockOscUlp32k clock