gd32e2-hal 0.26.0

HAL for the GD32E23x series (Cortex-M23), currently the GD32E230
Documentation
//! System configuration: the registers that wire peripherals to each other
//! rather than to the outside world.
//!
//! Covers the boot mode, the interrupt latency, the SRAM parity error flag, the
//! `PA11`/`PA12` remap of packages below 32 pins and `EXTISS`, the latter
//! through [`ExtiLine::source`](crate::exti::ExtiLine::source).

#[cfg(not(pads_ge_lqfp32))]
use crate::gpio::{Active, Input, Pin};
use crate::pac;
use crate::rcu::Rcu;

/// The memory the chip booted from (`BOOT_MODE`).
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BootMode {
    /// Main flash: the application.
    MainFlash,
    /// System flash memory: the factory bootloader.
    SystemFlash,
    /// Embedded SRAM.
    Sram,
}

/// Owns the SYSCFG registers.
pub struct Syscfg {
    syscfg: pac::Syscfg,
}

impl Syscfg {
    /// Returns the peripheral. The clock stays on, since `CFGCMPEN` also feeds
    /// the comparator.
    pub fn release(self) -> pac::Syscfg {
        self.syscfg
    }

    /// Returns the memory the chip booted from, as latched at the last reset.
    pub fn boot_mode(&self) -> BootMode {
        match self.syscfg.cfg0().read().boot_mode().bits() {
            0b00 | 0b10 => BootMode::MainFlash,
            0b01 => BootMode::SystemFlash,
            0b11 => BootMode::Sram,
            _ => unreachable!(),
        }
    }

    /// Holds interrupt entry back to no sooner than `latency + 1` cycles of
    /// `hclk` after the interrupt pends. A value above the worst natural latency
    /// makes entry take the same time whatever the core was executing; `0`, the
    /// reset value, enters as early as possible.
    pub fn set_irq_latency(&mut self, latency: u8) {
        // SAFETY: the field is eight bits wide, so every `u8` is a latency.
        self.syscfg
            .cpu_irq_lat()
            .modify(|_, w| unsafe { w.irq_latency().bits(latency) });
    }

    /// Whether an SRAM parity error has been caught (`SRAM_PCEF`). Raised only
    /// while the check is on, see
    /// [`OptionBytes::sram_parity`](crate::fmc::OptionBytes::sram_parity).
    pub fn sram_pcef(&self) -> bool {
        self.syscfg.cfg2().read().sram_pcef().is_error()
    }
    /// Clears `SRAM_PCEF`.
    pub fn clear_sram_pcef(&mut self) {
        self.syscfg.cfg2().modify(|_, w| w.sram_pcef().clear());
    }

    /// Points EXTI line `line` at the port encoded by `code`.
    ///
    /// # Panics
    ///
    /// If `line` is above 15 — the lines above that have no source to select.
    pub(crate) fn set_extiss(&mut self, line: u8, code: u8) {
        match line {
            // SAFETY: `code` is an `ExtiPin::SS_CODE`, one of the port codes this
            // field takes.
            l @ 0..=3 => self.syscfg.extiss0().modify(|_, w| unsafe {
                match l {
                    0 => w.exti0_ss().bits(code),
                    1 => w.exti1_ss().bits(code),
                    2 => w.exti2_ss().bits(code),
                    _ => w.exti3_ss().bits(code),
                }
            }),
            // SAFETY: as above.
            l @ 4..=7 => self.syscfg.extiss1().modify(|_, w| unsafe {
                match l {
                    4 => w.exti4_ss().bits(code),
                    5 => w.exti5_ss().bits(code),
                    6 => w.exti6_ss().bits(code),
                    _ => w.exti7_ss().bits(code),
                }
            }),
            // SAFETY: as above.
            l @ 8..=11 => self.syscfg.extiss2().modify(|_, w| unsafe {
                match l {
                    8 => w.exti8_ss().bits(code),
                    9 => w.exti9_ss().bits(code),
                    10 => w.exti10_ss().bits(code),
                    _ => w.exti11_ss().bits(code),
                }
            }),
            // SAFETY: as above.
            l @ 12..=15 => self.syscfg.extiss3().modify(|_, w| unsafe {
                match l {
                    12 => w.exti12_ss().bits(code),
                    13 => w.exti13_ss().bits(code),
                    14 => w.exti14_ss().bits(code),
                    _ => w.exti15_ss().bits(code),
                }
            }),
            _ => unreachable!(),
        }
    }
}

#[cfg(not(pads_ge_lqfp32))]
impl Syscfg {
    /// Hands the `PA9`/`PA10` pads over to `PA11`/`PA12`, which come back as
    /// inputs.
    ///
    /// Packages below 32 pins bond one pair or the other on the same two pads,
    /// `PA9`/`PA10` after reset.
    pub fn remap_pa11_pa12<M9: Active, M10: Active>(
        &mut self,
        _pa9: Pin<'A', 9, M9>,
        _pa10: Pin<'A', 10, M10>,
    ) -> (Pin<'A', 11, Input>, Pin<'A', 12, Input>) {
        let pins = (Pin::take_as_input(), Pin::take_as_input());
        self.syscfg
            .cfg0()
            .modify(|_, w| w.pa11_pa12_rmp().set_bit());
        pins
    }
    /// Gives the pads back to `PA9`/`PA10`, which come back as inputs.
    pub fn unmap_pa11_pa12<M11: Active, M12: Active>(
        &mut self,
        _pa11: Pin<'A', 11, M11>,
        _pa12: Pin<'A', 12, M12>,
    ) -> (Pin<'A', 9, Input>, Pin<'A', 10, Input>) {
        let pins = (Pin::take_as_input(), Pin::take_as_input());
        self.syscfg
            .cfg0()
            .modify(|_, w| w.pa11_pa12_rmp().clear_bit());
        pins
    }
}

/// Takes the raw peripheral into [`Syscfg`].
pub trait SyscfgExt {
    /// Switches the SYSCFG clock on and hands back the owning type.
    ///
    /// The clock bit is shared with the comparator, so CMP is clocked too; see
    /// [`Rcu::enable_cfgcmp`].
    fn constrain(self, rcu: &mut Rcu) -> Syscfg;
}

impl SyscfgExt for pac::Syscfg {
    fn constrain(self, rcu: &mut Rcu) -> Syscfg {
        rcu.enable_cfgcmp();
        Syscfg { syscfg: self }
    }
}