use super::gpio_cfg;
use crate::hal::digital::v2::{OutputPin, ToggleableOutputPin};
use core::convert::Infallible;
use core::marker::ConstParamTy;
use paste::paste;
#[derive(PartialEq, Eq)]
pub enum DriveStrength {
D2mA,
D4mA,
D8mA,
D12mA,
}
#[derive(PartialEq, Eq)]
pub enum OutputMode {
Disable = 0,
PushPull,
OpenDrain,
TriState,
}
#[derive(PartialEq, Eq)]
pub enum InputMode {
NoneOrAuto = 0, Enable = 1,
}
#[derive(PartialEq, Eq, ConstParamTy)]
pub enum Mode {
Floating,
Input,
Output,
AF0
}
pub struct Pin<const PINNUM: usize, const MODE: Mode> {}
pub trait PinCfg {
unsafe fn padfncsel(&mut self, f: u8);
unsafe fn padinpen(&mut self, on: bool);
unsafe fn padpull(&mut self, on: bool);
unsafe fn padstrng(&mut self, high: bool);
unsafe fn outcfg(&mut self, c: u8);
}
macro_rules! pin {
($id:literal, $padreg:ident, $cfgreg: ident) => {
paste! {
pub type [<P $id>]<const MODE: Mode> = Pin<$id, MODE>;
impl<const MODE: Mode>PinCfg for Pin<$id, MODE> {
unsafe fn padpull(&mut self, on: bool) {
(*pac::GPIO::ptr()).[<padreg $padreg:lower>]
.write(|p| p.[< pad $id pull >]().bit(on))
}
unsafe fn padinpen(&mut self, on: bool) {
(*pac::GPIO::ptr()).[<padreg $padreg:lower>]
.write(|p| p.[< pad $id inpen >]().bit(on))
}
unsafe fn padstrng(&mut self, high: bool) {
(*pac::GPIO::ptr()).[<padreg $padreg:lower>]
.write(|p| p.[< pad $id strng >]().bit(high))
}
unsafe fn padfncsel(&mut self, f: u8) {
(*pac::GPIO::ptr()).[<padreg $padreg:lower>]
.write(|p| p.[< pad $id fncsel >]().bits(f))
}
unsafe fn outcfg(&mut self, f: u8) {
(*pac::GPIO::ptr()).[<cfg $cfgreg:lower>]
.write(|p| p.[< gpio $id outcfg >]().bits(f))
}
}
}
};
}
impl<const P: usize> Pin<P, { Mode::Floating }> {
pub fn new() -> Self {
Self {}
}
}
impl<const P: usize, const M: Mode> Pin<P, M>
where
Pin<P, M>: PinCfg,
{
pub fn with_mode() -> Self {
Self {}.into_mode::<M>()
}
pub fn into_mode<const NEWM: Mode>(mut self) -> Pin<P, NEWM> {
gpio_cfg(|| unsafe {
self.padfncsel(3);
match NEWM {
Mode::Floating | Mode::Input => self.padinpen(true),
Mode::Output => {
self.padinpen(false);
self.outcfg(1); },
Mode::AF0 => {
self.padfncsel(0);
self.padinpen(false);
}
}
});
Pin {}
}
pub fn pin_num(&self) -> usize {
P
}
pub fn into_push_pull_output(self) -> Pin<P, { Mode::Output }> {
self.into_mode()
}
}
impl<const P: usize> Pin<P, { Mode::Output }>
where
Pin<P, { Mode::Output }>: PinCfg,
{
pub fn internal_pull_up(&mut self, on: bool) {
gpio_cfg(|| unsafe { self.padpull(on) })
}
}
impl<const P: usize> Pin<P, { Mode::AF0 }>
where
Pin<P, { Mode::AF0 }>: PinCfg,
{
pub fn set_drive_strength(&mut self, d: DriveStrength) {
gpio_cfg(|| unsafe {
match d {
DriveStrength::D2mA => self.padstrng(false),
DriveStrength::D4mA => self.padstrng(true),
_ => () }
});
}
}
impl<const P: usize> OutputPin for Pin<P, { Mode::Output }>
where
Pin<P, { Mode::Output }>: PinCfg,
{
type Error = Infallible;
fn set_low(&mut self) -> Result<(), Infallible> {
let mask: u32 = 0b1u32 << P % 32;
let reg = unsafe {
match P {
0..=31 => (*pac::GPIO::ptr()).wtca.as_ptr(),
_ => (*pac::GPIO::ptr()).wtcb.as_ptr(),
}
};
gpio_cfg(|| unsafe { reg.write(mask) });
Ok(())
}
fn set_high(&mut self) -> Result<(), Infallible> {
let mask: u32 = 0b1u32 << P % 32;
let reg = unsafe {
match P {
0..=31 => (*pac::GPIO::ptr()).wtsa.as_ptr(),
_ => (*pac::GPIO::ptr()).wtsb.as_ptr(),
}
};
gpio_cfg(|| unsafe { reg.write(mask) });
Ok(())
}
}
impl<const P: usize> ToggleableOutputPin for Pin<P, { Mode::Output }>
where
Pin<P, { Mode::Output }>: PinCfg,
{
type Error = Infallible;
fn toggle(&mut self) -> Result<(), Infallible> {
let mask: u32 = 0b1u32 << P % 32;
let reg = unsafe {
match P {
0..=31 => (*pac::GPIO::ptr()).wta.as_ptr(),
_ => (*pac::GPIO::ptr()).wtb.as_ptr(),
}
};
gpio_cfg(|| unsafe {
*reg ^= mask;
});
Ok(())
}
}
pin!(5, B, A);
pin!(6, B, A);
pin!(7, B, A);
pin!(11, C, B);
pin!(13, D, B);
pin!(19, E, C);
pin!(25, G, D);
pin!(27, G, D);
pin!(35, I, E);
pin!(39, J, E);
pin!(40, K, F);
pin!(42, K, F);
pin!(43, K, F);
pin!(48, M, G);
pin!(49, M, G);