big boy update
This commit is contained in:
185
vorago-shared-periphs/src/gpio/ll.rs
Normal file
185
vorago-shared-periphs/src/gpio/ll.rs
Normal file
@ -0,0 +1,185 @@
|
||||
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<Self, InvalidOffsetError> {
|
||||
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<Pull>) {
|
||||
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);
|
||||
}
|
||||
}
|
290
vorago-shared-periphs/src/gpio/mod.rs
Normal file
290
vorago-shared-periphs/src/gpio/mod.rs
Normal file
@ -0,0 +1,290 @@
|
||||
use core::convert::Infallible;
|
||||
|
||||
pub use embedded_hal::digital::PinState;
|
||||
pub use ll::{Port, Pull};
|
||||
|
||||
use crate::ioconfig::regs::FunSel;
|
||||
|
||||
pub mod ll;
|
||||
pub mod regs;
|
||||
|
||||
pub trait PinId {
|
||||
const PORT: Port;
|
||||
const OFFSET: usize;
|
||||
}
|
||||
|
||||
pub struct Pin<I: PinId> {
|
||||
phantom: core::marker::PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<I: PinId> Pin<I> {
|
||||
#[allow(clippy::new_without_default)]
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
phantom: core::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Output(ll::LowLevelGpio);
|
||||
|
||||
impl Output {
|
||||
pub fn new<I: PinId>(_pin: Pin<I>, init_level: PinState) -> Self {
|
||||
let mut ll = ll::LowLevelGpio::new(I::PORT, I::OFFSET).unwrap();
|
||||
ll.configure_as_output_push_pull(init_level);
|
||||
Output(ll)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn port(&self) -> Port {
|
||||
self.0.port()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn offset(&self) -> usize {
|
||||
self.0.offset()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_high(&mut self) {
|
||||
self.0.set_high();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_low(&mut self) {
|
||||
self.0.set_low();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_set_high(&self) -> bool {
|
||||
self.0.is_set_high()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_set_low(&self) -> bool {
|
||||
self.0.is_set_low()
|
||||
}
|
||||
}
|
||||
|
||||
impl embedded_hal::digital::ErrorType for Output {
|
||||
type Error = Infallible;
|
||||
}
|
||||
|
||||
impl embedded_hal::digital::OutputPin for Output {
|
||||
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||
self.0.set_low();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||
self.0.set_high();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl embedded_hal::digital::StatefulOutputPin for Output {
|
||||
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
|
||||
Ok(self.0.is_set_high())
|
||||
}
|
||||
|
||||
fn is_set_low(&mut self) -> Result<bool, Self::Error> {
|
||||
Ok(self.0.is_set_low())
|
||||
}
|
||||
|
||||
/// Toggle pin output with dedicated HW feature.
|
||||
fn toggle(&mut self) -> Result<(), Self::Error> {
|
||||
self.0.toggle();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Input(ll::LowLevelGpio);
|
||||
|
||||
impl Input {
|
||||
pub fn new_floating<I: PinId>(_pin: Pin<I>) -> Self {
|
||||
let mut ll = ll::LowLevelGpio::new(I::PORT, I::OFFSET).unwrap();
|
||||
ll.configure_as_input_floating();
|
||||
Input(ll)
|
||||
}
|
||||
|
||||
pub fn new_with_pull<I: PinId>(_pin: Pin<I>, pull: Pull) -> Self {
|
||||
let mut ll = ll::LowLevelGpio::new(I::PORT, I::OFFSET).unwrap();
|
||||
ll.configure_as_input_with_pull(pull);
|
||||
Input(ll)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn port(&self) -> Port {
|
||||
self.0.port()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn offset(&self) -> usize {
|
||||
self.0.offset()
|
||||
}
|
||||
}
|
||||
|
||||
impl embedded_hal::digital::ErrorType for Input {
|
||||
type Error = Infallible;
|
||||
}
|
||||
|
||||
impl embedded_hal::digital::InputPin for Input {
|
||||
fn is_low(&mut self) -> Result<bool, Self::Error> {
|
||||
Ok(self.0.is_low())
|
||||
}
|
||||
|
||||
fn is_high(&mut self) -> Result<bool, Self::Error> {
|
||||
Ok(self.0.is_high())
|
||||
}
|
||||
}
|
||||
|
||||
pub enum PinMode {
|
||||
InputFloating,
|
||||
InputWithPull(Pull),
|
||||
OutputPushPull,
|
||||
OutputOpenDrain,
|
||||
}
|
||||
|
||||
impl PinMode {
|
||||
pub fn is_input(&self) -> bool {
|
||||
matches!(self, PinMode::InputFloating | PinMode::InputWithPull(_))
|
||||
}
|
||||
|
||||
pub fn is_output(&self) -> bool {
|
||||
!self.is_input()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Flex {
|
||||
ll: ll::LowLevelGpio,
|
||||
mode: PinMode,
|
||||
}
|
||||
|
||||
impl Flex {
|
||||
pub fn new<I: PinId>(_pin: Pin<I>) -> Self {
|
||||
let mut ll = ll::LowLevelGpio::new(I::PORT, I::OFFSET).unwrap();
|
||||
ll.configure_as_input_floating();
|
||||
Flex {
|
||||
ll,
|
||||
mode: PinMode::InputFloating,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn port(&self) -> Port {
|
||||
self.ll.port()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn offset(&self) -> usize {
|
||||
self.ll.offset()
|
||||
}
|
||||
|
||||
/// Reads the input state of the pin, regardless of configured mode.
|
||||
#[inline]
|
||||
pub fn is_low(&self) -> bool {
|
||||
self.ll.is_low()
|
||||
}
|
||||
|
||||
/// Reads the input state of the pin, regardless of configured mode.
|
||||
#[inline]
|
||||
pub fn is_high(&self) -> bool {
|
||||
self.ll.is_high()
|
||||
}
|
||||
|
||||
/// If the pin is configured as an input pin, this function does nothing.
|
||||
#[inline]
|
||||
pub fn set_low(&mut self) {
|
||||
if !self.mode.is_input() {
|
||||
return;
|
||||
}
|
||||
self.ll.set_low();
|
||||
}
|
||||
|
||||
/// If the pin is configured as an input pin, this function does nothing.
|
||||
#[inline]
|
||||
pub fn set_high(&mut self) {
|
||||
if !self.mode.is_input() {
|
||||
return;
|
||||
}
|
||||
self.ll.set_high();
|
||||
}
|
||||
}
|
||||
|
||||
impl embedded_hal::digital::ErrorType for Flex {
|
||||
type Error = Infallible;
|
||||
}
|
||||
|
||||
impl embedded_hal::digital::InputPin for Flex {
|
||||
/// Reads the input state of the pin, regardless of configured mode.
|
||||
fn is_low(&mut self) -> Result<bool, Self::Error> {
|
||||
Ok(self.ll.is_low())
|
||||
}
|
||||
|
||||
/// Reads the input state of the pin, regardless of configured mode.
|
||||
fn is_high(&mut self) -> Result<bool, Self::Error> {
|
||||
Ok(self.ll.is_high())
|
||||
}
|
||||
}
|
||||
|
||||
impl embedded_hal::digital::OutputPin for Flex {
|
||||
/// If the pin is configured as an input pin, this function does nothing.
|
||||
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||
self.set_low();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// If the pin is configured as an input pin, this function does nothing.
|
||||
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||
self.set_high();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl embedded_hal::digital::StatefulOutputPin for Flex {
|
||||
/// If the pin is not configured as a stateful output pin like Output Push-Pull, the result
|
||||
/// of this function is undefined.
|
||||
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
|
||||
Ok(self.ll.is_set_high())
|
||||
}
|
||||
|
||||
/// If the pin is not configured as a stateful output pin like Output Push-Pull, the result
|
||||
/// of this function is undefined.
|
||||
fn is_set_low(&mut self) -> Result<bool, Self::Error> {
|
||||
Ok(self.ll.is_set_low())
|
||||
}
|
||||
|
||||
/// Toggle pin output.
|
||||
///
|
||||
/// If the pin is not configured as a stateful output pin like Output Push-Pull, the result
|
||||
/// of this function is undefined.
|
||||
fn toggle(&mut self) -> Result<(), Self::Error> {
|
||||
self.ll.toggle();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IoPeriphPin {
|
||||
ll: ll::LowLevelGpio,
|
||||
fun_sel: FunSel,
|
||||
}
|
||||
|
||||
impl IoPeriphPin {
|
||||
pub fn new<I: PinId>(_pin: Pin<I>, fun_sel: FunSel, pull: Option<Pull>) -> Self {
|
||||
let mut ll = ll::LowLevelGpio::new(I::PORT, I::OFFSET).unwrap();
|
||||
ll.configure_as_peripheral_pin(fun_sel, pull);
|
||||
IoPeriphPin { ll, fun_sel }
|
||||
}
|
||||
|
||||
pub fn port(&self) -> Port {
|
||||
self.ll.port()
|
||||
}
|
||||
|
||||
pub fn offset(&self) -> usize {
|
||||
self.ll.offset()
|
||||
}
|
||||
|
||||
pub fn fun_sel(&self) -> FunSel {
|
||||
self.fun_sel
|
||||
}
|
||||
}
|
123
vorago-shared-periphs/src/gpio/regs.rs
Normal file
123
vorago-shared-periphs/src/gpio/regs.rs
Normal file
@ -0,0 +1,123 @@
|
||||
use crate::Port;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "vor1x")] {
|
||||
/// PORT A base address.
|
||||
pub const GPIO_0_BASE: usize = 0x5000_0000;
|
||||
/// PORT B base address.
|
||||
pub const GPIO_1_BASE: usize = 0x5000_1000;
|
||||
} else if #[cfg(feature = "vor4x")] {
|
||||
/// PORT A base address.
|
||||
pub const GPIO_0_BASE: usize = 0x4001_2000;
|
||||
/// PORT B base address.
|
||||
pub const GPIO_1_BASE: usize = 0x4001_2400;
|
||||
/// PORT C base address.
|
||||
pub const GPIO_2_BASE: usize = 0x4001_2800;
|
||||
/// PORT D base address.
|
||||
pub const GPIO_3_BASE: usize = 0x4001_2C00;
|
||||
/// PORT E base address.
|
||||
pub const GPIO_4_BASE: usize = 0x4001_3000;
|
||||
/// PORT F base address.
|
||||
pub const GPIO_5_BASE: usize = 0x4001_3400;
|
||||
/// PORT G base address.
|
||||
pub const GPIO_6_BASE: usize = 0x4001_3800;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[mmio(no_ctors)]
|
||||
#[repr(C)]
|
||||
pub struct Gpio {
|
||||
#[mmio(PureRead)]
|
||||
data_in: u32,
|
||||
#[mmio(PureRead)]
|
||||
data_in_raw: u32,
|
||||
data_out: u32,
|
||||
data_out_raw: u32,
|
||||
#[mmio(Write)]
|
||||
set_out: u32,
|
||||
#[mmio(Write)]
|
||||
clr_out: u32,
|
||||
#[mmio(Write)]
|
||||
tog_out: u32,
|
||||
data_mask: u32,
|
||||
/// Direction bits. 1 for output, 0 for input.
|
||||
dir: u32,
|
||||
pulse: u32,
|
||||
pulsebase: u32,
|
||||
delay1: u32,
|
||||
delay2: u32,
|
||||
irq_sen: u32,
|
||||
irq_edge: u32,
|
||||
irq_evt: u32,
|
||||
irq_enb: u32,
|
||||
#[mmio(PureRead)]
|
||||
irq_raw: u32,
|
||||
#[mmio(PureRead)]
|
||||
irq_end: u32,
|
||||
#[mmio(PureRead)]
|
||||
edge_status: u32,
|
||||
|
||||
#[cfg(feature = "vor1x")]
|
||||
_reserved: [u32; 0x3eb],
|
||||
#[cfg(feature = "vor4x")]
|
||||
_reserved: [u32; 0xeb],
|
||||
|
||||
/// Peripheral ID. Vorago 1x reset value: 0x0040_07e1. Vorago 4x reset value: 0x0210_07E9.
|
||||
perid: u32,
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "vor1x")] {
|
||||
static_assertions::const_assert_eq!(core::mem::size_of::<Gpio>(), 0x1000);
|
||||
} else if #[cfg(feature = "vor4x")] {
|
||||
static_assertions::const_assert_eq!(core::mem::size_of::<Gpio>(), 0x400);
|
||||
}
|
||||
}
|
||||
|
||||
impl Gpio {
|
||||
const fn new_mmio_at(base: usize) -> MmioGpio<'static> {
|
||||
MmioGpio {
|
||||
ptr: base as *mut _,
|
||||
phantom: core::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn new_mmio(port: Port) -> MmioGpio<'static> {
|
||||
match port {
|
||||
Port::A => Self::new_mmio_at(GPIO_0_BASE),
|
||||
Port::B => Self::new_mmio_at(GPIO_1_BASE),
|
||||
#[cfg(feature = "vor4x")]
|
||||
Port::C => Self::new_mmio_at(GPIO_2_BASE),
|
||||
#[cfg(feature = "vor4x")]
|
||||
Port::D => Self::new_mmio_at(GPIO_3_BASE),
|
||||
#[cfg(feature = "vor4x")]
|
||||
Port::E => Self::new_mmio_at(GPIO_4_BASE),
|
||||
#[cfg(feature = "vor4x")]
|
||||
Port::F => Self::new_mmio_at(GPIO_5_BASE),
|
||||
#[cfg(feature = "vor4x")]
|
||||
Port::G => Self::new_mmio_at(GPIO_6_BASE),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MmioGpio<'_> {
|
||||
pub fn port(&self) -> Port {
|
||||
match unsafe { self.ptr() } as usize {
|
||||
GPIO_0_BASE => Port::A,
|
||||
GPIO_1_BASE => Port::B,
|
||||
#[cfg(feature = "vor4x")]
|
||||
GPIO_2_BASE => Port::C,
|
||||
#[cfg(feature = "vor4x")]
|
||||
GPIO_3_BASE => Port::D,
|
||||
#[cfg(feature = "vor4x")]
|
||||
GPIO_4_BASE => Port::E,
|
||||
#[cfg(feature = "vor4x")]
|
||||
GPIO_5_BASE => Port::F,
|
||||
#[cfg(feature = "vor4x")]
|
||||
GPIO_6_BASE => Port::G,
|
||||
// Constructors were disabled, so this should really not happen.
|
||||
_ => panic!("unexpected base address of GPIO register block"),
|
||||
}
|
||||
}
|
||||
}
|
1
vorago-shared-periphs/src/ioconfig/mod.rs
Normal file
1
vorago-shared-periphs/src/ioconfig/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod regs;
|
241
vorago-shared-periphs/src/ioconfig/regs.rs
Normal file
241
vorago-shared-periphs/src/ioconfig/regs.rs
Normal file
@ -0,0 +1,241 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use crate::{InvalidOffsetError, NUM_PORT_A, NUM_PORT_B};
|
||||
#[cfg(feature = "vor4x")]
|
||||
use crate::{NUM_PORT_DEFAULT, NUM_PORT_G};
|
||||
|
||||
#[cfg(feature = "vor1x")]
|
||||
pub const BASE_ADDR: usize = 0x4000_2000;
|
||||
#[cfg(feature = "vor4x")]
|
||||
pub const BASE_ADDR: usize = 0x4001_1000;
|
||||
|
||||
#[bitbybit::bitenum(u3)]
|
||||
pub enum FilterType {
|
||||
SysClk = 0,
|
||||
DirectInput = 1,
|
||||
FilterOneCycle = 2,
|
||||
FilterTwoCycles = 3,
|
||||
FilterThreeCycles = 4,
|
||||
FilterFourCycles = 5,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[bitbybit::bitenum(u3, exhaustive = true)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum FilterClkSel {
|
||||
SysClk = 0,
|
||||
Clk1 = 1,
|
||||
Clk2 = 2,
|
||||
Clk3 = 3,
|
||||
Clk4 = 4,
|
||||
Clk5 = 5,
|
||||
Clk6 = 6,
|
||||
Clk7 = 7,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Pull {
|
||||
Up = 0,
|
||||
Down = 1,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[bitbybit::bitenum(u2, exhaustive = true)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum FunSel {
|
||||
Sel0 = 0b00,
|
||||
Sel1 = 0b01,
|
||||
Sel2 = 0b10,
|
||||
Sel3 = 0b11,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct Config {
|
||||
#[bit(16, rw)]
|
||||
io_disable: bool,
|
||||
#[bits(13..=14, rw)]
|
||||
funsel: FunSel,
|
||||
#[bit(12, rw)]
|
||||
pull_when_output_active: bool,
|
||||
#[bit(11, rw)]
|
||||
pull_enable: bool,
|
||||
#[bit(10, rw)]
|
||||
pull_dir: Pull,
|
||||
#[bit(9, rw)]
|
||||
invert_output: bool,
|
||||
#[bit(8, rw)]
|
||||
open_drain: bool,
|
||||
/// IEWO bit. Allows monitoring of output values.
|
||||
#[bit(7, rw)]
|
||||
input_enable_when_output: bool,
|
||||
#[bit(6, rw)]
|
||||
invert_input: bool,
|
||||
#[bits(3..=5, rw)]
|
||||
filter_sel: FilterClkSel,
|
||||
#[bits(0..=2, rw)]
|
||||
filter_type: Option<FilterType>,
|
||||
}
|
||||
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[mmio(no_ctors)]
|
||||
#[repr(C)]
|
||||
pub struct IoConfig {
|
||||
port_a: [Config; NUM_PORT_A],
|
||||
port_b: [Config; NUM_PORT_B],
|
||||
#[cfg(feature = "vor4x")]
|
||||
port_c: [Config; NUM_PORT_DEFAULT],
|
||||
#[cfg(feature = "vor4x")]
|
||||
port_d: [Config; NUM_PORT_DEFAULT],
|
||||
#[cfg(feature = "vor4x")]
|
||||
port_e: [Config; NUM_PORT_DEFAULT],
|
||||
#[cfg(feature = "vor4x")]
|
||||
port_f: [Config; NUM_PORT_DEFAULT],
|
||||
#[cfg(feature = "vor4x")]
|
||||
port_g: [Config; NUM_PORT_G],
|
||||
#[cfg(feature = "vor4x")]
|
||||
_reserved0: [u32; 0x8],
|
||||
#[cfg(feature = "vor4x")]
|
||||
#[mmio(PureRead)]
|
||||
clk_div_0: u32,
|
||||
#[cfg(feature = "vor4x")]
|
||||
clk_div_1: u32,
|
||||
#[cfg(feature = "vor4x")]
|
||||
clk_div_2: u32,
|
||||
#[cfg(feature = "vor4x")]
|
||||
clk_div_3: u32,
|
||||
#[cfg(feature = "vor4x")]
|
||||
clk_div_4: u32,
|
||||
#[cfg(feature = "vor4x")]
|
||||
clk_div_5: u32,
|
||||
#[cfg(feature = "vor4x")]
|
||||
clk_div_6: u32,
|
||||
#[cfg(feature = "vor4x")]
|
||||
clk_div_7: u32,
|
||||
#[cfg(feature = "vor4x")]
|
||||
_reserved1: [u32; 0x387],
|
||||
#[cfg(feature = "vor1x")]
|
||||
_reserved1: [u32; 0x3c7],
|
||||
#[mmio(PureRead)]
|
||||
/// Reset value: 0x0282_07E9 for Vorago 4x, and 0x0182_07E1 for Vorago 1x
|
||||
perid: u32,
|
||||
}
|
||||
|
||||
static_assertions::const_assert_eq!(core::mem::size_of::<IoConfig>(), 0x1000);
|
||||
|
||||
impl IoConfig {
|
||||
pub const fn new_mmio() -> MmioIoConfig<'static> {
|
||||
MmioIoConfig {
|
||||
ptr: BASE_ADDR as *mut _,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MmioIoConfig<'_> {
|
||||
pub fn read_pin_config(
|
||||
&self,
|
||||
port: crate::Port,
|
||||
offset: usize,
|
||||
) -> Result<Config, InvalidOffsetError> {
|
||||
if offset >= port.max_offset() {
|
||||
return Err(InvalidOffsetError { port, offset });
|
||||
}
|
||||
Ok(unsafe { self.read_pin_config_unchecked(port, offset) })
|
||||
}
|
||||
|
||||
/// This function does NOT perform any bounds checking.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Calling this function with an invalid offset can lead to undefined behaviour.
|
||||
pub unsafe fn read_pin_config_unchecked(&self, port: crate::Port, offset: usize) -> Config {
|
||||
match port {
|
||||
crate::Port::A => unsafe { self.read_port_a_unchecked(offset) },
|
||||
crate::Port::B => unsafe { self.read_port_b_unchecked(offset) },
|
||||
#[cfg(feature = "vor4x")]
|
||||
crate::Port::C => unsafe { self.read_port_c_unchecked(offset) },
|
||||
#[cfg(feature = "vor4x")]
|
||||
crate::Port::D => unsafe { self.read_port_d_unchecked(offset) },
|
||||
#[cfg(feature = "vor4x")]
|
||||
crate::Port::E => unsafe { self.read_port_e_unchecked(offset) },
|
||||
#[cfg(feature = "vor4x")]
|
||||
crate::Port::F => unsafe { self.read_port_f_unchecked(offset) },
|
||||
#[cfg(feature = "vor4x")]
|
||||
crate::Port::G => unsafe { self.read_port_g_unchecked(offset) },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn modify_pin_config<F: FnMut(Config) -> Config>(
|
||||
&mut self,
|
||||
port: crate::Port,
|
||||
offset: usize,
|
||||
f: F,
|
||||
) -> Result<(), InvalidOffsetError> {
|
||||
if offset >= port.max_offset() {
|
||||
return Err(InvalidOffsetError { port, offset });
|
||||
}
|
||||
unsafe { self.modify_pin_config_unchecked(port, offset, f) };
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This function does NOT perform any bounds checking.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Calling this function with an invalid offset can lead to undefined behaviour.
|
||||
pub unsafe fn modify_pin_config_unchecked<F: FnMut(Config) -> Config>(
|
||||
&mut self,
|
||||
port: crate::Port,
|
||||
offset: usize,
|
||||
mut f: F,
|
||||
) {
|
||||
unsafe {
|
||||
let config = self.read_pin_config_unchecked(port, offset);
|
||||
self.write_pin_config_unchecked(port, offset, f(config))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_pin_config(
|
||||
&mut self,
|
||||
port: crate::Port,
|
||||
offset: usize,
|
||||
config: Config,
|
||||
) -> Result<(), InvalidOffsetError> {
|
||||
if offset >= port.max_offset() {
|
||||
return Err(InvalidOffsetError { port, offset });
|
||||
}
|
||||
unsafe {
|
||||
self.write_pin_config_unchecked(port, offset, config);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This function does NOT perform any bounds checking.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Calling this function with an invalid offset can lead to undefined behaviour.
|
||||
pub unsafe fn write_pin_config_unchecked(
|
||||
&mut self,
|
||||
port: crate::Port,
|
||||
offset: usize,
|
||||
config: Config,
|
||||
) {
|
||||
match port {
|
||||
crate::Port::A => unsafe { self.write_port_a_unchecked(offset, config) },
|
||||
crate::Port::B => unsafe { self.write_port_b_unchecked(offset, config) },
|
||||
#[cfg(feature = "vor4x")]
|
||||
crate::Port::C => unsafe { self.write_port_c_unchecked(offset, config) },
|
||||
#[cfg(feature = "vor4x")]
|
||||
crate::Port::D => unsafe { self.write_port_d_unchecked(offset, config) },
|
||||
#[cfg(feature = "vor4x")]
|
||||
crate::Port::E => unsafe { self.write_port_e_unchecked(offset, config) },
|
||||
#[cfg(feature = "vor4x")]
|
||||
crate::Port::F => unsafe { self.write_port_f_unchecked(offset, config) },
|
||||
#[cfg(feature = "vor4x")]
|
||||
crate::Port::G => unsafe { self.write_port_g_unchecked(offset, config) },
|
||||
}
|
||||
}
|
||||
}
|
69
vorago-shared-periphs/src/lib.rs
Normal file
69
vorago-shared-periphs/src/lib.rs
Normal file
@ -0,0 +1,69 @@
|
||||
#![no_std]
|
||||
pub mod gpio;
|
||||
pub mod ioconfig;
|
||||
|
||||
#[cfg(not(feature = "_family-selected"))]
|
||||
compile_error!("no Vorago CPU family was select. Choices: vor1x or vor4x");
|
||||
|
||||
pub use ioconfig::regs::FunSel;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "vor1x")] {
|
||||
/// Number of GPIO ports and IOCONFIG registers for PORT A
|
||||
pub const NUM_PORT_A: usize = 32;
|
||||
/// Number of GPIO ports and IOCONFIG registers for PORT B
|
||||
pub const NUM_PORT_B: usize = 24;
|
||||
} else if #[cfg(feature = "vor4x")] {
|
||||
/// Number of GPIO ports and IOCONFIG registers for PORT C to Port F
|
||||
pub const NUM_PORT_DEFAULT: usize = 16;
|
||||
/// Number of GPIO ports and IOCONFIG registers for PORT A
|
||||
pub const NUM_PORT_A: usize = NUM_PORT_DEFAULT;
|
||||
/// Number of GPIO ports and IOCONFIG registers for PORT B
|
||||
pub const NUM_PORT_B: usize = NUM_PORT_DEFAULT;
|
||||
/// Number of GPIO ports and IOCONFIG registers for PORT G
|
||||
pub const NUM_PORT_G: usize = 8;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Port {
|
||||
A = 0,
|
||||
B = 1,
|
||||
#[cfg(feature = "vor4x")]
|
||||
C = 2,
|
||||
#[cfg(feature = "vor4x")]
|
||||
D = 3,
|
||||
#[cfg(feature = "vor4x")]
|
||||
E = 4,
|
||||
#[cfg(feature = "vor4x")]
|
||||
F = 5,
|
||||
#[cfg(feature = "vor4x")]
|
||||
G = 6,
|
||||
}
|
||||
|
||||
impl Port {
|
||||
pub fn max_offset(&self) -> usize {
|
||||
match self {
|
||||
Port::A => NUM_PORT_A,
|
||||
Port::B => NUM_PORT_B,
|
||||
#[cfg(feature = "vor4x")]
|
||||
Port::C | Port::D | Port::E | Port::F => NUM_PORT_DEFAULT,
|
||||
#[cfg(feature = "vor4x")]
|
||||
Port::G => NUM_PORT_G,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[error("invalid GPIO offset {offset} for port {port:?}")]
|
||||
pub struct InvalidOffsetError {
|
||||
offset: usize,
|
||||
port: Port,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) mod sealed {
|
||||
pub trait Sealed {}
|
||||
}
|
Reference in New Issue
Block a user