Expand description
Advanced high performance bus clocks
Overview
AHB clocks facilitate communication between the processor core and
peripherals on the AHB bus. To communicate with a peripheral, the
corresponding AHB clock must be enabled, which is done by setting a bit in
the AHBMASK
register.
In this module, enabled AHB clocks are represented by the AhbClk<A>
struct, where the type parameter A
is a type that implements AhbId
and
corresponds to one of the bits in the AHBMASK
register.
While most other clocks in the clock
module are configured through
mutually exclusive registers, the AhbClk
s share a single AHBMASK
register. This presents a challenge for memory safety. Specifically, if we
allowed unrestricted access to the AHBMASK
register through each AhbClk
,
we could create data races.
To solve this problem, we restrict access to the AHBMASK
register using
the Ahb
type. Ahb
was created to act as a gateway to the AHBMASK
register, allowing us to use &mut Ahb
as compile-time proof of exclusive
access to it.
Example
Enabling and disabling the AhbClk
s 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,
},
pac::Peripherals,
};
let mut pac = Peripherals::take().unwrap();
let (mut buses, clocks, tokens) = clock_system_at_reset(
pac.OSCCTRL,
pac.OSC32KCTRL,
pac.GCLK,
pac.MCLK,
&mut pac.NVMCTRL,
);
All AHB clocks are enabled at power-on reset. We can find them in the
Clocks
struct.
let ahb_qspi = clocks.ahbs.qspi;
To disable an AhbClk
, we must have access to the Ahb
bus type, which
is found in the Buses
struct. As described above, Ahb
mediates
access to the shared AHBMASK
register. We call Ahb::disable
to convert
an AhbClk
into the corresponding AhbToken
.
let ahb_qspi = buses.ahb.disable(ahb_qspi);
To reenable an AhbClk
, users must save the AhbToken
and use it when
calling Ahb::enable
.
The complete example is shown below.
use atsamd_hal::{
clock::v2::{
clock_system_at_reset,
},
pac::Peripherals,
};
let mut pac = Peripherals::take().unwrap();
let (mut buses, clocks, tokens) = clock_system_at_reset(
pac.OSCCTRL,
pac.OSC32KCTRL,
pac.GCLK,
pac.MCLK,
&mut pac.NVMCTRL,
);
let ahb_qspi = clocks.ahbs.qspi;
let ahb_qspi = buses.ahb.disable(ahb_qspi);