use bb;
use core::marker::PhantomData;
use hal::digital::{InputPin, OutputPin};
use sysctl;
pub trait GpioExt {
type Parts;
fn split(self, power_control: &sysctl::PowerControl) -> Self::Parts;
}
pub trait IsUnlocked {}
pub trait InputMode {}
pub trait OutputMode {}
pub trait OpenDrainMode {
fn pup() -> bool;
}
pub trait AlternateFunctionChoice {
fn number() -> u32;
}
pub struct Input<MODE>
where
MODE: InputMode,
{
_mode: PhantomData<MODE>,
}
impl<MODE> IsUnlocked for Input<MODE>
where
MODE: InputMode,
{
}
pub struct Floating;
impl InputMode for Floating {}
impl OpenDrainMode for Floating {
fn pup() -> bool {
false
}
}
pub struct PullDown;
impl InputMode for PullDown {}
pub struct PullUp;
impl InputMode for PullUp {}
impl OpenDrainMode for PullUp {
fn pup() -> bool {
true
}
}
pub struct Tristate;
impl IsUnlocked for Tristate {}
pub struct Output<MODE>
where
MODE: OutputMode,
{
_mode: PhantomData<MODE>,
}
impl<MODE> IsUnlocked for Output<MODE>
where
MODE: OutputMode,
{
}
pub struct AlternateFunction<AF, MODE>
where
AF: AlternateFunctionChoice,
MODE: OutputMode,
{
_func: PhantomData<AF>,
_mode: PhantomData<MODE>,
}
impl<AF, MODE> IsUnlocked for AlternateFunction<AF, MODE>
where
AF: AlternateFunctionChoice,
MODE: OutputMode,
{
}
pub struct PushPull;
impl OutputMode for PushPull {}
pub struct OpenDrain<ODM>
where
ODM: OpenDrainMode,
{
_pull: PhantomData<ODM>,
}
impl<ODM> OutputMode for OpenDrain<ODM>
where
ODM: OpenDrainMode,
{
}
pub struct AF1;
impl AlternateFunctionChoice for AF1 {
fn number() -> u32 {
return 1;
}
}
pub struct AF2;
impl AlternateFunctionChoice for AF2 {
fn number() -> u32 {
return 2;
}
}
pub struct AF3;
impl AlternateFunctionChoice for AF3 {
fn number() -> u32 {
return 3;
}
}
pub struct AF4;
impl AlternateFunctionChoice for AF4 {
fn number() -> u32 {
return 4;
}
}
pub struct AF5;
impl AlternateFunctionChoice for AF5 {
fn number() -> u32 {
return 5;
}
}
pub struct AF6;
impl AlternateFunctionChoice for AF6 {
fn number() -> u32 {
return 6;
}
}
pub struct AF7;
impl AlternateFunctionChoice for AF7 {
fn number() -> u32 {
return 7;
}
}
pub struct AF8;
impl AlternateFunctionChoice for AF8 {
fn number() -> u32 {
return 8;
}
}
pub struct AF9;
impl AlternateFunctionChoice for AF9 {
fn number() -> u32 {
return 9;
}
}
pub struct AF14;
impl AlternateFunctionChoice for AF14 {
fn number() -> u32 {
return 14;
}
}
pub struct AF15;
impl AlternateFunctionChoice for AF15 {
fn number() -> u32 {
return 15;
}
}
pub struct Locked;
pub enum InterruptMode {
LevelLow,
LevelHigh,
EdgeRising,
EdgeFalling,
EdgeBoth,
Disabled,
}
macro_rules! gpio {
($GPIOX:ident, $gpiox:ident, $iopd:ident, $PXx:ident, [
$($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty),)+
]) => {
pub mod $gpiox {
use super::*;
use tm4c123x::$GPIOX;
pub struct GpioControl {
_0: (),
}
pub struct Parts {
pub control: GpioControl,
$(
pub $pxi: $PXi<$MODE>,
)+
}
impl GpioExt for $GPIOX {
type Parts = Parts;
fn split(self, pc: &sysctl::PowerControl) -> Parts {
sysctl::control_power(
pc, sysctl::Domain::$iopd,
sysctl::RunMode::Run, sysctl::PowerState::On);
sysctl::reset(pc, sysctl::Domain::$iopd);
Parts {
control: GpioControl { _0: () },
$(
$pxi: $PXi { _mode: PhantomData },
)+
}
}
}
pub struct $PXx<MODE> {
i: u8,
_mode: PhantomData<MODE>,
}
impl<MODE> OutputPin for $PXx<Output<MODE>> where MODE: OutputMode {
fn is_high(&self) -> bool {
let p = unsafe { &*$GPIOX::ptr() };
bb::read_bit(&p.data, self.i)
}
fn is_low(&self) -> bool {
!self.is_high()
}
fn set_high(&mut self) {
let p = unsafe { &*$GPIOX::ptr() };
unsafe { bb::change_bit(&p.data, self.i, true); }
}
fn set_low(&mut self) {
let p = unsafe { &*$GPIOX::ptr() };
unsafe { bb::change_bit(&p.data, self.i, false); }
}
}
impl<MODE> InputPin for $PXx<Input<MODE>> where MODE: InputMode {
fn is_high(&self) -> bool {
let p = unsafe { &*$GPIOX::ptr() };
bb::read_bit(&p.data, self.i)
}
fn is_low(&self) -> bool {
!self.is_high()
}
}
impl<MODE> $PXx<Input<MODE>> where MODE: InputMode {
pub fn set_interrupt_mode(&mut self, mode: InterruptMode) {
let p = unsafe { &*$GPIOX::ptr() };
unsafe { bb::change_bit(&p.im, self.i, false); }
match mode {
InterruptMode::LevelHigh => {
unsafe { bb::change_bit(&p.im, self.i, false); }
unsafe { bb::change_bit(&p.is, self.i, true); }
unsafe { bb::change_bit(&p.ibe, self.i, false); }
unsafe { bb::change_bit(&p.iev, self.i, true); }
unsafe { bb::change_bit(&p.im, self.i, true); }
},
InterruptMode::LevelLow => {
unsafe { bb::change_bit(&p.im, self.i, false); }
unsafe { bb::change_bit(&p.is, self.i, true); }
unsafe { bb::change_bit(&p.ibe, self.i, false); }
unsafe { bb::change_bit(&p.iev, self.i, false); }
unsafe { bb::change_bit(&p.im, self.i, true); }
},
InterruptMode::EdgeRising => {
unsafe { bb::change_bit(&p.im, self.i, false); }
unsafe { bb::change_bit(&p.is, self.i, false); }
unsafe { bb::change_bit(&p.ibe, self.i, false); }
unsafe { bb::change_bit(&p.iev, self.i, true); }
unsafe { bb::change_bit(&p.im, self.i, true); }
},
InterruptMode::EdgeFalling => {
unsafe { bb::change_bit(&p.im, self.i, false); }
unsafe { bb::change_bit(&p.is, self.i, false); }
unsafe { bb::change_bit(&p.ibe, self.i, false); }
unsafe { bb::change_bit(&p.iev, self.i, false); }
unsafe { bb::change_bit(&p.im, self.i, true); }
},
InterruptMode::EdgeBoth => {
unsafe { bb::change_bit(&p.im, self.i, false); }
unsafe { bb::change_bit(&p.is, self.i, false); }
unsafe { bb::change_bit(&p.ibe, self.i, true); }
unsafe { bb::change_bit(&p.iev, self.i, true); }
unsafe { bb::change_bit(&p.im, self.i, true); }
},
InterruptMode::Disabled => {
unsafe { bb::change_bit(&p.im, self.i, false); }
},
}
}
pub fn clear_interrupt(&self) {
let p = unsafe { &*$GPIOX::ptr() };
unsafe { bb::change_bit(&p.icr, self.i, true); }
}
}
$(
pub struct $PXi<MODE> {
_mode: PhantomData<MODE>,
}
impl<MODE> $PXi<MODE> where MODE: IsUnlocked {
pub fn into_af_push_pull<AF>(
self,
_gpio_control: &mut GpioControl,
) -> $PXi<AlternateFunction<AF, PushPull>> where AF: AlternateFunctionChoice {
let p = unsafe { &*$GPIOX::ptr() };
let mask = 0xF << ($i * 4);
let bits = AF::number() << ($i * 4);
unsafe {
p.pctl.modify(|r, w| w.bits((r.bits() & !mask) | bits));
}
unsafe { bb::change_bit(&p.afsel, $i, true); }
unsafe { bb::change_bit(&p.dir, $i, false); }
unsafe { bb::change_bit(&p.odr, $i, false); }
unsafe { bb::change_bit(&p.pur, $i, false); }
unsafe { bb::change_bit(&p.pdr, $i, false); }
unsafe { bb::change_bit(&p.den, $i, true); }
$PXi { _mode: PhantomData }
}
pub fn into_af_open_drain<AF, ODM>(
self,
_gpio_control: &mut GpioControl,
) -> $PXi<AlternateFunction<AF, OpenDrain<ODM>>> where AF: AlternateFunctionChoice, ODM: OpenDrainMode {
let p = unsafe { &*$GPIOX::ptr() };
let mask = 0xF << ($i * 4);
let bits = AF::number() << ($i * 4);
unsafe {
p.pctl.modify(|r, w| w.bits((r.bits() & !mask) | bits));
}
unsafe { bb::change_bit(&p.afsel, $i, true); }
unsafe { bb::change_bit(&p.dir, $i, false); }
unsafe { bb::change_bit(&p.odr, $i, true); }
unsafe { bb::change_bit(&p.pur, $i, ODM::pup()); }
unsafe { bb::change_bit(&p.pdr, $i, false); }
unsafe { bb::change_bit(&p.den, $i, true); }
$PXi { _mode: PhantomData }
}
pub fn into_floating_input(
self
) -> $PXi<Input<Floating>> {
let p = unsafe { &*$GPIOX::ptr() };
unsafe { bb::change_bit(&p.afsel, $i, false); }
unsafe { bb::change_bit(&p.dir, $i, false); }
unsafe { bb::change_bit(&p.odr, $i, false); }
unsafe { bb::change_bit(&p.pur, $i, false); }
unsafe { bb::change_bit(&p.pdr, $i, false); }
unsafe { bb::change_bit(&p.den, $i, true); }
$PXi { _mode: PhantomData }
}
pub fn into_pull_down_input(
self
) -> $PXi<Input<PullDown>> {
let p = unsafe { &*$GPIOX::ptr() };
unsafe { bb::change_bit(&p.afsel, $i, false); }
unsafe { bb::change_bit(&p.dir, $i, false); }
unsafe { bb::change_bit(&p.odr, $i, false); }
unsafe { bb::change_bit(&p.pur, $i, false); }
unsafe { bb::change_bit(&p.pdr, $i, true); }
unsafe { bb::change_bit(&p.den, $i, true); }
$PXi { _mode: PhantomData }
}
pub fn into_pull_up_input(
self
) -> $PXi<Input<PullUp>> {
let p = unsafe { &*$GPIOX::ptr() };
unsafe { bb::change_bit(&p.afsel, $i, false); }
unsafe { bb::change_bit(&p.dir, $i, false); }
unsafe { bb::change_bit(&p.odr, $i, false); }
unsafe { bb::change_bit(&p.pur, $i, true); }
unsafe { bb::change_bit(&p.pdr, $i, false); }
unsafe { bb::change_bit(&p.den, $i, true); }
$PXi { _mode: PhantomData }
}
pub fn into_open_drain_output<ODM>(
self
) -> $PXi<Output<OpenDrain<ODM>>> where ODM: OpenDrainMode {
let p = unsafe { &*$GPIOX::ptr() };
unsafe { bb::change_bit(&p.afsel, $i, false); }
unsafe { bb::change_bit(&p.dir, $i, true); }
unsafe { bb::change_bit(&p.odr, $i, true); }
unsafe { bb::change_bit(&p.pur, $i, ODM::pup()); }
unsafe { bb::change_bit(&p.pdr, $i, false); }
unsafe { bb::change_bit(&p.den, $i, true); }
$PXi { _mode: PhantomData }
}
pub fn into_push_pull_output(
self
) -> $PXi<Output<PushPull>> {
let p = unsafe { &*$GPIOX::ptr() };
unsafe { bb::change_bit(&p.afsel, $i, false); }
unsafe { bb::change_bit(&p.dir, $i, true); }
unsafe { bb::change_bit(&p.odr, $i, false); }
unsafe { bb::change_bit(&p.pur, $i, false); }
unsafe { bb::change_bit(&p.pdr, $i, false); }
unsafe { bb::change_bit(&p.den, $i, true); }
$PXi { _mode: PhantomData }
}
pub fn into_tri_state(
self
) -> $PXi<Tristate> {
let p = unsafe { &*$GPIOX::ptr() };
unsafe { bb::change_bit(&p.den, $i, false); }
unsafe { bb::change_bit(&p.afsel, $i, false); }
unsafe { bb::change_bit(&p.dir, $i, false); }
unsafe { bb::change_bit(&p.odr, $i, false); }
unsafe { bb::change_bit(&p.pur, $i, false); }
unsafe { bb::change_bit(&p.pdr, $i, false); }
$PXi { _mode: PhantomData }
}
}
impl<MODE> $PXi<MODE> {
pub fn downgrade(self) -> $PXx<MODE> {
$PXx {
i: $i,
_mode: self._mode,
}
}
}
impl<MODE> OutputPin for $PXi<Output<MODE>> where MODE: OutputMode {
fn is_high(&self) -> bool {
let p = unsafe { &*$GPIOX::ptr() };
bb::read_bit(&p.data, $i)
}
fn is_low(&self) -> bool {
!self.is_high()
}
fn set_high(&mut self) {
let p = unsafe { &*$GPIOX::ptr() };
unsafe { bb::change_bit(&p.data, $i, true); }
}
fn set_low(&mut self) {
let p = unsafe { &*$GPIOX::ptr() };
unsafe { bb::change_bit(&p.data, $i, false); }
}
}
impl<MODE> InputPin for $PXi<Input<MODE>> where MODE: InputMode {
fn is_high(&self) -> bool {
let p = unsafe { &*$GPIOX::ptr() };
bb::read_bit(&p.data, $i)
}
fn is_low(&self) -> bool {
!self.is_high()
}
}
impl<MODE> $PXi<Input<MODE>> where MODE: InputMode {
pub fn set_interrupt_mode(&mut self, mode: InterruptMode) {
let p = unsafe { &*$GPIOX::ptr() };
unsafe { bb::change_bit(&p.im, $i, false); }
match mode {
InterruptMode::LevelHigh => {
unsafe { bb::change_bit(&p.im, $i, false); }
unsafe { bb::change_bit(&p.is, $i, true); }
unsafe { bb::change_bit(&p.ibe, $i, false); }
unsafe { bb::change_bit(&p.iev, $i, true); }
unsafe { bb::change_bit(&p.im, $i, true); }
},
InterruptMode::LevelLow => {
unsafe { bb::change_bit(&p.im, $i, false); }
unsafe { bb::change_bit(&p.is, $i, true); }
unsafe { bb::change_bit(&p.ibe, $i, false); }
unsafe { bb::change_bit(&p.iev, $i, false); }
unsafe { bb::change_bit(&p.im, $i, true); }
},
InterruptMode::EdgeRising => {
unsafe { bb::change_bit(&p.im, $i, false); }
unsafe { bb::change_bit(&p.is, $i, false); }
unsafe { bb::change_bit(&p.ibe, $i, false); }
unsafe { bb::change_bit(&p.iev, $i, true); }
unsafe { bb::change_bit(&p.im, $i, true); }
},
InterruptMode::EdgeFalling => {
unsafe { bb::change_bit(&p.im, $i, false); }
unsafe { bb::change_bit(&p.is, $i, false); }
unsafe { bb::change_bit(&p.ibe, $i, false); }
unsafe { bb::change_bit(&p.iev, $i, false); }
unsafe { bb::change_bit(&p.im, $i, true); }
},
InterruptMode::EdgeBoth => {
unsafe { bb::change_bit(&p.im, $i, false); }
unsafe { bb::change_bit(&p.is, $i, false); }
unsafe { bb::change_bit(&p.ibe, $i, true); }
unsafe { bb::change_bit(&p.iev, $i, true); }
unsafe { bb::change_bit(&p.im, $i, true); }
},
InterruptMode::Disabled => {
unsafe { bb::change_bit(&p.im, $i, false); }
},
}
}
pub fn clear_interrupt(&self) {
let p = unsafe { &*$GPIOX::ptr() };
unsafe { bb::change_bit(&p.icr, $i, true); }
}
}
impl $PXi<Locked> {
pub fn unlock(self, _gpio_control: &mut GpioControl) -> $PXi<Tristate> {
let p = unsafe { &*$GPIOX::ptr() };
p.lock.write(|w| w.lock().key());
p.cr.modify(|_, w| unsafe { w.bits(1 << $i) });
p.lock.write(|w| w.lock().unlocked());
unsafe { bb::change_bit(&p.den, $i, false); }
unsafe { bb::change_bit(&p.afsel, $i, false); }
unsafe { bb::change_bit(&p.dir, $i, false); }
unsafe { bb::change_bit(&p.odr, $i, false); }
unsafe { bb::change_bit(&p.pur, $i, false); }
unsafe { bb::change_bit(&p.pdr, $i, false); }
$PXi { _mode: PhantomData }
}
}
)+
}
}
}
gpio!(GPIO_PORTA, gpioa, GpioA, PAx, [
PA0: (pa0, 0, Tristate),
PA1: (pa1, 1, Tristate),
PA2: (pa2, 2, Tristate),
PA3: (pa3, 3, Tristate),
PA4: (pa4, 4, Tristate),
PA5: (pa5, 5, Tristate),
PA6: (pa6, 6, Tristate),
PA7: (pa7, 7, Tristate),
]);
gpio!(GPIO_PORTB, gpiob, GpioB, PBx, [
PB0: (pb0, 0, Tristate),
PB1: (pb1, 1, Tristate),
PB2: (pb2, 2, Tristate),
PB3: (pb3, 3, Tristate),
PB4: (pb4, 4, Tristate),
PB5: (pb5, 5, Tristate),
PB6: (pb6, 6, Tristate),
PB7: (pb7, 7, Tristate),
]);
gpio!(GPIO_PORTC, gpioc, GpioC, PCx, [
PC0: (pc0, 0, Locked), PC1: (pc1, 1, Locked), PC2: (pc2, 2, Locked), PC3: (pc3, 3, Locked), PC4: (pc4, 4, Tristate),
PC5: (pc5, 5, Tristate),
PC6: (pc6, 6, Tristate),
PC7: (pc7, 7, Tristate),
]);
gpio!(GPIO_PORTD, gpiod, GpioD, PDx, [
PD0: (pd0, 0, Tristate),
PD1: (pd1, 1, Tristate),
PD2: (pd2, 2, Tristate),
PD3: (pd3, 3, Tristate),
PD4: (pd4, 4, Tristate),
PD5: (pd5, 5, Tristate),
PD6: (pd6, 6, Tristate),
PD7: (pd7, 7, Locked), ]);
gpio!(GPIO_PORTE, gpioe, GpioE, PEx, [
PE0: (pe0, 0, Tristate),
PE1: (pe1, 1, Tristate),
PE2: (pe2, 2, Tristate),
PE3: (pe3, 3, Tristate),
PE4: (pe4, 4, Tristate),
PE5: (pe5, 5, Tristate),
PE6: (pe6, 6, Tristate),
PE7: (pe7, 7, Tristate),
]);
gpio!(GPIO_PORTF, gpiof, GpioF, PFx, [
PF0: (pf0, 0, Locked), PF1: (pf1, 1, Tristate),
PF2: (pf2, 2, Tristate),
PF3: (pf3, 3, Tristate),
PF4: (pf4, 4, Tristate),
PF5: (pf5, 5, Tristate),
PF6: (pf6, 6, Tristate),
PF7: (pf7, 7, Tristate),
]);