Skip to content
This repository has been archived by the owner on Jun 23, 2024. It is now read-only.

Commit

Permalink
continuing GPIO implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
robamu committed Nov 4, 2021
1 parent 923c32b commit bf44097
Showing 1 changed file with 239 additions and 39 deletions.
278 changes: 239 additions & 39 deletions src/gpio.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use embedded_hal::digital::v2::toggleable;
use core::marker::PhantomData;
use crate::{pac::SYSCONFIG};

/// Extension trait to split a GPIO peripheral in independent pins and registers
pub trait GpioExt {
/// The parts to split the GPIO into.
type Parts;

/// Splits the GPIO block into independent pins and registers.
fn split(self) -> Self::Parts;
fn split(self, syscfg: &mut SYSCONFIG) -> Self::Parts;
}

trait GpioRegExt {
Expand Down Expand Up @@ -40,77 +41,276 @@ pub struct OutputInverted;

pub struct InputInverted;

// FUNSEL0 is the regular GPIO port configuration
pub struct FUNSEL1;
pub struct FUNSEL2;
pub struct FUNSEL3;

/// Function select (type state)
pub struct Funsel<FUN> {
_mode: PhantomData<FUN>,
}

pub enum FilterType {
SystemClock = 0,
DirectInputWithSynchronization = 1,
FilterOneClockCycle = 2,
FilterTwoClockCycles = 3,
FilterThreeClockCycles = 4,
FilterFourClockCycles = 5
}

pub enum FilterClkSel {
SysClk = 0,
Clk1 = 1,
Clk2 = 2,
Clk3 = 3,
Clk4 = 4,
Clk5 = 5,
Clk6 = 6,
Clk7 = 7
}

/// Fully erased pin
pub struct Pin<MODE> {
i: u8,
port: *const dyn GpioRegExt,
_mode: PhantomData<MODE>,
}
unsafe impl<MODE> Sync for Pin<MODE> {}
// NOTE(unsafe) this only enables read access to the same pin from multiple threads
unsafe impl<MODE> Send for Pin<MODE> {}
// pub struct PA0;
// pub struct PA1;
// pub struct PA2;
// pub struct PA3;

// pub struct PORTA;
// pub struct PORTB;

// impl PORTA {
// pub fn split(self) -> PortAPins {
// PortAPins {
// pa0: PA0,
// pa1: PA1,
// pa2: PA2,
// pa3: PA3
// }
// }
// }

// pub struct PortAPins {
// pub pa0: PA0,
// pub pa1: PA1,
// pub pa2: PA2,
// pub pa3: PA3
// }

impl GpioRegExt for crate::pac::porta::RegisterBlock {
fn is_low(&self, pos: u8) -> bool {
self.datainraw().read().bits() & (1 << pos) == 0
}
fn is_set_low(&self, pos: u8) -> bool {
// TODO: The SVD files might have errors again. This pin should be readable
false
//self.dataoutraw().read().bits() & (1 << pos) == 0
}
fn set_high(&self, pos: u8) {
unsafe { self.setout().write(|w| w.bits(1 << pos)) }
}
fn set_low(&self, pos: u8) {
unsafe { self.clrout().write(|w| w.bits(1 << pos)) }
}
}

pub mod gpioa {
use core::marker::PhantomData;
use core::convert::Infallible;
use cortex_m::interrupt::CriticalSection;
use super::{
Input, GpioExt, Floating
FUNSEL1, FUNSEL2, FUNSEL3, Floating, Funsel, GpioExt, Input, OpenDrain,
PullUp, Output, FilterType, FilterClkSel, Pin, GpioRegExt
};
use crate::{pac::PORTA, pac::SYSCONFIG};
use crate::{pac::PORTA, pac::SYSCONFIG, pac::IOCONFIG};
pub struct Parts {
pub pa0: PA0<Input<Floating>>
}

impl GpioExt for PORTA {
type Parts = Parts;
fn split(self) -> Parts {
unsafe {
let reg = &(*SYSCONFIG::ptr());
reg.peripheral_clk_enable.modify(|r, w| {
w.bits(r.bits() & 1 << 24 | 1 << 0 | 1 << 2)
})
}
fn split(self, syscfg: &mut SYSCONFIG) -> Parts {
syscfg.peripheral_clk_enable.modify(|_, w| {
w.porta().set_bit();
w.gpio().set_bit();
w.ioconfig().set_bit();
w
});
Parts {
pa0: PA0 { _mode: PhantomData }
}
}
}

fn _set_alternate_mode(index: usize, mode: u32) {
let offset = 2 * index;
let offset2 = 4 * index;
fn _set_alternate_mode(index: usize, mode: u8) {
unsafe {
let reg = &(*IOCONFIG::ptr());
reg.porta[index].modify(|_, w| {
w.funsel().bits(mode)
})
}
}

pub struct PA0<MODE> {
_mode: PhantomData<MODE>,
}
impl<MODE> PA0<MODE> {
pub fn into_funsel_1(self, _cs: &CriticalSection) -> PA0<Funsel<FUNSEL1>> {
_set_alternate_mode(0, 1);
PA0 { _mode: PhantomData }
}
pub fn into_funsel_2(self, _cs: &CriticalSection) -> PA0<Funsel<FUNSEL2>> {
_set_alternate_mode(0, 2);
PA0 { _mode: PhantomData }
}
pub fn into_funsel_3(self, _cs: &CriticalSection) -> PA0<Funsel<FUNSEL3>> {
_set_alternate_mode(0, 3);
PA0 { _mode: PhantomData }
}
pub fn into_floating_input(self, _cs: &CriticalSection) -> PA0<Input<Floating>> {
unsafe {
let reg = &(*IOCONFIG::ptr());
reg.porta[0].modify(|_, w| {
w.funsel().bits(0);
w.pen().clear_bit();
w.opendrn().clear_bit()
});
let port_reg = &(*PORTA::ptr());
port_reg.dir().modify(|r,w| w.bits(r.bits() & !(1 << 0)));
}
PA0 { _mode: PhantomData }
}

pub fn into_pull_up_input(self, _cs: &CriticalSection) -> PA0<Input<PullUp>> {
unsafe {
let reg = &(*IOCONFIG::ptr());
reg.porta[0].modify(|_, w| {
w.funsel().bits(0);
w.pen().set_bit();
w.plevel().set_bit();
w.opendrn().clear_bit()
});
let port_reg = &(*PORTA::ptr());
port_reg.dir().modify(|r,w| w.bits(r.bits() & !(1 << 0)));
}
PA0 { _mode: PhantomData }
}

pub fn into_pull_down_input(self, _cs: &CriticalSection) -> PA0<Input<PullUp>> {
unsafe {
let reg = &(*IOCONFIG::ptr());
reg.porta[0].modify(|_, w| {
w.funsel().bits(0);
w.pen().set_bit();
w.plevel().clear_bit();
w.opendrn().clear_bit()
});
let port_reg = &(*PORTA::ptr());
port_reg.dir().modify(|r,w| w.bits(r.bits() & !(1 << 0)));
}
PA0 { _mode: PhantomData }
}

pub fn into_open_drain_output(self, _cs: &CriticalSection) -> PA0<OpenDrain> {
unsafe {
let reg = &(*IOCONFIG::ptr());
reg.porta[0].modify(|_, w| {
w.funsel().bits(0);
w.pen().clear_bit();
w.opendrn().set_bit()
});
let port_reg = &(*PORTA::ptr());
port_reg.dir().modify(|r,w| w.bits(r.bits() | (1 << 0)));
}
PA0 { _mode: PhantomData }
}

pub fn filter_type(self, _cs: &CriticalSection, filter: FilterType, clksel: FilterClkSel) -> Self {
unsafe {
let reg = &(*IOCONFIG::ptr());
reg.porta[0].modify(|_, w| {
w.flttype().bits(filter as u8);
w.fltclk().bits(clksel as u8)
})
}
self
}
}
impl<MODE> PA0<Input<MODE>> {
pub fn input_inversion(self, _cs: &CriticalSection, enable: bool) -> Self {
unsafe {
let reg = &(*IOCONFIG::ptr());
if enable {
reg.porta[0].modify(|_, w| w.invinp().set_bit());
} else {
reg.porta[0].modify(|_, w| w.invinp().clear_bit());
}
}
self
}
}
impl<MODE> PA0<Output<MODE>> {
pub fn output_inversion(self, _cs: &CriticalSection, enable: bool) -> Self {
unsafe {
let reg = &(*IOCONFIG::ptr());
if enable {
reg.porta[0].modify(|_, w| w.invout().set_bit());
} else {
reg.porta[0].modify(|_, w| w.invout().clear_bit());
}
}
self
}

/// Enable Input even when in output mode. In
/// this mode the input receiver is enabled even
/// if the direction is configured as an output.
/// This allows monitoring of output values
pub fn enable_input(self, _cs: &CriticalSection, enable: bool) -> Self {
unsafe {
let reg = &(*IOCONFIG::ptr());
if enable {
reg.porta[0].modify(|_, w| w.iewo().set_bit());
} else {
reg.porta[0].modify(|_, w| w.iewo().clear_bit());
}
}
self
}

/// Enable Pull up/down even when output is active. The Default is to disable pull
/// up/down when output is actively driven. This bit enables the pull up/down all the time.
///
/// # Arguments
///
/// `enable` - Enable the peripheral functionality
/// `enable_pullup` - Enable the pullup itself
pub fn enable_pull_up(self, _cs: &CriticalSection, enable: bool, enable_pullup: bool) -> Self {
unsafe {
let reg = &(*IOCONFIG::ptr());
reg.porta[0].modify(|_, w| {
if enable { w.pwoa().set_bit(); } else { w.pwoa().clear_bit(); }
if enable_pullup { w.pen().set_bit(); } else { w.pen().clear_bit(); }
w.plevel().set_bit()

});
}
self
}
/// Enable Pull up/down even when output is active. The Default is to disable pull
/// up/down when output is actively driven. This bit enables the pull up/down all the time.
///
/// # Arguments
///
/// `enable` - Enable the peripheral functionality
/// `enable_pullup` - Enable the pulldown itself
pub fn enable_pull_down(self, _cs: &CriticalSection, enable: bool, enable_pulldown: bool) -> Self {
unsafe {
let reg = &(*IOCONFIG::ptr());
reg.porta[0].modify(|_, w| {
if enable { w.pwoa().set_bit(); } else { w.pwoa().clear_bit(); }
if enable_pulldown { w.pen().set_bit(); } else { w.pen().clear_bit(); }
w.plevel().clear_bit()

});
}
self
}
}
impl<MODE> PA0<Output<MODE>> {
/// Erases the pin number from the type
///
/// This is useful when you want to collect the pins into an array where you
/// need all the elements to have the same type
pub fn downgrade(self) -> Pin<Output<MODE>> {
Pin {
i: 0,
port: PORTA::ptr() as *const dyn GpioRegExt,
_mode: self._mode,
}
}
}
}

0 comments on commit bf44097

Please sign in to comment.