Merge #14
14: Added GPIO IRQ interface, refactoring r=robamu a=robamu - Adds the IRQ interface to configure interrupts on output and input pins - Moved the `FilterClkSel` struct to the `clock` module, reexporting in `gpio` - Added function to set clock divisor registers - Clearing output state at initialization of Output pins - Added utility function to set up millisecond timer with `TIM0` Co-authored-by: Robin Mueller <robin.mueller.m@gmail.com>
This commit is contained in:
commit
030b555a7f
10
CHANGELOG.md
10
CHANGELOG.md
@ -8,9 +8,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
## [unreleased]
|
## [unreleased]
|
||||||
|
|
||||||
|
## [0.2.1]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Adds the IRQ interface to configure interrupts on output and input pins
|
||||||
|
- Utility function to set up millisecond timer with `TIM0`
|
||||||
|
- Function to set clock divisor registers in `clock` module
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Minor optimizations and tweaks for GPIO module
|
- Minor optimizations and tweaks for GPIO module
|
||||||
|
- Moved the `FilterClkSel` struct to the `clock` module, re-exporting in `gpio`
|
||||||
|
- Clearing output state at initialization of Output pins
|
||||||
|
|
||||||
## [0.2.0]
|
## [0.2.0]
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "va108xx-hal"
|
name = "va108xx-hal"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
authors = ["Robin Mueller <robin.mueller.m@gmail.com>"]
|
authors = ["Robin Mueller <robin.mueller.m@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "HAL for the Vorago VA108xx family of microcontrollers"
|
description = "HAL for the Vorago VA108xx family of microcontrollers"
|
||||||
|
@ -12,7 +12,7 @@ use va108xx_hal::{
|
|||||||
pac::{self, interrupt},
|
pac::{self, interrupt},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
time::Hertz,
|
time::Hertz,
|
||||||
timer::{CountDownTimer, Event},
|
timer::{set_up_ms_timer, CountDownTimer, Event},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -65,23 +65,21 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
LibType::Hal => {
|
LibType::Hal => {
|
||||||
let mut ms_timer =
|
set_up_ms_timer(
|
||||||
CountDownTimer::tim0(&mut dp.SYSCONFIG, get_sys_clock().unwrap(), dp.TIM0);
|
|
||||||
let mut second_timer =
|
|
||||||
CountDownTimer::tim1(&mut dp.SYSCONFIG, get_sys_clock().unwrap(), dp.TIM1);
|
|
||||||
ms_timer.listen(
|
|
||||||
Event::TimeOut,
|
|
||||||
&mut dp.SYSCONFIG,
|
&mut dp.SYSCONFIG,
|
||||||
&mut dp.IRQSEL,
|
&mut dp.IRQSEL,
|
||||||
|
50.mhz().into(),
|
||||||
|
dp.TIM0,
|
||||||
interrupt::OC0,
|
interrupt::OC0,
|
||||||
);
|
);
|
||||||
|
let mut second_timer =
|
||||||
|
CountDownTimer::tim1(&mut dp.SYSCONFIG, get_sys_clock().unwrap(), dp.TIM1);
|
||||||
second_timer.listen(
|
second_timer.listen(
|
||||||
Event::TimeOut,
|
Event::TimeOut,
|
||||||
&mut dp.SYSCONFIG,
|
&mut dp.SYSCONFIG,
|
||||||
&mut dp.IRQSEL,
|
&mut dp.IRQSEL,
|
||||||
interrupt::OC1,
|
interrupt::OC1,
|
||||||
);
|
);
|
||||||
ms_timer.start(1000.hz());
|
|
||||||
second_timer.start(1.hz());
|
second_timer.start(1.hz());
|
||||||
unmask_irqs();
|
unmask_irqs();
|
||||||
}
|
}
|
||||||
|
25
src/clock.rs
25
src/clock.rs
@ -25,6 +25,18 @@ pub enum PeripheralClocks {
|
|||||||
Gpio = 24,
|
Gpio = 24,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum FilterClkSel {
|
||||||
|
SysClk = 0,
|
||||||
|
Clk1 = 1,
|
||||||
|
Clk2 = 2,
|
||||||
|
Clk3 = 3,
|
||||||
|
Clk4 = 4,
|
||||||
|
Clk5 = 5,
|
||||||
|
Clk6 = 6,
|
||||||
|
Clk7 = 7,
|
||||||
|
}
|
||||||
|
|
||||||
/// The Vorago in powered by an external clock which might have different frequencies.
|
/// The Vorago in powered by an external clock which might have different frequencies.
|
||||||
/// The clock can be set here so it can be used by other software components as well.
|
/// The clock can be set here so it can be used by other software components as well.
|
||||||
/// The clock can be set exactly once
|
/// The clock can be set exactly once
|
||||||
@ -39,6 +51,19 @@ pub fn get_sys_clock() -> Option<Hertz> {
|
|||||||
interrupt::free(|cs| SYS_CLOCK.borrow(cs).get().copied())
|
interrupt::free(|cs| SYS_CLOCK.borrow(cs).get().copied())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_clk_div_register(syscfg: &mut SYSCONFIG, clk_sel: FilterClkSel, div: u32) {
|
||||||
|
match clk_sel {
|
||||||
|
FilterClkSel::SysClk => (),
|
||||||
|
FilterClkSel::Clk1 => syscfg.ioconfig_clkdiv1.write(|w| unsafe { w.bits(div) }),
|
||||||
|
FilterClkSel::Clk2 => syscfg.ioconfig_clkdiv2.write(|w| unsafe { w.bits(div) }),
|
||||||
|
FilterClkSel::Clk3 => syscfg.ioconfig_clkdiv3.write(|w| unsafe { w.bits(div) }),
|
||||||
|
FilterClkSel::Clk4 => syscfg.ioconfig_clkdiv4.write(|w| unsafe { w.bits(div) }),
|
||||||
|
FilterClkSel::Clk5 => syscfg.ioconfig_clkdiv5.write(|w| unsafe { w.bits(div) }),
|
||||||
|
FilterClkSel::Clk6 => syscfg.ioconfig_clkdiv6.write(|w| unsafe { w.bits(div) }),
|
||||||
|
FilterClkSel::Clk7 => syscfg.ioconfig_clkdiv7.write(|w| unsafe { w.bits(div) }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn enable_peripheral_clock(syscfg: &mut SYSCONFIG, clock: PeripheralClocks) {
|
pub fn enable_peripheral_clock(syscfg: &mut SYSCONFIG, clock: PeripheralClocks) {
|
||||||
syscfg
|
syscfg
|
||||||
.peripheral_clk_enable
|
.peripheral_clk_enable
|
||||||
|
@ -57,9 +57,17 @@
|
|||||||
//! operation, the trait functions will return
|
//! operation, the trait functions will return
|
||||||
//! [`InvalidPinType`](Error::InvalidPinType).
|
//! [`InvalidPinType`](Error::InvalidPinType).
|
||||||
|
|
||||||
use super::pins::{FilterClkSel, FilterType, Pin, PinError, PinId, PinMode, PinState};
|
use super::pins::{
|
||||||
|
common_reg_if_functions, FilterType, InterruptEdge, InterruptLevel, Pin, PinError, PinId,
|
||||||
|
PinMode, PinState,
|
||||||
|
};
|
||||||
use super::reg::RegisterInterface;
|
use super::reg::RegisterInterface;
|
||||||
|
use crate::{
|
||||||
|
clock::FilterClkSel,
|
||||||
|
pac::{self, IRQSEL, SYSCONFIG},
|
||||||
|
};
|
||||||
use embedded_hal::digital::v2::{InputPin, OutputPin, ToggleableOutputPin};
|
use embedded_hal::digital::v2::{InputPin, OutputPin, ToggleableOutputPin};
|
||||||
|
use paste::paste;
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// DynPinMode configurations
|
// DynPinMode configurations
|
||||||
@ -293,42 +301,7 @@ impl DynPin {
|
|||||||
self.into_mode(DYN_RD_OPEN_DRAIN_OUTPUT);
|
self.into_mode(DYN_RD_OPEN_DRAIN_OUTPUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
common_reg_if_functions!();
|
||||||
pub fn datamask(&self) -> bool {
|
|
||||||
self.regs.datamask()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn clear_datamask(self) -> Self {
|
|
||||||
self.regs.clear_datamask();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn set_datamask(self) -> Self {
|
|
||||||
self.regs.set_datamask();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn is_high_masked(&self) -> Result<bool, PinError> {
|
|
||||||
self.regs.read_pin_masked()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn is_low_masked(&self) -> Result<bool, PinError> {
|
|
||||||
self.regs.read_pin_masked().map(|v| !v)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn set_high_masked(&mut self) -> Result<(), PinError> {
|
|
||||||
self.regs.write_pin_masked(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn set_low_masked(&mut self) -> Result<(), PinError> {
|
|
||||||
self.regs.write_pin_masked(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See p.53 of the programmers guide for more information.
|
/// See p.53 of the programmers guide for more information.
|
||||||
/// Possible delays in clock cycles:
|
/// Possible delays in clock cycles:
|
||||||
@ -371,6 +344,40 @@ impl DynPin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn interrupt_edge(
|
||||||
|
mut self,
|
||||||
|
edge_type: InterruptEdge,
|
||||||
|
syscfg: Option<&mut SYSCONFIG>,
|
||||||
|
irqsel: &mut IRQSEL,
|
||||||
|
interrupt: pac::Interrupt,
|
||||||
|
) -> Result<Self, PinError> {
|
||||||
|
match self.mode {
|
||||||
|
DynPinMode::Input(_) | DynPinMode::Output(_) => {
|
||||||
|
self._irq_enb(syscfg, irqsel, interrupt);
|
||||||
|
self.regs.interrupt_edge(edge_type);
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
_ => Err(PinError::InvalidPinType),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn interrupt_level(
|
||||||
|
mut self,
|
||||||
|
level_type: InterruptLevel,
|
||||||
|
syscfg: Option<&mut SYSCONFIG>,
|
||||||
|
irqsel: &mut IRQSEL,
|
||||||
|
interrupt: crate::pac::Interrupt,
|
||||||
|
) -> Result<Self, PinError> {
|
||||||
|
match self.mode {
|
||||||
|
DynPinMode::Input(_) | DynPinMode::Output(_) => {
|
||||||
|
self._irq_enb(syscfg, irqsel, interrupt);
|
||||||
|
self.regs.interrupt_level(level_type);
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
_ => Err(PinError::InvalidPinType),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn _read(&self) -> Result<bool, PinError> {
|
fn _read(&self) -> Result<bool, PinError> {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
|
191
src/gpio/pins.rs
191
src/gpio/pins.rs
@ -89,9 +89,11 @@
|
|||||||
|
|
||||||
use super::dynpins::{DynAlternate, DynGroup, DynInput, DynOutput, DynPinId, DynPinMode};
|
use super::dynpins::{DynAlternate, DynGroup, DynInput, DynOutput, DynPinId, DynPinMode};
|
||||||
use super::reg::RegisterInterface;
|
use super::reg::RegisterInterface;
|
||||||
use crate::pac::{IOCONFIG, PORTA, PORTB, SYSCONFIG};
|
use crate::{
|
||||||
use crate::typelevel::Is;
|
pac::{self, IOCONFIG, IRQSEL, PORTA, PORTB, SYSCONFIG},
|
||||||
use crate::Sealed;
|
typelevel::Is,
|
||||||
|
Sealed,
|
||||||
|
};
|
||||||
use core::convert::Infallible;
|
use core::convert::Infallible;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use embedded_hal::digital::v2::{InputPin, OutputPin, ToggleableOutputPin};
|
use embedded_hal::digital::v2::{InputPin, OutputPin, ToggleableOutputPin};
|
||||||
@ -101,6 +103,19 @@ use paste::paste;
|
|||||||
// Errors and Definitions
|
// Errors and Definitions
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum InterruptEdge {
|
||||||
|
HighToLow,
|
||||||
|
LowToHigh,
|
||||||
|
BothEdges,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum InterruptLevel {
|
||||||
|
Low = 0,
|
||||||
|
High = 1,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum PinState {
|
pub enum PinState {
|
||||||
Low = 0,
|
Low = 0,
|
||||||
@ -164,6 +179,7 @@ pub struct Input<C: InputConfig> {
|
|||||||
|
|
||||||
impl<C: InputConfig> Sealed for Input<C> {}
|
impl<C: InputConfig> Sealed for Input<C> {}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum FilterType {
|
pub enum FilterType {
|
||||||
SystemClock = 0,
|
SystemClock = 0,
|
||||||
DirectInputWithSynchronization = 1,
|
DirectInputWithSynchronization = 1,
|
||||||
@ -173,16 +189,7 @@ pub enum FilterType {
|
|||||||
FilterFourClockCycles = 5,
|
FilterFourClockCycles = 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum FilterClkSel {
|
pub use crate::clock::FilterClkSel;
|
||||||
SysClk = 0,
|
|
||||||
Clk1 = 1,
|
|
||||||
Clk2 = 2,
|
|
||||||
Clk3 = 3,
|
|
||||||
Clk4 = 4,
|
|
||||||
Clk5 = 5,
|
|
||||||
Clk6 = 6,
|
|
||||||
Clk7 = 7,
|
|
||||||
}
|
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Output configuration
|
// Output configuration
|
||||||
@ -347,6 +354,77 @@ impl<I: PinId, M: PinMode> AnyPin for Pin<I, M> {
|
|||||||
type Mode = M;
|
type Mode = M;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! common_reg_if_functions {
|
||||||
|
() => {
|
||||||
|
paste!(
|
||||||
|
#[inline]
|
||||||
|
pub fn datamask(&self) -> bool {
|
||||||
|
self.regs.datamask()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn clear_datamask(self) -> Self {
|
||||||
|
self.regs.clear_datamask();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_datamask(self) -> Self {
|
||||||
|
self.regs.set_datamask();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_high_masked(&self) -> Result<bool, PinError> {
|
||||||
|
self.regs.read_pin_masked()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_low_masked(&self) -> Result<bool, PinError> {
|
||||||
|
self.regs.read_pin_masked().map(|v| !v)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_high_masked(&mut self) -> Result<(), PinError> {
|
||||||
|
self.regs.write_pin_masked(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_low_masked(&mut self) -> Result<(), PinError> {
|
||||||
|
self.regs.write_pin_masked(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _irq_enb(
|
||||||
|
&mut self,
|
||||||
|
syscfg: Option<&mut va108xx::SYSCONFIG>,
|
||||||
|
irqsel: &mut va108xx::IRQSEL,
|
||||||
|
interrupt: va108xx::Interrupt,
|
||||||
|
) {
|
||||||
|
if syscfg.is_some() {
|
||||||
|
crate::clock::enable_peripheral_clock(
|
||||||
|
syscfg.unwrap(),
|
||||||
|
crate::clock::PeripheralClocks::Irqsel,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
self.regs.enable_irq();
|
||||||
|
match self.regs.id().group {
|
||||||
|
// Set the correct interrupt number in the IRQSEL register
|
||||||
|
DynGroup::A => {
|
||||||
|
irqsel.porta[self.regs.id().num as usize]
|
||||||
|
.write(|w| unsafe { w.bits(interrupt as u32) });
|
||||||
|
}
|
||||||
|
DynGroup::B => {
|
||||||
|
irqsel.portb[self.regs.id().num as usize]
|
||||||
|
.write(|w| unsafe { w.bits(interrupt as u32) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) use common_reg_if_functions;
|
||||||
|
|
||||||
impl<I: PinId, M: PinMode> Pin<I, M> {
|
impl<I: PinId, M: PinMode> Pin<I, M> {
|
||||||
/// Create a new [`Pin`]
|
/// Create a new [`Pin`]
|
||||||
///
|
///
|
||||||
@ -429,42 +507,7 @@ impl<I: PinId, M: PinMode> Pin<I, M> {
|
|||||||
self.into_mode()
|
self.into_mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
common_reg_if_functions!();
|
||||||
pub fn datamask(&self) -> bool {
|
|
||||||
self.regs.datamask()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn clear_datamask(self) -> Self {
|
|
||||||
self.regs.clear_datamask();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn set_datamask(self) -> Self {
|
|
||||||
self.regs.set_datamask();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn is_high_masked(&self) -> Result<bool, PinError> {
|
|
||||||
self.regs.read_pin_masked()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn is_low_masked(&self) -> Result<bool, PinError> {
|
|
||||||
self.regs.read_pin_masked().map(|v| !v)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn set_high_masked(&mut self) -> Result<(), PinError> {
|
|
||||||
self.regs.write_pin_masked(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn set_low_masked(&mut self) -> Result<(), PinError> {
|
|
||||||
self.regs.write_pin_masked(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn _set_high(&mut self) {
|
pub(crate) fn _set_high(&mut self) {
|
||||||
@ -526,6 +569,32 @@ impl<I: PinId, M: PinMode> AsMut<Self> for Pin<I, M> {
|
|||||||
// Additional functionality
|
// Additional functionality
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
|
impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
|
||||||
|
pub fn interrupt_edge(
|
||||||
|
mut self,
|
||||||
|
edge_type: InterruptEdge,
|
||||||
|
syscfg: Option<&mut SYSCONFIG>,
|
||||||
|
irqsel: &mut IRQSEL,
|
||||||
|
interrupt: pac::Interrupt,
|
||||||
|
) -> Self {
|
||||||
|
self._irq_enb(syscfg, irqsel, interrupt);
|
||||||
|
self.regs.interrupt_edge(edge_type);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn interrupt_level(
|
||||||
|
mut self,
|
||||||
|
level_type: InterruptLevel,
|
||||||
|
syscfg: Option<&mut SYSCONFIG>,
|
||||||
|
irqsel: &mut IRQSEL,
|
||||||
|
interrupt: pac::Interrupt,
|
||||||
|
) -> Self {
|
||||||
|
self._irq_enb(syscfg, irqsel, interrupt);
|
||||||
|
self.regs.interrupt_level(level_type);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<I: PinId, C: OutputConfig> Pin<I, Output<C>> {
|
impl<I: PinId, C: OutputConfig> Pin<I, Output<C>> {
|
||||||
/// See p.53 of the programmers guide for more information.
|
/// See p.53 of the programmers guide for more information.
|
||||||
/// Possible delays in clock cycles:
|
/// Possible delays in clock cycles:
|
||||||
@ -545,6 +614,30 @@ impl<I: PinId, C: OutputConfig> Pin<I, Output<C>> {
|
|||||||
self.regs.pulse_mode(enable, default_state);
|
self.regs.pulse_mode(enable, default_state);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn interrupt_edge(
|
||||||
|
mut self,
|
||||||
|
edge_type: InterruptEdge,
|
||||||
|
syscfg: Option<&mut SYSCONFIG>,
|
||||||
|
irqsel: &mut IRQSEL,
|
||||||
|
interrupt: pac::Interrupt,
|
||||||
|
) -> Self {
|
||||||
|
self._irq_enb(syscfg, irqsel, interrupt);
|
||||||
|
self.regs.interrupt_edge(edge_type);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn interrupt_level(
|
||||||
|
mut self,
|
||||||
|
level_type: InterruptLevel,
|
||||||
|
syscfg: Option<&mut SYSCONFIG>,
|
||||||
|
irqsel: &mut IRQSEL,
|
||||||
|
interrupt: pac::Interrupt,
|
||||||
|
) -> Self {
|
||||||
|
self._irq_enb(syscfg, irqsel, interrupt);
|
||||||
|
self.regs.interrupt_level(level_type);
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
|
impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use super::dynpins::{self, DynGroup, DynPinId, DynPinMode};
|
use super::dynpins::{self, DynGroup, DynPinId, DynPinMode};
|
||||||
use super::pins::{FilterClkSel, FilterType, PinError, PinState};
|
use super::pins::{FilterType, InterruptEdge, InterruptLevel, PinError, PinState};
|
||||||
|
use crate::clock::FilterClkSel;
|
||||||
use va108xx::{ioconfig, porta, IOCONFIG, PORTA, PORTB};
|
use va108xx::{ioconfig, porta, IOCONFIG, PORTA, PORTB};
|
||||||
|
|
||||||
/// Type definition to avoid confusion: These register blocks are identical
|
/// Type definition to avoid confusion: These register blocks are identical
|
||||||
@ -31,16 +32,13 @@ impl From<DynPinMode> for ModeFields {
|
|||||||
use dynpins::DynInput::*;
|
use dynpins::DynInput::*;
|
||||||
fields.dir = false;
|
fields.dir = false;
|
||||||
match config {
|
match config {
|
||||||
Floating => {
|
Floating => (),
|
||||||
fields.pull_en = false;
|
|
||||||
}
|
|
||||||
PullUp => {
|
PullUp => {
|
||||||
fields.pull_en = true;
|
fields.pull_en = true;
|
||||||
fields.pull_dir = true;
|
fields.pull_dir = true;
|
||||||
}
|
}
|
||||||
PullDown => {
|
PullDown => {
|
||||||
fields.pull_en = true;
|
fields.pull_en = true;
|
||||||
fields.pull_dir = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -48,9 +46,7 @@ impl From<DynPinMode> for ModeFields {
|
|||||||
use dynpins::DynOutput::*;
|
use dynpins::DynOutput::*;
|
||||||
fields.dir = true;
|
fields.dir = true;
|
||||||
match config {
|
match config {
|
||||||
PushPull => {
|
PushPull => (),
|
||||||
fields.opendrn = false;
|
|
||||||
}
|
|
||||||
OpenDrain => {
|
OpenDrain => {
|
||||||
fields.opendrn = true;
|
fields.opendrn = true;
|
||||||
}
|
}
|
||||||
@ -60,7 +56,6 @@ impl From<DynPinMode> for ModeFields {
|
|||||||
}
|
}
|
||||||
ReadablePushPull => {
|
ReadablePushPull => {
|
||||||
fields.enb_input = true;
|
fields.enb_input = true;
|
||||||
fields.opendrn = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,6 +149,8 @@ pub(super) unsafe trait RegisterInterface {
|
|||||||
unsafe {
|
unsafe {
|
||||||
if dir {
|
if dir {
|
||||||
portreg.dir().modify(|r, w| w.bits(r.bits() | mask));
|
portreg.dir().modify(|r, w| w.bits(r.bits() | mask));
|
||||||
|
// Clear output
|
||||||
|
portreg.clrout().write(|w| w.bits(mask));
|
||||||
} else {
|
} else {
|
||||||
portreg.dir().modify(|r, w| w.bits(r.bits() & !mask));
|
portreg.dir().modify(|r, w| w.bits(r.bits() & !mask));
|
||||||
}
|
}
|
||||||
@ -200,6 +197,20 @@ pub(super) unsafe trait RegisterInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn enable_irq(&self) {
|
||||||
|
self.port_reg()
|
||||||
|
.irq_enb
|
||||||
|
.modify(|r, w| unsafe { w.bits(r.bits() | self.mask_32()) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn disable_irq(&self) {
|
||||||
|
self.port_reg()
|
||||||
|
.irq_enb
|
||||||
|
.modify(|r, w| unsafe { w.bits(r.bits() & !self.mask_32()) });
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_perid(&self) -> u32 {
|
fn get_perid(&self) -> u32 {
|
||||||
let portreg = self.port_reg();
|
let portreg = self.port_reg();
|
||||||
@ -273,6 +284,53 @@ pub(super) unsafe trait RegisterInterface {
|
|||||||
unsafe { self.port_reg().togout().write(|w| w.bits(self.mask_32())) };
|
unsafe { self.port_reg().togout().write(|w| w.bits(self.mask_32())) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Only useful for interrupt pins. Configure whether to use edges or level as interrupt soure
|
||||||
|
/// When using edge mode, it is possible to generate interrupts on both edges as well
|
||||||
|
#[inline]
|
||||||
|
fn interrupt_edge(&mut self, edge_type: InterruptEdge) {
|
||||||
|
unsafe {
|
||||||
|
self.port_reg()
|
||||||
|
.irq_sen
|
||||||
|
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
|
||||||
|
match edge_type {
|
||||||
|
InterruptEdge::HighToLow => {
|
||||||
|
self.port_reg()
|
||||||
|
.irq_evt
|
||||||
|
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
|
||||||
|
}
|
||||||
|
InterruptEdge::LowToHigh => {
|
||||||
|
self.port_reg()
|
||||||
|
.irq_evt
|
||||||
|
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
|
||||||
|
}
|
||||||
|
InterruptEdge::BothEdges => {
|
||||||
|
self.port_reg()
|
||||||
|
.irq_edge
|
||||||
|
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure which edge or level type triggers an interrupt
|
||||||
|
#[inline]
|
||||||
|
fn interrupt_level(&mut self, level: InterruptLevel) {
|
||||||
|
unsafe {
|
||||||
|
self.port_reg()
|
||||||
|
.irq_sen
|
||||||
|
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
|
||||||
|
if level == InterruptLevel::Low {
|
||||||
|
self.port_reg()
|
||||||
|
.irq_evt
|
||||||
|
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
|
||||||
|
} else {
|
||||||
|
self.port_reg()
|
||||||
|
.irq_evt
|
||||||
|
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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) {
|
||||||
|
17
src/timer.rs
17
src/timer.rs
@ -5,7 +5,10 @@
|
|||||||
//! - [MS and second tick implementation](https://github.com/robamu-org/va108xx-hal-rs/blob/main/examples/timer-ticks.rs)
|
//! - [MS and second tick implementation](https://github.com/robamu-org/va108xx-hal-rs/blob/main/examples/timer-ticks.rs)
|
||||||
use crate::{
|
use crate::{
|
||||||
clock::{enable_peripheral_clock, PeripheralClocks},
|
clock::{enable_peripheral_clock, PeripheralClocks},
|
||||||
|
pac,
|
||||||
|
prelude::*,
|
||||||
time::Hertz,
|
time::Hertz,
|
||||||
|
timer,
|
||||||
};
|
};
|
||||||
use embedded_hal::timer::{Cancel, CountDown, Periodic};
|
use embedded_hal::timer::{Cancel, CountDown, Periodic};
|
||||||
use va108xx::{Interrupt, IRQSEL, SYSCONFIG};
|
use va108xx::{Interrupt, IRQSEL, SYSCONFIG};
|
||||||
@ -160,6 +163,20 @@ macro_rules! timers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up a millisecond timer on TIM0. Please note that you still need to unmask the related IRQ
|
||||||
|
// and provide an IRQ handler yourself
|
||||||
|
pub fn set_up_ms_timer(
|
||||||
|
syscfg: &mut pac::SYSCONFIG,
|
||||||
|
irqsel: &mut pac::IRQSEL,
|
||||||
|
sys_clk: Hertz,
|
||||||
|
tim0: TIM0,
|
||||||
|
irq: pac::Interrupt,
|
||||||
|
) {
|
||||||
|
let mut ms_timer = CountDownTimer::tim0(syscfg, sys_clk, tim0);
|
||||||
|
ms_timer.listen(timer::Event::TimeOut, syscfg, irqsel, irq);
|
||||||
|
ms_timer.start(1000.hz());
|
||||||
|
}
|
||||||
|
|
||||||
timers! {
|
timers! {
|
||||||
TIM0: (tim0, 0),
|
TIM0: (tim0, 0),
|
||||||
TIM1: (tim1, 1),
|
TIM1: (tim1, 1),
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! # API for the UART peripheral
|
//! # API for the UART peripheral
|
||||||
//!
|
//!
|
||||||
//! ## Examples
|
//! ## Examples
|
||||||
|
//!
|
||||||
//! - [UART example](https://github.com/robamu-org/va108xx-hal-rs/blob/main/examples/uart.rs)
|
//! - [UART example](https://github.com/robamu-org/va108xx-hal-rs/blob/main/examples/uart.rs)
|
||||||
use core::{convert::Infallible, ptr};
|
use core::{convert::Infallible, ptr};
|
||||||
use core::{marker::PhantomData, ops::Deref};
|
use core::{marker::PhantomData, ops::Deref};
|
||||||
|
Reference in New Issue
Block a user