pub use embedded_hal::digital::PinState; pub use crate::InvalidOffsetError; pub use crate::Port; pub use crate::ioconfig::regs::Pull; use crate::ioconfig::regs::{FunSel, IoConfig, MmioIoConfig}; pub struct LowLevelGpio { gpio: super::regs::MmioGpio<'static>, ioconfig: MmioIoConfig<'static>, port: Port, offset: usize, } impl LowLevelGpio { pub fn new(port: Port, offset: usize) -> Result { if offset >= port.max_offset() { return Err(InvalidOffsetError { offset, port: Port::A, }); } Ok(LowLevelGpio { gpio: super::regs::Gpio::new_mmio(port), ioconfig: IoConfig::new_mmio(), port, offset, }) } #[inline] pub fn port(&self) -> Port { self.port } #[inline] pub fn offset(&self) -> usize { self.offset } pub fn configure_as_input_floating(&mut self) { unsafe { self.ioconfig .modify_pin_config_unchecked(self.port, self.offset, |mut config| { config.set_funsel(FunSel::Sel0); config.set_io_disable(false); config.set_invert_input(false); config.set_open_drain(false); config.set_pull_enable(false); config.set_pull_when_output_active(false); config.set_invert_output(false); config.set_input_enable_when_output(false); config }); } self.gpio.modify_dir(|mut dir| { dir &= !(1 << self.offset); dir }); } pub fn configure_as_input_with_pull(&mut self, pull: Pull) { unsafe { self.ioconfig .modify_pin_config_unchecked(self.port, self.offset, |mut config| { config.set_funsel(FunSel::Sel0); config.set_io_disable(false); config.set_invert_input(false); config.set_open_drain(false); config.set_pull_enable(true); config.set_pull_dir(pull); config.set_pull_when_output_active(false); config.set_invert_output(false); config.set_input_enable_when_output(false); config }); } self.gpio.modify_dir(|mut dir| { dir &= !(1 << self.offset); dir }); } pub fn configure_as_output_push_pull(&mut self, init_level: PinState) { unsafe { self.ioconfig .modify_pin_config_unchecked(self.port, self.offset, |mut config| { config.set_funsel(FunSel::Sel0); config.set_io_disable(false); config.set_invert_input(false); config.set_open_drain(false); config.set_pull_enable(false); config.set_pull_when_output_active(false); config.set_invert_output(false); config.set_input_enable_when_output(true); config }); } match init_level { PinState::Low => self.gpio.write_clr_out(1 << self.offset), PinState::High => self.gpio.write_set_out(1 << self.offset), } self.gpio.modify_dir(|mut dir| { dir |= 1 << self.offset; dir }); } pub fn configure_as_output_open_drain(&mut self, init_level: PinState) { unsafe { self.ioconfig .modify_pin_config_unchecked(self.port, self.offset, |mut config| { config.set_funsel(FunSel::Sel0); config.set_io_disable(false); config.set_invert_input(false); config.set_open_drain(true); config.set_pull_enable(true); config.set_pull_dir(Pull::Up); config.set_pull_when_output_active(false); config.set_invert_output(false); config.set_input_enable_when_output(true); config }); } match init_level { PinState::Low => self.gpio.write_clr_out(1 << self.offset), PinState::High => self.gpio.write_set_out(1 << self.offset), } self.gpio.modify_dir(|mut dir| { dir |= 1 << self.offset; dir }); } pub fn configure_as_peripheral_pin(&mut self, fun_sel: FunSel, pull: Option) { unsafe { self.ioconfig .modify_pin_config_unchecked(self.port, self.offset, |mut config| { config.set_funsel(fun_sel); config.set_io_disable(false); config.set_invert_input(false); config.set_open_drain(false); config.set_pull_enable(pull.is_some()); config.set_pull_dir(pull.unwrap_or(Pull::Up)); config.set_invert_output(false); config }); } } #[inline] pub fn is_high(&self) -> bool { (self.gpio.read_data_in() >> self.offset) & 1 == 1 } #[inline] pub fn is_low(&self) -> bool { !self.is_high() } #[inline] pub fn set_high(&mut self) { self.gpio.write_set_out(1 << self.offset); } #[inline] pub fn set_low(&mut self) { self.gpio.write_clr_out(1 << self.offset); } #[inline] pub fn is_set_high(&self) -> bool { (self.gpio.read_data_out() >> self.offset) & 1 == 1 } #[inline] pub fn is_set_low(&self) -> bool { !self.is_set_high() } #[inline] pub fn toggle(&mut self) { self.gpio.write_tog_out(1 << self.offset); } }