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
clockOscUlp1k
OscUlp32kBase
clockOscUlp32k
Enums
OscUlp1k
clockOscUlp32k
clock