use crate::peripherals::IoConfig;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DriveStrength {
Strongest = 0,
Strong = 1,
Medium = 2,
Weak = 3,
Weaker = 4,
VeryWeak = 5,
Weakest = 6,
Minimum = 7,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PullResistor {
None,
Up,
Down,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GpioPad {
Gpio00,
Gpio01,
Gpio02,
Gpio03,
Gpio04,
Gpio05,
Gpio06,
Gpio07,
Gpio08,
Gpio09,
Gpio10,
Gpio11,
Gpio12,
Gpio13,
Gpio14,
}
impl GpioPad {
pub const fn from_index(index: u8) -> Option<Self> {
match index {
0 => Some(Self::Gpio00),
1 => Some(Self::Gpio01),
2 => Some(Self::Gpio02),
3 => Some(Self::Gpio03),
4 => Some(Self::Gpio04),
5 => Some(Self::Gpio05),
6 => Some(Self::Gpio06),
7 => Some(Self::Gpio07),
8 => Some(Self::Gpio08),
9 => Some(Self::Gpio09),
10 => Some(Self::Gpio10),
11 => Some(Self::Gpio11),
12 => Some(Self::Gpio12),
13 => Some(Self::Gpio13),
14 => Some(Self::Gpio14),
_ => None,
}
}
pub const fn index(self) -> u8 {
match self {
Self::Gpio00 => 0,
Self::Gpio01 => 1,
Self::Gpio02 => 2,
Self::Gpio03 => 3,
Self::Gpio04 => 4,
Self::Gpio05 => 5,
Self::Gpio06 => 6,
Self::Gpio07 => 7,
Self::Gpio08 => 8,
Self::Gpio09 => 9,
Self::Gpio10 => 10,
Self::Gpio11 => 11,
Self::Gpio12 => 12,
Self::Gpio13 => 13,
Self::Gpio14 => 14,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UartPad {
Uart0Txd,
Uart0Rxd,
Uart1Txd,
Uart1Rxd,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MuxFunction(u8);
impl MuxFunction {
pub const F0: Self = Self(0);
pub const F1: Self = Self(1);
pub const F2: Self = Self(2);
pub const F3: Self = Self(3);
pub const F4: Self = Self(4);
pub const F5: Self = Self(5);
pub const F6: Self = Self(6);
pub const F7: Self = Self(7);
pub const fn from_bits(bits: u8) -> Option<Self> {
if bits <= 0x07 { Some(Self(bits)) } else { None }
}
pub const fn bits(self) -> u8 {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[instability::unstable]
pub enum SfcPad {
Clk,
Csn,
Io0,
Io1,
Io2,
Io3,
}
pub struct IoConfigDriver<'d> {
_io_config: IoConfig<'d>,
}
impl<'d> IoConfigDriver<'d> {
pub fn new(io_config: IoConfig<'d>) -> Self {
Self { _io_config: io_config }
}
fn regs(&self) -> &'static crate::soc::pac::io_config::RegisterBlock {
unsafe { &*IoConfig::ptr() }
}
pub fn set_gpio_mux(&mut self, pin: GpioPad, function: MuxFunction) {
let val = function.bits() as u32;
let r = self.regs();
match pin {
GpioPad::Gpio00 => unsafe {
r.gpio_00_sel().write(|w| w.bits(val));
},
GpioPad::Gpio01 => unsafe {
r.gpio_01_sel().write(|w| w.bits(val));
},
GpioPad::Gpio02 => unsafe {
r.gpio_02_sel().write(|w| w.bits(val));
},
GpioPad::Gpio03 => unsafe {
r.gpio_03_sel().write(|w| w.bits(val));
},
GpioPad::Gpio04 => unsafe {
r.gpio_04_sel().write(|w| w.bits(val));
},
GpioPad::Gpio05 => unsafe {
r.gpio_05_sel().write(|w| w.bits(val));
},
GpioPad::Gpio06 => unsafe {
r.gpio_06_sel().write(|w| w.bits(val));
},
GpioPad::Gpio07 => unsafe {
r.gpio_07_sel().write(|w| w.bits(val));
},
GpioPad::Gpio08 => unsafe {
r.gpio_08_sel().write(|w| w.bits(val));
},
GpioPad::Gpio09 => unsafe {
r.gpio_09_sel().write(|w| w.bits(val));
},
GpioPad::Gpio10 => unsafe {
r.gpio_10_sel().write(|w| w.bits(val));
},
GpioPad::Gpio11 => unsafe {
r.gpio_11_sel().write(|w| w.bits(val));
},
GpioPad::Gpio12 => unsafe {
r.gpio_12_sel().write(|w| w.bits(val));
},
GpioPad::Gpio13 => unsafe {
r.gpio_13_sel().write(|w| w.bits(val));
},
GpioPad::Gpio14 => unsafe {
r.gpio_14_sel().write(|w| w.bits(val));
},
}
}
pub fn gpio_mux(&self, pin: GpioPad) -> MuxFunction {
let r = self.regs();
let bits = match pin {
GpioPad::Gpio00 => r.gpio_00_sel().read().bits(),
GpioPad::Gpio01 => r.gpio_01_sel().read().bits(),
GpioPad::Gpio02 => r.gpio_02_sel().read().bits(),
GpioPad::Gpio03 => r.gpio_03_sel().read().bits(),
GpioPad::Gpio04 => r.gpio_04_sel().read().bits(),
GpioPad::Gpio05 => r.gpio_05_sel().read().bits(),
GpioPad::Gpio06 => r.gpio_06_sel().read().bits(),
GpioPad::Gpio07 => r.gpio_07_sel().read().bits(),
GpioPad::Gpio08 => r.gpio_08_sel().read().bits(),
GpioPad::Gpio09 => r.gpio_09_sel().read().bits(),
GpioPad::Gpio10 => r.gpio_10_sel().read().bits(),
GpioPad::Gpio11 => r.gpio_11_sel().read().bits(),
GpioPad::Gpio12 => r.gpio_12_sel().read().bits(),
GpioPad::Gpio13 => r.gpio_13_sel().read().bits(),
GpioPad::Gpio14 => r.gpio_14_sel().read().bits(),
};
MuxFunction((bits & 0x07) as u8)
}
pub fn set_uart_mux(&mut self, pin: UartPad, function: MuxFunction) {
let val = function.bits() as u32;
let r = self.regs();
match pin {
UartPad::Uart0Txd => unsafe {
r.uart0_txd_sel().write(|w| w.bits(val));
},
UartPad::Uart0Rxd => unsafe {
r.uart0_rxd_sel().write(|w| w.bits(val));
},
UartPad::Uart1Txd => unsafe {
r.uart1_txd_sel().write(|w| w.bits(val));
},
UartPad::Uart1Rxd => unsafe {
r.uart1_rxd_sel().write(|w| w.bits(val));
},
}
}
pub fn configure_gpio_pad(
&mut self,
pin: GpioPad,
drive: DriveStrength,
pull: PullResistor,
schmitt_trigger: bool,
input_enable: bool,
) {
let val = build_pad_ctrl(drive, pull, schmitt_trigger, input_enable);
let r = self.regs();
match pin {
GpioPad::Gpio00 => unsafe {
r.pad_gpio_00_ctrl().write(|w| w.bits(val));
},
GpioPad::Gpio01 => unsafe {
r.pad_gpio_01_ctrl().write(|w| w.bits(val));
},
GpioPad::Gpio02 => unsafe {
r.pad_gpio_02_ctrl().write(|w| w.bits(val));
},
GpioPad::Gpio03 => unsafe {
r.pad_gpio_03_ctrl().write(|w| w.bits(val));
},
GpioPad::Gpio04 => unsafe {
r.pad_gpio_04_ctrl().write(|w| w.bits(val));
},
GpioPad::Gpio05 => unsafe {
r.pad_gpio_05_ctrl().write(|w| w.bits(val));
},
GpioPad::Gpio06 => unsafe {
r.pad_gpio_06_ctrl().write(|w| w.bits(val));
},
GpioPad::Gpio07 => unsafe {
r.pad_gpio_07_ctrl().write(|w| w.bits(val));
},
GpioPad::Gpio08 => unsafe {
r.pad_gpio_08_ctrl().write(|w| w.bits(val));
},
GpioPad::Gpio09 => unsafe {
r.pad_gpio_09_ctrl().write(|w| w.bits(val));
},
GpioPad::Gpio10 => unsafe {
r.pad_gpio_10_ctrl().write(|w| w.bits(val));
},
GpioPad::Gpio11 => unsafe {
r.pad_gpio_11_ctrl().write(|w| w.bits(val));
},
GpioPad::Gpio12 => unsafe {
r.pad_gpio_12_ctrl().write(|w| w.bits(val));
},
GpioPad::Gpio13 => unsafe {
r.pad_gpio_13_ctrl().write(|w| w.bits(val));
},
GpioPad::Gpio14 => unsafe {
r.pad_gpio_14_ctrl().write(|w| w.bits(val));
},
}
}
pub fn configure_uart_pad(
&mut self,
uart_pad: UartPad,
drive: DriveStrength,
pull: PullResistor,
schmitt_trigger: bool,
input_enable: bool,
) {
let val = build_pad_ctrl(drive, pull, schmitt_trigger, input_enable);
let r = self.regs();
match uart_pad {
UartPad::Uart0Txd => unsafe {
r.pad_uart0_txd_ctrl().write(|w| w.bits(val));
},
UartPad::Uart0Rxd => unsafe {
r.pad_uart0_rxd_ctrl().write(|w| w.bits(val));
},
UartPad::Uart1Txd => unsafe {
r.pad_uart1_txd_ctrl().write(|w| w.bits(val));
},
UartPad::Uart1Rxd => unsafe {
r.pad_uart1_rxd_ctrl().write(|w| w.bits(val));
},
}
}
#[instability::unstable]
pub fn configure_sfc_pad(
&mut self,
sfc_pad: SfcPad,
drive: DriveStrength,
pull: PullResistor,
schmitt_trigger: bool,
input_enable: bool,
) {
let val = build_pad_ctrl(drive, pull, schmitt_trigger, input_enable);
let r = self.regs();
match sfc_pad {
SfcPad::Clk => unsafe {
r.pad_sfc_clk_ctrl().write(|w| w.bits(val));
},
SfcPad::Csn => unsafe {
r.pad_sfc_csn_ctrl().write(|w| w.bits(val));
},
SfcPad::Io0 => unsafe {
r.pad_sfc_io0_ctrl().write(|w| w.bits(val));
},
SfcPad::Io1 => unsafe {
r.pad_sfc_io1_ctrl().write(|w| w.bits(val));
},
SfcPad::Io2 => unsafe {
r.pad_sfc_io2_ctrl().write(|w| w.bits(val));
},
SfcPad::Io3 => unsafe {
r.pad_sfc_io3_ctrl().write(|w| w.bits(val));
},
}
}
pub fn read_gpio_pad(&self, pin: GpioPad) -> u32 {
let r = self.regs();
match pin {
GpioPad::Gpio00 => r.pad_gpio_00_ctrl().read().bits(),
GpioPad::Gpio01 => r.pad_gpio_01_ctrl().read().bits(),
GpioPad::Gpio02 => r.pad_gpio_02_ctrl().read().bits(),
GpioPad::Gpio03 => r.pad_gpio_03_ctrl().read().bits(),
GpioPad::Gpio04 => r.pad_gpio_04_ctrl().read().bits(),
GpioPad::Gpio05 => r.pad_gpio_05_ctrl().read().bits(),
GpioPad::Gpio06 => r.pad_gpio_06_ctrl().read().bits(),
GpioPad::Gpio07 => r.pad_gpio_07_ctrl().read().bits(),
GpioPad::Gpio08 => r.pad_gpio_08_ctrl().read().bits(),
GpioPad::Gpio09 => r.pad_gpio_09_ctrl().read().bits(),
GpioPad::Gpio10 => r.pad_gpio_10_ctrl().read().bits(),
GpioPad::Gpio11 => r.pad_gpio_11_ctrl().read().bits(),
GpioPad::Gpio12 => r.pad_gpio_12_ctrl().read().bits(),
GpioPad::Gpio13 => r.pad_gpio_13_ctrl().read().bits(),
GpioPad::Gpio14 => r.pad_gpio_14_ctrl().read().bits(),
}
}
}
fn build_pad_ctrl(drive: DriveStrength, pull: PullResistor, schmitt_trigger: bool, input_enable: bool) -> u32 {
let mut val: u32 = 0;
let ds = drive as u32;
val |= ((ds & 0x04) << 4) | ((ds & 0x02) << 4) | ((ds & 0x01) << 4);
match pull {
PullResistor::None => {} PullResistor::Up => {
val |= (1 << 9) | (1 << 10); }
PullResistor::Down => {
val |= 1 << 9; }
}
if schmitt_trigger {
val |= 1 << 3;
}
if input_enable {
val |= 1 << 11;
}
val
}
#[cfg(all(test, not(target_arch = "riscv32")))]
mod tests {
use super::*;
const ST_BIT: u32 = 1 << 3; const DS_MASK: u32 = 0x7 << 4; const PE_BIT: u32 = 1 << 9; const PS_BIT: u32 = 1 << 10; const IE_BIT: u32 = 1 << 11;
#[test]
fn drive_strength_discriminants_are_dense() {
assert_eq!(DriveStrength::Strongest as u32, 0);
assert_eq!(DriveStrength::Strong as u32, 1);
assert_eq!(DriveStrength::Medium as u32, 2);
assert_eq!(DriveStrength::Weak as u32, 3);
assert_eq!(DriveStrength::Weaker as u32, 4);
assert_eq!(DriveStrength::VeryWeak as u32, 5);
assert_eq!(DriveStrength::Weakest as u32, 6);
assert_eq!(DriveStrength::Minimum as u32, 7);
}
#[test]
fn drive_strength_lands_in_bits_4_to_6() {
for (ds, expect) in [
(DriveStrength::Strongest, 0u32),
(DriveStrength::Strong, 1 << 4),
(DriveStrength::Medium, 2 << 4),
(DriveStrength::Minimum, 7 << 4),
] {
let val = build_pad_ctrl(ds, PullResistor::None, false, false);
assert_eq!(val & DS_MASK, expect, "ds {ds:?} mis-placed");
assert_eq!(val & !DS_MASK, 0);
}
}
#[test]
fn drive_strength_covers_full_mask() {
let strongest = build_pad_ctrl(DriveStrength::Strongest, PullResistor::None, false, false);
let minimum = build_pad_ctrl(DriveStrength::Minimum, PullResistor::None, false, false);
assert_eq!(strongest & DS_MASK, 0);
assert_eq!(minimum & DS_MASK, DS_MASK);
}
#[test]
fn pull_none_sets_neither_pe_nor_ps() {
let val = build_pad_ctrl(DriveStrength::Strongest, PullResistor::None, false, false);
assert_eq!(val & (PE_BIT | PS_BIT), 0);
}
#[test]
fn pull_up_sets_pe_and_ps() {
let val = build_pad_ctrl(DriveStrength::Strongest, PullResistor::Up, false, false);
assert_eq!(val & PE_BIT, PE_BIT);
assert_eq!(val & PS_BIT, PS_BIT);
}
#[test]
fn pull_down_sets_pe_only() {
let val = build_pad_ctrl(DriveStrength::Strongest, PullResistor::Down, false, false);
assert_eq!(val & PE_BIT, PE_BIT);
assert_eq!(val & PS_BIT, 0);
}
#[test]
fn schmitt_and_input_enable_are_independent_bits() {
let none = build_pad_ctrl(DriveStrength::Strongest, PullResistor::None, false, false);
assert_eq!(none & (ST_BIT | IE_BIT), 0);
let st = build_pad_ctrl(DriveStrength::Strongest, PullResistor::None, true, false);
assert_eq!(st, ST_BIT);
let ie = build_pad_ctrl(DriveStrength::Strongest, PullResistor::None, false, true);
assert_eq!(ie, IE_BIT);
let both = build_pad_ctrl(DriveStrength::Strongest, PullResistor::None, true, true);
assert_eq!(both, ST_BIT | IE_BIT);
}
#[test]
fn all_fields_compose_without_collision() {
let val = build_pad_ctrl(DriveStrength::Minimum, PullResistor::Up, true, true);
assert_eq!(val, DS_MASK | PE_BIT | PS_BIT | ST_BIT | IE_BIT);
}
#[test]
fn no_bits_set_outside_known_fields() {
let defined = DS_MASK | PE_BIT | PS_BIT | ST_BIT | IE_BIT;
for &drive in &[DriveStrength::Strongest, DriveStrength::Medium, DriveStrength::Minimum] {
for &pull in &[PullResistor::None, PullResistor::Up, PullResistor::Down] {
for st in [false, true] {
for ie in [false, true] {
let val = build_pad_ctrl(drive, pull, st, ie);
assert_eq!(val & !defined, 0, "reserved bit set for {drive:?}/{pull:?}/{st}/{ie}");
}
}
}
}
}
}
#[cfg(all(test, not(target_arch = "riscv32")))]
mod proptests {
use super::*;
use proptest::prelude::*;
const ST_BIT: u32 = 1 << 3;
const DS_MASK: u32 = 0x7 << 4;
const PE_BIT: u32 = 1 << 9;
const PS_BIT: u32 = 1 << 10;
const IE_BIT: u32 = 1 << 11;
const DEFINED: u32 = DS_MASK | PE_BIT | PS_BIT | ST_BIT | IE_BIT;
fn drive_from(i: u8) -> DriveStrength {
match i % 8 {
0 => DriveStrength::Strongest,
1 => DriveStrength::Strong,
2 => DriveStrength::Medium,
3 => DriveStrength::Weak,
4 => DriveStrength::Weaker,
5 => DriveStrength::VeryWeak,
6 => DriveStrength::Weakest,
_ => DriveStrength::Minimum,
}
}
fn pull_from(i: u8) -> PullResistor {
match i % 3 {
0 => PullResistor::None,
1 => PullResistor::Up,
_ => PullResistor::Down,
}
}
proptest! {
#[test]
fn never_sets_reserved_bits(d in any::<u8>(), p in any::<u8>(), st: bool, ie: bool) {
let val = build_pad_ctrl(drive_from(d), pull_from(p), st, ie);
prop_assert_eq!(val & !DEFINED, 0);
}
#[test]
fn ds_field_equals_discriminant_shifted(d in any::<u8>(), p in any::<u8>(), st: bool, ie: bool) {
let drive = drive_from(d);
let val = build_pad_ctrl(drive, pull_from(p), st, ie);
prop_assert_eq!(val & DS_MASK, (drive as u32) << 4);
}
#[test]
fn st_ie_track_inputs(d in any::<u8>(), p in any::<u8>(), st: bool, ie: bool) {
let val = build_pad_ctrl(drive_from(d), pull_from(p), st, ie);
prop_assert_eq!(val & ST_BIT != 0, st);
prop_assert_eq!(val & IE_BIT != 0, ie);
}
#[test]
fn pull_encoding_is_consistent(d in any::<u8>(), p in any::<u8>(), st: bool, ie: bool) {
let pull = pull_from(p);
let val = build_pad_ctrl(drive_from(d), pull, st, ie);
let pe = val & PE_BIT != 0;
let ps = val & PS_BIT != 0;
match pull {
PullResistor::None => { prop_assert!(!pe); prop_assert!(!ps); }
PullResistor::Up => { prop_assert!(pe); prop_assert!(ps); }
PullResistor::Down => { prop_assert!(pe); prop_assert!(!ps); }
}
}
}
}