1 Commits

Author SHA1 Message Date
0d74fd250f EGit integration
All checks were successful
Rust/va108xx-hal/pipeline/pr-main This commit looks good
- Changed license to Apache-2.0 only
- Added NOTICE file
- Added Jenkins CI/CD files
2021-12-06 13:01:50 +01:00
17 changed files with 73 additions and 199 deletions

View File

@ -16,11 +16,14 @@ jobs:
override: true override: true
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
use-cross: true
command: check command: check
args: --target thumbv6m-none-eabi
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
use-cross: true
command: check command: check
args: --examples args: --examples --target thumbv6m-none-eabi
fmt: fmt:
name: Rustfmt name: Rustfmt
@ -52,8 +55,9 @@ jobs:
- run: rustup component add clippy - run: rustup component add clippy
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
use-cross: true
command: clippy command: clippy
args: -- -D warnings args: --target thumbv6m-none-eabi -- -D warnings
ci: ci:
if: ${{ success() }} if: ${{ success() }}

View File

@ -8,42 +8,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [unreleased] ## [unreleased]
## [v0.4.3]
- Various smaller fixes for READMEs, update of links in documentation
- Simplified CI for github, do not use `cross`
- New `blinky-pac` example
- Use HAL delay in `blinky` example
## [v0.4.2]
### Added
- `port_mux` function to set pin function select manually
### Changed
- Clear TX and RX FIFO in SPI transfer function
## [v0.4.1]
### Fixed
- Initial blockmode setting was not set in SPI constructor
## [v0.4.0]
### Changed
- Replaced `Hertz` by `impl Into<Hertz>` completely and removed
`+ Copy` where not necessary
## [v0.3.1]
- Updated all links to point to new repository
## [v0.3.0]
### Added ### Added
- TIM Cascade example - TIM Cascade example
@ -51,8 +15,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Changed ### Changed
- `CountDownTimer` new function now expects an `impl Into<Hertz>` instead of `Hertz` - `CountDownTimer` new function now expects an `impl Into<Hertz>` instead of `Hertz`
- Primary repository now hosted on IRS external git: https://egit.irs.uni-stuttgart.de/rust/va108xx-hal
- Relicensed as Apache-2.0
## [0.2.3] ## [0.2.3]

View File

@ -1,7 +1,7 @@
[package] [package]
name = "va108xx-hal" name = "va108xx-hal"
version = "0.4.3" version = "0.2.3"
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"] 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"
homepage = "https://egit.irs.uni-stuttgart.de/rust/va108xx-hal" homepage = "https://egit.irs.uni-stuttgart.de/rust/va108xx-hal"
@ -36,16 +36,10 @@ debug = true
lto = false lto = false
[profile.release] [profile.release]
# Problematic because RTT won't work lto = true
lto = false
debug = true debug = true
opt-level = "s" opt-level = "s"
# Commented until named-profiles feature is stabilized
# [profile.release-lto]
# inherits = "release"
# lto = true
[[example]] [[example]]
name = "timer-ticks" name = "timer-ticks"
required-features = ["rt"] required-features = ["rt"]

View File

@ -59,7 +59,7 @@ your custom board.
The hello world of embedded development is usually to blinky a LED. This example The hello world of embedded development is usually to blinky a LED. This example
is contained within the is contained within the
[examples folder](https://egit.irs.uni-stuttgart.de/rust/va108xx-hal/src/branch/main/examples/blinky.rs). [examples folder](https://github.com/robamu-org/va108xx-hal-rs/tree/main/examples/blinky.rs).
1. Set up your Rust cross-compiler if you have not done so yet. See more in the [build chapter](#Building) 1. Set up your Rust cross-compiler if you have not done so yet. See more in the [build chapter](#Building)
2. Create a new binary crate with `cargo init` 2. Create a new binary crate with `cargo init`
@ -81,8 +81,12 @@ is contained within the
features = ["rt"] features = ["rt"]
``` ```
6. Build the application with `cargo build` 6. Build the application with
```sh
cargo build
```
7. Flashing the board might work differently for different boards and there is usually 7. Flashing the board might work differently for different boards and there is usually
more than one way. You can find example instructions for the REB1 development board more than one way. You can find example instructions for the REB1 development board
[here](https://egit.irs.uni-stuttgart.de/rust/vorago-reb1). [here](https://github.com/robamu/vorago-reb1-rs).

View File

@ -1,47 +0,0 @@
//! Blinky examples using only the PAC
//!
//! Additional note on LEDs:
//! Pulling the GPIOs low makes the LEDs blink. See REB1
//! schematic for more details.
#![no_main]
#![no_std]
use cortex_m_rt::entry;
use panic_halt as _;
use va108xx as pac;
// REB LED pin definitions. All on port A
const LED_D2: u32 = 1 << 10;
const LED_D3: u32 = 1 << 7;
const LED_D4: u32 = 1 << 6;
#[entry]
fn main() -> ! {
let dp = pac::Peripherals::take().unwrap();
// Enable all peripheral clocks
dp.SYSCONFIG
.peripheral_clk_enable
.modify(|_, w| unsafe { w.bits(0xffffffff) });
dp.PORTA
.dir()
.modify(|_, w| unsafe { w.bits(LED_D2 | LED_D3 | LED_D4) });
dp.PORTA
.datamask()
.modify(|_, w| unsafe { w.bits(LED_D2 | LED_D3 | LED_D4) });
for _ in 0..10 {
dp.PORTA
.clrout()
.write(|w| unsafe { w.bits(LED_D2 | LED_D3 | LED_D4) });
cortex_m::asm::delay(5_000_000);
dp.PORTA
.setout()
.write(|w| unsafe { w.bits(LED_D2 | LED_D3 | LED_D4) });
cortex_m::asm::delay(5_000_000);
}
loop {
dp.PORTA
.togout()
.write(|w| unsafe { w.bits(LED_D2 | LED_D3 | LED_D4) });
cortex_m::asm::delay(25_000_000);
}
}

View File

@ -9,7 +9,7 @@
use cortex_m_rt::entry; use cortex_m_rt::entry;
use embedded_hal::digital::v2::ToggleableOutputPin; use embedded_hal::digital::v2::ToggleableOutputPin;
use panic_halt as _; use panic_halt as _;
use va108xx_hal::{gpio::PinsA, pac, prelude::*, timer::set_up_ms_timer}; use va108xx_hal::{gpio::PinsA, pac, prelude::*};
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
@ -18,29 +18,22 @@ fn main() -> ! {
let mut led1 = porta.pa10.into_push_pull_output(); let mut led1 = porta.pa10.into_push_pull_output();
let mut led2 = porta.pa7.into_push_pull_output(); let mut led2 = porta.pa7.into_push_pull_output();
let mut led3 = porta.pa6.into_push_pull_output(); let mut led3 = porta.pa6.into_push_pull_output();
let mut delay = set_up_ms_timer(
&mut dp.SYSCONFIG,
&mut dp.IRQSEL,
50.mhz().into(),
dp.TIM0,
pac::Interrupt::OC0,
);
for _ in 0..10 { for _ in 0..10 {
led1.set_low().ok(); led1.set_low().ok();
led2.set_low().ok(); led2.set_low().ok();
led3.set_low().ok(); led3.set_low().ok();
delay.delay_ms(200_u16); cortex_m::asm::delay(5_000_000);
led1.set_high().ok(); led1.set_high().ok();
led2.set_high().ok(); led2.set_high().ok();
led3.set_high().ok(); led3.set_high().ok();
delay.delay_ms(200_u16); cortex_m::asm::delay(5_000_000);
} }
loop { loop {
led1.toggle().ok(); led1.toggle().ok();
delay.delay_ms(200_u16); cortex_m::asm::delay(5_000_000);
led2.toggle().ok(); led2.toggle().ok();
delay.delay_ms(200_u16); cortex_m::asm::delay(5_000_000);
led3.toggle().ok(); led3.toggle().ok();
delay.delay_ms(200_u16); cortex_m::asm::delay(5_000_000);
} }
} }

View File

@ -114,8 +114,12 @@ fn main() -> ! {
match SPI_BUS_SEL { match SPI_BUS_SEL {
SpiBusSelect::SpiAPortA | SpiBusSelect::SpiAPortB => { SpiBusSelect::SpiAPortA | SpiBusSelect::SpiAPortB => {
if let Some(ref mut spi) = *spia_ref.borrow_mut() { if let Some(ref mut spi) = *spia_ref.borrow_mut() {
let transfer_cfg = let transfer_cfg = TransferConfig::new_no_hw_cs(
TransferConfig::new_no_hw_cs(SPI_SPEED_KHZ.khz(), SPI_MODE, BLOCKMODE, false); SPI_SPEED_KHZ.khz().into(),
SPI_MODE,
BLOCKMODE,
false,
);
spi.cfg_transfer(&transfer_cfg); spi.cfg_transfer(&transfer_cfg);
} }
} }
@ -123,7 +127,7 @@ fn main() -> ! {
if let Some(ref mut spi) = *spib_ref.borrow_mut() { if let Some(ref mut spi) = *spib_ref.borrow_mut() {
let hw_cs_pin = pinsb.pb2.into_funsel_1(); let hw_cs_pin = pinsb.pb2.into_funsel_1();
let transfer_cfg = TransferConfig::new( let transfer_cfg = TransferConfig::new(
SPI_SPEED_KHZ.khz(), SPI_SPEED_KHZ.khz().into(),
SPI_MODE, SPI_MODE,
Some(hw_cs_pin), Some(hw_cs_pin),
BLOCKMODE, BLOCKMODE,

View File

@ -25,7 +25,7 @@ fn main() -> ! {
(tx, rx), (tx, rx),
115200.bps(), 115200.bps(),
&mut dp.SYSCONFIG, &mut dp.SYSCONFIG,
50.mhz(), 50.mhz().into(),
); );
let (mut tx, mut rx) = uartb.split(); let (mut tx, mut rx) = uartb.split();
writeln!(tx, "Hello World\r").unwrap(); writeln!(tx, "Hello World\r").unwrap();

View File

@ -57,17 +57,14 @@
//! operation, the trait functions will return //! operation, the trait functions will return
//! [`InvalidPinType`](PinError::InvalidPinType). //! [`InvalidPinType`](PinError::InvalidPinType).
use super::{ use super::pins::{
pins::{ common_reg_if_functions, FilterType, InterruptEdge, InterruptLevel, Pin, PinError, PinId,
common_reg_if_functions, FilterType, InterruptEdge, InterruptLevel, Pin, PinError, PinId, PinMode, PinState,
PinMode, PinState,
},
reg::RegisterInterface,
}; };
use super::reg::RegisterInterface;
use crate::{ use crate::{
clock::FilterClkSel, clock::FilterClkSel,
pac::{self, IRQSEL, SYSCONFIG}, pac::{self, IRQSEL, SYSCONFIG},
utility::Funsel,
}; };
use embedded_hal::digital::v2::{InputPin, OutputPin, ToggleableOutputPin}; use embedded_hal::digital::v2::{InputPin, OutputPin, ToggleableOutputPin};
use paste::paste; use paste::paste;
@ -101,7 +98,13 @@ pub enum DynOutput {
ReadableOpenDrain, ReadableOpenDrain,
} }
pub type DynAlternate = Funsel; /// Value-level `enum` for alternate peripheral function configurations
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum DynAlternate {
Funsel1,
Funsel2,
Funsel3,
}
//================================================================================================== //==================================================================================================
// DynPinMode // DynPinMode

View File

@ -20,7 +20,7 @@
//! //!
//! ## Examples //! ## Examples
//! //!
//! - [Blinky example](https://egit.irs.uni-stuttgart.de/rust/va108xx-hal/src/branch/main/examples/blinky.rs) //! - [Blinky example](https://github.com/robamu-org/va108xx-hal-rs/blob/main/examples/blinky.rs)
pub mod dynpins; pub mod dynpins;
pub use dynpins::*; pub use dynpins::*;

View File

@ -60,7 +60,18 @@ impl From<DynPinMode> for ModeFields {
} }
} }
Alternate(config) => { Alternate(config) => {
fields.funsel = config as u8; use dynpins::DynAlternate::*;
match config {
Funsel1 => {
fields.funsel = 1;
}
Funsel2 => {
fields.funsel = 2;
}
Funsel3 => {
fields.funsel = 3;
}
}
} }
} }
fields fields

View File

@ -2,7 +2,7 @@
//! //!
//! ## Examples //! ## Examples
//! //!
//! - [REB1 I2C temperature sensor example](https://egit.irs.uni-stuttgart.de/rust/vorago-reb1/src/branch/main/examples/adt75-temp-sensor.rs) //! - [REB1 I2C temperature sensor example](https://github.com/robamu-org/vorago-reb1-rs/blob/main/examples/temp-sensor.rs)
use crate::{ use crate::{
clock::{enable_peripheral_clock, PeripheralClocks}, clock::{enable_peripheral_clock, PeripheralClocks},
pac::{I2CA, I2CB, SYSCONFIG}, pac::{I2CA, I2CB, SYSCONFIG},
@ -231,7 +231,7 @@ macro_rules! i2c_base {
impl I2cBase<$I2CX> { impl I2cBase<$I2CX> {
pub fn $i2cx( pub fn $i2cx(
i2c: $I2CX, i2c: $I2CX,
sys_clk: impl Into<Hertz>, sys_clk: impl Into<Hertz> + Copy,
speed_mode: I2cSpeed, speed_mode: I2cSpeed,
ms_cfg: Option<&MasterConfig>, ms_cfg: Option<&MasterConfig>,
sl_cfg: Option<&SlaveConfig>, sl_cfg: Option<&SlaveConfig>,
@ -740,7 +740,7 @@ macro_rules! i2c_slave {
fn $i2cx_slave( fn $i2cx_slave(
i2c: $I2CX, i2c: $I2CX,
cfg: SlaveConfig, cfg: SlaveConfig,
sys_clk: impl Into<Hertz>, sys_clk: impl Into<Hertz> + Copy,
speed_mode: I2cSpeed, speed_mode: I2cSpeed,
sys_cfg: Option<&mut SYSCONFIG>, sys_cfg: Option<&mut SYSCONFIG>,
) -> Self { ) -> Self {
@ -897,7 +897,7 @@ macro_rules! i2c_slave {
pub fn i2ca( pub fn i2ca(
i2c: $I2CX, i2c: $I2CX,
cfg: SlaveConfig, cfg: SlaveConfig,
sys_clk: impl Into<Hertz>, sys_clk: impl Into<Hertz> + Copy,
speed_mode: I2cSpeed, speed_mode: I2cSpeed,
sys_cfg: Option<&mut SYSCONFIG>, sys_cfg: Option<&mut SYSCONFIG>,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
@ -912,7 +912,7 @@ macro_rules! i2c_slave {
pub fn $i2cx( pub fn $i2cx(
i2c: $I2CX, i2c: $I2CX,
cfg: SlaveConfig, cfg: SlaveConfig,
sys_clk: impl Into<Hertz>, sys_clk: impl Into<Hertz> + Copy,
speed_mode: I2cSpeed, speed_mode: I2cSpeed,
sys_cfg: Option<&mut SYSCONFIG>, sys_cfg: Option<&mut SYSCONFIG>,
) -> Self { ) -> Self {

View File

@ -4,7 +4,7 @@
//! //!
//! ## Examples //! ## Examples
//! //!
//! - [PWM example](https://egit.irs.uni-stuttgart.de/rust/va108xx-hal/src/branch/main/examples/pwm.rs) //! - [PWM example](https://github.com/robamu-org/va108xx-hal-rs/blob/main/examples/pwm.rs)
use core::marker::PhantomData; use core::marker::PhantomData;
use crate::{clock::enable_peripheral_clock, gpio::DynPinId}; use crate::{clock::enable_peripheral_clock, gpio::DynPinId};

View File

@ -2,7 +2,7 @@
//! //!
//! ## Examples //! ## Examples
//! //!
//! - [Blocking SPI example](https://egit.irs.uni-stuttgart.de/rust/va108xx-hal/src/branch/main/examples/spi.rs) //! - [Blocking SPI example](https://github.com/robamu-org/va108xx-hal-rs/blob/main/examples/spi.rs)
use crate::Sealed; use crate::Sealed;
use crate::{ use crate::{
clock::{enable_peripheral_clock, PeripheralClocks}, clock::{enable_peripheral_clock, PeripheralClocks},
@ -218,9 +218,9 @@ pub struct ReducedTransferConfig {
} }
impl TransferConfig<NoneT> { impl TransferConfig<NoneT> {
pub fn new_no_hw_cs(spi_clk: impl Into<Hertz>, mode: Mode, blockmode: bool, sod: bool) -> Self { pub fn new_no_hw_cs(spi_clk: Hertz, mode: Mode, blockmode: bool, sod: bool) -> Self {
TransferConfig { TransferConfig {
spi_clk: spi_clk.into(), spi_clk,
mode, mode,
hw_cs: None, hw_cs: None,
sod, sod,
@ -231,14 +231,14 @@ impl TransferConfig<NoneT> {
impl<HWCS: HwCs> TransferConfig<HWCS> { impl<HWCS: HwCs> TransferConfig<HWCS> {
pub fn new( pub fn new(
spi_clk: impl Into<Hertz>, spi_clk: Hertz,
mode: Mode, mode: Mode,
hw_cs: Option<HWCS>, hw_cs: Option<HWCS>,
blockmode: bool, blockmode: bool,
sod: bool, sod: bool,
) -> Self { ) -> Self {
TransferConfig { TransferConfig {
spi_clk: spi_clk.into(), spi_clk,
mode, mode,
hw_cs, hw_cs,
sod, sod,
@ -428,7 +428,6 @@ macro_rules! spi {
w.sod().bit(sod); w.sod().bit(sod);
w.ms().bit(ms); w.ms().bit(ms);
w.mdlycap().bit(mdlycap); w.mdlycap().bit(mdlycap);
w.blockmode().bit(init_blockmode);
unsafe { w.ss().bits(ss) } unsafe { w.ss().bits(ss) }
}); });
@ -453,7 +452,7 @@ macro_rules! spi {
} }
#[inline] #[inline]
pub fn cfg_clock(&mut self, spi_clk: impl Into<Hertz>) { pub fn cfg_clock(&mut self, spi_clk: Hertz) {
self.spi_base.cfg_clock(spi_clk); self.spi_base.cfg_clock(spi_clk);
} }
@ -483,8 +482,8 @@ macro_rules! spi {
impl<WORD: Word> SpiBase<$SPIX, WORD> { impl<WORD: Word> SpiBase<$SPIX, WORD> {
#[inline] #[inline]
pub fn cfg_clock(&mut self, spi_clk: impl Into<Hertz>) { pub fn cfg_clock(&mut self, spi_clk: Hertz) {
let clk_prescale = self.sys_clk.0 / (spi_clk.into().0 * (self.cfg.scrdv as u32 + 1)); let clk_prescale = self.sys_clk.0 / (spi_clk.0 * (self.cfg.scrdv as u32 + 1));
self.spi self.spi
.clkprescale .clkprescale
.write(|w| unsafe { w.bits(clk_prescale) }); .write(|w| unsafe { w.bits(clk_prescale) });
@ -504,16 +503,6 @@ macro_rules! spi {
}); });
} }
#[inline]
pub fn clear_tx_fifo(&self) {
self.spi.fifo_clr.write(|w| w.txfifo().set_bit());
}
#[inline]
pub fn clear_rx_fifo(&self) {
self.spi.fifo_clr.write(|w| w.rxfifo().set_bit());
}
#[inline] #[inline]
pub fn perid(&self) -> u32 { pub fn perid(&self) -> u32 {
self.spi.perid.read().bits() self.spi.perid.read().bits()
@ -650,9 +639,6 @@ macro_rules! spi {
// FIFO has a depth of 16. // FIFO has a depth of 16.
const FILL_DEPTH: usize = 12; const FILL_DEPTH: usize = 12;
self.clear_tx_fifo();
self.clear_rx_fifo();
if self.blockmode { if self.blockmode {
self.spi.ctrl1.modify(|_, w| { self.spi.ctrl1.modify(|_, w| {
w.mtxpause().set_bit() w.mtxpause().set_bit()

View File

@ -2,8 +2,7 @@
//! //!
//! ## Examples //! ## Examples
//! //!
//! - [MS and second tick implementation](https://egit.irs.uni-stuttgart.de/rust/va108xx-hal/src/branch/main/examples/timer-ticks.rs) //! - [MS and second tick implementation](https://github.com/robamu-org/va108xx-hal-rs/blob/main/examples/timer-ticks.rs)
//! - [Cascade feature example](https://egit.irs.uni-stuttgart.de/rust/va108xx-hal/src/branch/main/examples/cascade.rs)
use crate::{ use crate::{
clock::{enable_peripheral_clock, PeripheralClocks}, clock::{enable_peripheral_clock, PeripheralClocks},
gpio::{ gpio::{

View File

@ -2,7 +2,7 @@
//! //!
//! ## Examples //! ## Examples
//! //!
//! - [UART example](https://egit.irs.uni-stuttgart.de/rust/va108xx-hal/src/branch/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};
use libm::floorf; use libm::floorf;
@ -306,12 +306,12 @@ macro_rules! uart_impl {
pins: PINS, pins: PINS,
config: impl Into<Config>, config: impl Into<Config>,
syscfg: &mut SYSCONFIG, syscfg: &mut SYSCONFIG,
sys_clk: impl Into<Hertz> sys_clk: Hertz
) -> Self ) -> Self
{ {
enable_peripheral_clock(syscfg, $clk_enb_enum); enable_peripheral_clock(syscfg, $clk_enb_enum);
Uart { uart, pins, tx: Tx::new(), rx: Rx::new() }.init( Uart { uart, pins, tx: Tx::new(), rx: Rx::new() }.init(
config.into(), sys_clk.into() config.into(), sys_clk
) )
} }
} }

View File

@ -3,25 +3,11 @@
//! Some more information about the recommended scrub rates can be found on the //! Some more information about the recommended scrub rates can be found on the
//! [Vorago White Paper website](https://www.voragotech.com/resources) in the //! [Vorago White Paper website](https://www.voragotech.com/resources) in the
//! application note AN1212 //! application note AN1212
use va108xx::{IOCONFIG, SYSCONFIG}; use va108xx::SYSCONFIG;
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug)]
pub enum UtilityError { pub enum UtilityError {
InvalidCounterResetVal, InvalidCounterResetVal,
InvalidPin,
}
#[derive(Debug, Eq, Copy, Clone, PartialEq)]
pub enum Funsel {
Funsel1 = 0b01,
Funsel2 = 0b10,
Funsel3 = 0b11,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum PortSel {
PortA,
PortB,
} }
#[derive(Copy, Clone, PartialEq)] #[derive(Copy, Clone, PartialEq)]
@ -86,28 +72,3 @@ pub fn set_reset_bit(syscfg: &mut SYSCONFIG, periph_sel: PeripheralSelect) {
.peripheral_reset .peripheral_reset
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << periph_sel as u8)) }); .modify(|r, w| unsafe { w.bits(r.bits() | (1 << periph_sel as u8)) });
} }
/// Can be used to manually manipulate the function select of port pins
pub fn port_mux(
ioconfig: &mut IOCONFIG,
port: PortSel,
pin: u8,
funsel: Funsel,
) -> Result<(), UtilityError> {
match port {
PortSel::PortA => {
if pin > 31 {
return Err(UtilityError::InvalidPin);
}
ioconfig.porta[pin as usize].modify(|_, w| unsafe { w.funsel().bits(funsel as u8) });
Ok(())
}
PortSel::PortB => {
if pin > 23 {
return Err(UtilityError::InvalidPin);
}
ioconfig.portb[pin as usize].modify(|_, w| unsafe { w.funsel().bits(funsel as u8) });
Ok(())
}
}
}