use crate::gpio::{Input, Output};
use crate::pac::GIO_AON;
use core::marker::PhantomData;
pub const ACT_LED: u8 = 9;
pub struct Pin<const N: u8, MODE> {
_gio: GIO_AON,
_mode: PhantomData<MODE>,
}
impl<const N: u8> Pin<N, Input> {
pub fn new(gio: GIO_AON) -> Self {
const { Self::VALID_LINE };
Self {
_gio: gio,
_mode: PhantomData,
}
}
}
impl<const N: u8, MODE> Pin<N, MODE> {
const VALID_LINE: () = assert!(N <= 22, "gio_aon only has lines 0..=22");
pub fn into_output(self) -> Pin<N, Output> {
modify(N, IODIR, false);
Pin {
_gio: self._gio,
_mode: PhantomData,
}
}
pub fn into_input(self) -> Pin<N, Input> {
modify(N, IODIR, true);
Pin {
_gio: self._gio,
_mode: PhantomData,
}
}
pub unsafe fn assume_mode(gio: GIO_AON) -> Self {
const { Self::VALID_LINE };
Self {
_gio: gio,
_mode: PhantomData,
}
}
}
impl<const N: u8> embedded_hal::digital::ErrorType for Pin<N, Output> {
type Error = core::convert::Infallible;
}
impl<const N: u8> embedded_hal::digital::OutputPin for Pin<N, Output> {
fn set_low(&mut self) -> Result<(), Self::Error> {
modify(N, DATA, false);
Ok(())
}
fn set_high(&mut self) -> Result<(), Self::Error> {
modify(N, DATA, true);
Ok(())
}
}
impl<const N: u8> embedded_hal::digital::StatefulOutputPin for Pin<N, Output> {
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
Ok(read(N, DATA))
}
fn is_set_low(&mut self) -> Result<bool, Self::Error> {
Ok(!read(N, DATA))
}
}
impl<const N: u8> embedded_hal::digital::ErrorType for Pin<N, Input> {
type Error = core::convert::Infallible;
}
impl<const N: u8> embedded_hal::digital::InputPin for Pin<N, Input> {
fn is_high(&mut self) -> Result<bool, Self::Error> {
Ok(read(N, DATA))
}
fn is_low(&mut self) -> Result<bool, Self::Error> {
Ok(!read(N, DATA))
}
}
pub(crate) fn drive(n: u8, high: bool) {
modify(n, DATA, high);
modify(n, IODIR, false);
}
const BANK0_WIDTH: u8 = 17;
const BANK_BYTES: usize = 0x20;
const DATA: usize = 0x04;
const IODIR: usize = 0x08;
fn locate(n: u8, register: usize) -> (*mut u32, u32) {
let (bank, bit) = if n < BANK0_WIDTH {
(0, n)
} else {
(1, n - BANK0_WIDTH)
};
let address = GIO_AON::PTR as usize + bank * BANK_BYTES + register;
(address as *mut u32, 1 << bit)
}
fn read(n: u8, register: usize) -> bool {
let (address, bit) = locate(n, register);
unsafe { address.read_volatile() & bit != 0 }
}
fn modify(n: u8, register: usize, set: bool) {
let (address, bit) = locate(n, register);
unsafe {
let value = address.read_volatile();
address.write_volatile(if set { value | bit } else { value & !bit });
}
}