pub use crate::batch_gpio::*;
use crate::hw_traits::gpio::{GpioPeriph, IntrPeriph};
use crate::util::BitsExt;
use core::marker::PhantomData;
use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin};
use msp430fr247x as pac;
pub use pac::{P1, P2, P3, P4, P5, P6};
mod sealed {
use super::*;
pub trait SealedPinNum {}
pub trait SealedGpioFunction {}
impl SealedPinNum for Pin0 {}
impl SealedPinNum for Pin1 {}
impl SealedPinNum for Pin2 {}
impl SealedPinNum for Pin3 {}
impl SealedPinNum for Pin4 {}
impl SealedPinNum for Pin5 {}
impl SealedPinNum for Pin6 {}
impl SealedPinNum for Pin7 {}
impl SealedGpioFunction for Output {}
impl<PULL> SealedGpioFunction for Input<PULL> {}
}
pub trait PinNum: sealed::SealedPinNum {
#[doc(hidden)]
const NUM: u8;
#[doc(hidden)]
const SET_MASK: u8 = 1 << Self::NUM;
#[doc(hidden)]
const CLR_MASK: u8 = !Self::SET_MASK;
}
pub trait PortNum: GpioPeriph {}
impl<PORT: GpioPeriph> PortNum for PORT {}
pub trait IntrPortNum: IntrPeriph {}
impl<PORT: IntrPeriph> IntrPortNum for PORT {}
pub struct Pin0;
impl PinNum for Pin0 {
const NUM: u8 = 0;
}
pub struct Pin1;
impl PinNum for Pin1 {
const NUM: u8 = 1;
}
pub struct Pin2;
impl PinNum for Pin2 {
const NUM: u8 = 2;
}
pub struct Pin3;
impl PinNum for Pin3 {
const NUM: u8 = 3;
}
pub struct Pin4;
impl PinNum for Pin4 {
const NUM: u8 = 4;
}
pub struct Pin5;
impl PinNum for Pin5 {
const NUM: u8 = 5;
}
pub struct Pin6;
impl PinNum for Pin6 {
const NUM: u8 = 6;
}
pub struct Pin7;
impl PinNum for Pin7 {
const NUM: u8 = 7;
}
pub trait GpioFunction: sealed::SealedGpioFunction {}
pub struct Output;
impl GpioFunction for Output {}
pub struct Input<PULL>(PhantomData<PULL>);
impl<PULL> GpioFunction for Input<PULL> {}
pub struct Pullup;
pub struct Pulldown;
pub struct Floating;
pub struct Pin<PORT: PortNum, PIN: PinNum, DIR> {
_port: PhantomData<PORT>,
_pin: PhantomData<PIN>,
_dir: PhantomData<DIR>,
}
macro_rules! make_pin {
() => {
Pin {
_port: PhantomData,
_pin: PhantomData,
_dir: PhantomData,
}
};
($dir:ty) => {
Pin::<_, _, $dir> {
_port: PhantomData,
_pin: PhantomData,
_dir: PhantomData,
}
};
}
impl<PORT: PortNum, PIN: PinNum, PULL> Pin<PORT, PIN, Input<PULL>> {
#[inline]
pub fn pulldown(self) -> Pin<PORT, PIN, Input<Pulldown>> {
let p = unsafe { PORT::steal() };
p.pxout_clear(PIN::CLR_MASK);
p.pxren_set(PIN::SET_MASK);
make_pin!()
}
#[inline]
pub fn pullup(self) -> Pin<PORT, PIN, Input<Pullup>> {
let p = unsafe { PORT::steal() };
p.pxout_set(PIN::SET_MASK);
p.pxren_set(PIN::SET_MASK);
make_pin!()
}
#[inline]
pub fn floating(self) -> Pin<PORT, PIN, Input<Floating>> {
let p = unsafe { PORT::steal() };
p.pxren_clear(PIN::CLR_MASK);
make_pin!()
}
}
impl<PORT: IntrPortNum, PIN: PinNum, PULL> Pin<PORT, PIN, Input<PULL>> {
#[inline]
pub fn select_rising_edge_trigger(&mut self) -> &mut Self {
let p = unsafe { PORT::steal() };
p.pxies_clear(PIN::CLR_MASK);
p.pxifg_clear(PIN::CLR_MASK);
self
}
#[inline]
pub fn select_falling_edge_trigger(&mut self) -> &mut Self {
let p = unsafe { PORT::steal() };
p.pxies_set(PIN::SET_MASK);
p.pxifg_clear(PIN::CLR_MASK);
self
}
#[inline]
pub fn enable_interrupts(&mut self) -> &mut Self {
let p = unsafe { PORT::steal() };
p.pxie_set(PIN::SET_MASK);
self
}
#[inline]
pub fn disable_interrupt(&mut self) -> &mut Self {
let p = unsafe { PORT::steal() };
p.pxie_clear(PIN::CLR_MASK);
self
}
#[inline]
pub fn set_ifg(&mut self) -> &mut Self {
let p = unsafe { PORT::steal() };
p.pxifg_set(PIN::SET_MASK);
self
}
#[inline]
pub fn clear_ifg(&mut self) -> &mut Self {
let p = unsafe { PORT::steal() };
p.pxifg_clear(PIN::CLR_MASK);
self
}
#[inline]
pub fn wait_for_ifg(&mut self) -> nb::Result<(), void::Void> {
let p = unsafe { PORT::steal() };
if p.pxifg_rd().check(PIN::NUM) != 0 {
p.pxifg_clear(PIN::CLR_MASK);
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
pub struct PxIV<PORT: PortNum>(PhantomData<PORT>);
impl<PORT: IntrPortNum> PxIV<PORT> {
#[inline]
pub fn get_interrupt_vector(&mut self) -> GpioVector {
let p = unsafe { PORT::steal() };
match p.pxiv_rd() {
0 => GpioVector::NoIsr,
2 => GpioVector::Pin0Isr,
4 => GpioVector::Pin1Isr,
6 => GpioVector::Pin2Isr,
8 => GpioVector::Pin3Isr,
10 => GpioVector::Pin4Isr,
12 => GpioVector::Pin5Isr,
14 => GpioVector::Pin6Isr,
16 => GpioVector::Pin7Isr,
_ => unsafe { core::hint::unreachable_unchecked() },
}
}
}
pub enum GpioVector {
NoIsr,
Pin0Isr,
Pin1Isr,
Pin2Isr,
Pin3Isr,
Pin4Isr,
Pin5Isr,
Pin6Isr,
Pin7Isr,
}
impl<PORT: PortNum, PIN: PinNum, PULL> Pin<PORT, PIN, Input<PULL>> {
#[inline]
pub fn to_output(self) -> Pin<PORT, PIN, Output> {
let p = unsafe { PORT::steal() };
p.pxdir_set(PIN::SET_MASK);
make_pin!()
}
}
impl<PORT: PortNum, PIN: PinNum> Pin<PORT, PIN, Output> {
#[inline]
pub fn to_input_floating(self) -> Pin<PORT, PIN, Input<Floating>> {
let p = unsafe { PORT::steal() };
p.pxdir_clear(PIN::CLR_MASK);
make_pin!(Input<Floating>).floating()
}
#[inline]
pub fn to_input_pullup(self) -> Pin<PORT, PIN, Input<Pullup>> {
let p = unsafe { PORT::steal() };
p.pxdir_clear(PIN::CLR_MASK);
make_pin!(Input<Floating>).pullup()
}
#[inline]
pub fn to_input_pulldown(self) -> Pin<PORT, PIN, Input<Pulldown>> {
let p = unsafe { PORT::steal() };
p.pxdir_clear(PIN::CLR_MASK);
make_pin!(Input<Floating>).pulldown()
}
}
impl<PORT: PortNum, PIN: PinNum, PULL> InputPin for Pin<PORT, PIN, Input<PULL>> {
type Error = void::Void;
#[inline]
fn is_high(&self) -> Result<bool, Self::Error> {
let p = unsafe { PORT::steal() };
Ok(p.pxin_rd().check(PIN::NUM) != 0)
}
#[inline]
fn is_low(&self) -> Result<bool, Self::Error> {
self.is_high().map(|r| !r)
}
}
impl<PORT: PortNum, PIN: PinNum> OutputPin for Pin<PORT, PIN, Output> {
type Error = void::Void;
#[inline]
fn set_low(&mut self) -> Result<(), Self::Error> {
let p = unsafe { PORT::steal() };
p.pxout_clear(PIN::CLR_MASK);
Ok(())
}
#[inline]
fn set_high(&mut self) -> Result<(), Self::Error> {
let p = unsafe { PORT::steal() };
p.pxout_set(PIN::SET_MASK);
Ok(())
}
}
impl<PORT: PortNum, PIN: PinNum> StatefulOutputPin for Pin<PORT, PIN, Output> {
#[inline]
fn is_set_high(&self) -> Result<bool, Self::Error> {
let p = unsafe { PORT::steal() };
Ok(p.pxout_rd().check(PIN::NUM) != 0)
}
#[inline]
fn is_set_low(&self) -> Result<bool, Self::Error> {
self.is_set_high().map(|r| !r)
}
}
impl<PORT: PortNum, PIN: PinNum> ToggleableOutputPin for Pin<PORT, PIN, Output> {
type Error = void::Void;
#[inline]
fn toggle(&mut self) -> Result<(), Self::Error> {
let p = unsafe { PORT::steal() };
p.pxout_toggle(PIN::SET_MASK);
Ok(())
}
}
pub struct Parts<PORT: PortNum, DIR0, DIR1, DIR2, DIR3, DIR4, DIR5, DIR6, DIR7> {
pub pin0: Pin<PORT, Pin0, DIR0>,
pub pin1: Pin<PORT, Pin1, DIR1>,
pub pin2: Pin<PORT, Pin2, DIR2>,
pub pin3: Pin<PORT, Pin3, DIR3>,
pub pin4: Pin<PORT, Pin4, DIR4>,
pub pin5: Pin<PORT, Pin5, DIR5>,
pub pin6: Pin<PORT, Pin6, DIR6>,
pub pin7: Pin<PORT, Pin7, DIR7>,
pub pxiv: PxIV<PORT>,
}
impl<PORT: PortNum, DIR0, DIR1, DIR2, DIR3, DIR4, DIR5, DIR6, DIR7>
Parts<PORT, DIR0, DIR1, DIR2, DIR3, DIR4, DIR5, DIR6, DIR7>
{
#[inline]
pub fn batch(self) -> Batch<PORT, DIR0, DIR1, DIR2, DIR3, DIR4, DIR5, DIR6, DIR7> {
Batch::create()
}
#[inline]
pub(super) fn new() -> Self {
Self {
pin0: make_pin!(),
pin1: make_pin!(),
pin2: make_pin!(),
pin3: make_pin!(),
pin4: make_pin!(),
pin5: make_pin!(),
pin6: make_pin!(),
pin7: make_pin!(),
pxiv: PxIV(PhantomData),
}
}
}
#[doc(hidden)]
pub trait ChangeSelectBits {
fn set_sel0(&mut self);
fn set_sel1(&mut self);
fn clear_sel0(&mut self);
fn clear_sel1(&mut self);
fn flip_selc(&mut self);
}
impl<PORT: PortNum, PIN: PinNum, DIR> ChangeSelectBits for Pin<PORT, PIN, DIR> {
#[inline]
fn set_sel0(&mut self) {
let p = unsafe { PORT::steal() };
p.pxsel0_set(PIN::SET_MASK);
}
#[inline]
fn set_sel1(&mut self) {
let p = unsafe { PORT::steal() };
p.pxsel1_set(PIN::SET_MASK);
}
#[inline]
fn clear_sel0(&mut self) {
let p = unsafe { PORT::steal() };
p.pxsel0_clear(PIN::CLR_MASK);
}
#[inline]
fn clear_sel1(&mut self) {
let p = unsafe { PORT::steal() };
p.pxsel1_clear(PIN::CLR_MASK);
}
#[inline]
fn flip_selc(&mut self) {
let p = unsafe { PORT::steal() };
p.pxselc_wr(0u8.set(PIN::NUM));
}
}
pub struct Alternate1<DIR>(PhantomData<DIR>);
pub struct Alternate2<DIR>(PhantomData<DIR>);
pub struct Alternate3<DIR>(PhantomData<DIR>);
pub trait ToAlternate1 {}
pub trait ToAlternate2 {}
pub trait ToAlternate3 {}
impl<PORT: PortNum, PIN: PinNum, DIR: GpioFunction> Pin<PORT, PIN, DIR>
where
Self: ToAlternate1,
{
#[inline]
pub fn to_alternate1(mut self) -> Pin<PORT, PIN, Alternate1<DIR>> {
self.set_sel0();
make_pin!()
}
}
impl<PORT: PortNum, PIN: PinNum, DIR: GpioFunction> Pin<PORT, PIN, DIR>
where
Self: ToAlternate2,
{
#[inline]
pub fn to_alternate2(mut self) -> Pin<PORT, PIN, Alternate2<DIR>> {
self.set_sel1();
make_pin!()
}
}
impl<PORT: PortNum, PIN: PinNum, DIR: GpioFunction> Pin<PORT, PIN, DIR>
where
Self: ToAlternate3,
{
#[inline]
pub fn to_alternate3(mut self) -> Pin<PORT, PIN, Alternate3<DIR>> {
self.flip_selc();
make_pin!()
}
}
impl<PORT: PortNum, PIN: PinNum, DIR> Pin<PORT, PIN, Alternate1<DIR>> {
#[inline]
pub fn to_gpio(mut self) -> Pin<PORT, PIN, DIR> {
self.clear_sel0();
make_pin!()
}
}
impl<PORT: PortNum, PIN: PinNum, DIR> Pin<PORT, PIN, Alternate1<DIR>>
where
Self: ToAlternate2,
{
#[inline]
pub fn to_alternate2(mut self) -> Pin<PORT, PIN, Alternate2<DIR>> {
self.flip_selc();
make_pin!()
}
}
impl<PORT: PortNum, PIN: PinNum, DIR> Pin<PORT, PIN, Alternate1<DIR>>
where
Self: ToAlternate3,
{
#[inline]
pub fn to_alternate3(mut self) -> Pin<PORT, PIN, Alternate3<DIR>> {
self.set_sel1();
make_pin!()
}
}
impl<PORT: PortNum, PIN: PinNum, DIR> Pin<PORT, PIN, Alternate2<DIR>> {
#[inline]
pub fn to_gpio(mut self) -> Pin<PORT, PIN, DIR> {
self.clear_sel1();
make_pin!()
}
}
impl<PORT: PortNum, PIN: PinNum, DIR> Pin<PORT, PIN, Alternate2<DIR>>
where
Self: ToAlternate1,
{
#[inline]
pub fn to_alternate1(mut self) -> Pin<PORT, PIN, Alternate1<DIR>> {
self.flip_selc();
make_pin!()
}
}
impl<PORT: PortNum, PIN: PinNum, DIR> Pin<PORT, PIN, Alternate2<DIR>>
where
Self: ToAlternate3,
{
#[inline]
pub fn to_alternate3(mut self) -> Pin<PORT, PIN, Alternate3<DIR>> {
self.set_sel0();
make_pin!()
}
}
impl<PORT: PortNum, PIN: PinNum, DIR> Pin<PORT, PIN, Alternate3<DIR>> {
#[inline]
pub fn to_gpio(mut self) -> Pin<PORT, PIN, DIR> {
self.flip_selc();
make_pin!()
}
}
impl<PORT: PortNum, PIN: PinNum, DIR> Pin<PORT, PIN, Alternate3<DIR>>
where
Self: ToAlternate1,
{
#[inline]
pub fn to_alternate1(mut self) -> Pin<PORT, PIN, Alternate1<DIR>> {
self.clear_sel1();
make_pin!()
}
}
impl<PORT: PortNum, PIN: PinNum, DIR> Pin<PORT, PIN, Alternate3<DIR>>
where
Self: ToAlternate2,
{
#[inline]
pub fn to_alternate2(mut self) -> Pin<PORT, PIN, Alternate2<DIR>> {
self.clear_sel0();
make_pin!()
}
}
impl<PIN: PinNum, DIR> ToAlternate1 for Pin<P1, PIN, DIR> {}
impl<PULL> ToAlternate2 for Pin<P1, Pin0, Input<PULL>> {}
impl<DIR> ToAlternate2 for Pin<P1, Pin1, DIR> {}
impl<PULL> ToAlternate2 for Pin<P1, Pin2, Input<PULL>> {}
impl ToAlternate2 for Pin<P1, Pin3, Output> {}
impl<DIR> ToAlternate2 for Pin<P1, Pin4, DIR> {}
impl<DIR> ToAlternate2 for Pin<P1, Pin5, DIR> {}
impl<PULL> ToAlternate2 for Pin<P1, Pin6, Input<PULL>> {}
impl<DIR> ToAlternate2 for Pin<P1, Pin7, DIR> {}
impl ToAlternate2 for Pin<P1, Pin7, Output> {}
impl<PIN: PinNum, DIR> ToAlternate3 for Pin<P1, PIN, DIR> {}
impl<DIR> ToAlternate1 for Pin<P2, Pin0, DIR> {}
impl<DIR> ToAlternate1 for Pin<P2, Pin1, DIR> {}
impl<DIR> ToAlternate1 for Pin<P2, Pin3, DIR> {}
impl<DIR> ToAlternate1 for Pin<P2, Pin4, DIR> {}
impl<DIR> ToAlternate1 for Pin<P2, Pin5, DIR> {}
impl<DIR> ToAlternate1 for Pin<P2, Pin6, DIR> {}
impl<DIR> ToAlternate1 for Pin<P2, Pin7, DIR> {}
impl ToAlternate2 for Pin<P2, Pin2, Output> {}
impl<DIR> ToAlternate3 for Pin<P2, Pin2, DIR> {}
impl<DIR> ToAlternate1 for Pin<P3, Pin0, DIR> {}
impl<DIR> ToAlternate1 for Pin<P3, Pin1, DIR> {}
impl<DIR> ToAlternate1 for Pin<P3, Pin2, DIR> {}
impl<DIR> ToAlternate1 for Pin<P3, Pin3, DIR> {}
impl<PULL> ToAlternate1 for Pin<P3, Pin4, Input<PULL>> {}
impl<DIR> ToAlternate1 for Pin<P3, Pin5, DIR> {}
impl<DIR> ToAlternate1 for Pin<P3, Pin6, DIR> {}
impl<DIR> ToAlternate1 for Pin<P3, Pin7, DIR> {}
impl ToAlternate2 for Pin<P3, Pin4, Output> {}
impl<PULL> ToAlternate2 for Pin<P3, Pin4, Input<PULL>> {}
impl<DIR> ToAlternate3 for Pin<P3, Pin1, DIR> {}
impl<DIR> ToAlternate3 for Pin<P3, Pin2, DIR> {}
impl<DIR> ToAlternate3 for Pin<P3, Pin3, DIR> {}
impl<DIR> ToAlternate3 for Pin<P3, Pin5, DIR> {}
impl<DIR> ToAlternate3 for Pin<P3, Pin6, DIR> {}
impl<DIR> ToAlternate3 for Pin<P3, Pin7, DIR> {}
impl<DIR> ToAlternate1 for Pin<P4, Pin0, DIR> {}
impl<DIR> ToAlternate1 for Pin<P4, Pin1, DIR> {}
impl<PULL> ToAlternate1 for Pin<P4, Pin2, Input<PULL>> {}
impl<DIR> ToAlternate1 for Pin<P4, Pin3, DIR> {}
impl<DIR> ToAlternate1 for Pin<P4, Pin4, DIR> {}
impl<DIR> ToAlternate1 for Pin<P4, Pin5, DIR> {}
impl<DIR> ToAlternate1 for Pin<P4, Pin6, DIR> {}
impl<DIR> ToAlternate1 for Pin<P4, Pin7, DIR> {}
impl<DIR> ToAlternate2 for Pin<P4, Pin3, DIR> {}
impl<DIR> ToAlternate2 for Pin<P4, Pin4, DIR> {}
impl<DIR> ToAlternate2 for Pin<P4, Pin5, DIR> {}
impl<DIR> ToAlternate2 for Pin<P4, Pin6, DIR> {}
impl<DIR> ToAlternate2 for Pin<P4, Pin7, DIR> {}
impl<PIN:PinNum, DIR> ToAlternate1 for Pin<P5, PIN, DIR> {}
impl<DIR> ToAlternate2 for Pin<P5, Pin0, DIR> {}
impl<DIR> ToAlternate2 for Pin<P5, Pin1, DIR> {}
impl<DIR> ToAlternate2 for Pin<P5, Pin2, DIR> {}
impl<DIR> ToAlternate2 for Pin<P5, Pin3, DIR> {}
impl<PULL> ToAlternate2 for Pin<P5, Pin4, Input<PULL>> {}
impl<DIR> ToAlternate2 for Pin<P5, Pin6, DIR> {}
impl<DIR> ToAlternate3 for Pin<P5, Pin3, DIR> {}
impl<DIR> ToAlternate3 for Pin<P5, Pin4, DIR> {}
impl<DIR> ToAlternate3 for Pin<P5, Pin2, DIR> {}
impl<DIR> ToAlternate3 for Pin<P5, Pin7, DIR> {}
impl<DIR> ToAlternate1 for Pin<P6, Pin0, DIR> {}
impl<DIR> ToAlternate1 for Pin<P6, Pin1, DIR> {}
impl<DIR> ToAlternate1 for Pin<P6, Pin2, DIR> {}
impl<DIR> ToAlternate3 for Pin<P6, Pin0, DIR> {}