GPIO example works

This commit is contained in:
Robin Müller 2024-06-12 11:29:12 +02:00
parent 622c0573f7
commit cd7a6499d4
Signed by: muellerr
GPG Key ID: A649FB78196E3849
8 changed files with 49 additions and 43 deletions

View File

@ -3,7 +3,7 @@
#![no_std] #![no_std]
use cortex_m_rt::entry; use cortex_m_rt::entry;
use embedded_hal::digital::{OutputPin, StatefulOutputPin}; use embedded_hal::digital::StatefulOutputPin;
use panic_halt as _; use panic_halt as _;
use va416xx_hal::{gpio::PinsG, pac}; use va416xx_hal::{gpio::PinsG, pac};
@ -11,17 +11,11 @@ use va416xx_hal::{gpio::PinsG, pac};
fn main() -> ! { fn main() -> ! {
// SAFETY: Peripherals are only stolen once here. // SAFETY: Peripherals are only stolen once here.
let mut dp = unsafe { pac::Peripherals::steal() }; let mut dp = unsafe { pac::Peripherals::steal() };
// Enable all peripheral clocks
dp.sysconfig
.peripheral_clk_enable()
.modify(|_, w| unsafe { w.bits(0xffffffff) });
let portg = PinsG::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.portg); let portg = PinsG::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.portg);
let mut led = portg.pg5.into_readable_push_pull_output(); let mut led = portg.pg5.into_readable_push_pull_output();
//let mut delay = CountDownTimer::new(&mut dp.SYSCONFIG, 50.mhz(), dp.TIM0); //let mut delay = CountDownTimer::new(&mut dp.SYSCONFIG, 50.mhz(), dp.TIM0);
loop { loop {
led.set_high().ok();
cortex_m::asm::delay(2_000_000);
led.set_low().ok();
cortex_m::asm::delay(2_000_000); cortex_m::asm::delay(2_000_000);
led.toggle().ok();
} }
} }

View File

@ -138,7 +138,7 @@ impl DynRegisters {
/// operations are fallible. This `enum` represents the corresponding errors. /// operations are fallible. This `enum` represents the corresponding errors.
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct InvalidPinTypeError(pub (crate) ()); pub struct InvalidPinTypeError(pub(crate) ());
impl embedded_hal::digital::Error for InvalidPinTypeError { impl embedded_hal::digital::Error for InvalidPinTypeError {
fn kind(&self) -> embedded_hal::digital::ErrorKind { fn kind(&self) -> embedded_hal::digital::ErrorKind {
@ -268,32 +268,40 @@ impl DynPin {
self.regs.delay(delay_1, delay_2); self.regs.delay(delay_1, delay_2);
Ok(self) Ok(self)
} }
_ => Err(InvalidPinTypeError(())) _ => Err(InvalidPinTypeError(())),
} }
} }
/// See p.52 of the programmers guide for more information. /// See p.52 of the programmers guide for more information.
/// When configured for pulse mode, a given pin will set the non-default state for exactly /// When configured for pulse mode, a given pin will set the non-default state for exactly
/// one clock cycle before returning to the configured default state /// one clock cycle before returning to the configured default state
pub fn pulse_mode(self, enable: bool, default_state: PinState) -> Result<Self, InvalidPinTypeError> { pub fn pulse_mode(
self,
enable: bool,
default_state: PinState,
) -> Result<Self, InvalidPinTypeError> {
match self.mode { match self.mode {
DynPinMode::Output(_) => { DynPinMode::Output(_) => {
self.regs.pulse_mode(enable, default_state); self.regs.pulse_mode(enable, default_state);
Ok(self) Ok(self)
} }
_ => Err(InvalidPinTypeError(())) _ => Err(InvalidPinTypeError(())),
} }
} }
/// See p.37 and p.38 of the programmers guide for more information. /// See p.37 and p.38 of the programmers guide for more information.
#[inline] #[inline]
pub fn filter_type(self, filter: FilterType, clksel: FilterClkSel) -> Result<Self, InvalidPinTypeError> { pub fn filter_type(
self,
filter: FilterType,
clksel: FilterClkSel,
) -> Result<Self, InvalidPinTypeError> {
match self.mode { match self.mode {
DynPinMode::Input(_) => { DynPinMode::Input(_) => {
self.regs.filter_type(filter, clksel); self.regs.filter_type(filter, clksel);
Ok(self) Ok(self)
} }
_ => Err(InvalidPinTypeError(())) _ => Err(InvalidPinTypeError(())),
} }
} }
@ -304,18 +312,21 @@ impl DynPin {
self.irq_enb(); self.irq_enb();
Ok(self) Ok(self)
} }
_ => Err(InvalidPinTypeError(())) _ => Err(InvalidPinTypeError(())),
} }
} }
pub fn interrupt_level(mut self, level_type: InterruptLevel) -> Result<Self, InvalidPinTypeError> { pub fn interrupt_level(
mut self,
level_type: InterruptLevel,
) -> Result<Self, InvalidPinTypeError> {
match self.mode { match self.mode {
DynPinMode::Input(_) | DynPinMode::Output(_) => { DynPinMode::Input(_) | DynPinMode::Output(_) => {
self.regs.interrupt_level(level_type); self.regs.interrupt_level(level_type);
self.irq_enb(); self.irq_enb();
Ok(self) Ok(self)
} }
_ => Err(InvalidPinTypeError(())) _ => Err(InvalidPinTypeError(())),
} }
} }
@ -325,7 +336,7 @@ impl DynPin {
DynPinMode::Input(_) | DYN_RD_OPEN_DRAIN_OUTPUT | DYN_RD_PUSH_PULL_OUTPUT => { DynPinMode::Input(_) | DYN_RD_OPEN_DRAIN_OUTPUT | DYN_RD_PUSH_PULL_OUTPUT => {
Ok(self.regs.read_pin()) Ok(self.regs.read_pin())
} }
_ => Err(InvalidPinTypeError(())) _ => Err(InvalidPinTypeError(())),
} }
} }
#[inline] #[inline]
@ -335,7 +346,7 @@ impl DynPin {
self.regs.write_pin(bit); self.regs.write_pin(bit);
Ok(()) Ok(())
} }
_ => Err(InvalidPinTypeError(())) _ => Err(InvalidPinTypeError(())),
} }
} }

View File

@ -97,6 +97,8 @@ pub trait OutputConfig: Sealed {
const DYN: DynOutput; const DYN: DynOutput;
} }
pub trait ReadableOutput: Sealed {}
/// Type-level variant of [`OutputConfig`] for a push-pull configuration /// Type-level variant of [`OutputConfig`] for a push-pull configuration
pub enum PushPull {} pub enum PushPull {}
/// Type-level variant of [`OutputConfig`] for an open drain configuration /// Type-level variant of [`OutputConfig`] for an open drain configuration
@ -111,6 +113,8 @@ impl Sealed for PushPull {}
impl Sealed for OpenDrain {} impl Sealed for OpenDrain {}
impl Sealed for ReadableOpenDrain {} impl Sealed for ReadableOpenDrain {}
impl Sealed for ReadablePushPull {} impl Sealed for ReadablePushPull {}
impl ReadableOutput for ReadableOpenDrain {}
impl ReadableOutput for ReadablePushPull {}
impl OutputConfig for PushPull { impl OutputConfig for PushPull {
const DYN: DynOutput = DynOutput::PushPull; const DYN: DynOutput = DynOutput::PushPull;
@ -538,7 +542,7 @@ where
impl<I, C> StatefulOutputPin for Pin<I, Output<C>> impl<I, C> StatefulOutputPin for Pin<I, Output<C>>
where where
I: PinId, I: PinId,
C: OutputConfig, C: OutputConfig + ReadableOutput,
{ {
#[inline] #[inline]
fn is_set_high(&mut self) -> Result<bool, Self::Error> { fn is_set_high(&mut self) -> Result<bool, Self::Error> {

View File

@ -76,11 +76,7 @@ impl From<DynPinMode> for ModeFields {
// RegisterInterface // RegisterInterface
//============================================================================== //==============================================================================
pub type IocfgPort = ioconfig::Porta; pub type PortReg = ioconfig::Porta;
#[repr(C)]
pub(super) struct IocfgConfigGroupDefault {
port: [IocfgPort; 16],
}
/// Provide a safe register interface for pin objects /// Provide a safe register interface for pin objects
/// ///
@ -124,7 +120,6 @@ pub(super) unsafe trait RegisterInterface {
const PORTE: *const PortRegisterBlock = Porte::ptr(); const PORTE: *const PortRegisterBlock = Porte::ptr();
const PORTF: *const PortRegisterBlock = Portf::ptr(); const PORTF: *const PortRegisterBlock = Portf::ptr();
const PORTG: *const PortRegisterBlock = Portg::ptr(); const PORTG: *const PortRegisterBlock = Portg::ptr();
const PORT_CFG_BASE: *const IocfgConfigGroupDefault = Ioconfig::ptr() as *const _;
/// Change the pin mode /// Change the pin mode
#[inline] #[inline]
@ -138,7 +133,7 @@ pub(super) unsafe trait RegisterInterface {
enb_input, enb_input,
} = mode.into(); } = mode.into();
let (portreg, iocfg) = (self.port_reg(), self.iocfg_port()); let (portreg, iocfg) = (self.port_reg(), self.iocfg_port());
iocfg.port[self.id().num as usize].write(|w| { iocfg.write(|w| {
w.opendrn().bit(opendrn); w.opendrn().bit(opendrn);
w.pen().bit(pull_en); w.pen().bit(pull_en);
w.plevel().bit(pull_dir); w.plevel().bit(pull_dir);
@ -170,15 +165,16 @@ pub(super) unsafe trait RegisterInterface {
} }
} }
fn iocfg_port(&self) -> &IocfgConfigGroupDefault { fn iocfg_port(&self) -> &PortReg {
let ioconfig = unsafe { Ioconfig::ptr().as_ref().unwrap() };
match self.id().group { match self.id().group {
DynGroup::A => unsafe { &*Self::PORT_CFG_BASE }, DynGroup::A => ioconfig.porta(self.id().num as usize),
DynGroup::B => unsafe { &*Self::PORT_CFG_BASE.add(1) }, DynGroup::B => ioconfig.portb0(self.id().num as usize),
DynGroup::C => unsafe { &*Self::PORT_CFG_BASE.add(3) }, DynGroup::C => ioconfig.portc0(self.id().num as usize),
DynGroup::D => unsafe { &*Self::PORT_CFG_BASE.add(4) }, DynGroup::D => ioconfig.portd0(self.id().num as usize),
DynGroup::E => unsafe { &*Self::PORT_CFG_BASE.add(5) }, DynGroup::E => ioconfig.porte0(self.id().num as usize),
DynGroup::F => unsafe { &*Self::PORT_CFG_BASE.add(6) }, DynGroup::F => ioconfig.portf0(self.id().num as usize),
DynGroup::G => unsafe { &*Self::PORT_CFG_BASE.add(7) }, DynGroup::G => ioconfig.portg0(self.id().num as usize),
} }
} }
@ -303,7 +299,7 @@ pub(super) unsafe trait RegisterInterface {
/// Only useful for input pins /// Only useful for input pins
#[inline] #[inline]
fn filter_type(&self, filter: FilterType, clksel: FilterClkSel) { fn filter_type(&self, filter: FilterType, clksel: FilterClkSel) {
self.iocfg_port().port[self.id().num as usize].modify(|_, w| { self.iocfg_port().modify(|_, w| {
// Safety: Only write to register for this Pin ID // Safety: Only write to register for this Pin ID
unsafe { unsafe {
w.flttype().bits(filter as u8); w.flttype().bits(filter as u8);

View File

@ -5,8 +5,8 @@ pub use va416xx as pac;
pub mod prelude; pub mod prelude;
pub mod clock; pub mod clock;
pub mod time;
pub mod gpio; pub mod gpio;
pub mod time;
pub mod typelevel; pub mod typelevel;
#[derive(Debug, Eq, Copy, Clone, PartialEq)] #[derive(Debug, Eq, Copy, Clone, PartialEq)]

View File

@ -0,0 +1 @@

View File

@ -1,3 +1,6 @@
// Manually inserted.
#![allow(clippy::identity_op)]
#[repr(C)] #[repr(C)]
#[doc = "Register block"] #[doc = "Register block"]
pub struct RegisterBlock { pub struct RegisterBlock {

View File

@ -3,12 +3,9 @@
#![no_std] #![no_std]
use cortex_m_rt::entry; use cortex_m_rt::entry;
use embedded_hal::digital::v2::{OutputPin, ToggleableOutputPin};
use panic_halt as _; use panic_halt as _;
use va416xx_hal::{ use va416xx_hal::{gpio::PinsG, pac};
pac,
gpio::PinsG
};
use embedded_hal::digital::v2::{ToggleableOutputPin, OutputPin};
// Mask for the LED // Mask for the LED
const LED_PG5: u32 = 1 << 5; const LED_PG5: u32 = 1 << 5;
@ -54,7 +51,7 @@ fn main() -> ! {
led.set_low().ok(); led.set_low().ok();
cortex_m::asm::delay(5_000_000); cortex_m::asm::delay(5_000_000);
led.set_high().ok(); led.set_high().ok();
}; }
loop { loop {
led.toggle().ok(); led.toggle().ok();
cortex_m::asm::delay(25_000_000); cortex_m::asm::delay(25_000_000);