rlvgl 0.2.4

A modular, idiomatic Rust reimplementation of the LVGL graphics library for embedded and simulator use.
Documentation
//! Clock tree initialization for {{ ir.board.name }}.
//!
//! Peripheral clock gating on {{ ir.chip.name }} is **two-step** per
//! CHIPS-MICROCHIP-00 §6 INV-MC1 — the SAM D-class clock controller
//! splits responsibility between MCLK and GCLK:
//!
//! 1. `MCLK.APBxMASK` ungates the bus clock for the peripheral. The
//!    `apba` / `apbb` / `apbc` / `apbd` mask register is named per
//!    peripheral in the chip yaml's `clock_tree.mclk_gates:` table.
//!    The pinned `atsamd51j19a 0.7.1` PAC exposes these as direct
//!    register-block fields (`p.MCLK.apbamask`), not method accessors.
//! 2. `GCLK.PCHCTRL[n]` selects the generic-clock generator and enables
//!    the functional clock. The channel index `n` comes from the chip
//!    yaml's `peripherals.<name>.gclk_pchctrl_id:` field; the default
//!    generator comes from `clock_tree.pchctrl_channels`. `pchctrl` is
//!    a fixed-size array (`[PCHCTRL; 48]`) on this PAC era, so we
//!    index it directly rather than via a `pchctrl(N)` method.
//!
//! AHB-only peripherals (USB on D5x) carry `mclk_field: null` in the
//! chip yaml and emit only the PCHCTRL write — their AHB clock is
//! always-on at reset.
//!
//! CPU frequency selection (XOSC0/XOSC1, DFLL48M, FDPLL0/1) is handled
//! by the bootloader / cortex-m-rt reset path; this code does not
//! reprogram the oscillators. See `board.rs` for the configured
//! frequencies.

use {{ ir.chip.pac_crate }} as pac;

/// Enable every peripheral used by this board.
///
/// Called by [`crate::pac::init`] as the first bring-up step, before PORT
/// PMUX configuration so that peripheral registers are writable. Each
/// used peripheral's `mclk_field:` and `gclk_pchctrl_id:` in the chip
/// yaml are looked up against `clock_tree.mclk_gates:` and
/// `clock_tree.pchctrl_channels:` respectively.
pub fn init() {
    let p = unsafe { pac::Peripherals::steal() };
    {% for name in peripherals_used %}
    {% set periph = ir.chip.peripherals[name] %}
    {% if periph %}
    // {{ name }} — class {{ periph.class }}
    {% if periph.mclk_field %}
    {% set gate = ir.chip.clock_tree.mclk_gates[name] %}
    {% if gate %}
    // Step 1: MCLK {{ gate.reg }} {{ gate.field }} bit (APB bus-clock gate)
    p.MCLK.{{ gate.reg }}.modify(|_, w| w.{{ gate.field }}().set_bit());
    {% else %}
    // {{ name }}: mclk_field set on peripheral but no entry in clock_tree.mclk_gates (TODO)
    {% endif %}
    {% else %}
    // {{ name }}: AHB-only (no APB gate write)
    {% endif %}
    {% if periph.gclk_pchctrl_id is not none %}
    // Step 2: GCLK PCHCTRL channel {{ periph.gclk_pchctrl_id }} — enable + select generator
    // (default generator from clock_tree.pchctrl_channels; override via board kernels map)
    p.GCLK.pchctrl[{{ periph.gclk_pchctrl_id }}].modify(|_, w| unsafe {
        w.gen().bits(0).chen().set_bit()
    });
    while p.GCLK.pchctrl[{{ periph.gclk_pchctrl_id }}].read().chen().bit_is_clear() {}
    {% else %}
    // {{ name }}: no functional GCLK (AHB-only or self-clocked)
    {% endif %}
    {% else %}
    // {{ name }}: not in chip IR peripherals map (TODO)
    {% endif %}
    {% endfor %}
}