#![no_std]
#![deny(missing_docs, warnings)]
#![allow(deprecated)]
pub mod bb;
pub mod delay;
pub mod gpio;
pub mod i2c;
pub mod serial;
pub mod sysctl;
pub mod time;
#[macro_export]
macro_rules! gpio_macro {
($chip_crate:ident, $GPIOX:ident, $gpiox:ident, $iopd:ident, $PXx:ident, [
$($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty),)+
]) => {
pub mod $gpiox {
use super::*;
use $chip_crate::$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> StatefulOutputPin for $PXx<Output<MODE>> where MODE: OutputMode {
fn is_set_high(&self) -> bool {
let p = unsafe { &*$GPIOX::ptr() };
bb::read_bit(&p.data, self.i)
}
fn is_set_low(&self) -> bool {
!self.is_set_high()
}
}
impl<MODE> OutputPin for $PXx<Output<MODE>> where MODE: OutputMode {
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 get_interrupt_status(&self) -> bool {
let p = unsafe { &*$GPIOX::ptr() };
bb::read_bit(&p.mis, self.i)
}
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_pull_up<AF>(
self,
_gpio_control: &mut GpioControl,
) -> $PXi<AlternateFunction<AF, PullUp>> 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, true); }
unsafe { bb::change_bit(&p.pdr, $i, false); }
unsafe { bb::change_bit(&p.den, $i, true); }
$PXi { _mode: PhantomData }
}
pub fn into_af_pull_down<AF>(
self,
_gpio_control: &mut GpioControl,
) -> $PXi<AlternateFunction<AF, PullDown>> 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, true); }
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> StatefulOutputPin for $PXi<Output<MODE>> where MODE: OutputMode {
fn is_set_high(&self) -> bool {
let p = unsafe { &*$GPIOX::ptr() };
bb::read_bit(&p.data, $i)
}
fn is_set_low(&self) -> bool {
!self.is_set_high()
}
}
impl<MODE> OutputPin for $PXi<Output<MODE>> where MODE: OutputMode {
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 get_interrupt_status(&self) -> bool {
let p = unsafe { &*$GPIOX::ptr() };
bb::read_bit(&p.mis, $i)
}
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 }
}
}
)+
}
}
}
#[macro_export]
macro_rules! uart_hal_macro {
($(
$UARTX:ident: ($powerDomain:ident, $uartX:ident),
)+) => {
$(
impl<TX, RX, RTS, CTS> Serial<$UARTX, TX, RX, RTS, CTS> {
pub fn $uartX(
mut uart: $UARTX,
tx_pin: TX,
rx_pin: RX,
mut rts_pin: RTS,
mut cts_pin: CTS,
baud_rate: Bps,
nl_mode: NewlineMode,
clocks: &Clocks,
pc: &sysctl::PowerControl
) -> Self
where
TX: TxPin<$UARTX>,
RX: RxPin<$UARTX>,
CTS: CtsPin<$UARTX>,
RTS: RtsPin<$UARTX>,
{
sysctl::control_power(
pc, sysctl::Domain::$powerDomain,
sysctl::RunMode::Run, sysctl::PowerState::On);
sysctl::reset(pc, sysctl::Domain::$powerDomain);
uart.ctl.reset();
let baud_int: u32 = (((clocks.sysclk.0 * 8) / baud_rate.0) + 1) / 2;
uart.ibrd.write(|w|
unsafe { w.divint().bits((baud_int / 64) as u16) });
uart.fbrd.write(|w|
unsafe { w.divfrac().bits((baud_int % 64) as u8) });
uart.lcrh.write(|w| w.wlen()._8().fen().bit(true));
rts_pin.enable(&mut uart);
cts_pin.enable(&mut uart);
uart.ctl.modify(|_, w| w.rxe().bit(true).txe().bit(true).uarten().bit(true));
Serial { uart, tx_pin, rx_pin, rts_pin, cts_pin, nl_mode }
}
pub fn change_baud_rate(&mut self, baud_rate: Bps, clocks: &Clocks) {
self.uart.ctl.modify(|_, w| w.uarten().bit(false));
let baud_int: u32 = (((clocks.sysclk.0 * 8) / baud_rate.0) + 1) / 2;
self.uart.ibrd.write(|w|
unsafe { w.divint().bits((baud_int / 64) as u16) });
self.uart.fbrd.write(|w|
unsafe { w.divfrac().bits((baud_int % 64) as u8) });
self.uart.lcrh.write(|w| w.wlen()._8().fen().bit(true));
self.uart.ctl.modify(|_, w| w.uarten().bit(true));
}
pub fn split(self) -> (Tx<$UARTX, TX, RTS>, Rx<$UARTX, RX, CTS>) {
(
Tx {
uart: self.uart,
pin: self.tx_pin,
nl_mode: self.nl_mode,
flow_pin: self.rts_pin,
},
Rx {
_uart: PhantomData,
pin: self.rx_pin,
flow_pin: self.cts_pin,
},
)
}
pub fn write_all<I: ?Sized>(&mut self, data: &I)
where
I: AsRef<[u8]>,
{
for octet in data.as_ref().iter() {
block!(self.write(*octet)).unwrap();
}
}
pub fn combine(tx: Tx<$UARTX, TX, RTS>, rx: Rx<$UARTX, RX, CTS>) -> Serial<$UARTX, TX, RX, RTS, CTS> {
Serial {
uart: tx.uart,
nl_mode: tx.nl_mode,
rx_pin: rx.pin,
tx_pin: tx.pin,
rts_pin: tx.flow_pin,
cts_pin: rx.flow_pin,
}
}
pub fn free(self) -> ($UARTX, TX, RX, RTS, CTS) {
(self.uart, self.tx_pin, self.rx_pin, self.rts_pin, self.cts_pin)
}
}
impl<TX, RTS> Tx<$UARTX, TX, RTS> {
pub fn write_all<I: ?Sized>(&mut self, data: &I)
where
I: AsRef<[u8]>,
{
for octet in data.as_ref().iter() {
block!(self.write(*octet)).unwrap();
}
}
}
impl<TX, RX, RTS, CTS> serial::Read<u8> for Serial<$UARTX, TX, RX, RTS, CTS> {
type Error = Void;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
if self.uart.fr.read().rxfe().bit() {
return Err(nb::Error::WouldBlock);
}
Ok(self.uart.dr.read().data().bits())
}
}
impl<RX, CTS> serial::Read<u8> for Rx<$UARTX, RX, CTS> {
type Error = Void;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
let p = unsafe { &*$UARTX::ptr() };
if p.fr.read().rxfe().bit() {
return Err(nb::Error::WouldBlock);
}
Ok(p.dr.read().data().bits())
}
}
impl<TX, RX, RTS, CTS> serial::Write<u8> for Serial<$UARTX, TX, RX, RTS, CTS> {
type Error = Void;
fn flush(&mut self) -> nb::Result<(), Void> {
if self.uart.fr.read().txff().bit() {
return Err(nb::Error::WouldBlock);
}
Ok(())
}
fn write(&mut self, byte: u8) -> nb::Result<(), Void> {
if self.uart.fr.read().txff().bit() {
return Err(nb::Error::WouldBlock);
}
self.uart.dr.write(|w| unsafe { w.data().bits(byte) });
Ok(())
}
}
impl<TX, RTS> serial::Write<u8> for Tx<$UARTX, TX, RTS> {
type Error = Void;
fn flush(&mut self) -> nb::Result<(), Void> {
if self.uart.fr.read().txff().bit() {
return Err(nb::Error::WouldBlock);
}
Ok(())
}
fn write(&mut self, byte: u8) -> nb::Result<(), Void> {
if self.uart.fr.read().txff().bit() {
return Err(nb::Error::WouldBlock);
}
self.uart.dr.write(|w| unsafe { w.data().bits(byte) });
Ok(())
}
}
impl<TX, RX, RTS, CTS> fmt::Write for Serial<$UARTX, TX, RX, RTS, CTS> {
fn write_str(&mut self, s: &str) -> fmt::Result {
match self.nl_mode {
NewlineMode::Binary => self.write_all(s),
NewlineMode::SwapLFtoCRLF => {
for byte in s.bytes() {
if byte == 0x0A {
block!(self.write(0x0D)).unwrap();
}
block!(self.write(byte)).unwrap();
}
}
}
Ok(())
}
}
impl<TX, RTS> fmt::Write for Tx<$UARTX, TX, RTS> {
fn write_str(&mut self, s: &str) -> fmt::Result {
match self.nl_mode {
NewlineMode::Binary => self.write_all(s),
NewlineMode::SwapLFtoCRLF => {
for byte in s.bytes() {
if byte == 0x0A {
block!(self.write(0x0D)).unwrap();
}
block!(self.write(byte)).unwrap();
}
}
}
Ok(())
}
}
)+
}
}
#[macro_export]
macro_rules! uart_pin_macro {
($UARTn:ident,
cts: [$(($($ctsgpio: ident)::*, $ctsaf: ident)),*],
rts: [$(($($rtsgpio: ident)::*, $rtsaf: ident)),*],
rx: [$(($($rxgpio: ident)::*, $rxaf: ident)),*],
tx: [$(($($txgpio: ident)::*, $txaf: ident)),*],
) => {
$(
unsafe impl<T> CtsPin<$UARTn> for $($ctsgpio)::*<AlternateFunction<$ctsaf, T>>
where
T: OutputMode,
{
fn enable(&mut self, uart: &mut $UARTn) {
uart.ctl.modify(|_, w| w.ctsen().set_bit());
}
}
)*
$(
unsafe impl<T> RtsPin<$UARTn> for $($rtsgpio)::*<AlternateFunction<$rtsaf, T>>
where
T: OutputMode,
{
fn enable(&mut self, uart: &mut $UARTn) {
uart.ctl.modify(|_, w| w.rtsen().set_bit());
}
}
)*
$(
unsafe impl <T> RxPin<$UARTn> for $($rxgpio)::*<AlternateFunction<$rxaf, T>>
where
T: OutputMode,
{}
)*
$(
unsafe impl <T> TxPin<$UARTn> for $($txgpio)::*<AlternateFunction<$txaf, T>>
where
T: OutputMode,
{}
)*
}
}