hk32-partial-hal 0.3.1

HK32 partial HAL
use crate::gpio::{AltFunc, AnyPin, Pin, Pull};
use embassy_hal_internal::Peri;

impl Pull {
    const fn to_pupdr(self) -> u32 {
        match self {
            Pull::None => 0,
            Pull::Up => 1,
            Pull::Down => 2,
        }
    }
}

/// GPIO flexible pin.
///
/// This pin can either be a disconnected, input, or output pin, or both. The level register bit will remain
/// set while not in output mode, so the pin's level will be 'remembered' when it is not in output
/// mode.
pub struct Flex<'d> {
    pub(crate) pin: Peri<'d, AnyPin>,
}

impl<'d> Flex<'d> {
    /// Wrap the pin in a `Flex`.
    ///
    /// The pin remains disconnected. The initial output level is unspecified, but can be changed
    /// before the pin is put into output mode.
    ///
    pub fn new(pin: Peri<'d, impl Pin>) -> Self {
        // Pin will be in disconnected state.
        Self { pin: pin.into() }
    }

    /// Put the pin into input mode.
    ///
    /// The internal weak pull-up and pull-down resistors will be enabled according to `pull`.
    #[inline(never)]
    pub fn set_as_input(&mut self, pull: Pull) {
        let r = self.pin.block();
        let n = 2 * self.pin.pin() as usize;

        r.pupdr()
            .modify(|w| w.0 = (w.0 & !(0x03 << n)) | (pull.to_pupdr() << n));
        r.moder().modify(|w| w.0 = w.0 & !(0x03 << n));
    }

    /// Put the pin into push-pull output mode.
    ///
    /// The pin level will be whatever was set before (or low by default). If you want it to begin
    /// at a specific level, call `set_high`/`set_low` on the pin first.
    ///
    /// The internal weak pull-up and pull-down resistors will be disabled.
    #[inline(never)]
    pub fn set_as_output(&self) {
        let r = self.pin.block();
        let n = 2 * self.pin.pin() as usize;

        r.ospeedr().modify(|w| w.0 |= 0x03 << n); //high speed
        r.pupdr().modify(|w| w.0 = w.0 & !(0x03 << n)); //no pull
        r.otyper().modify(|w| w.0 = w.0 & !(0x01 << (n >> 1))); //push-pull
        r.moder()
            .modify(|w| w.0 = (w.0 & !(0x03 << n)) | (0x01 << n));
    }

    #[inline(never)]
    pub fn set_as_input_output_pull(&self, pull: Pull) {
        let r = self.pin.block();
        let n = 2 * self.pin.pin() as usize;
        r.pupdr()
            .modify(|w| w.0 = (w.0 & !(0x03 << n)) | (pull.to_pupdr() << n));
        r.otyper().modify(|w| w.0 = w.0 | (0x01 << (n >> 1))); //OD
        r.moder()
            .modify(|w| w.0 = (w.0 & !(0x03 << n)) | (0x01 << n));
    }

    /// Put the pin into alternate function mode.
    #[inline(never)]
    pub fn set_as_alternate(&self, mode: AltFunc) {
        let r = self.pin.block();
        let pin_num = self.pin.pin() as usize;
        let n = 2 * pin_num;

        r.moder()
            .modify(|w| w.0 = (w.0 & !(0x03 << n)) | (0x02 << n));
        let afr = mode as u32;

        if self.pin.pin() < 8 {
            let n = 4 * pin_num;
            r.afrl().modify(|w| w.0 = (w.0 & !(0x0F << n)) | afr << n);
        } else {
            let n = 4 * pin_num;
            r.afrh().modify(|w| w.0 = (w.0 & !(0x0F << n)) | afr << n);
        }
    }
    /// Put the pin into analog mode.
    #[inline(never)]
    pub fn set_as_analog(&mut self) {
        let r = self.pin.block();
        let n = 2 * self.pin.pin() as usize;
        r.pupdr().modify(|w| w.0 = w.0 & !(0x03 << n));
        r.otyper().modify(|w| w.0 = w.0 | (0x01 << (n >> 1))); //OD
        r.moder().modify(|w| w.0 |= 0x03 << n);
    }
}