From 2852a4e3522682fe2273aacbe0e3d22d941ad055 Mon Sep 17 00:00:00 2001 From: Zeqing Qin Date: Mon, 15 May 2023 20:33:04 +0800 Subject: [PATCH] =?UTF-8?q?gpio:=20=E5=A4=96=E8=AE=BE=E7=9A=84=E5=AE=8C?= =?UTF-8?q?=E6=95=B4=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Zeqing Qin Signed-off-by: Mingrui Ma --- Cargo.toml | 4 ++ src/glb.rs | 140 ++++++++++++++++++++++++++++++++++++++++++- src/gpio.rs | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 307 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ed8869a..9babd2a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,10 @@ [package] name = "bl-soc" version = "0.1.0" +authors = [ + "Mingrui Ma ", + "Zeqing Qin " +] edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/glb.rs b/src/glb.rs index ae305ab..e025980 100644 --- a/src/glb.rs +++ b/src/glb.rs @@ -1,4 +1,4 @@ -/// Author: Mingrui Ma, Zeqing Qin +//! Global peripheral. use core::cell::UnsafeCell; use volatile_register::{RO, RW, WO}; @@ -48,8 +48,10 @@ impl GpioConfig { const INPUT_ENABLE: u32 = 1 << 0; const SCHMITT: u32 = 1 << 1; const DRIVE: u32 = 0x3 << 2; + const PULL: u32 = 0x3 << 4; const OUTPUT_ENABLE: u32 = 1 << 6; const FUNCTION: u32 = 0x1f << 8; + const INTERRUPT_MODE: u32 = 0xf << 16; const CLEAR_INTERRUPT: u32 = 1 << 20; const HAS_INTERRUPT: u32 = 1 << 21; const INTERRUPT_MASK: u32 = 1 << 22; @@ -57,6 +59,7 @@ impl GpioConfig { const SET: u32 = 1 << 25; const CLEAR: u32 = 1 << 26; const INPUT: u32 = 1 << 28; + const MODE: u32 = 0x3 << 30; /// Enable input function of current pin. #[inline] @@ -168,8 +171,32 @@ impl GpioConfig { #[inline] pub const fn function(self) -> Function { match (self.0 & Self::FUNCTION) >> 8 { + 0 => Function::Sdh, + 1 => Function::Spi0, + 2 => Function::Flash, + 3 => Function::I2s, + 4 => Function::Pdm, + 5 => Function::I2c0, + 6 => Function::I2c1, + 7 => Function::Uart, + 8 => Function::Emac, + 9 => Function::Cam, + 10 => Function::Analog, 11 => Function::Gpio, - _ => todo!(), + 16 => Function::Pwm0, + 17 => Function::Pwm1, + 18 => Function::Spi1, + 19 => Function::I2c2, + 20 => Function::I2c3, + 21 => Function::MmUart, + 22 => Function::DbiB, + 23 => Function::DbiC, + 24 => Function::Dpi, + 25 => Function::JtagLp, + 26 => Function::JtagM0, + 27 => Function::JtagD0, + 31 => Function::ClockOut, + _ => unreachable!(), } } /// Set function of current pin. @@ -177,6 +204,55 @@ impl GpioConfig { pub const fn set_function(self, val: Function) -> Self { Self((self.0 & !Self::FUNCTION) | ((val as u32) << 8)) } + /// Get interrupt mode of current pin. + pub const fn interrupt_mode(self) -> InterruptMode { + match (self.0 & Self::INTERRUPT_MODE) >> 16 { + 0 => InterruptMode::SyncFallingEdge, + 1 => InterruptMode::SyncRisingEdge, + 2 => InterruptMode::SyncLowLevel, + 3 => InterruptMode::SyncHighLevel, + 4 => InterruptMode::SyncBothEdges, + 8 => InterruptMode::AsyncFallingEdge, + 9 => InterruptMode::AsyncRisingEdge, + 10 => InterruptMode::AsyncLowLevel, + 11 => InterruptMode::AsyncHighLevel, + _ => unreachable!(), + } + } + /// Set interrupt mode of current pin. + #[inline] + pub const fn set_interrupt_mode(self, val: InterruptMode) -> Self { + Self((self.0 & !Self::INTERRUPT_MODE) | ((val as u32) << 16)) + } + /// Get mode of current pin. + pub const fn mode(self) -> Mode { + match (self.0 & Self::MODE) >> 30 { + 0 => Mode::Normal, + 1 => Mode::SetClear, + 2 => Mode::Programmable, + 3 => Mode::BufferedSetClear, + _ => unreachable!(), + } + } + /// Set mode of current pin. + #[inline] + pub const fn set_mode(self, val: Mode) -> Self { + Self((self.0 & !Self::MODE) | ((val as u32) << 30)) + } + /// Get pull direction of current pin. + pub const fn pull(self) -> Pull { + match (self.0 & Self::PULL) >> 4 { + 0 => Pull::None, + 1 => Pull::Up, + 2 => Pull::Down, + _ => unreachable!(), + } + } + /// Set pull direction of current pin. + #[inline] + pub const fn set_pull(self, val: Pull) -> Self { + Self((self.0 & !Self::PULL) | ((val as u32) << 4)) + } } /// Pin drive strength. @@ -193,9 +269,67 @@ pub enum Drive { Drive3 = 3, } +/// Pin alternate function. #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[repr(u8)] pub enum Function { + Sdh = 0, + Spi0 = 1, + Flash = 2, + I2s = 3, + Pdm = 4, + I2c0 = 5, + I2c1 = 6, + Uart = 7, + Emac = 8, + Cam = 9, + Analog = 10, Gpio = 11, - //still remaining + Pwm0 = 16, + Pwm1 = 17, + Spi1 = 18, + I2c2 = 19, + I2c3 = 20, + MmUart = 21, + DbiB = 22, + DbiC = 23, + Dpi = 24, + JtagLp = 25, + JtagM0 = 26, + JtagD0 = 27, + ClockOut = 31, +} + +/// Pin interrupt mode. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(u8)] +pub enum InterruptMode { + SyncFallingEdge = 0, + SyncRisingEdge = 1, + SyncLowLevel = 2, + SyncHighLevel = 3, + SyncBothEdges = 4, + AsyncFallingEdge = 8, + AsyncRisingEdge = 9, + AsyncLowLevel = 10, + AsyncHighLevel = 11, +} + +/// Pin mode as GPIO. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(u8)] +pub enum Mode { + Normal = 0, + SetClear = 1, + Programmable = 2, + BufferedSetClear = 3, +} + +/// Pin pull direction. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(u8)] +pub enum Pull { + None = 0, + Up = 1, + Down = 2, } diff --git a/src/gpio.rs b/src/gpio.rs index 94e926a..01b1a79 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -1,4 +1,8 @@ -use crate::{glb::Function, GLB}; +//! General Purpose Input/Output. +use crate::{ + glb::{Drive, Function, InterruptMode, Mode, Pull}, + GLB, +}; use base_address::BaseAddress; use core::marker::PhantomData; use embedded_hal::digital::{ErrorType, InputPin, OutputPin}; @@ -25,6 +29,9 @@ pub struct Output { _mode: PhantomData, } +/// Disabled (type state) +pub struct Disabled; + /// Pulled down (type state) pub struct PullDown; @@ -42,6 +49,10 @@ impl Alternate for Output { const F: Function = Function::Gpio; } +impl Alternate for Disabled { + const F: Function = Function::Gpio; +} + impl ErrorType for Pin> { type Error = core::convert::Infallible; } @@ -87,4 +98,158 @@ impl Pin> { let config = self.base.gpio_config[N].read().disable_schmitt(); self.base.gpio_config[N].write(config); } + /// Clear interrupt flag. + #[inline] + pub fn clear_interrupt(&mut self) { + let config = self.base.gpio_config[N].read().clear_interrupt(); + self.base.gpio_config[N].write(config); + } + /// Check if interrupt flag is set. + #[inline] + pub fn has_interrupt(&self) -> bool { + self.base.gpio_config[N].read().has_interrupt() + } + /// Mask interrupt. + #[inline] + pub fn mask_interrupt(&mut self) { + let config = self.base.gpio_config[N].read().mask_interrupt(); + self.base.gpio_config[N].write(config); + } + /// Unmask interrupt. + #[inline] + pub fn unmask_interrupt(&mut self) { + let config = self.base.gpio_config[N].read().unmask_interrupt(); + self.base.gpio_config[N].write(config); + } + /// Get interrupt mode. + #[inline] + pub fn interrupt_mode(&self) -> InterruptMode { + self.base.gpio_config[N].read().interrupt_mode() + } + /// Set interrupt mode. + #[inline] + pub fn set_interrupt_mode(&mut self, val: InterruptMode) { + let config = self.base.gpio_config[N].read().set_interrupt_mode(val); + self.base.gpio_config[N].write(config); + } +} + +impl Pin> { + /// Get drive strength of this pin. + #[inline] + pub fn drive(&self) -> Drive { + self.base.gpio_config[N].read().drive() + } + /// Set drive strength of this pin. + #[inline] + pub fn set_drive(&mut self, val: Drive) { + let config = self.base.gpio_config[N].read().set_drive(val); + self.base.gpio_config[N].write(config); + } +} + +impl Pin { + /// Configures the pin to operate as a pull up output pin. + #[inline] + pub fn into_pull_up_output(self) -> Pin> { + let config = self.base.gpio_config[N] + .read() + .set_function(Function::Gpio) + .set_mode(Mode::SetClear) + .disable_input() + .enable_output() + .set_pull(Pull::Up); + self.base.gpio_config[N].write(config); + Pin { + base: self.base, + _mode: PhantomData, + } + } + /// Configures the pin to operate as a pull down output pin. + #[inline] + pub fn into_pull_down_output(self) -> Pin> { + let config = self.base.gpio_config[N] + .read() + .set_function(Function::Gpio) + .set_mode(Mode::SetClear) + .disable_input() + .enable_output() + .set_pull(Pull::Down); + self.base.gpio_config[N].write(config); + Pin { + base: self.base, + _mode: PhantomData, + } + } + /// Configures the pin to operate as a floating output pin. + #[inline] + pub fn into_floating_output(self) -> Pin> { + let config = self.base.gpio_config[N] + .read() + .set_function(Function::Gpio) + .set_mode(Mode::SetClear) + .disable_input() + .enable_output() + .set_pull(Pull::None); + self.base.gpio_config[N].write(config); + Pin { + base: self.base, + _mode: PhantomData, + } + } + /// Configures the pin to operate as a pull up input pin. + #[inline] + pub fn into_pull_up_input(self) -> Pin> { + let config = self.base.gpio_config[N] + .read() + .set_function(Function::Gpio) + .set_mode(Mode::SetClear) + .enable_input() + .disable_output() + .set_pull(Pull::Up); + self.base.gpio_config[N].write(config); + Pin { + base: self.base, + _mode: PhantomData, + } + } + /// Configures the pin to operate as a pull down input pin. + #[inline] + pub fn into_pull_down_input(self) -> Pin> { + let config = self.base.gpio_config[N] + .read() + .set_function(Function::Gpio) + .set_mode(Mode::SetClear) + .enable_input() + .disable_output() + .set_pull(Pull::Down); + self.base.gpio_config[N].write(config); + Pin { + base: self.base, + _mode: PhantomData, + } + } + /// Configures the pin to operate as a floating input pin. + #[inline] + pub fn into_floating_input(self) -> Pin> { + let config = self.base.gpio_config[N] + .read() + .set_function(Function::Gpio) + .set_mode(Mode::SetClear) + .enable_input() + .disable_output() + .set_pull(Pull::None); + self.base.gpio_config[N].write(config); + Pin { + base: self.base, + _mode: PhantomData, + } + } +} + +/// Available GPIO pins. +pub struct Pins { + pub io8: Pin, + pub io22: Pin, + pub io23: Pin, } -- Gitee