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 AhbClks 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 AhbClks 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);

Structs

AHB clock controller
An enabled AHB clock
Set of all AhbClks
Singleton token that can be exchanged for an AhbClk

Enums

Value-level enum identifying a single AHB clock

Traits

Type-level enum identifying one of the possible AHB clocks