diff --git a/Cargo.toml b/Cargo.toml index 9220a80629b3b90c207b745a94bcba10bb6abbc8..ed8869ab7642aa042629956d77fbb8072afafd1b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +base-address = "0.0.0" +volatile-register = "0.2.1" +embedded-hal = "1.0.0-alpha.10" diff --git a/src/glb.rs b/src/glb.rs new file mode 100644 index 0000000000000000000000000000000000000000..ae305abdbe159f784548a5e5e520e8b1b3728725 --- /dev/null +++ b/src/glb.rs @@ -0,0 +1,201 @@ +/// Author: Mingrui Ma, Zeqing Qin +use core::cell::UnsafeCell; + +use volatile_register::{RO, RW, WO}; + +/// Generic Purpose Input/Output registers. +#[repr(C)] +pub struct RegisterBlock { + _reserved0: [u8; 0x8c4], + /// Generic Purpose Input/Output config + pub gpio_config: [GPIO_CONFIG; 46], + _reserved1: [u8; 0x148], + /// Read value from Generic Purpose Input/Output pins + pub gpio_input: [RO; 2], + _reserved2: [u8; 0x18], + /// Write value to Generic Purpose Input/Output pins + pub gpio_output: [RW; 2], + /// Set pin output value to high + pub gpio_set: [WO; 2], + /// Clear pin output value to low + pub gpio_clear: [WO; 2], +} + +/// Generic Purpose Input/Output Configuration register. +#[allow(non_camel_case_types)] +#[repr(transparent)] +pub struct GPIO_CONFIG(UnsafeCell); + +/// Configuration structure for current GPIO pin. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] +#[repr(transparent)] +pub struct GpioConfig(u32); + +impl GPIO_CONFIG { + /// Read GPIO pin configuration. + #[inline] + pub fn read(&self) -> GpioConfig { + GpioConfig(unsafe { self.0.get().read_volatile() }) + } + /// Write GPIO pin configuration. + #[inline] + pub fn write(&self, val: GpioConfig) { + unsafe { self.0.get().write_volatile(val.0) } + } +} + +impl GpioConfig { + const INPUT_ENABLE: u32 = 1 << 0; + const SCHMITT: u32 = 1 << 1; + const DRIVE: u32 = 0x3 << 2; + const OUTPUT_ENABLE: u32 = 1 << 6; + const FUNCTION: u32 = 0x1f << 8; + const CLEAR_INTERRUPT: u32 = 1 << 20; + const HAS_INTERRUPT: u32 = 1 << 21; + const INTERRUPT_MASK: u32 = 1 << 22; + const OUTPUT: u32 = 1 << 24; + const SET: u32 = 1 << 25; + const CLEAR: u32 = 1 << 26; + const INPUT: u32 = 1 << 28; + + /// Enable input function of current pin. + #[inline] + pub const fn enable_input(self) -> Self { + Self(self.0 | Self::INPUT_ENABLE) + } + /// Disable input function of current pin. + #[inline] + pub const fn disable_input(self) -> Self { + Self(self.0 & !Self::INPUT_ENABLE) + } + /// Check if input function of current pin is enabled. + #[inline] + pub const fn is_input_enabled(self) -> bool { + self.0 & Self::INPUT_ENABLE != 0 + } + /// Enable Schmitt trigger function of current pin. + #[inline] + pub const fn enable_schmitt(self) -> Self { + Self(self.0 | Self::SCHMITT) + } + /// Disable Schmitt trigger function of current pin. + #[inline] + pub const fn disable_schmitt(self) -> Self { + Self(self.0 & !Self::SCHMITT) + } + /// Check if Schmitt trigger function of current pin is enabled. + #[inline] + pub const fn is_schmitt_enabled(self) -> bool { + self.0 & Self::SCHMITT != 0 + } + /// Enable output function of current pin. + #[inline] + pub const fn enable_output(self) -> Self { + Self(self.0 | Self::OUTPUT_ENABLE) + } + /// Disable output function of current pin. + #[inline] + pub const fn disable_output(self) -> Self { + Self(self.0 & !Self::OUTPUT_ENABLE) + } + /// Check if output function of current pin is enabled. + #[inline] + pub const fn is_output_enabled(self) -> bool { + self.0 & Self::OUTPUT_ENABLE != 0 + } + /// Enable interrupt function of current pin. + #[inline] + pub const fn mask_interrupt(self) -> Self { + Self(self.0 | Self::INTERRUPT_MASK) + } + /// Disable interrupt function of current pin. + #[inline] + pub const fn unmask_interrupt(self) -> Self { + Self(self.0 & !Self::INTERRUPT_MASK) + } + /// Check if interrupt function of current pin is enabled. + #[inline] + pub const fn is_interrupt_masked(self) -> bool { + self.0 & Self::INTERRUPT_MASK != 0 + } + /// Get output of current pin. + #[inline] + pub const fn output(self) -> bool { + self.0 & Self::OUTPUT != 0 + } + /// Get intput of current pin. + #[inline] + pub const fn input(self) -> bool { + self.0 & Self::INPUT != 0 + } + /// Check if current pin has interrupt function + #[inline] + pub const fn has_interrupt(self) -> bool { + self.0 & Self::HAS_INTERRUPT != 0 + } + /// Set pin output value to high. + #[inline] + pub const fn set(self) -> Self { + Self(self.0 | Self::SET) + } + /// Clear pin output value to low. + #[inline] + pub const fn clear(self) -> Self { + Self(self.0 | Self::CLEAR) + } + /// Clear interrupt pin output flag. + #[inline] + pub const fn clear_interrupt(self) -> Self { + Self(self.0 | Self::CLEAR_INTERRUPT) + } + /// Get drive strength of current pin. + #[inline] + pub const fn drive(self) -> Drive { + match (self.0 & Self::DRIVE) >> 2 { + 0 => Drive::Drive0, + 1 => Drive::Drive1, + 2 => Drive::Drive2, + 3 => Drive::Drive3, + _ => unreachable!(), + } + } + /// Set drive strength of current pin. + #[inline] + pub const fn set_drive(self, val: Drive) -> Self { + Self((self.0 & !Self::DRIVE) | ((val as u32) << 2)) + } + /// Get function of current pin. + #[inline] + pub const fn function(self) -> Function { + match (self.0 & Self::FUNCTION) >> 8 { + 11 => Function::Gpio, + _ => todo!(), + } + } + /// Set function of current pin. + #[inline] + pub const fn set_function(self, val: Function) -> Self { + Self((self.0 & !Self::FUNCTION) | ((val as u32) << 8)) + } +} + +/// Pin drive strength. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(u8)] +pub enum Drive { + /// Drive strength 0. + Drive0 = 0, + /// Drive strength 1. + Drive1 = 1, + /// Drive strength 2. + Drive2 = 2, + /// Drive strength 3. + Drive3 = 3, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(u8)] +pub enum Function { + Gpio = 11, + //still remaining +} diff --git a/src/gpio.rs b/src/gpio.rs new file mode 100644 index 0000000000000000000000000000000000000000..94e926a6352de4bb08f930d3d85d35c339476b3b --- /dev/null +++ b/src/gpio.rs @@ -0,0 +1,90 @@ +use crate::{glb::Function, GLB}; +use base_address::BaseAddress; +use core::marker::PhantomData; +use embedded_hal::digital::{ErrorType, InputPin, OutputPin}; + +/// Individual GPIO pin. +pub struct Pin { + base: GLB, + _mode: PhantomData, +} + +/// Alternate type state. +pub trait Alternate { + /// Function number for this alternate type state. + const F: Function; +} + +/// Input mode (type state) +pub struct Input { + _mode: PhantomData, +} + +/// Output mode (type state) +pub struct Output { + _mode: PhantomData, +} + +/// Pulled down (type state) +pub struct PullDown; + +/// Pulled up (type state) +pub struct PullUp; + +/// Floating (type state) +pub struct Floating; + +impl Alternate for Input { + const F: Function = Function::Gpio; +} + +impl Alternate for Output { + const F: Function = Function::Gpio; +} + +impl ErrorType for Pin> { + type Error = core::convert::Infallible; +} + +impl ErrorType for Pin> { + type Error = core::convert::Infallible; +} + +impl InputPin for Pin> { + #[inline] + fn is_high(&self) -> Result { + Ok(self.base.gpio_input[N >> 5].read() & (1 << (N & 0x1F)) != 0) + } + #[inline] + fn is_low(&self) -> Result { + Ok(self.base.gpio_input[N >> 5].read() & (1 << (N & 0x1F)) == 0) + } +} + +impl OutputPin for Pin> { + #[inline] + fn set_low(&mut self) -> Result<(), Self::Error> { + unsafe { self.base.gpio_clear[N >> 5].write(1 << (N & 0x1F)) }; + Ok(()) + } + #[inline] + fn set_high(&mut self) -> Result<(), Self::Error> { + unsafe { self.base.gpio_set[N >> 5].write(1 << (N & 0x1F)) }; + Ok(()) + } +} + +impl Pin> { + /// Enable schmitt trigger. + #[inline] + pub fn enable_schmitt(&mut self) { + let config = self.base.gpio_config[N].read().enable_schmitt(); + self.base.gpio_config[N].write(config); + } + /// Disable schmitt trigger. + #[inline] + pub fn disable_schmitt(&mut self) { + let config = self.base.gpio_config[N].read().disable_schmitt(); + self.base.gpio_config[N].write(config); + } +} diff --git a/src/lib.rs b/src/lib.rs index 0c9ac1ac8e4bd702086402213af792ae0636d192..0e0f958fe11fa2e0a93670573069a00702cdd358 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,23 @@ #![no_std] + +use base_address::BaseAddress; +use core::ops; + +pub mod glb; +pub mod gpio; + +/// Global register. +pub struct GLB { + base: A, +} + +unsafe impl Send for GLB {} + +impl ops::Deref for GLB { + type Target = glb::RegisterBlock; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*(self.base.ptr() as *const _) } + } +}