move to updated API

This commit is contained in:
Robin Müller 2025-04-16 14:35:57 +02:00
parent dfe34e965f
commit 121b467fb9
Signed by: muellerr
GPG Key ID: A649FB78196E3849
49 changed files with 751 additions and 986 deletions

View File

@ -16,9 +16,11 @@ static_assertions = "1"
[dependencies.va108xx-hal] [dependencies.va108xx-hal]
version = "0.11" version = "0.11"
path = "../va108xx-hal"
[dependencies.vorago-reb1] [dependencies.vorago-reb1]
version = "0.8" version = "0.8"
path = "../vorago-reb1"
[features] [features]
default = [] default = []

View File

@ -104,11 +104,11 @@ fn main() -> ! {
rtt_init_print!(); rtt_init_print!();
rprintln!("-- VA108xx bootloader --"); rprintln!("-- VA108xx bootloader --");
} }
let mut dp = pac::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap();
let cp = cortex_m::Peripherals::take().unwrap(); let cp = cortex_m::Peripherals::take().unwrap();
let mut timer = CountdownTimer::new(&mut dp.sysconfig, CLOCK_FREQ, dp.tim0); let mut timer = CountdownTimer::new(CLOCK_FREQ, dp.tim0);
let mut nvm = M95M01::new(&mut dp.sysconfig, CLOCK_FREQ, dp.spic); let mut nvm = M95M01::new(CLOCK_FREQ, dp.spic);
if FLASH_SELF { if FLASH_SELF {
let mut first_four_bytes: [u8; 4] = [0; 4]; let mut first_four_bytes: [u8; 4] = [0; 4];
@ -186,7 +186,7 @@ fn check_own_crc(
sysconfig: &pac::Sysconfig, sysconfig: &pac::Sysconfig,
cp: &cortex_m::Peripherals, cp: &cortex_m::Peripherals,
nvm: &mut NvmWrapper, nvm: &mut NvmWrapper,
timer: &mut CountdownTimer<pac::Tim0>, timer: &mut CountdownTimer,
) { ) {
let crc_exp = unsafe { (BOOTLOADER_CRC_ADDR as *const u16).read_unaligned().to_be() }; let crc_exp = unsafe { (BOOTLOADER_CRC_ADDR as *const u16).read_unaligned().to_be() };
// I'd prefer to use [core::slice::from_raw_parts], but that is problematic // I'd prefer to use [core::slice::from_raw_parts], but that is problematic
@ -276,7 +276,7 @@ fn boot_app(
syscfg: &pac::Sysconfig, syscfg: &pac::Sysconfig,
cp: &cortex_m::Peripherals, cp: &cortex_m::Peripherals,
app_sel: AppSel, app_sel: AppSel,
timer: &mut CountdownTimer<pac::Tim0>, timer: &mut CountdownTimer,
) -> ! { ) -> ! {
if DEBUG_PRINTOUTS && RTT_PRINTOUT { if DEBUG_PRINTOUTS && RTT_PRINTOUT {
rprintln!("booting app {:?}", app_sel); rprintln!("booting app {:?}", app_sel);

View File

@ -29,7 +29,7 @@ embassy-executor = { version = "0.7", features = [
"executor-interrupt" "executor-interrupt"
]} ]}
va108xx-hal = { version = "0.11", features = ["defmt"] } va108xx-hal = { version = "0.11", path = "../../va108xx-hal", features = ["defmt"] }
va108xx-embassy = { version = "0.2" } va108xx-embassy = { version = "0.2" }
[features] [features]

View File

@ -12,11 +12,10 @@ use embassy_sync::channel::{Receiver, Sender};
use embassy_sync::{blocking_mutex::raw::ThreadModeRawMutex, channel::Channel}; use embassy_sync::{blocking_mutex::raw::ThreadModeRawMutex, channel::Channel};
use embassy_time::{Duration, Instant, Timer}; use embassy_time::{Duration, Instant, Timer};
use embedded_hal_async::digital::Wait; use embedded_hal_async::digital::Wait;
use va108xx_hal::gpio::{ use va108xx_hal::gpio::asynch::{on_interrupt_for_async_gpio_for_port, InputPinAsync};
on_interrupt_for_async_gpio_for_port, InputDynPinAsync, InputPinAsync, PinsB, Port, use va108xx_hal::gpio::{Input, Output, PinState, Port};
}; use va108xx_hal::pins::{PinsA, PinsB};
use va108xx_hal::{ use va108xx_hal::{
gpio::{DynPin, PinsA},
pac::{self, interrupt}, pac::{self, interrupt},
prelude::*, prelude::*,
}; };
@ -71,30 +70,28 @@ async fn main(spawner: Spawner) {
dp.tim22, dp.tim22,
); );
let porta = PinsA::new(&mut dp.sysconfig, dp.porta); let porta = PinsA::new(dp.porta);
let portb = PinsB::new(&mut dp.sysconfig, dp.portb); let portb = PinsB::new(dp.portb);
let mut led0 = porta.pa10.into_readable_push_pull_output(); let mut led0 = Output::new(porta.pa10, PinState::Low);
let out_pa0 = porta.pa0.into_readable_push_pull_output(); let out_pa0 = Output::new(porta.pa0, PinState::Low);
let in_pa1 = porta.pa1.into_floating_input(); let in_pa1 = Input::new_floating(porta.pa1);
let out_pb22 = portb.pb22.into_readable_push_pull_output(); let out_pb22 = Output::new(portb.pb22, PinState::Low);
let in_pb23 = portb.pb23.into_floating_input(); let in_pb23 = Input::new_floating(portb.pb23);
let in_pa1_async = InputPinAsync::new(in_pa1, pac::Interrupt::OC10); let in_pa1_async = InputPinAsync::new(in_pa1, pac::Interrupt::OC10);
let out_pa0_dyn = out_pa0.downgrade(); let in_pb23_async = InputPinAsync::new(in_pb23, PB22_TO_PB23_IRQ);
let in_pb23_async = InputDynPinAsync::new(in_pb23.downgrade(), PB22_TO_PB23_IRQ).unwrap();
let out_pb22_dyn = out_pb22.downgrade();
spawner spawner
.spawn(output_task( .spawn(output_task(
"PA0 to PA1", "PA0 to PA1",
out_pa0_dyn, out_pa0,
CHANNEL_PA0_PA1.receiver(), CHANNEL_PA0_PA1.receiver(),
)) ))
.unwrap(); .unwrap();
spawner spawner
.spawn(output_task( .spawn(output_task(
"PB22 to PB23", "PB22 to PB23",
out_pb22_dyn, out_pb22,
CHANNEL_PB22_TO_PB23.receiver(), CHANNEL_PB22_TO_PB23.receiver(),
)) ))
.unwrap(); .unwrap();
@ -207,7 +204,7 @@ async fn check_pin_to_pin_async_ops(
#[embassy_executor::task(pool_size = 2)] #[embassy_executor::task(pool_size = 2)]
async fn output_task( async fn output_task(
ctx: &'static str, ctx: &'static str,
mut out: DynPin, mut out: Output,
receiver: Receiver<'static, ThreadModeRawMutex, GpioCmd, 3>, receiver: Receiver<'static, ThreadModeRawMutex, GpioCmd, 3>,
) { ) {
loop { loop {
@ -216,25 +213,25 @@ async fn output_task(
match next_cmd.cmd_type { match next_cmd.cmd_type {
GpioCmdType::SetHigh => { GpioCmdType::SetHigh => {
defmt::info!("{}: Set output high", ctx); defmt::info!("{}: Set output high", ctx);
out.set_high().unwrap(); out.set_high();
} }
GpioCmdType::SetLow => { GpioCmdType::SetLow => {
defmt::info!("{}: Set output low", ctx); defmt::info!("{}: Set output low", ctx);
out.set_low().unwrap(); out.set_low();
} }
GpioCmdType::RisingEdge => { GpioCmdType::RisingEdge => {
defmt::info!("{}: Rising edge", ctx); defmt::info!("{}: Rising edge", ctx);
if !out.is_low().unwrap() { if !out.is_set_high() {
out.set_low().unwrap(); out.set_low();
} }
out.set_high().unwrap(); out.set_high();
} }
GpioCmdType::FallingEdge => { GpioCmdType::FallingEdge => {
defmt::info!("{}: Falling edge", ctx); defmt::info!("{}: Falling edge", ctx);
if !out.is_high().unwrap() { if !out.is_set_high() {
out.set_high().unwrap(); out.set_high();
} }
out.set_low().unwrap(); out.set_low();
} }
} }
} }

View File

@ -24,13 +24,14 @@ use embedded_io::Write;
use embedded_io_async::Read; use embedded_io_async::Read;
use heapless::spsc::{Consumer, Producer, Queue}; use heapless::spsc::{Consumer, Producer, Queue};
use va108xx_hal::{ use va108xx_hal::{
gpio::PinsA, gpio::{Output, PinState},
pac::{self, interrupt}, pac::{self, interrupt},
pins::PinsA,
prelude::*, prelude::*,
uart::{ uart::{
self, on_interrupt_rx_overwriting, self, on_interrupt_rx_overwriting,
rx_asynch::{on_interrupt_rx, RxAsync}, rx_asynch::{on_interrupt_rx, RxAsync},
Bank, RxAsyncOverwriting, Tx, RxAsyncOverwriting, Tx, UartId,
}, },
InterruptConfig, InterruptConfig,
}; };
@ -62,34 +63,34 @@ async fn main(spawner: Spawner) {
dp.tim22, dp.tim22,
); );
let porta = PinsA::new(&mut dp.sysconfig, dp.porta); let porta = PinsA::new(dp.porta);
let mut led0 = porta.pa10.into_readable_push_pull_output(); let mut led0 = Output::new(porta.pa10, PinState::Low);
let mut led1 = porta.pa7.into_readable_push_pull_output(); let mut led1 = Output::new(porta.pa7, PinState::Low);
let mut led2 = porta.pa6.into_readable_push_pull_output(); let mut led2 = Output::new(porta.pa6, PinState::Low);
let tx_uart_a = porta.pa9.into_funsel_2(); let tx_uart_a = porta.pa9;
let rx_uart_a = porta.pa8.into_funsel_2(); let rx_uart_a = porta.pa8;
let uarta = uart::Uart::new_with_interrupt( let uarta = uart::Uart::new_with_interrupt(
&mut dp.sysconfig,
50.MHz(), 50.MHz(),
dp.uarta, dp.uarta,
(tx_uart_a, rx_uart_a), (tx_uart_a, rx_uart_a),
115200.Hz(), 115200.Hz().into(),
InterruptConfig::new(pac::Interrupt::OC2, true, true), InterruptConfig::new(pac::Interrupt::OC2, true, true),
); )
.unwrap();
let tx_uart_b = porta.pa3.into_funsel_2(); let tx_uart_b = porta.pa3;
let rx_uart_b = porta.pa2.into_funsel_2(); let rx_uart_b = porta.pa2;
let uartb = uart::Uart::new_with_interrupt( let uartb = uart::Uart::new_with_interrupt(
&mut dp.sysconfig,
50.MHz(), 50.MHz(),
dp.uartb, dp.uartb,
(tx_uart_b, rx_uart_b), (tx_uart_b, rx_uart_b),
115200.Hz(), 115200.Hz().into(),
InterruptConfig::new(pac::Interrupt::OC3, true, true), InterruptConfig::new(pac::Interrupt::OC3, true, true),
); )
.unwrap();
let (mut tx_uart_a, rx_uart_a) = uarta.split(); let (mut tx_uart_a, rx_uart_a) = uarta.split();
let (tx_uart_b, rx_uart_b) = uartb.split(); let (tx_uart_b, rx_uart_b) = uartb.split();
let (prod_uart_a, cons_uart_a) = QUEUE_UART_A.take().split(); let (prod_uart_a, cons_uart_a) = QUEUE_UART_A.take().split();
@ -123,7 +124,7 @@ async fn main(spawner: Spawner) {
} }
#[embassy_executor::task] #[embassy_executor::task]
async fn uart_b_task(mut async_rx: RxAsyncOverwriting<pac::Uartb, 256>, mut tx: Tx<pac::Uartb>) { async fn uart_b_task(mut async_rx: RxAsyncOverwriting<256>, mut tx: Tx) {
let mut buf = [0u8; 256]; let mut buf = [0u8; 256];
loop { loop {
defmt::info!("Current time UART B: {}", Instant::now().as_secs()); defmt::info!("Current time UART B: {}", Instant::now().as_secs());
@ -144,7 +145,7 @@ async fn uart_b_task(mut async_rx: RxAsyncOverwriting<pac::Uartb, 256>, mut tx:
fn OC2() { fn OC2() {
let mut prod = let mut prod =
critical_section::with(|cs| PRODUCER_UART_A.borrow(cs).borrow_mut().take().unwrap()); critical_section::with(|cs| PRODUCER_UART_A.borrow(cs).borrow_mut().take().unwrap());
let errors = on_interrupt_rx(Bank::A, &mut prod); let errors = on_interrupt_rx(UartId::A, &mut prod);
critical_section::with(|cs| *PRODUCER_UART_A.borrow(cs).borrow_mut() = Some(prod)); critical_section::with(|cs| *PRODUCER_UART_A.borrow(cs).borrow_mut() = Some(prod));
// In a production app, we could use a channel to send the errors to the main task. // In a production app, we could use a channel to send the errors to the main task.
if let Err(errors) = errors { if let Err(errors) = errors {
@ -157,7 +158,7 @@ fn OC2() {
fn OC3() { fn OC3() {
let mut prod = let mut prod =
critical_section::with(|cs| PRODUCER_UART_B.borrow(cs).borrow_mut().take().unwrap()); critical_section::with(|cs| PRODUCER_UART_B.borrow(cs).borrow_mut().take().unwrap());
let errors = on_interrupt_rx_overwriting(Bank::B, &mut prod, &CONSUMER_UART_B); let errors = on_interrupt_rx_overwriting(UartId::B, &mut prod, &CONSUMER_UART_B);
critical_section::with(|cs| *PRODUCER_UART_B.borrow(cs).borrow_mut() = Some(prod)); critical_section::with(|cs| *PRODUCER_UART_B.borrow(cs).borrow_mut() = Some(prod));
// In a production app, we could use a channel to send the errors to the main task. // In a production app, we could use a channel to send the errors to the main task.
if let Err(errors) = errors { if let Err(errors) = errors {

View File

@ -17,10 +17,11 @@ use embassy_executor::Spawner;
use embassy_time::{Duration, Instant, Ticker}; use embassy_time::{Duration, Instant, Ticker};
use embedded_io_async::Write; use embedded_io_async::Write;
use va108xx_hal::{ use va108xx_hal::{
gpio::PinsA, gpio::{Output, PinState},
pac::{self, interrupt}, pac::{self, interrupt},
pins::PinsA,
prelude::*, prelude::*,
uart::{self, on_interrupt_tx, Bank, TxAsync}, uart::{self, on_interrupt_tx, TxAsync, UartId},
InterruptConfig, InterruptConfig,
}; };
@ -49,22 +50,23 @@ async fn main(_spawner: Spawner) {
dp.tim22, dp.tim22,
); );
let porta = PinsA::new(&mut dp.sysconfig, dp.porta); let porta = PinsA::new(dp.porta);
let mut led0 = porta.pa10.into_readable_push_pull_output();
let mut led1 = porta.pa7.into_readable_push_pull_output();
let mut led2 = porta.pa6.into_readable_push_pull_output();
let tx = porta.pa9.into_funsel_2(); let mut led0 = Output::new(porta.pa10, PinState::Low);
let rx = porta.pa8.into_funsel_2(); let mut led1 = Output::new(porta.pa7, PinState::Low);
let mut led2 = Output::new(porta.pa6, PinState::Low);
let tx = porta.pa9;
let rx = porta.pa8;
let uarta = uart::Uart::new_with_interrupt( let uarta = uart::Uart::new_with_interrupt(
&mut dp.sysconfig,
50.MHz(), 50.MHz(),
dp.uarta, dp.uarta,
(tx, rx), (tx, rx),
115200.Hz(), 115200.Hz().into(),
InterruptConfig::new(pac::Interrupt::OC2, true, true), InterruptConfig::new(pac::Interrupt::OC2, true, true),
); )
.unwrap();
let (tx, _rx) = uarta.split(); let (tx, _rx) = uarta.split();
let mut async_tx = TxAsync::new(tx); let mut async_tx = TxAsync::new(tx);
let mut ticker = Ticker::every(Duration::from_secs(1)); let mut ticker = Ticker::every(Duration::from_secs(1));
@ -89,5 +91,5 @@ async fn main(_spawner: Spawner) {
#[interrupt] #[interrupt]
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn OC2() { fn OC2() {
on_interrupt_tx(Bank::A); on_interrupt_tx(UartId::A);
} }

View File

@ -12,7 +12,12 @@ cfg_if::cfg_if! {
} }
} }
use va108xx_hal::{gpio::PinsA, pac, prelude::*}; use va108xx_hal::{
gpio::{Output, PinState},
pac,
pins::PinsA,
prelude::*,
};
const SYSCLK_FREQ: Hertz = Hertz::from_raw(50_000_000); const SYSCLK_FREQ: Hertz = Hertz::from_raw(50_000_000);
@ -35,8 +40,6 @@ async fn main(_spawner: Spawner) {
); );
} else { } else {
va108xx_embassy::init_with_custom_irqs( va108xx_embassy::init_with_custom_irqs(
&mut dp.sysconfig,
&dp.irqsel,
SYSCLK_FREQ, SYSCLK_FREQ,
dp.tim23, dp.tim23,
dp.tim22, dp.tim22,
@ -46,10 +49,10 @@ async fn main(_spawner: Spawner) {
} }
} }
let porta = PinsA::new(&mut dp.sysconfig, dp.porta); let porta = PinsA::new(dp.porta);
let mut led0 = porta.pa10.into_readable_push_pull_output(); let mut led0 = Output::new(porta.pa10, PinState::Low);
let mut led1 = porta.pa7.into_readable_push_pull_output(); let mut led1 = Output::new(porta.pa7, PinState::Low);
let mut led2 = porta.pa6.into_readable_push_pull_output(); let mut led2 = Output::new(porta.pa6, PinState::Low);
let mut ticker = Ticker::every(Duration::from_secs(1)); let mut ticker = Ticker::every(Duration::from_secs(1));
loop { loop {
ticker.next().await; ticker.next().await;

View File

@ -22,5 +22,5 @@ rtic-sync = { version = "1.3", features = ["defmt-03"] }
once_cell = {version = "1", default-features = false, features = ["critical-section"]} once_cell = {version = "1", default-features = false, features = ["critical-section"]}
ringbuf = { version = "0.4.7", default-features = false, features = ["portable-atomic"] } ringbuf = { version = "0.4.7", default-features = false, features = ["portable-atomic"] }
va108xx-hal = { version = "0.11" } va108xx-hal = { version = "0.11", path = "../../va108xx-hal" }
vorago-reb1 = { version = "0.8" } vorago-reb1 = { version = "0.8", path = "../../vorago-reb1" }

View File

@ -9,10 +9,10 @@ mod app {
use rtt_target::{rprintln, rtt_init_default, set_print_channel}; use rtt_target::{rprintln, rtt_init_default, set_print_channel};
use va108xx_hal::{ use va108xx_hal::{
clock::{set_clk_div_register, FilterClkSel}, clock::{set_clk_div_register, FilterClkSel},
gpio::{FilterType, InterruptEdge, PinsA}, gpio::{FilterType, InterruptEdge},
pac, pac,
prelude::*, pins::PinsA,
timer::{default_ms_irq_handler, set_up_ms_tick, InterruptConfig}, timer::InterruptConfig,
}; };
use vorago_reb1::button::Button; use vorago_reb1::button::Button;
use vorago_reb1::leds::Leds; use vorago_reb1::leds::Leds;
@ -61,39 +61,28 @@ mod app {
rprintln!("Using {:?} mode", mode); rprintln!("Using {:?} mode", mode);
let mut dp = cx.device; let mut dp = cx.device;
let pinsa = PinsA::new(&mut dp.sysconfig, dp.porta); let pinsa = PinsA::new(dp.porta);
let edge_irq = match mode { let edge_irq = match mode {
PressMode::Toggle => InterruptEdge::HighToLow, PressMode::Toggle => InterruptEdge::HighToLow,
PressMode::Keep => InterruptEdge::BothEdges, PressMode::Keep => InterruptEdge::BothEdges,
}; };
// Configure an edge interrupt on the button and route it to interrupt vector 15 // Configure an edge interrupt on the button and route it to interrupt vector 15
let mut button = Button::new(pinsa.pa11.into_floating_input()); let mut button = Button::new(pinsa.pa11);
if mode == PressMode::Toggle { if mode == PressMode::Toggle {
// This filter debounces the switch for edge based interrupts // This filter debounces the switch for edge based interrupts
button.configure_filter_type(FilterType::FilterFourClockCycles, FilterClkSel::Clk1); button.configure_filter_type(FilterType::FilterFourCycles, FilterClkSel::Clk1);
set_clk_div_register(&mut dp.sysconfig, FilterClkSel::Clk1, 50_000); set_clk_div_register(&mut dp.sysconfig, FilterClkSel::Clk1, 50_000);
} }
button.configure_and_enable_edge_interrupt( button.configure_and_enable_edge_interrupt(
edge_irq, edge_irq,
InterruptConfig::new(pac::interrupt::OC15, true, true), InterruptConfig::new(pac::interrupt::OC15, true, true),
); );
let mut leds = Leds::new( let mut leds = Leds::new(pinsa.pa10, pinsa.pa7, pinsa.pa6);
pinsa.pa10.into_push_pull_output(),
pinsa.pa7.into_push_pull_output(),
pinsa.pa6.into_push_pull_output(),
);
for led in leds.iter_mut() { for led in leds.iter_mut() {
led.off(); led.off();
} }
set_up_ms_tick(
InterruptConfig::new(pac::Interrupt::OC0, true, true),
&mut dp.sysconfig,
Some(&mut dp.irqsel),
50.MHz(),
dp.tim0,
);
(Shared {}, Local { leds, button, mode }) (Shared {}, Local { leds, button, mode })
} }
@ -119,11 +108,6 @@ mod app {
} }
} }
#[task(binds = OC0)]
fn ms_tick(_cx: ms_tick::Context) {
default_ms_irq_handler();
}
fn prompt_mode(mut down_channel: rtt_target::DownChannel) -> PressMode { fn prompt_mode(mut down_channel: rtt_target::DownChannel) -> PressMode {
rprintln!("Using prompt mode"); rprintln!("Using prompt mode");
rprintln!("Please enter the mode [0: Toggle, 1: Keep]"); rprintln!("Please enter the mode [0: Toggle, 1: Keep]");

View File

@ -20,17 +20,13 @@ mod app {
use rtic_monotonics::Monotonic; use rtic_monotonics::Monotonic;
use rtt_target::{rprintln, rtt_init_print}; use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{ use va108xx_hal::{
gpio::PinsA, pac, pins::PinsA, prelude::*, uart::{self, RxWithInterrupt, Tx}, InterruptConfig
pac,
prelude::*,
uart::{self, RxWithInterrupt, Tx},
InterruptConfig,
}; };
#[local] #[local]
struct Local { struct Local {
rx: RxWithInterrupt<pac::Uarta>, rx: RxWithInterrupt,
tx: Tx<pac::Uarta>, tx: Tx,
} }
#[shared] #[shared]
@ -47,19 +43,18 @@ mod app {
Mono::start(cx.core.SYST, SYSCLK_FREQ.raw()); Mono::start(cx.core.SYST, SYSCLK_FREQ.raw());
let mut dp = cx.device; let dp = cx.device;
let gpioa = PinsA::new(&mut dp.sysconfig, dp.porta); let gpioa = PinsA::new(dp.porta);
let tx = gpioa.pa9.into_funsel_2(); let tx = gpioa.pa9;
let rx = gpioa.pa8.into_funsel_2(); let rx = gpioa.pa8;
let irq_uart = uart::Uart::new_with_interrupt( let irq_uart = uart::Uart::new_with_interrupt(
&mut dp.sysconfig,
SYSCLK_FREQ, SYSCLK_FREQ,
dp.uarta, dp.uarta,
(tx, rx), (tx, rx),
115200.Hz(), 115200.Hz().into(),
InterruptConfig::new(pac::Interrupt::OC3, true, true), InterruptConfig::new(pac::Interrupt::OC3, true, true),
); ).unwrap();
let (tx, rx) = irq_uart.split(); let (tx, rx) = irq_uart.split();
let mut rx = rx.into_rx_with_irq(); let mut rx = rx.into_rx_with_irq();

View File

@ -11,15 +11,15 @@ mod app {
use rtic_monotonics::Monotonic; use rtic_monotonics::Monotonic;
use rtt_target::{rprintln, rtt_init_print}; use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{ use va108xx_hal::{
gpio::{OutputReadablePushPull, Pin, PinsA, PA10, PA6, PA7}, gpio::{Output, PinState},
pac, pac, pins::PinsA,
}; };
#[local] #[local]
struct Local { struct Local {
led0: Pin<PA10, OutputReadablePushPull>, led0: Output,
led1: Pin<PA7, OutputReadablePushPull>, led1: Output,
led2: Pin<PA6, OutputReadablePushPull>, led2: Output,
} }
#[shared] #[shared]
@ -28,16 +28,16 @@ mod app {
rtic_monotonics::systick_monotonic!(Mono, 1_000); rtic_monotonics::systick_monotonic!(Mono, 1_000);
#[init] #[init]
fn init(mut cx: init::Context) -> (Shared, Local) { fn init(cx: init::Context) -> (Shared, Local) {
rtt_init_print!(); rtt_init_print!();
rprintln!("-- Vorago VA108xx RTIC template --"); rprintln!("-- Vorago VA108xx RTIC template --");
Mono::start(cx.core.SYST, SYSCLK_FREQ.raw()); Mono::start(cx.core.SYST, SYSCLK_FREQ.raw());
let porta = PinsA::new(&mut cx.device.sysconfig, cx.device.porta); let porta = PinsA::new(cx.device.porta);
let led0 = porta.pa10.into_readable_push_pull_output(); let led0 = Output::new(porta.pa10, PinState::Low);
let led1 = porta.pa7.into_readable_push_pull_output(); let led1 = Output::new(porta.pa7, PinState::Low);
let led2 = porta.pa6.into_readable_push_pull_output(); let led2 = Output::new(porta.pa6, PinState::Low);
blinky::spawn().ok(); blinky::spawn().ok();
(Shared {}, Local { led0, led1, led2 }) (Shared {}, Local { led0, led1, led2 })
} }

View File

@ -17,7 +17,9 @@ cortex-m-semihosting = "0.5.0"
[dependencies.va108xx-hal] [dependencies.va108xx-hal]
version = "0.11" version = "0.11"
path = "../../va108xx-hal"
features = ["defmt"] features = ["defmt"]
[dependencies.vorago-reb1] [dependencies.vorago-reb1]
path = "../../vorago-reb1"
version = "0.8" version = "0.8"

View File

@ -10,52 +10,37 @@ use cortex_m_rt::entry;
use embedded_hal::delay::DelayNs; use embedded_hal::delay::DelayNs;
use panic_halt as _; use panic_halt as _;
use va108xx_hal::{ use va108xx_hal::{
gpio::PinsA, gpio::{Output, PinState},
pac::{self, interrupt}, pac::{self},
pins::PinsA,
prelude::*, prelude::*,
timer::DelayMs, timer::CountdownTimer,
timer::{default_ms_irq_handler, set_up_ms_tick, CountdownTimer},
InterruptConfig,
}; };
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
let mut dp = pac::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap();
let mut delay_ms = DelayMs::new(set_up_ms_tick( let mut delay = CountdownTimer::new(50.MHz(), dp.tim1);
InterruptConfig::new(interrupt::OC0, true, true), let porta = PinsA::new(dp.porta);
&mut dp.sysconfig, let mut led1 = Output::new(porta.pa10, PinState::Low);
Some(&mut dp.irqsel), let mut led2 = Output::new(porta.pa7, PinState::Low);
50.MHz(), let mut led3 = Output::new(porta.pa6, PinState::Low);
dp.tim0,
))
.unwrap();
let mut delay_tim1 = CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim1);
let porta = PinsA::new(&mut dp.sysconfig, dp.porta);
let mut led1 = porta.pa10.into_readable_push_pull_output();
let mut led2 = porta.pa7.into_readable_push_pull_output();
let mut led3 = porta.pa6.into_readable_push_pull_output();
for _ in 0..10 { for _ in 0..10 {
led1.set_low(); led1.set_low();
led2.set_low(); led2.set_low();
led3.set_low(); led3.set_low();
delay_ms.delay_ms(200); delay.delay_ms(200);
led1.set_high(); led1.set_high();
led2.set_high(); led2.set_high();
led3.set_high(); led3.set_high();
delay_tim1.delay_ms(200); delay.delay_ms(200);
} }
loop { loop {
led1.toggle(); led1.toggle();
delay_ms.delay_ms(200); delay.delay_ms(200);
led2.toggle(); led2.toggle();
delay_tim1.delay_ms(200); delay.delay_ms(200);
led3.toggle(); led3.toggle();
delay_ms.delay_ms(200); delay.delay_ms(200);
} }
} }
#[interrupt]
#[allow(non_snake_case)]
fn OC0() {
default_ms_irq_handler()
}

View File

@ -15,38 +15,27 @@ use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{ use va108xx_hal::{
pac::{self, interrupt}, pac::{self, interrupt},
prelude::*, prelude::*,
timer::{ timer::{CascadeCtrl, CascadeSource, CountdownTimer, InterruptConfig},
default_ms_irq_handler, set_up_ms_delay_provider, CascadeCtrl, CascadeSource,
CountdownTimer, Event, InterruptConfig,
},
}; };
static CSD_TGT_1: Mutex<RefCell<Option<CountdownTimer<pac::Tim4>>>> = static CSD_TGT_1: Mutex<RefCell<Option<CountdownTimer>>> = Mutex::new(RefCell::new(None));
Mutex::new(RefCell::new(None)); static CSD_TGT_2: Mutex<RefCell<Option<CountdownTimer>>> = Mutex::new(RefCell::new(None));
static CSD_TGT_2: Mutex<RefCell<Option<CountdownTimer<pac::Tim5>>>> =
Mutex::new(RefCell::new(None));
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
rtt_init_print!(); rtt_init_print!();
rprintln!("-- VA108xx Cascade example application--"); rprintln!("-- VA108xx Cascade example application--");
let mut dp = pac::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap();
let mut delay = set_up_ms_delay_provider(&mut dp.sysconfig, 50.MHz(), dp.tim0); let mut delay = CountdownTimer::new(50.MHz(), dp.tim0);
// Will be started periodically to trigger a cascade // Will be started periodically to trigger a cascade
let mut cascade_triggerer = let mut cascade_triggerer = CountdownTimer::new(50.MHz(), dp.tim3).auto_disable(true);
CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim3).auto_disable(true); cascade_triggerer.enable_interupt(InterruptConfig::new(pac::Interrupt::OC1, true, false));
cascade_triggerer.listen( cascade_triggerer.enable();
Event::TimeOut,
InterruptConfig::new(pac::Interrupt::OC1, true, false),
Some(&mut dp.irqsel),
Some(&mut dp.sysconfig),
);
// First target for cascade // First target for cascade
let mut cascade_target_1 = let mut cascade_target_1 = CountdownTimer::new(50.MHz(), dp.tim4).auto_deactivate(true);
CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim4).auto_deactivate(true);
cascade_target_1 cascade_target_1
.cascade_0_source(CascadeSource::Tim(3)) .cascade_0_source(CascadeSource::Tim(3))
.expect("Configuring cascade source for TIM4 failed"); .expect("Configuring cascade source for TIM4 failed");
@ -60,19 +49,13 @@ fn main() -> ! {
// Normally it should already be sufficient to activate IRQ in the CTRL // Normally it should already be sufficient to activate IRQ in the CTRL
// register but a full interrupt is use here to display print output when // register but a full interrupt is use here to display print output when
// the timer expires // the timer expires
cascade_target_1.listen( cascade_target_1.enable_interupt(InterruptConfig::new(pac::Interrupt::OC2, true, false));
Event::TimeOut,
InterruptConfig::new(pac::Interrupt::OC2, true, false),
Some(&mut dp.irqsel),
Some(&mut dp.sysconfig),
);
// The counter will only activate when the cascade signal is coming in so // The counter will only activate when the cascade signal is coming in so
// it is okay to call start here to set the reset value // it is okay to call start here to set the reset value
cascade_target_1.start(1.Hz()); cascade_target_1.start(1.Hz());
// Activated by first cascade target // Activated by first cascade target
let mut cascade_target_2 = let mut cascade_target_2 = CountdownTimer::new(50.MHz(), dp.tim5).auto_deactivate(true);
CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim5).auto_deactivate(true);
// Set TIM4 as cascade source // Set TIM4 as cascade source
cascade_target_2 cascade_target_2
.cascade_1_source(CascadeSource::Tim(4)) .cascade_1_source(CascadeSource::Tim(4))
@ -86,12 +69,7 @@ fn main() -> ! {
// Normally it should already be sufficient to activate IRQ in the CTRL // Normally it should already be sufficient to activate IRQ in the CTRL
// register but a full interrupt is use here to display print output when // register but a full interrupt is use here to display print output when
// the timer expires // the timer expires
cascade_target_2.listen( cascade_target_2.enable_interupt(InterruptConfig::new(pac::Interrupt::OC3, true, false));
Event::TimeOut,
InterruptConfig::new(pac::Interrupt::OC3, true, false),
Some(&mut dp.irqsel),
Some(&mut dp.sysconfig),
);
// The counter will only activate when the cascade signal is coming in so // The counter will only activate when the cascade signal is coming in so
// it is okay to call start here to set the reset value // it is okay to call start here to set the reset value
cascade_target_2.start(1.Hz()); cascade_target_2.start(1.Hz());
@ -115,11 +93,6 @@ fn main() -> ! {
} }
} }
#[interrupt]
fn OC0() {
default_ms_irq_handler()
}
#[interrupt] #[interrupt]
fn OC1() { fn OC1() {
static mut IDX: u32 = 0; static mut IDX: u32 = 0;

View File

@ -7,33 +7,27 @@ use embedded_hal::{delay::DelayNs, pwm::SetDutyCycle};
use panic_rtt_target as _; use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print}; use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{ use va108xx_hal::{
gpio::PinsA,
pac, pac,
pins::PinsA,
prelude::*, prelude::*,
pwm::{self, get_duty_from_percent, PwmA, PwmB, ReducedPwmPin}, pwm::{self, get_duty_from_percent, PwmA, PwmB, PwmPin},
timer::set_up_ms_delay_provider, timer::CountdownTimer,
}; };
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
rtt_init_print!(); rtt_init_print!();
rprintln!("-- VA108xx PWM example application--"); rprintln!("-- VA108xx PWM example application--");
let mut dp = pac::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap();
let pinsa = PinsA::new(&mut dp.sysconfig, dp.porta); let pinsa = PinsA::new(dp.porta);
let mut pwm = pwm::PwmPin::new( let mut pwm = pwm::PwmPin::new(50.MHz(), (pinsa.pa3, dp.tim3), 10.Hz()).unwrap();
&mut dp.sysconfig, let mut delay = CountdownTimer::new(50.MHz(), dp.tim0);
50.MHz(),
(pinsa.pa3.into_funsel_1(), dp.tim3),
10.Hz(),
);
let mut delay = set_up_ms_delay_provider(&mut dp.sysconfig, 50.MHz(), dp.tim0);
let mut current_duty_cycle = 0.0; let mut current_duty_cycle = 0.0;
pwm.set_duty_cycle(get_duty_from_percent(current_duty_cycle)) pwm.set_duty_cycle(get_duty_from_percent(current_duty_cycle))
.unwrap(); .unwrap();
pwm.enable(); pwm.enable();
// Delete type information, increased code readibility for the rest of the code // Delete type information, increased code readibility for the rest of the code
let mut reduced_pin = ReducedPwmPin::from(pwm);
loop { loop {
let mut counter = 0; let mut counter = 0;
// Increase duty cycle continuously // Increase duty cycle continuously
@ -45,8 +39,7 @@ fn main() -> ! {
rprintln!("current duty cycle: {}", current_duty_cycle); rprintln!("current duty cycle: {}", current_duty_cycle);
} }
reduced_pin pwm.set_duty_cycle(get_duty_from_percent(current_duty_cycle))
.set_duty_cycle(get_duty_from_percent(current_duty_cycle))
.unwrap(); .unwrap();
} }
@ -55,7 +48,7 @@ fn main() -> ! {
current_duty_cycle = 0.0; current_duty_cycle = 0.0;
let mut upper_limit = 1.0; let mut upper_limit = 1.0;
let mut lower_limit = 0.0; let mut lower_limit = 0.0;
let mut pwmb: ReducedPwmPin<PwmB> = ReducedPwmPin::from(reduced_pin); let mut pwmb: PwmPin<PwmB> = PwmPin::from(pwm);
pwmb.set_pwmb_lower_limit(get_duty_from_percent(lower_limit)); pwmb.set_pwmb_lower_limit(get_duty_from_percent(lower_limit));
pwmb.set_pwmb_upper_limit(get_duty_from_percent(upper_limit)); pwmb.set_pwmb_upper_limit(get_duty_from_percent(upper_limit));
while lower_limit < 0.5 { while lower_limit < 0.5 {
@ -67,6 +60,6 @@ fn main() -> ! {
rprintln!("Lower limit: {}", pwmb.pwmb_lower_limit()); rprintln!("Lower limit: {}", pwmb.pwmb_lower_limit());
rprintln!("Upper limit: {}", pwmb.pwmb_upper_limit()); rprintln!("Upper limit: {}", pwmb.pwmb_upper_limit());
} }
reduced_pin = ReducedPwmPin::<PwmA>::from(pwmb); pwm = PwmPin::<PwmA>::from(pwmb);
} }
} }

View File

@ -12,11 +12,11 @@ use embedded_hal::{
use panic_rtt_target as _; use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print}; use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{ use va108xx_hal::{
gpio::{PinsA, PinsB},
pac::{self, interrupt}, pac::{self, interrupt},
pins::{PinsA, PinsB},
prelude::*, prelude::*,
spi::{self, Spi, SpiBase, SpiClkConfig, TransferConfigWithHwcs}, spi::{self, configure_pin_as_hw_cs_pin, Spi, SpiClkConfig, TransferConfig},
timer::{default_ms_irq_handler, set_up_ms_tick}, timer::CountdownTimer,
InterruptConfig, InterruptConfig,
}; };
@ -46,20 +46,15 @@ fn main() -> ! {
rtt_init_print!(); rtt_init_print!();
rprintln!("-- VA108xx SPI example application--"); rprintln!("-- VA108xx SPI example application--");
let mut dp = pac::Peripherals::take().unwrap(); let mut dp = pac::Peripherals::take().unwrap();
let mut delay = set_up_ms_tick( let mut delay = CountdownTimer::new(50.MHz(), dp.tim0);
InterruptConfig::new(interrupt::OC0, true, true),
&mut dp.sysconfig,
Some(&mut dp.irqsel),
50.MHz(),
dp.tim0,
);
let spi_clk_cfg = SpiClkConfig::from_clk(50.MHz(), SPI_SPEED_KHZ.kHz()) let spi_clk_cfg = SpiClkConfig::from_clk(50.MHz(), SPI_SPEED_KHZ.kHz())
.expect("creating SPI clock config failed"); .expect("creating SPI clock config failed");
let spia_ref: RefCell<Option<SpiBase<pac::Spia, u8>>> = RefCell::new(None); //let spia_ref: RefCell<Option<SpiBase<pac::Spia, u8>>> = RefCell::new(None);
let spib_ref: RefCell<Option<SpiBase<pac::Spib, u8>>> = RefCell::new(None); //let spib_ref: RefCell<Option<SpiBase<pac::Spib, u8>>> = RefCell::new(None);
let pinsa = PinsA::new(&mut dp.sysconfig, dp.porta); let spi = None;
let pinsb = PinsB::new(&mut dp.sysconfig, dp.portb); let pinsa = PinsA::new(dp.porta);
let pinsb = PinsB::new(dp.portb);
let mut spi_cfg = spi::SpiConfig::default(); let mut spi_cfg = spi::SpiConfig::default();
if EXAMPLE_SEL == ExampleSelect::Loopback { if EXAMPLE_SEL == ExampleSelect::Loopback {
@ -67,158 +62,82 @@ fn main() -> ! {
} }
// Set up the SPI peripheral // Set up the SPI peripheral
match SPI_BUS_SEL { let spi = match SPI_BUS_SEL {
SpiBusSelect::SpiAPortA => { SpiBusSelect::SpiAPortA => {
let (sck, mosi, miso) = ( let (sck, mosi, miso) = (pinsa.pa31, pinsa.pa30, pinsa.pa29);
pinsa.pa31.into_funsel_1(), let mut spia = Spi::new(50.MHz(), dp.spia, (sck, miso, mosi), spi_cfg).unwrap();
pinsa.pa30.into_funsel_1(),
pinsa.pa29.into_funsel_1(),
);
let mut spia = Spi::new(
&mut dp.sysconfig,
50.MHz(),
dp.spia,
(sck, miso, mosi),
spi_cfg,
);
spia.set_fill_word(FILL_WORD); spia.set_fill_word(FILL_WORD);
spia_ref.borrow_mut().replace(spia.downgrade()); spia
} }
SpiBusSelect::SpiAPortB => { SpiBusSelect::SpiAPortB => {
let (sck, mosi, miso) = ( let (sck, mosi, miso) = (pinsb.pb9, pinsb.pb8, pinsb.pb7);
pinsb.pb9.into_funsel_2(), let mut spia = Spi::new(50.MHz(), dp.spia, (sck, miso, mosi), spi_cfg).unwrap();
pinsb.pb8.into_funsel_2(),
pinsb.pb7.into_funsel_2(),
);
let mut spia = Spi::new(
&mut dp.sysconfig,
50.MHz(),
dp.spia,
(sck, miso, mosi),
spi_cfg,
);
spia.set_fill_word(FILL_WORD); spia.set_fill_word(FILL_WORD);
spia_ref.borrow_mut().replace(spia.downgrade()); spia
} }
SpiBusSelect::SpiBPortB => { SpiBusSelect::SpiBPortB => {
let (sck, mosi, miso) = ( let (sck, mosi, miso) = (pinsb.pb5, pinsb.pb4, pinsb.pb3);
pinsb.pb5.into_funsel_1(), let mut spib = Spi::new(50.MHz(), dp.spib, (sck, miso, mosi), spi_cfg).unwrap();
pinsb.pb4.into_funsel_1(),
pinsb.pb3.into_funsel_1(),
);
let mut spib = Spi::new(
&mut dp.sysconfig,
50.MHz(),
dp.spib,
(sck, miso, mosi),
spi_cfg,
);
spib.set_fill_word(FILL_WORD); spib.set_fill_word(FILL_WORD);
spib_ref.borrow_mut().replace(spib.downgrade()); spib
} }
} };
// Configure transfer specific properties here // Configure transfer specific properties here
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() { let transfer_cfg = TransferConfig {
let transfer_cfg = TransferConfigWithHwcs::new_no_hw_cs( clk_cfg: Some(spi_clk_cfg),
Some(spi_clk_cfg), mode: Some(SPI_MODE),
Some(SPI_MODE), sod: true,
BLOCKMODE, blockmode: BLOCKMODE,
true, bmstall: true,
false, hw_cs: None,
); };
spi.cfg_transfer(&transfer_cfg); spi.cfg_transfer(&transfer_cfg);
}
} }
SpiBusSelect::SpiBPortB => { SpiBusSelect::SpiBPortB => {
if let Some(ref mut spi) = *spib_ref.borrow_mut() { let hw_cs_pin = configure_pin_as_hw_cs_pin(pinsb.pb2);
let hw_cs_pin = pinsb.pb2.into_funsel_1(); let transfer_cfg = TransferConfig {
let transfer_cfg = TransferConfigWithHwcs::new( clk_cfg: Some(spi_clk_cfg),
Some(spi_clk_cfg), mode: Some(SPI_MODE),
Some(SPI_MODE), sod: false,
Some(hw_cs_pin), blockmode: BLOCKMODE,
BLOCKMODE, bmstall: true,
true, hw_cs: Some(hw_cs_pin),
false, };
); spi.cfg_transfer(&transfer_cfg);
spi.cfg_transfer(&transfer_cfg);
}
} }
} }
// Application logic // Application logic
loop { loop {
let mut reply_buf: [u8; 8] = [0; 8]; let mut reply_buf: [u8; 8] = [0; 8];
match SPI_BUS_SEL { // Can't really verify correct reply here.
SpiBusSelect::SpiAPortA | SpiBusSelect::SpiAPortB => { spi.write(&[0x42]).expect("write failed");
if let Some(ref mut spi) = *spia_ref.borrow_mut() { // Because of the loopback mode, we should get back the fill word here.
// Can't really verify correct reply here. spi.read(&mut reply_buf[0..1]).unwrap();
spi.write(&[0x42]).expect("write failed"); assert_eq!(reply_buf[0], FILL_WORD);
// Because of the loopback mode, we should get back the fill word here. delay.delay_ms(500_u32);
spi.read(&mut reply_buf[0..1]).unwrap();
assert_eq!(reply_buf[0], FILL_WORD);
delay.delay_ms(500_u32);
let tx_buf: [u8; 3] = [0x01, 0x02, 0x03]; let tx_buf: [u8; 3] = [0x01, 0x02, 0x03];
spi.transfer(&mut reply_buf[0..3], &tx_buf).unwrap(); spi.transfer(&mut reply_buf[0..3], &tx_buf).unwrap();
assert_eq!(tx_buf, reply_buf[0..3]); assert_eq!(tx_buf, reply_buf[0..3]);
rprintln!( rprintln!(
"Received reply: {}, {}, {}", "Received reply: {}, {}, {}",
reply_buf[0], reply_buf[0],
reply_buf[1], reply_buf[1],
reply_buf[2] reply_buf[2]
); );
delay.delay_ms(500_u32); delay.delay_ms(500_u32);
let mut tx_rx_buf: [u8; 3] = [0x03, 0x02, 0x01]; let mut tx_rx_buf: [u8; 3] = [0x03, 0x02, 0x01];
spi.transfer_in_place(&mut tx_rx_buf).unwrap(); spi.transfer_in_place(&mut tx_rx_buf).unwrap();
rprintln!( rprintln!(
"Received reply: {}, {}, {}", "Received reply: {}, {}, {}",
tx_rx_buf[0], tx_rx_buf[0],
tx_rx_buf[1], tx_rx_buf[1],
tx_rx_buf[2] tx_rx_buf[2]
); );
assert_eq!(&tx_rx_buf[0..3], &[0x03, 0x02, 0x01]); assert_eq!(&tx_rx_buf[0..3], &[0x03, 0x02, 0x01]);
}
}
SpiBusSelect::SpiBPortB => {
if let Some(ref mut spi) = *spib_ref.borrow_mut() {
// Can't really verify correct reply here.
spi.write(&[0x42]).expect("write failed");
// Because of the loopback mode, we should get back the fill word here.
spi.read(&mut reply_buf[0..1]).unwrap();
assert_eq!(reply_buf[0], FILL_WORD);
delay.delay_ms(500_u32);
let tx_buf: [u8; 3] = [0x01, 0x02, 0x03];
spi.transfer(&mut reply_buf[0..3], &tx_buf).unwrap();
assert_eq!(tx_buf, reply_buf[0..3]);
rprintln!(
"Received reply: {}, {}, {}",
reply_buf[0],
reply_buf[1],
reply_buf[2]
);
delay.delay_ms(500_u32);
let mut tx_rx_buf: [u8; 3] = [0x03, 0x02, 0x01];
spi.transfer_in_place(&mut tx_rx_buf).unwrap();
rprintln!(
"Received reply: {}, {}, {}",
tx_rx_buf[0],
tx_rx_buf[1],
tx_rx_buf[2]
);
assert_eq!(&tx_rx_buf[0..3], &[0x03, 0x02, 0x01]);
}
}
}
} }
} }
#[interrupt]
#[allow(non_snake_case)]
fn OC0() {
default_ms_irq_handler()
}

View File

@ -12,9 +12,7 @@ use va108xx_hal::{
pac::{self, interrupt}, pac::{self, interrupt},
prelude::*, prelude::*,
time::Hertz, time::Hertz,
timer::{ timer::{default_ms_irq_handler, CountdownTimer, Event, InterruptConfig, MS_COUNTER},
default_ms_irq_handler, set_up_ms_tick, CountdownTimer, Event, InterruptConfig, MS_COUNTER,
},
}; };
#[allow(dead_code)] #[allow(dead_code)]
@ -66,21 +64,11 @@ fn main() -> ! {
} }
} }
LibType::Hal => { LibType::Hal => {
set_up_ms_tick( let mut ms_timer = CountdownTimer::new(get_sys_clock().unwrap(), dp.tim0);
InterruptConfig::new(interrupt::OC0, true, true), ms_timer.enable_interupt(InterruptConfig::new(interrupt::OC0, true, true));
&mut dp.sysconfig, ms_timer.start(1.kHz());
Some(&mut dp.irqsel), let mut second_timer = CountdownTimer::new(get_sys_clock().unwrap(), dp.tim1);
50.MHz(), second_timer.enable_interupt(InterruptConfig::new(interrupt::OC1, true, true));
dp.tim0,
);
let mut second_timer =
CountdownTimer::new(&mut dp.sysconfig, get_sys_clock().unwrap(), dp.tim1);
second_timer.listen(
Event::TimeOut,
InterruptConfig::new(interrupt::OC1, true, true),
Some(&mut dp.irqsel),
Some(&mut dp.sysconfig),
);
second_timer.start(1.Hz()); second_timer.start(1.Hz());
} }
} }

View File

@ -15,25 +15,20 @@ use embedded_hal_nb::{nb, serial::Read};
use embedded_io::Write as _; use embedded_io::Write as _;
use panic_rtt_target as _; use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print}; use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{gpio::PinsA, pac, prelude::*, uart}; use va108xx_hal::{pac, pins::PinsA, prelude::*, uart};
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
rtt_init_print!(); rtt_init_print!();
rprintln!("-- VA108xx UART example application--"); rprintln!("-- VA108xx UART example application--");
let mut dp = pac::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap();
let gpioa = PinsA::new(&mut dp.sysconfig, dp.porta); let gpioa = PinsA::new(dp.porta);
let tx = gpioa.pa9.into_funsel_2(); let tx = gpioa.pa9;
let rx = gpioa.pa8.into_funsel_2(); let rx = gpioa.pa8;
let uart = uart::Uart::new_without_interrupt( let uart = uart::Uart::new_without_interrupt(50.MHz(), dp.uarta, (tx, rx), 115200.Hz().into())
&mut dp.sysconfig, .unwrap();
50.MHz(),
dp.uarta,
(tx, rx),
115200.Hz(),
);
let (mut tx, mut rx) = uart.split(); let (mut tx, mut rx) = uart.split();
writeln!(tx, "Hello World\r").unwrap(); writeln!(tx, "Hello World\r").unwrap();

View File

@ -29,6 +29,7 @@ rtic-sync = {version = "1", features = ["defmt-03"]}
[dependencies.va108xx-hal] [dependencies.va108xx-hal]
version = "0.11" version = "0.11"
path = "../va108xx-hal"
features = ["defmt"] features = ["defmt"]
[dependencies.vorago-reb1] [dependencies.vorago-reb1]

View File

@ -68,7 +68,7 @@ mod app {
use spacepackets::ecss::{ use spacepackets::ecss::{
tc::PusTcReader, tm::PusTmCreator, EcssEnumU8, PusPacket, WritablePusPacket, tc::PusTcReader, tm::PusTmCreator, EcssEnumU8, PusPacket, WritablePusPacket,
}; };
use va108xx_hal::gpio::PinsA; use va108xx_hal::pins::PinsA;
use va108xx_hal::uart::IrqContextTimeoutOrMaxSize; use va108xx_hal::uart::IrqContextTimeoutOrMaxSize;
use va108xx_hal::{pac, uart, InterruptConfig}; use va108xx_hal::{pac, uart, InterruptConfig};
use vorago_reb1::m95m01::M95M01; use vorago_reb1::m95m01::M95M01;
@ -83,8 +83,8 @@ mod app {
#[local] #[local]
struct Local { struct Local {
uart_rx: uart::RxWithInterrupt<pac::Uarta>, uart_rx: uart::RxWithInterrupt,
uart_tx: uart::Tx<pac::Uarta>, uart_tx: uart::Tx,
rx_context: IrqContextTimeoutOrMaxSize, rx_context: IrqContextTimeoutOrMaxSize,
verif_reporter: VerificationReportCreator, verif_reporter: VerificationReportCreator,
nvm: M95M01, nvm: M95M01,
@ -108,18 +108,18 @@ mod app {
let mut dp = cx.device; let mut dp = cx.device;
let nvm = M95M01::new(&mut dp.sysconfig, SYSCLK_FREQ, dp.spic); let nvm = M95M01::new(&mut dp.sysconfig, SYSCLK_FREQ, dp.spic);
let gpioa = PinsA::new(&mut dp.sysconfig, dp.porta); let gpioa = PinsA::new(dp.porta);
let tx = gpioa.pa9.into_funsel_2(); let tx = gpioa.pa9;
let rx = gpioa.pa8.into_funsel_2(); let rx = gpioa.pa8;
let irq_uart = uart::Uart::new_with_interrupt( let irq_uart = uart::Uart::new_with_interrupt(
&mut dp.sysconfig,
SYSCLK_FREQ, SYSCLK_FREQ,
dp.uarta, dp.uarta,
(tx, rx), (tx, rx),
UART_BAUDRATE.Hz(), UART_BAUDRATE.Hz().into(),
InterruptConfig::new(pac::Interrupt::OC0, true, true), InterruptConfig::new(pac::Interrupt::OC0, true, true),
); )
.unwrap();
let (tx, rx) = irq_uart.split(); let (tx, rx) = irq_uart.split();
// Unwrap is okay, we explicitely set the interrupt ID. // Unwrap is okay, we explicitely set the interrupt ID.
let mut rx = rx.into_rx_with_irq(); let mut rx = rx.into_rx_with_irq();

View File

@ -20,7 +20,7 @@ embassy-time-queue-utils = "0.1"
once_cell = { version = "1", default-features = false, features = ["critical-section"] } once_cell = { version = "1", default-features = false, features = ["critical-section"] }
va108xx-hal = { version = ">=0.10, <=0.11" } va108xx-hal = { version = ">=0.10, <=0.11", path = "../va108xx-hal" }
[target.'cfg(all(target_arch = "arm", target_os = "none"))'.dependencies] [target.'cfg(all(target_arch = "arm", target_os = "none"))'.dependencies]
portable-atomic = { version = "1", features = ["unsafe-assume-single-core"] } portable-atomic = { version = "1", features = ["unsafe-assume-single-core"] }

View File

@ -45,7 +45,7 @@ use va108xx_hal::{
clock::enable_peripheral_clock, clock::enable_peripheral_clock,
enable_nvic_interrupt, pac, enable_nvic_interrupt, pac,
prelude::*, prelude::*,
timer::{enable_tim_clk, get_tim_raw, TimRegInterface, ValidTim}, timer::{enable_tim_clk, get_tim_raw, TimMarker, TimRegInterface},
PeripheralSelect, PeripheralSelect,
}; };
@ -109,48 +109,28 @@ pub fn time_driver() -> &'static TimerDriver {
/// This should be used if the interrupt handler is provided by the library, which is the /// This should be used if the interrupt handler is provided by the library, which is the
/// default case. /// default case.
#[cfg(feature = "irqs-in-lib")] #[cfg(feature = "irqs-in-lib")]
pub fn init<TimekeeperTim: TimRegInterface + ValidTim, AlarmTim: TimRegInterface + ValidTim>( pub fn init<TimekeeperTim: TimRegInterface + TimMarker, AlarmTim: TimRegInterface + TimMarker>(
syscfg: &mut pac::Sysconfig, sysclk: Hertz,
irqsel: &pac::Irqsel,
sysclk: impl Into<Hertz>,
timekeeper_tim: TimekeeperTim, timekeeper_tim: TimekeeperTim,
alarm_tim: AlarmTim, alarm_tim: AlarmTim,
) { ) {
TIME_DRIVER.init( TIME_DRIVER.init(sysclk, timekeeper_tim, alarm_tim, TIMEKEEPER_IRQ, ALARM_IRQ)
syscfg,
irqsel,
sysclk,
timekeeper_tim,
alarm_tim,
TIMEKEEPER_IRQ,
ALARM_IRQ,
)
} }
/// Initialization method for embassy when using custom IRQ handlers. /// Initialization method for embassy when using custom IRQ handlers.
/// ///
/// Requires an explicit [pac::Interrupt] argument for the timekeeper and alarm IRQs. /// Requires an explicit [pac::Interrupt] argument for the timekeeper and alarm IRQs.
pub fn init_with_custom_irqs< pub fn init_with_custom_irqs<
TimekeeperTim: TimRegInterface + ValidTim, TimekeeperTim: TimRegInterface + TimMarker,
AlarmTim: TimRegInterface + ValidTim, AlarmTim: TimRegInterface + TimMarker,
>( >(
syscfg: &mut pac::Sysconfig, sysclk: Hertz,
irqsel: &pac::Irqsel,
sysclk: impl Into<Hertz>,
timekeeper_tim: TimekeeperTim, timekeeper_tim: TimekeeperTim,
alarm_tim: AlarmTim, alarm_tim: AlarmTim,
timekeeper_irq: pac::Interrupt, timekeeper_irq: pac::Interrupt,
alarm_irq: pac::Interrupt, alarm_irq: pac::Interrupt,
) { ) {
TIME_DRIVER.init( TIME_DRIVER.init(sysclk, timekeeper_tim, alarm_tim, timekeeper_irq, alarm_irq)
syscfg,
irqsel,
sysclk,
timekeeper_tim,
alarm_tim,
timekeeper_irq,
alarm_irq,
)
} }
struct AlarmState { struct AlarmState {
@ -180,11 +160,9 @@ pub struct TimerDriver {
impl TimerDriver { impl TimerDriver {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn init<TimekeeperTim: TimRegInterface + ValidTim, AlarmTim: TimRegInterface + ValidTim>( fn init<TimekeeperTim: TimRegInterface + TimMarker, AlarmTim: TimRegInterface + TimMarker>(
&self, &self,
syscfg: &mut pac::Sysconfig, sysclk: Hertz,
irqsel: &pac::Irqsel,
sysclk: impl Into<Hertz>,
timekeeper_tim: TimekeeperTim, timekeeper_tim: TimekeeperTim,
alarm_tim: AlarmTim, alarm_tim: AlarmTim,
timekeeper_irq: pac::Interrupt, timekeeper_irq: pac::Interrupt,
@ -193,13 +171,12 @@ impl TimerDriver {
if ALARM_TIM.get().is_some() || TIMEKEEPER_TIM.get().is_some() { if ALARM_TIM.get().is_some() || TIMEKEEPER_TIM.get().is_some() {
return; return;
} }
ALARM_TIM.set(AlarmTim::TIM_ID).ok(); ALARM_TIM.set(AlarmTim::ID.raw_id()).ok();
TIMEKEEPER_TIM.set(TimekeeperTim::TIM_ID).ok(); TIMEKEEPER_TIM.set(TimekeeperTim::ID.raw_id()).ok();
enable_peripheral_clock(syscfg, PeripheralSelect::Irqsel); enable_peripheral_clock(PeripheralSelect::Irqsel);
enable_tim_clk(syscfg, timekeeper_tim.tim_id()); enable_tim_clk(timekeeper_tim.raw_id());
let timekeeper_reg_block = timekeeper_tim.reg_block(); let timekeeper_reg_block = timekeeper_tim.reg_block();
let alarm_tim_reg_block = alarm_tim.reg_block(); let alarm_tim_reg_block = alarm_tim.reg_block();
let sysclk = sysclk.into();
// Initiate scale value here. This is required to convert timer ticks back to a timestamp. // Initiate scale value here. This is required to convert timer ticks back to a timestamp.
SCALE.set((sysclk.raw() / TICK_HZ as u32) as u64).unwrap(); SCALE.set((sysclk.raw() / TICK_HZ as u32) as u64).unwrap();
timekeeper_reg_block timekeeper_reg_block
@ -209,9 +186,10 @@ impl TimerDriver {
timekeeper_reg_block timekeeper_reg_block
.cnt_value() .cnt_value()
.write(|w| unsafe { w.bits(u32::MAX) }); .write(|w| unsafe { w.bits(u32::MAX) });
let irqsel = unsafe { va108xx_hal::pac::Irqsel::steal() };
// Switch on. Timekeeping should always be done. // Switch on. Timekeeping should always be done.
irqsel irqsel
.tim0(timekeeper_tim.tim_id() as usize) .tim0(timekeeper_tim.raw_id() as usize)
.write(|w| unsafe { w.bits(timekeeper_irq as u32) }); .write(|w| unsafe { w.bits(timekeeper_irq as u32) });
unsafe { unsafe {
enable_nvic_interrupt(timekeeper_irq); enable_nvic_interrupt(timekeeper_irq);
@ -223,7 +201,7 @@ impl TimerDriver {
.enable() .enable()
.write(|w| unsafe { w.bits(1) }); .write(|w| unsafe { w.bits(1) });
enable_tim_clk(syscfg, alarm_tim.tim_id()); enable_tim_clk(alarm_tim.raw_id());
// Explicitely disable alarm timer until needed. // Explicitely disable alarm timer until needed.
alarm_tim_reg_block.ctrl().modify(|_, w| { alarm_tim_reg_block.ctrl().modify(|_, w| {
@ -235,7 +213,7 @@ impl TimerDriver {
enable_nvic_interrupt(alarm_irq); enable_nvic_interrupt(alarm_irq);
} }
irqsel irqsel
.tim0(alarm_tim.tim_id() as usize) .tim0(alarm_tim.raw_id() as usize)
.write(|w| unsafe { w.bits(alarm_irq as u32) }); .write(|w| unsafe { w.bits(alarm_irq as u32) });
} }

View File

@ -2,24 +2,13 @@
//! //!
//! This also includes functionality to enable the peripheral clocks //! This also includes functionality to enable the peripheral clocks
use crate::time::Hertz; use crate::time::Hertz;
use crate::PeripheralSelect;
use cortex_m::interrupt::{self, Mutex}; use cortex_m::interrupt::{self, Mutex};
use once_cell::unsync::OnceCell; use once_cell::unsync::OnceCell;
static SYS_CLOCK: Mutex<OnceCell<Hertz>> = Mutex::new(OnceCell::new()); pub use vorago_shared_periphs::gpio::FilterClkSel;
pub use vorago_shared_periphs::sysconfig::{disable_peripheral_clock, enable_peripheral_clock};
#[derive(Debug, PartialEq, Eq)] static SYS_CLOCK: Mutex<OnceCell<Hertz>> = Mutex::new(OnceCell::new());
#[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,
}
/// 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.
@ -61,5 +50,3 @@ pub fn set_clk_div_register(syscfg: &mut va108xx::Sysconfig, clk_sel: FilterClkS
} }
} }
} }
pub use vorago_shared_periphs::sysconfig::{disable_peripheral_clock, enable_peripheral_clock};

View File

@ -307,7 +307,7 @@ impl<I2C> I2cBase<I2C> {
impl<I2c: Instance> I2cBase<I2c> { impl<I2c: Instance> I2cBase<I2c> {
pub fn new( pub fn new(
sysclk: Hertz, sys_clk: Hertz,
i2c: I2c, i2c: I2c,
speed_mode: I2cSpeed, speed_mode: I2cSpeed,
ms_cfg: Option<&MasterConfig>, ms_cfg: Option<&MasterConfig>,
@ -315,10 +315,7 @@ impl<I2c: Instance> I2cBase<I2c> {
) -> Result<Self, ClockTooSlowForFastI2cError> { ) -> Result<Self, ClockTooSlowForFastI2cError> {
enable_peripheral_clock(I2c::PERIPH_SEL); enable_peripheral_clock(I2c::PERIPH_SEL);
let mut i2c_base = I2cBase { let mut i2c_base = I2cBase { i2c, sys_clk };
i2c,
sys_clk: sysclk.into(),
};
if let Some(ms_cfg) = ms_cfg { if let Some(ms_cfg) = ms_cfg {
i2c_base.cfg_master(ms_cfg); i2c_base.cfg_master(ms_cfg);
} }

View File

@ -1,6 +1,13 @@
pub use vorago_shared_periphs::gpio::{Pin, PinId, PinMarker, Port}; use vorago_shared_periphs::sysconfig::reset_peripheral_for_cycles;
use crate::{sysconfig::reset_peripheral_for_cycles, PeripheralSelect}; pub use crate::gpio::{Pin, PinId, PinIdProvider, Port};
use crate::sealed::Sealed;
use crate::PeripheralSelect;
pub trait PinMarker: Sealed {
const ID: PinId;
}
macro_rules! pin_id { macro_rules! pin_id {
($Id:ident, $Port:path, $num:literal) => { ($Id:ident, $Port:path, $num:literal) => {
@ -11,14 +18,18 @@ macro_rules! pin_id {
pub enum $Id {} pub enum $Id {}
impl $crate::sealed::Sealed for $Id {} impl $crate::sealed::Sealed for $Id {}
impl PinMarker for $Id { impl PinIdProvider for $Id {
const ID: PinId = PinId::new($Port, $num); const ID: PinId = PinId::new_unchecked($Port, $num);
}
impl PinMarker for Pin<$Id> {
const ID: PinId = $Id::ID;
} }
} }
}; };
} }
impl<I: PinMarker + crate::sealed::Sealed> crate::sealed::Sealed for Pin<I> {} impl<I: PinIdProvider + Sealed> Sealed for Pin<I> {}
pin_id!(Pa0, Port::A, 0); pin_id!(Pa0, Port::A, 0);
pin_id!(Pa1, Port::A, 1); pin_id!(Pa1, Port::A, 1);

View File

@ -8,10 +8,11 @@
use core::convert::Infallible; use core::convert::Infallible;
use core::marker::PhantomData; use core::marker::PhantomData;
use vorago_shared_periphs::PeripheralSelect;
use crate::clock::enable_peripheral_clock; use crate::clock::enable_peripheral_clock;
use crate::pac;
use crate::time::Hertz; use crate::time::Hertz;
use crate::timer::{TimId, TimPeripheralMarker, TimPin, TimRegInterface}; use crate::timer::{TimId, TimMarker, TimPin, TimRegInterface};
const DUTY_MAX: u16 = u16::MAX; const DUTY_MAX: u16 = u16::MAX;
@ -56,9 +57,8 @@ pub struct PwmPin<Mode = PwmA> {
impl<Mode> PwmPin<Mode> { impl<Mode> PwmPin<Mode> {
/// Create a new strongly typed PWM pin /// Create a new strongly typed PWM pin
pub fn new<Pin: TimPin, Tim: TimPeripheralMarker + TimRegInterface>( pub fn new<Pin: TimPin, Tim: TimMarker + TimRegInterface>(
sys_cfg: &mut pac::Sysconfig, sys_clk: Hertz,
sys_clk: impl Into<Hertz> + Copy,
pin_and_tim: (Pin, Tim), pin_and_tim: (Pin, Tim),
initial_period: impl Into<Hertz> + Copy, initial_period: impl Into<Hertz> + Copy,
) -> Result<Self, TimMissmatchError> { ) -> Result<Self, TimMissmatchError> {
@ -74,12 +74,13 @@ impl<Mode> PwmPin<Mode> {
current_lower_limit: 0, current_lower_limit: 0,
current_period: initial_period.into(), current_period: initial_period.into(),
current_rst_val: 0, current_rst_val: 0,
sys_clk: sys_clk.into(), sys_clk,
mode: PhantomData, mode: PhantomData,
}; };
enable_peripheral_clock(crate::clock::PeripheralClocks::Gpio); enable_peripheral_clock(PeripheralSelect::Gpio);
enable_peripheral_clock(crate::clock::PeripheralClocks::Ioconfig); enable_peripheral_clock(PeripheralSelect::Ioconfig);
sys_cfg let syscfg = unsafe { va108xx::Sysconfig::steal() };
syscfg
.tim_clk_enable() .tim_clk_enable()
.modify(|r, w| unsafe { w.bits(r.bits() | pin_and_tim.1.mask_32()) }); .modify(|r, w| unsafe { w.bits(r.bits() | pin_and_tim.1.mask_32()) });
pin.enable_pwm_a(); pin.enable_pwm_a();

View File

@ -9,13 +9,22 @@
//! - [Blocking SPI example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/spi.rs) //! - [Blocking SPI example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/spi.rs)
//! - [REB1 ADC example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/max11519-adc.rs) //! - [REB1 ADC example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/max11519-adc.rs)
//! - [REB1 EEPROM library](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/src/m95m01.rs) //! - [REB1 EEPROM library](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/src/m95m01.rs)
use crate::{clock::enable_peripheral_clock, pac, time::Hertz, PeripheralSelect}; use crate::{
clock::enable_peripheral_clock, pac, pins::PinMarker, sealed::Sealed, time::Hertz,
PeripheralSelect,
};
use core::{convert::Infallible, fmt::Debug, marker::PhantomData, ops::Deref}; use core::{convert::Infallible, fmt::Debug, marker::PhantomData, ops::Deref};
use embedded_hal::spi::{Mode, MODE_0}; use embedded_hal::spi::{Mode, MODE_0};
use pins::{HwCsProvider, PinMiso, PinMosi, PinSck}; use pins::{HwCsProvider, PinMiso, PinMosi, PinSck};
use vorago_shared_periphs::gpio::IoPeriphPin;
pub mod pins; pub mod pins;
pub fn configure_pin_as_hw_cs_pin<P: PinMarker + HwCsProvider>(_pin: P) -> HwChipSelectId {
IoPeriphPin::new(P::ID, P::FUN_SEL, None);
P::CS_ID
}
//================================================================================================== //==================================================================================================
// Defintions // Defintions
//================================================================================================== //==================================================================================================
@ -41,7 +50,7 @@ pub enum HwChipSelectId {
Id7 = 7, Id7 = 7,
} }
#[derive(Debug)] #[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum SpiId { pub enum SpiId {
A, A,
@ -80,7 +89,7 @@ pub type SpiRegBlock = pac::spia::RegisterBlock;
/// Common trait implemented by all PAC peripheral access structures. The register block /// Common trait implemented by all PAC peripheral access structures. The register block
/// format is the same for all SPI blocks. /// format is the same for all SPI blocks.
pub trait SpiPeripheralMarker: Deref<Target = SpiRegBlock> { pub trait SpiMarker: Deref<Target = SpiRegBlock> + Sealed {
const ID: SpiId; const ID: SpiId;
const PERIPH_SEL: PeripheralSelect; const PERIPH_SEL: PeripheralSelect;
@ -92,7 +101,7 @@ pub trait SpiPeripheralMarker: Deref<Target = SpiRegBlock> {
} }
} }
impl SpiPeripheralMarker for pac::Spia { impl SpiMarker for pac::Spia {
const ID: SpiId = SpiId::A; const ID: SpiId = SpiId::A;
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi0; const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi0;
@ -101,8 +110,9 @@ impl SpiPeripheralMarker for pac::Spia {
Self::ptr() Self::ptr()
} }
} }
impl Sealed for pac::Spia {}
impl SpiPeripheralMarker for pac::Spib { impl SpiMarker for pac::Spib {
const ID: SpiId = SpiId::B; const ID: SpiId = SpiId::B;
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi1; const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi1;
@ -111,8 +121,9 @@ impl SpiPeripheralMarker for pac::Spib {
Self::ptr() Self::ptr()
} }
} }
impl Sealed for pac::Spib {}
impl SpiPeripheralMarker for pac::Spic { impl SpiMarker for pac::Spic {
const ID: SpiId = SpiId::C; const ID: SpiId = SpiId::C;
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi2; const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi2;
@ -121,6 +132,7 @@ impl SpiPeripheralMarker for pac::Spic {
Self::ptr() Self::ptr()
} }
} }
impl Sealed for pac::Spic {}
//================================================================================================== //==================================================================================================
// Config // Config
@ -134,17 +146,6 @@ pub trait TransferConfigProvider {
fn hw_cs_id(&self) -> u8; fn hw_cs_id(&self) -> u8;
} }
/*
/// This struct contains all configuration parameter which are transfer specific
/// and might change for transfers to different SPI slaves
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct TransferConfigWithHwcs<HwCs> {
pub hw_cs: Option<HwCs>,
pub cfg: TransferConfig,
}
*/
/// Type erased variant of the transfer configuration. This is required to avoid generics in /// Type erased variant of the transfer configuration. This is required to avoid generics in
/// the SPI constructor. /// the SPI constructor.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
@ -163,80 +164,26 @@ pub struct TransferConfig {
pub hw_cs: Option<HwChipSelectId>, pub hw_cs: Option<HwChipSelectId>,
} }
/* impl TransferConfig {
impl TransferConfigWithHwcs<NoneT> { pub fn new_with_hw_cs(
pub fn new_no_hw_cs(
clk_cfg: Option<SpiClkConfig>, clk_cfg: Option<SpiClkConfig>,
mode: Option<Mode>, mode: Option<Mode>,
blockmode: bool, blockmode: bool,
bmstall: bool, bmstall: bool,
sod: bool, sod: bool,
hw_cs_id: HwChipSelectId,
) -> Self { ) -> Self {
TransferConfigWithHwcs { TransferConfig {
hw_cs: None, clk_cfg,
cfg: TransferConfig { mode,
clk_cfg, sod,
mode, blockmode,
sod, bmstall,
blockmode, hw_cs: Some(hw_cs_id),
bmstall,
hw_cs: HwChipSelectId::Invalid,
},
} }
} }
} }
impl<HwCs: HwCsProvider> TransferConfigWithHwcs<HwCs> {
pub fn new(
clk_cfg: Option<SpiClkConfig>,
mode: Option<Mode>,
hw_cs: Option<HwCs>,
blockmode: bool,
bmstall: bool,
sod: bool,
) -> Self {
TransferConfigWithHwcs {
hw_cs,
cfg: TransferConfig {
clk_cfg,
mode,
sod,
blockmode,
bmstall,
hw_cs: HwCs::CS_ID,
},
}
}
pub fn downgrade(self) -> TransferConfig {
self.cfg
}
}
impl<HwCs: HwCsProvider> TransferConfigProvider for TransferConfigWithHwcs<HwCs> {
/// Slave Output Disable
fn sod(&mut self, sod: bool) {
self.cfg.sod = sod;
}
fn blockmode(&mut self, blockmode: bool) {
self.cfg.blockmode = blockmode;
}
fn mode(&mut self, mode: Mode) {
self.cfg.mode = Some(mode);
}
fn clk_cfg(&mut self, clk_cfg: SpiClkConfig) {
self.cfg.clk_cfg = Some(clk_cfg);
}
fn hw_cs_id(&self) -> u8 {
HwCs::CS_ID as u8
}
}
*/
/// Configuration options for the whole SPI bus. See Programmer Guide p.92 for more details /// Configuration options for the whole SPI bus. See Programmer Guide p.92 for more details
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -373,25 +320,6 @@ pub trait SpiLowLevel {
fn read_fifo_unchecked(&mut self) -> u32; fn read_fifo_unchecked(&mut self) -> u32;
} }
pub struct Spi<Word = u8> {
id: SpiId,
reg_block: *mut SpiRegBlock,
cfg: SpiConfig,
sys_clk: Hertz,
/// Fill word for read-only SPI transactions.
pub fill_word: Word,
blockmode: bool,
bmstall: bool,
word: PhantomData<Word>,
}
/*
pub struct Spi<, Pins, Word = u8> {
inner: SpiBase<SpiInstance, Word>,
pins: Pins,
}
*/
#[inline(always)] #[inline(always)]
pub fn mode_to_cpo_cph_bit(mode: embedded_hal::spi::Mode) -> (bool, bool) { pub fn mode_to_cpo_cph_bit(mode: embedded_hal::spi::Mode) -> (bool, bool) {
match mode { match mode {
@ -510,28 +438,69 @@ pub fn clk_div_for_target_clock(
Some(rounded_div as u16) Some(rounded_div as u16)
} }
#[derive(Debug, thiserror::Error)]
#[error("peripheral or peripheral pin ID is not consistent")]
pub struct SpiIdMissmatchError;
/// SPI peripheral driver structure.
pub struct Spi<Word = u8> {
id: SpiId,
reg_block: *mut SpiRegBlock,
cfg: SpiConfig,
sys_clk: Hertz,
/// Fill word for read-only SPI transactions.
fill_word: Word,
blockmode: bool,
bmstall: bool,
word: PhantomData<Word>,
}
impl<Word: WordProvider> Spi<Word> impl<Word: WordProvider> Spi<Word>
where where
<Word as TryFrom<u32>>::Error: core::fmt::Debug, <Word as TryFrom<u32>>::Error: core::fmt::Debug,
{ {
/// Create a new SPI struct /// Create a new SPI struct.
///
/// You can delete the pin type information by calling the
/// [`downgrade`](Self::downgrade) function
/// ///
/// ## Arguments /// ## Arguments
/// * `syscfg` - Can be passed optionally to enable the peripheral clock
/// * `sys_clk` - System clock /// * `sys_clk` - System clock
/// * `spi` - SPI bus to use /// * `spi` - SPI bus to use
/// * `pins` - Pins to be used for SPI transactions. These pins are consumed /// * `pins` - Pins to be used for SPI transactions. These pins are consumed
/// to ensure the pins can not be used for other purposes anymore /// to ensure the pins can not be used for other purposes anymore
/// * `spi_cfg` - Configuration specific to the SPI bus /// * `spi_cfg` - Configuration specific to the SPI bus
pub fn new<SpiI: SpiPeripheralMarker, Sck: PinSck, Miso: PinMiso, Mosi: PinMosi>( pub fn new_for_rom<SpiI: SpiMarker>(
sys_clk: impl Into<Hertz>, sys_clk: Hertz,
spi: SpiI,
spi_cfg: SpiConfig,
) -> Result<Self, SpiIdMissmatchError> {
if SpiI::ID != SpiId::C {
return Err(SpiIdMissmatchError);
}
Ok(Self::new_generic(sys_clk, spi, spi_cfg))
}
/// Create a new SPI struct.
///
/// ## Arguments
/// * `sys_clk` - System clock
/// * `spi` - SPI bus to use
/// * `pins` - Pins to be used for SPI transactions. These pins are consumed
/// to ensure the pins can not be used for other purposes anymore
/// * `spi_cfg` - Configuration specific to the SPI bus
pub fn new<SpiI: SpiMarker, Sck: PinSck, Miso: PinMiso, Mosi: PinMosi>(
sys_clk: Hertz,
spi: SpiI, spi: SpiI,
_pins: (Sck, Miso, Mosi), _pins: (Sck, Miso, Mosi),
spi_cfg: SpiConfig, spi_cfg: SpiConfig,
) -> Self { ) -> Result<Self, SpiIdMissmatchError> {
if SpiI::ID != Sck::SPI_ID || SpiI::ID != Miso::SPI_ID || SpiI::ID != Mosi::SPI_ID {
return Err(SpiIdMissmatchError);
}
IoPeriphPin::new(Sck::ID, Sck::FUN_SEL, None);
IoPeriphPin::new(Miso::ID, Miso::FUN_SEL, None);
IoPeriphPin::new(Mosi::ID, Mosi::FUN_SEL, None);
Ok(Self::new_generic(sys_clk, spi, spi_cfg))
}
pub fn new_generic<SpiI: SpiMarker>(sys_clk: Hertz, spi: SpiI, spi_cfg: SpiConfig) -> Self {
enable_peripheral_clock(SpiI::PERIPH_SEL); enable_peripheral_clock(SpiI::PERIPH_SEL);
let (cpo_bit, cph_bit) = mode_to_cpo_cph_bit(spi_cfg.init_mode); let (cpo_bit, cph_bit) = mode_to_cpo_cph_bit(spi_cfg.init_mode);
spi.ctrl0().write(|w| { spi.ctrl0().write(|w| {
@ -568,7 +537,7 @@ where
id: SpiI::ID, id: SpiI::ID,
reg_block: spi.reg_block(), reg_block: spi.reg_block(),
cfg: spi_cfg, cfg: spi_cfg,
sys_clk: sys_clk.into(), sys_clk,
fill_word: Default::default(), fill_word: Default::default(),
bmstall: spi_cfg.bmstall, bmstall: spi_cfg.bmstall,
blockmode: spi_cfg.blockmode, blockmode: spi_cfg.blockmode,
@ -596,6 +565,10 @@ where
.write(|w| unsafe { w.bits(cfg.prescale_val as u32) }); .write(|w| unsafe { w.bits(cfg.prescale_val as u32) });
} }
pub fn set_fill_word(&mut self, fill_word: Word) {
self.fill_word = fill_word;
}
#[inline] #[inline]
pub fn cfg_clock_from_div(&mut self, div: u16) -> Result<(), SpiClkConfigError> { pub fn cfg_clock_from_div(&mut self, div: u16) -> Result<(), SpiClkConfigError> {
let val = spi_clk_config_from_div(div)?; let val = spi_clk_config_from_div(div)?;
@ -633,6 +606,10 @@ where
} }
/// Configure the hardware chip select given a hardware chip select ID. /// Configure the hardware chip select given a hardware chip select ID.
///
/// The pin also needs to be configured to be used as a HW CS pin. This can be done
/// by using the [configure_pin_as_hw_cs_pin] function which also returns the
/// corresponding [HwChipSelectId].
#[inline] #[inline]
pub fn cfg_hw_cs(&mut self, hw_cs: HwChipSelectId) { pub fn cfg_hw_cs(&mut self, hw_cs: HwChipSelectId) {
self.reg_block_mut().ctrl1().modify(|_, w| { self.reg_block_mut().ctrl1().modify(|_, w| {
@ -644,13 +621,6 @@ where
}); });
} }
/// Configure the hardware chip select given a physical hardware CS pin.
#[inline]
pub fn cfg_hw_cs_with_pin<HwCs: HwCsProvider>(&mut self, _: &HwCs) {
// TODO: Error handling.
self.cfg_hw_cs(HwCs::CS_ID);
}
/// Disables the hardware chip select functionality. This can be used when performing /// Disables the hardware chip select functionality. This can be used when performing
/// external chip select handling, for example with GPIO pins. /// external chip select handling, for example with GPIO pins.
#[inline] #[inline]

View File

@ -1,32 +1,33 @@
use vorago_shared_periphs::gpio::{PinId, PinIdProvider};
use vorago_shared_periphs::FunSel; use vorago_shared_periphs::FunSel;
use crate::{ use crate::{
pins::{ pins::{
Pa10, Pa11, Pa12, Pa13, Pa14, Pa15, Pa16, Pa17, Pa18, Pa19, Pa20, Pa21, Pa22, Pa23, Pa24, Pa10, Pa11, Pa12, Pa13, Pa14, Pa15, Pa16, Pa17, Pa18, Pa19, Pa20, Pa21, Pa22, Pa23, Pa24,
Pa25, Pa26, Pa27, Pa28, Pa29, Pa30, Pa31, Pb0, Pb1, Pb10, Pb11, Pb12, Pb13, Pb14, Pb15, Pa25, Pa26, Pa27, Pa28, Pa29, Pa30, Pa31, Pb0, Pb1, Pb10, Pb11, Pb12, Pb13, Pb14, Pb15,
Pb16, Pb17, Pb18, Pb19, Pb2, Pb22, Pb23, Pb3, Pb4, Pb5, Pb6, Pb7, Pb8, Pb9, Pin, Pb16, Pb17, Pb18, Pb19, Pb2, Pb22, Pb23, Pb3, Pb4, Pb5, Pb6, Pb7, Pb8, Pb9, Pin, PinMarker,
}, },
sealed::Sealed, sealed::Sealed,
}; };
use super::{HwChipSelectId, SpiId}; use super::{HwChipSelectId, SpiId};
pub trait PinSck: Sealed { pub trait PinSck: PinMarker {
const SPI_ID: SpiId; const SPI_ID: SpiId;
const FUN_SEL: FunSel; const FUN_SEL: FunSel;
} }
pub trait PinMosi: Sealed { pub trait PinMosi: PinMarker {
const SPI_ID: SpiId; const SPI_ID: SpiId;
const FUN_SEL: FunSel; const FUN_SEL: FunSel;
} }
pub trait PinMiso: Sealed { pub trait PinMiso: PinMarker {
const SPI_ID: SpiId; const SPI_ID: SpiId;
const FUN_SEL: FunSel; const FUN_SEL: FunSel;
} }
pub trait HwCsProvider: Sealed { pub trait HwCsProvider: PinMarker {
const SPI_ID: SpiId; const SPI_ID: SpiId;
const FUN_SEL: FunSel; const FUN_SEL: FunSel;
const CS_ID: HwChipSelectId; const CS_ID: HwChipSelectId;
@ -48,7 +49,7 @@ macro_rules! hw_cs_multi_pin {
// name of the newtype wrapper struct // name of the newtype wrapper struct
$name:ident, $name:ident,
// Pb0 // Pb0
$pin_id:path, $pin_id:ident,
// SpiId::B // SpiId::B
$spi_id:path, $spi_id:path,
// FunSel::Sel1 // FunSel::Sel1
@ -71,6 +72,10 @@ macro_rules! hw_cs_multi_pin {
impl Sealed for $name {} impl Sealed for $name {}
impl PinMarker for $name {
const ID: PinId = <$pin_id as PinIdProvider>::ID;
}
impl HwCsProvider for $name { impl HwCsProvider for $name {
const SPI_ID: SpiId = $spi_id; const SPI_ID: SpiId = $spi_id;
const FUN_SEL: FunSel = $fun_sel; const FUN_SEL: FunSel = $fun_sel;
@ -185,7 +190,7 @@ impl PinMosi for Pin<Pa19> {
const SPI_ID: SpiId = SpiId::B; const SPI_ID: SpiId = SpiId::B;
const FUN_SEL: FunSel = FunSel::Sel2; const FUN_SEL: FunSel = FunSel::Sel2;
} }
impl PinMosi for Pin<Pa18> { impl PinMiso for Pin<Pa18> {
const SPI_ID: SpiId = SpiId::B; const SPI_ID: SpiId = SpiId::B;
const FUN_SEL: FunSel = FunSel::Sel2; const FUN_SEL: FunSel = FunSel::Sel2;
} }
@ -202,7 +207,7 @@ impl PinMosi for Pin<Pb18> {
const SPI_ID: SpiId = SpiId::B; const SPI_ID: SpiId = SpiId::B;
const FUN_SEL: FunSel = FunSel::Sel1; const FUN_SEL: FunSel = FunSel::Sel1;
} }
impl PinMosi for Pin<Pb17> { impl PinMiso for Pin<Pb17> {
const SPI_ID: SpiId = SpiId::B; const SPI_ID: SpiId = SpiId::B;
const FUN_SEL: FunSel = FunSel::Sel1; const FUN_SEL: FunSel = FunSel::Sel1;
} }
@ -215,7 +220,7 @@ impl PinMosi for Pin<Pb4> {
const SPI_ID: SpiId = SpiId::B; const SPI_ID: SpiId = SpiId::B;
const FUN_SEL: FunSel = FunSel::Sel1; const FUN_SEL: FunSel = FunSel::Sel1;
} }
impl PinMosi for Pin<Pb3> { impl PinMiso for Pin<Pb3> {
const SPI_ID: SpiId = SpiId::B; const SPI_ID: SpiId = SpiId::B;
const FUN_SEL: FunSel = FunSel::Sel1; const FUN_SEL: FunSel = FunSel::Sel1;
} }
@ -330,6 +335,7 @@ hw_cs_multi_pin!(
// SPIC // SPIC
/*
// Dummy pin defintion for the ROM SCK. // Dummy pin defintion for the ROM SCK.
pub struct RomSck; pub struct RomSck;
// Dummy pin defintion for the ROM MOSI. // Dummy pin defintion for the ROM MOSI.
@ -358,6 +364,7 @@ impl PinMiso for RomMiso {
const FUN_SEL: FunSel = FunSel::Sel0; const FUN_SEL: FunSel = FunSel::Sel0;
} }
impl Sealed for RomCs {} impl Sealed for RomCs {}
*/
hw_cs_pins!( hw_cs_pins!(
SpiId::C, SpiId::C,
@ -408,9 +415,11 @@ hw_cs_multi_pin!(
HwChipSelectId::Id4 HwChipSelectId::Id4
); );
/*
impl HwCsProvider for RomCs { impl HwCsProvider for RomCs {
const CS_ID: HwChipSelectId = HwChipSelectId::Id0; const CS_ID: HwChipSelectId = HwChipSelectId::Id0;
const SPI_ID: SpiId = SpiId::C; const SPI_ID: SpiId = SpiId::C;
/// Function select does not make sense here, just select default value. /// Function select does not make sense here, just select default value.
const FUN_SEL: FunSel = FunSel::Sel0; const FUN_SEL: FunSel = FunSel::Sel0;
} }
*/

View File

@ -1,5 +1,3 @@
use crate::PeripheralSelect;
#[derive(PartialEq, Eq, Debug)] #[derive(PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct InvalidCounterResetVal(pub(crate) ()); pub struct InvalidCounterResetVal(pub(crate) ());
@ -40,26 +38,6 @@ pub fn disable_ram_scrubbing() {
syscfg.ram_scrub().write(|w| unsafe { w.bits(0) }); syscfg.ram_scrub().write(|w| unsafe { w.bits(0) });
} }
#[inline] pub use vorago_shared_periphs::sysconfig::{
pub fn assert_peripheral_reset(periph_sel: PeripheralSelect) { assert_peripheral_reset, disable_peripheral_clock, enable_peripheral_clock,
let syscfg = unsafe { va108xx::Sysconfig::steal() }; };
syscfg
.peripheral_reset()
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << periph_sel as u8)) });
}
#[inline]
pub fn deassert_peripheral_reset(periph_sel: PeripheralSelect) {
let syscfg = unsafe { va108xx::Sysconfig::steal() };
syscfg
.peripheral_reset()
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << periph_sel as u8)) });
}
pub fn reset_peripheral_for_cycles(periph_sel: PeripheralSelect, cycles: u32) {
assert_peripheral_reset(periph_sel);
cortex_m::asm::delay(cycles);
deassert_peripheral_reset(periph_sel);
}
pub use vorago_shared_periphs::sysconfig::{disable_peripheral_clock, enable_peripheral_clock};

View File

@ -16,17 +16,13 @@ use crate::{
sealed::Sealed, sealed::Sealed,
time::Hertz, time::Hertz,
}; };
use core::cell::Cell;
use critical_section::Mutex;
use fugit::RateExtU32; use fugit::RateExtU32;
use vorago_shared_periphs::{ use vorago_shared_periphs::{
gpio::{Pin, PinMarker}, gpio::{Pin, PinIdProvider},
ioconfig::regs::FunSel, ioconfig::regs::FunSel,
Port, Port,
}; };
pub static MS_COUNTER: Mutex<Cell<u32>> = Mutex::new(Cell::new(0));
/// Get the peripheral block of a TIM peripheral given the index. /// Get the peripheral block of a TIM peripheral given the index.
/// ///
/// This function panics if the given index is greater than 23. /// This function panics if the given index is greater than 23.
@ -170,17 +166,23 @@ pub trait TimPin: Sealed {
const TIM_ID: TimId; const TIM_ID: TimId;
} }
pub trait TimPeripheralMarker: Sealed { pub trait TimMarker: Sealed {
// TIM ID ranging from 0 to 23 for 24 TIM peripherals // TIM ID ranging from 0 to 23 for 24 TIM peripherals
const ID: TimId; const ID: TimId;
} }
macro_rules! tim_marker { macro_rules! tim_marker {
($TIMX:path, $ID:expr) => { ($TIMX:path, $ID:expr) => {
impl TimPeripheralMarker for $TIMX { impl TimMarker for $TIMX {
const ID: TimId = TimId($ID); const ID: TimId = TimId($ID);
} }
unsafe impl TimRegInterface for $TIMX {
fn raw_id(&self) -> u8 {
Self::ID.0
}
}
impl Sealed for $TIMX {} impl Sealed for $TIMX {}
}; };
} }
@ -210,13 +212,13 @@ tim_marker!(pac::Tim21, 21);
tim_marker!(pac::Tim22, 22); tim_marker!(pac::Tim22, 22);
tim_marker!(pac::Tim23, 23); tim_marker!(pac::Tim23, 23);
pub trait ValidTimAndPin<Pin: TimPin, Tim: TimPeripheralMarker>: Sealed {} pub trait ValidTimAndPin<Pin: TimPin, Tim: TimMarker>: Sealed {}
macro_rules! pin_and_tim { macro_rules! pin_and_tim {
($Px:ident, $FunSel:path, $ID:expr) => { ($Px:ident, $FunSel:path, $ID:expr) => {
impl TimPin for Pin<$Px> impl TimPin for Pin<$Px>
where where
$Px: PinMarker, $Px: PinIdProvider,
{ {
const PORT: Port = $Px::ID.port(); const PORT: Port = $Px::ID.port();
const OFFSET: usize = $Px::ID.offset(); const OFFSET: usize = $Px::ID.offset();
@ -368,7 +370,7 @@ unsafe impl TimRegInterface for CountdownTimer {
impl CountdownTimer { impl CountdownTimer {
/// Configures a TIM peripheral as a periodic count down timer /// Configures a TIM peripheral as a periodic count down timer
pub fn new<Tim: TimPeripheralMarker>(sys_clk: Hertz, _tim: Tim) -> Self { pub fn new<Tim: TimMarker>(sys_clk: Hertz, _tim: Tim) -> Self {
enable_tim_clk(Tim::ID.raw_id()); enable_tim_clk(Tim::ID.raw_id());
let cd_timer = CountdownTimer { let cd_timer = CountdownTimer {
tim: Tim::ID, tim: Tim::ID,
@ -593,6 +595,10 @@ impl CountdownTimer {
} }
} }
//==================================================================================================
// Delay implementations
//==================================================================================================
//
impl embedded_hal::delay::DelayNs for CountdownTimer { impl embedded_hal::delay::DelayNs for CountdownTimer {
fn delay_ns(&mut self, ns: u32) { fn delay_ns(&mut self, ns: u32) {
let ticks = (u64::from(ns)) * (u64::from(self.sys_clk.raw())) / 1_000_000_000; let ticks = (u64::from(ns)) * (u64::from(self.sys_clk.raw())) / 1_000_000_000;
@ -647,59 +653,6 @@ impl embedded_hal::delay::DelayNs for CountdownTimer {
} }
} }
pub fn set_up_ms_delay_provider(sys_clk: Hertz, tim: impl TimPeripheralMarker) -> CountdownTimer {
let mut provider = CountdownTimer::new(sys_clk, tim);
provider.start(1000.Hz());
provider
}
/// This function can be called in a specified interrupt handler to increment
/// the MS counter
pub fn default_ms_irq_handler() {
critical_section::with(|cs| {
let mut ms = MS_COUNTER.borrow(cs).get();
ms += 1;
MS_COUNTER.borrow(cs).set(ms);
});
}
/// Get the current MS tick count
pub fn get_ms_ticks() -> u32 {
critical_section::with(|cs| MS_COUNTER.borrow(cs).get())
}
//==================================================================================================
// Delay implementations
//==================================================================================================
/*
pub struct DelayMs(CountdownTimer<pac::Tim0>);
impl DelayMs {
pub fn new(timer: CountdownTimer<pac::Tim0>) -> Option<Self> {
if timer.curr_freq() != Hertz::from_raw(1000) || !timer.listening() {
return None;
}
Some(Self(timer))
}
}
/// This assumes that the user has already set up a MS tick timer in TIM0 as a system tick
/// with [`set_up_ms_delay_provider`]
impl embedded_hal::delay::DelayNs for DelayMs {
fn delay_ns(&mut self, ns: u32) {
let ns_as_ms = ns / 1_000_000;
if self.0.curr_freq() != Hertz::from_raw(1000) || !self.0.listening() {
return;
}
let start_time = get_ms_ticks();
while get_ms_ticks() - start_time < ns_as_ms {
cortex_m::asm::nop();
}
}
}
*/
#[inline(always)] #[inline(always)]
pub fn enable_tim_clk(idx: u8) { pub fn enable_tim_clk(idx: u8) {
let syscfg = unsafe { va108xx::Sysconfig::steal() }; let syscfg = unsafe { va108xx::Sysconfig::steal() };

View File

@ -14,7 +14,10 @@
//! - [Flashloader exposing a CCSDS interface via UART](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/flashloader) //! - [Flashloader exposing a CCSDS interface via UART](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/flashloader)
use core::{convert::Infallible, ops::Deref}; use core::{convert::Infallible, ops::Deref};
use fugit::RateExtU32; use fugit::RateExtU32;
use vorago_shared_periphs::{gpio::Pin, FunSel, InterruptConfig}; use vorago_shared_periphs::{
gpio::{IoPeriphPin, Pin},
FunSel, InterruptConfig,
};
use crate::{ use crate::{
clock::enable_peripheral_clock, clock::enable_peripheral_clock,
@ -22,7 +25,7 @@ use crate::{
pac::{self, uarta as uart_base}, pac::{self, uarta as uart_base},
pins::{ pins::{
Pa16, Pa17, Pa18, Pa19, Pa2, Pa26, Pa27, Pa3, Pa30, Pa31, Pa8, Pa9, Pb18, Pb19, Pb20, Pb21, Pa16, Pa17, Pa18, Pa19, Pa2, Pa26, Pa27, Pa3, Pa30, Pa31, Pa8, Pa9, Pb18, Pb19, Pb20, Pb21,
Pb22, Pb23, Pb6, Pb7, Pb8, Pb9, Pb22, Pb23, Pb6, Pb7, Pb8, Pb9, PinMarker,
}, },
time::Hertz, time::Hertz,
PeripheralSelect, PeripheralSelect,
@ -55,11 +58,11 @@ impl UartId {
// Type-Level support // Type-Level support
//================================================================================================== //==================================================================================================
pub trait TxPin { pub trait TxPin: PinMarker {
const UART_ID: UartId; const UART_ID: UartId;
const FUN_SEL: FunSel; const FUN_SEL: FunSel;
} }
pub trait RxPin { pub trait RxPin: PinMarker {
const UART_ID: UartId; const UART_ID: UartId;
const FUN_SEL: FunSel; const FUN_SEL: FunSel;
} }
@ -557,6 +560,8 @@ impl Uart {
if UartI::ID != TxPinI::UART_ID || UartI::ID != RxPinI::UART_ID { if UartI::ID != TxPinI::UART_ID || UartI::ID != RxPinI::UART_ID {
return Err(UartIdMissmatchError); return Err(UartIdMissmatchError);
} }
IoPeriphPin::new(TxPinI::ID, TxPinI::FUN_SEL, None);
IoPeriphPin::new(RxPinI::ID, TxPinI::FUN_SEL, None);
crate::clock::enable_peripheral_clock(UartI::PERIPH_SEL); crate::clock::enable_peripheral_clock(UartI::PERIPH_SEL);
let reg_block = unsafe { UartI::reg_block() }; let reg_block = unsafe { UartI::reg_block() };

View File

@ -411,10 +411,10 @@ impl<const N: usize> embedded_io_async::Read for RxAsyncOverwriting<N> {
critical_section::with(|cs| { critical_section::with(|cs| {
let queue = inner.shared_consumer.borrow(cs); let queue = inner.shared_consumer.borrow(cs);
if queue.borrow().as_ref().unwrap().len() == 0 { if queue.borrow().as_ref().unwrap().len() == 0 {
RX_HAS_DATA[id as usize].store(false, Ordering::Relaxed); RX_HAS_DATA[id].store(false, Ordering::Relaxed);
} }
}); });
let _guard = ActiveReadGuard(id as usize); let _guard = ActiveReadGuard(id);
let mut handle_data_in_queue = |inner: &mut RxAsyncOverwritingInner<N>| { let mut handle_data_in_queue = |inner: &mut RxAsyncOverwritingInner<N>| {
critical_section::with(|cs| { critical_section::with(|cs| {
let mut consumer_ref = inner.shared_consumer.borrow(cs).borrow_mut(); let mut consumer_ref = inner.shared_consumer.borrow(cs).borrow_mut();

View File

@ -15,10 +15,11 @@ cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7" cortex-m-rt = "0.7"
embedded-hal = "1" embedded-hal = "1"
nb = "1" nb = "1"
bitfield = ">=0.17, <=0.19" bitbybit = "1.3"
arbitrary-int = "1.3"
max116xx-10bit = "0.3" max116xx-10bit = "0.3"
va108xx-hal = { version = ">=0.10, <=0.11", features = ["rt"] } va108xx-hal = { version = ">=0.10, <=0.11", path = "../va108xx-hal", features = ["rt"] }
[features] [features]
rt = ["va108xx-hal/rt"] rt = ["va108xx-hal/rt"]

View File

@ -4,16 +4,16 @@ use cortex_m_rt::entry;
use embedded_hal::delay::DelayNs; use embedded_hal::delay::DelayNs;
use panic_rtt_target as _; use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print}; use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{pac, prelude::*, timer::set_up_ms_delay_provider}; use va108xx_hal::{pac, prelude::*, timer::CountdownTimer};
use vorago_reb1::temp_sensor::Adt75TempSensor; use vorago_reb1::temp_sensor::Adt75TempSensor;
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
rtt_init_print!(); rtt_init_print!();
rprintln!("-- Vorago Temperature Sensor and I2C Example --"); rprintln!("-- Vorago Temperature Sensor and I2C Example --");
let mut dp = pac::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap();
let mut delay = set_up_ms_delay_provider(&mut dp.sysconfig, 50.MHz(), dp.tim0); let mut delay = CountdownTimer::new(50.MHz(), dp.tim0);
let mut temp_sensor = Adt75TempSensor::new(&mut dp.sysconfig, 50.MHz(), dp.i2ca) let mut temp_sensor = Adt75TempSensor::new(50.MHz(), dp.i2ca)
.expect("Creating temperature sensor struct failed"); .expect("Creating temperature sensor struct failed");
loop { loop {
let temp = temp_sensor let temp = temp_sensor

View File

@ -9,13 +9,14 @@ use embedded_hal::delay::DelayNs;
use embedded_hal::spi::{SpiBus, MODE_3}; use embedded_hal::spi::{SpiBus, MODE_3};
use panic_rtt_target as _; use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print}; use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::spi::SpiClkConfig; use va108xx_hal::gpio::{Output, PinState};
use va108xx_hal::pins::PinsA;
use va108xx_hal::spi::{configure_pin_as_hw_cs_pin, SpiClkConfig};
use va108xx_hal::timer::CountdownTimer;
use va108xx_hal::{ use va108xx_hal::{
gpio::PinsA,
pac, pac,
prelude::*, prelude::*,
spi::{Spi, SpiConfig}, spi::{Spi, SpiConfig},
timer::set_up_ms_delay_provider,
}; };
const READ_MASK: u8 = 1 << 7; const READ_MASK: u8 = 1 << 7;
@ -29,19 +30,19 @@ const PWR_MEASUREMENT_MODE_MASK: u8 = 1 << 3;
fn main() -> ! { fn main() -> ! {
rtt_init_print!(); rtt_init_print!();
rprintln!("-- Vorago Accelerometer Example --"); rprintln!("-- Vorago Accelerometer Example --");
let mut dp = pac::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap();
let mut delay = set_up_ms_delay_provider(&mut dp.sysconfig, 50.MHz(), dp.tim0); let pinsa = PinsA::new(dp.porta);
let pinsa = PinsA::new(&mut dp.sysconfig, dp.porta); let mut delay = CountdownTimer::new(50.MHz(), dp.tim0);
let (sck, mosi, miso) = ( let (sck, mosi, miso) = (
pinsa.pa20.into_funsel_2(), pinsa.pa20,
pinsa.pa19.into_funsel_2(), pinsa.pa19,
pinsa.pa18.into_funsel_2(), pinsa.pa18,
); );
let cs_pin = pinsa.pa16.into_funsel_2(); let cs_pin = pinsa.pa16;
let hw_cs_id = configure_pin_as_hw_cs_pin(cs_pin);
// Need to set the ADC chip select low // Need to set the ADC chip select low
let mut adc_cs = pinsa.pa17.into_push_pull_output(); Output::new(pinsa.pa17, PinState::Low);
adc_cs.set_high();
let spi_cfg = SpiConfig::default() let spi_cfg = SpiConfig::default()
.clk_cfg( .clk_cfg(
@ -50,13 +51,12 @@ fn main() -> ! {
.mode(MODE_3) .mode(MODE_3)
.slave_output_disable(true); .slave_output_disable(true);
let mut spi = Spi::new( let mut spi = Spi::new(
&mut dp.sysconfig,
50.MHz(), 50.MHz(),
dp.spib, dp.spib,
(sck, miso, mosi), (sck, miso, mosi),
spi_cfg, spi_cfg,
); ).unwrap();
spi.cfg_hw_cs_with_pin(&cs_pin); spi.cfg_hw_cs(hw_cs_id);
let mut tx_rx_buf: [u8; 3] = [0; 3]; let mut tx_rx_buf: [u8; 3] = [0; 3];
tx_rx_buf[0] = READ_MASK | DEVID_REG; tx_rx_buf[0] = READ_MASK | DEVID_REG;

View File

@ -10,10 +10,10 @@ use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print}; use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{ use va108xx_hal::{
clock::{set_clk_div_register, FilterClkSel}, clock::{set_clk_div_register, FilterClkSel},
gpio::{FilterType, InterruptEdge, PinsA}, gpio::{FilterType, InterruptEdge},
pac::{self, interrupt}, pac::{self, interrupt},
prelude::*, pins::PinsA,
timer::{default_ms_irq_handler, set_up_ms_tick, InterruptConfig}, timer::InterruptConfig,
}; };
use vorago_reb1::button::Button; use vorago_reb1::button::Button;
use vorago_reb1::leds::Leds; use vorago_reb1::leds::Leds;
@ -35,18 +35,18 @@ fn main() -> ! {
rtt_init_print!(); rtt_init_print!();
rprintln!("-- Vorago Button IRQ Example --"); rprintln!("-- Vorago Button IRQ Example --");
let mut dp = pac::Peripherals::take().unwrap(); let mut dp = pac::Peripherals::take().unwrap();
let pinsa = PinsA::new(&mut dp.sysconfig, dp.porta); let pinsa = PinsA::new(dp.porta);
let edge_irq = match PRESS_MODE { let edge_irq = match PRESS_MODE {
PressMode::Toggle => InterruptEdge::HighToLow, PressMode::Toggle => InterruptEdge::HighToLow,
PressMode::Keep => InterruptEdge::BothEdges, PressMode::Keep => InterruptEdge::BothEdges,
}; };
// Configure an edge interrupt on the button and route it to interrupt vector 15 // Configure an edge interrupt on the button and route it to interrupt vector 15
let mut button = Button::new(pinsa.pa11.into_floating_input()); let mut button = Button::new(pinsa.pa11);
if PRESS_MODE == PressMode::Toggle { if PRESS_MODE == PressMode::Toggle {
// This filter debounces the switch for edge based interrupts // This filter debounces the switch for edge based interrupts
button.configure_filter_type(FilterType::FilterFourClockCycles, FilterClkSel::Clk1); button.configure_filter_type(FilterType::FilterFourCycles, FilterClkSel::Clk1);
set_clk_div_register(&mut dp.sysconfig, FilterClkSel::Clk1, 50_000); set_clk_div_register(&mut dp.sysconfig, FilterClkSel::Clk1, 50_000);
} }
button.configure_and_enable_edge_interrupt( button.configure_and_enable_edge_interrupt(
@ -54,18 +54,7 @@ fn main() -> ! {
InterruptConfig::new(pac::interrupt::OC15, true, true), InterruptConfig::new(pac::interrupt::OC15, true, true),
); );
set_up_ms_tick( let mut leds = Leds::new(pinsa.pa10, pinsa.pa7, pinsa.pa6);
InterruptConfig::new(pac::Interrupt::OC0, true, true),
&mut dp.sysconfig,
Some(&mut dp.irqsel),
50.MHz(),
dp.tim0,
);
let mut leds = Leds::new(
pinsa.pa10.into_push_pull_output(),
pinsa.pa7.into_push_pull_output(),
pinsa.pa6.into_push_pull_output(),
);
for led in leds.iter_mut() { for led in leds.iter_mut() {
led.off(); led.off();
} }
@ -79,11 +68,6 @@ fn main() -> ! {
} }
} }
#[interrupt]
fn OC0() {
default_ms_irq_handler();
}
#[interrupt] #[interrupt]
fn OC15() { fn OC15() {
cortex_m::interrupt::free(|cs| { cortex_m::interrupt::free(|cs| {

View File

@ -9,7 +9,13 @@
use cortex_m_rt::entry; use cortex_m_rt::entry;
use embedded_hal::delay::DelayNs; use embedded_hal::delay::DelayNs;
use panic_halt as _; use panic_halt as _;
use va108xx_hal::{gpio::PinsA, pac, prelude::*, timer::set_up_ms_delay_provider}; use va108xx_hal::{
gpio::{Output, PinState},
pac,
pins::PinsA,
prelude::*,
timer::CountdownTimer,
};
use vorago_reb1::leds::Leds; use vorago_reb1::leds::Leds;
// REB LED pin definitions. All on port A // REB LED pin definitions. All on port A
@ -26,7 +32,7 @@ enum LibType {
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
let mut dp = pac::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap();
let lib_type = LibType::Bsp; let lib_type = LibType::Bsp;
@ -60,11 +66,11 @@ fn main() -> ! {
} }
} }
LibType::Hal => { LibType::Hal => {
let pins = PinsA::new(&mut dp.sysconfig, dp.porta); let pins = PinsA::new(dp.porta);
let mut led1 = pins.pa10.into_readable_push_pull_output(); let mut led1 = Output::new(pins.pa10, PinState::Low);
let mut led2 = pins.pa7.into_readable_push_pull_output(); let mut led2 = Output::new(pins.pa7, PinState::Low);
let mut led3 = pins.pa6.into_readable_push_pull_output(); let mut led3 = Output::new(pins.pa6, PinState::Low);
let mut delay = set_up_ms_delay_provider(&mut dp.sysconfig, 50.MHz(), dp.tim0); let mut delay = CountdownTimer::new(50.MHz(), dp.tim0);
for _ in 0..10 { for _ in 0..10 {
led1.set_low(); led1.set_low();
led2.set_low(); led2.set_low();
@ -83,13 +89,9 @@ fn main() -> ! {
} }
} }
LibType::Bsp => { LibType::Bsp => {
let pinsa = PinsA::new(&mut dp.sysconfig, dp.porta); let pinsa = PinsA::new(dp.porta);
let mut leds = Leds::new( let mut leds = Leds::new(pinsa.pa10, pinsa.pa7, pinsa.pa6);
pinsa.pa10.into_push_pull_output(), let mut delay = CountdownTimer::new(50.MHz(), dp.tim0);
pinsa.pa7.into_push_pull_output(),
pinsa.pa6.into_push_pull_output(),
);
let mut delay = set_up_ms_delay_provider(&mut dp.sysconfig, 50.MHz(), dp.tim0);
for _ in 0..10 { for _ in 0..10 {
// Blink all LEDs quickly // Blink all LEDs quickly
for led in leds.iter_mut() { for led in leds.iter_mut() {

View File

@ -5,16 +5,18 @@
//! - [Button Blinky with IRQs](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/blinky-button-irq.rs) //! - [Button Blinky with IRQs](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/blinky-button-irq.rs)
//! - [Button Blinky with IRQs and RTIC](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/blinky-button-rtic.rs) //! - [Button Blinky with IRQs and RTIC](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/blinky-button-rtic.rs)
use va108xx_hal::{ use va108xx_hal::{
gpio::{FilterClkSel, FilterType, InputFloating, InterruptEdge, InterruptLevel, Pin, PA11}, clock::FilterClkSel,
gpio::{FilterType, Input, InterruptEdge, InterruptLevel, Pin},
pins::Pa11,
InterruptConfig, InterruptConfig,
}; };
#[derive(Debug)] #[derive(Debug)]
pub struct Button(pub Pin<PA11, InputFloating>); pub struct Button(pub Input);
impl Button { impl Button {
pub fn new(pin: Pin<PA11, InputFloating>) -> Button { pub fn new(pin: Pin<Pa11>) -> Button {
Button(pin) Button(Input::new_floating(pin))
} }
#[inline] #[inline]

View File

@ -6,20 +6,20 @@
//! - [Button Blinky using IRQs](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/blinky-button-irq.rs) //! - [Button Blinky using IRQs](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/blinky-button-irq.rs)
//! - [Button Blinky using IRQs and RTIC](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/blinky-button-rtic.rs) //! - [Button Blinky using IRQs and RTIC](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/blinky-button-rtic.rs)
use va108xx_hal::{ use va108xx_hal::{
gpio::dynpin::DynPin, gpio::{Output, PinState},
gpio::pin::{Pin, PushPullOutput, PA10, PA6, PA7}, pins::{Pa10, Pa6, Pa7, Pin},
}; };
pub type LD2 = Pin<PA10, PushPullOutput>;
pub type LD3 = Pin<PA7, PushPullOutput>;
pub type LD4 = Pin<PA6, PushPullOutput>;
#[derive(Debug)] #[derive(Debug)]
pub struct Leds(pub [Led; 3]); pub struct Leds(pub [Led; 3]);
impl Leds { impl Leds {
pub fn new(led_pin1: LD2, led_pin2: LD3, led_pin3: LD4) -> Leds { pub fn new(led_pin1: Pin<Pa10>, led_pin2: Pin<Pa7>, led_pin3: Pin<Pa6>) -> Leds {
Leds([led_pin1.into(), led_pin2.into(), led_pin3.into()]) Leds([
Led(Output::new(led_pin1, PinState::Low)),
Led(Output::new(led_pin2, PinState::Low)),
Led(Output::new(led_pin3, PinState::Low)),
])
} }
} }
@ -52,38 +52,24 @@ impl core::ops::IndexMut<usize> for Leds {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Led(pub DynPin); pub struct Led(Output);
macro_rules! ctor {
($($ldx:ident),+) => {
$(
impl From<$ldx> for Led {
fn from(led: $ldx) -> Self {
Led(led.into())
}
}
)+
}
}
ctor!(LD2, LD3, LD4);
impl Led { impl Led {
/// Turns the LED off. Setting the pin high actually turns the LED off /// Turns the LED off. Setting the pin high actually turns the LED off
#[inline] #[inline]
pub fn off(&mut self) { pub fn off(&mut self) {
self.0.set_high().ok(); self.0.set_high();
} }
/// Turns the LED on. Setting the pin low actually turns the LED on /// Turns the LED on. Setting the pin low actually turns the LED on
#[inline] #[inline]
pub fn on(&mut self) { pub fn on(&mut self) {
self.0.set_low().ok(); self.0.set_low();
} }
/// Toggles the LED /// Toggles the LED
#[inline] #[inline]
pub fn toggle(&mut self) { pub fn toggle(&mut self) {
self.0.toggle().ok(); self.0.toggle();
} }
} }

View File

@ -7,20 +7,25 @@
//! # Example //! # Example
//! //!
//! - [REB1 EEPROM example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/nvm.rs) //! - [REB1 EEPROM example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/nvm.rs)
use arbitrary_int::{u2, u3};
use core::convert::Infallible; use core::convert::Infallible;
use embedded_hal::spi::SpiBus; use embedded_hal::spi::SpiBus;
pub const PAGE_SIZE: usize = 256; pub const PAGE_SIZE: usize = 256;
bitfield::bitfield! { #[bitbybit::bitfield(u8)]
pub struct StatusReg(u8); #[derive(Debug)]
impl Debug; pub struct StatusReg {
u8; #[bit(7, r)]
pub status_register_write_protect, _: 7; status_register_write_protect: bool,
pub zero_segment, _: 6, 4; #[bits(4..=6, r)]
pub block_protection_bits, set_block_protection_bits: 3, 2; zero_segment: u3,
pub write_enable_latch, _: 1; #[bits(2..=3, rw)]
pub write_in_progress, _: 0; block_protection_bits: u2,
#[bit(1, r)]
write_enable_latch: bool,
#[bit(0, r)]
write_in_progress: bool,
} }
// Registers. // Registers.
@ -43,10 +48,10 @@ use regs::*;
use va108xx_hal::{ use va108xx_hal::{
pac, pac,
prelude::*, prelude::*,
spi::{RomMiso, RomMosi, RomSck, Spi, SpiClkConfig, SpiConfig, BMSTART_BMSTOP_MASK}, spi::{Spi, SpiClkConfig, SpiConfig, SpiLowLevel, BMSTART_BMSTOP_MASK},
}; };
pub type RomSpi = Spi<pac::Spic, (RomSck, RomMiso, RomMosi), u8>; pub type RomSpi = Spi<u8>;
/// Driver for the ST device M95M01 EEPROM memory. /// Driver for the ST device M95M01 EEPROM memory.
/// ///
@ -59,14 +64,13 @@ pub struct M95M01 {
pub struct PageBoundaryExceededError; pub struct PageBoundaryExceededError;
impl M95M01 { impl M95M01 {
pub fn new(syscfg: &mut pac::Sysconfig, sys_clk: impl Into<Hertz>, spi: pac::Spic) -> Self { pub fn new(sys_clk: Hertz, spi: pac::Spic) -> Self {
let spi = RomSpi::new( let spi = RomSpi::new_for_rom(
syscfg,
sys_clk, sys_clk,
spi, spi,
(RomSck, RomMiso, RomMosi),
SpiConfig::default().clk_cfg(SpiClkConfig::new(2, 4)), SpiConfig::default().clk_cfg(SpiClkConfig::new(2, 4)),
); )
.unwrap();
let mut spi_dev = Self { spi }; let mut spi_dev = Self { spi };
spi_dev.clear_block_protection().unwrap(); spi_dev.clear_block_protection().unwrap();
spi_dev spi_dev
@ -74,7 +78,7 @@ impl M95M01 {
pub fn release(mut self) -> pac::Spic { pub fn release(mut self) -> pac::Spic {
self.set_block_protection().unwrap(); self.set_block_protection().unwrap();
self.spi.release().0 unsafe { pac::Spic::steal() }
} }
// Wait until the write-in-progress state is cleared. This exposes a [nb] API, so this function // Wait until the write-in-progress state is cleared. This exposes a [nb] API, so this function
@ -90,7 +94,7 @@ impl M95M01 {
pub fn read_status_reg(&mut self) -> Result<StatusReg, Infallible> { pub fn read_status_reg(&mut self) -> Result<StatusReg, Infallible> {
let mut write_read: [u8; 2] = [regs::RDSR, 0x00]; let mut write_read: [u8; 2] = [regs::RDSR, 0x00];
self.spi.transfer_in_place(&mut write_read)?; self.spi.transfer_in_place(&mut write_read)?;
Ok(StatusReg(write_read[1])) Ok(StatusReg::new_with_raw_value(write_read[1]))
} }
pub fn write_enable(&mut self) -> Result<(), Infallible> { pub fn write_enable(&mut self) -> Result<(), Infallible> {
@ -104,10 +108,10 @@ impl M95M01 {
} }
pub fn set_block_protection(&mut self) -> Result<(), Infallible> { pub fn set_block_protection(&mut self) -> Result<(), Infallible> {
let mut reg = StatusReg(0); let mut reg = StatusReg::new_with_raw_value(0);
reg.set_block_protection_bits(0b11); reg.set_block_protection_bits(u2::new(0b11));
self.write_enable()?; self.write_enable()?;
self.spi.write(&[WRSR, reg.0]) self.spi.write(&[WRSR, reg.raw_value()])
} }
fn common_init_write_and_read(&mut self, address: usize, reg: u8) -> Result<(), Infallible> { fn common_init_write_and_read(&mut self, address: usize, reg: u8) -> Result<(), Infallible> {

View File

@ -9,7 +9,7 @@ use max116xx_10bit::{
Error, ExternallyClocked, InternallyClockedInternallyTimedSerialInterface, Max116xx10Bit, Error, ExternallyClocked, InternallyClockedInternallyTimedSerialInterface, Max116xx10Bit,
Max116xx10BitEocExt, VoltageRefMode, WithWakeupDelay, WithoutWakeupDelay, Max116xx10BitEocExt, VoltageRefMode, WithWakeupDelay, WithoutWakeupDelay,
}; };
use va108xx_hal::gpio::{Floating, Input, Pin, PA14}; use va108xx_hal::gpio::Input;
pub type Max11619ExternallyClockedNoWakeup<Spi> = pub type Max11619ExternallyClockedNoWakeup<Spi> =
Max116xx10Bit<Spi, ExternallyClocked, WithoutWakeupDelay>; Max116xx10Bit<Spi, ExternallyClocked, WithoutWakeupDelay>;
@ -17,7 +17,6 @@ pub type Max11619ExternallyClockedWithWakeup<Spi> =
Max116xx10Bit<Spi, ExternallyClocked, WithWakeupDelay>; Max116xx10Bit<Spi, ExternallyClocked, WithWakeupDelay>;
pub type Max11619InternallyClocked<Spi, Eoc> = pub type Max11619InternallyClocked<Spi, Eoc> =
Max116xx10BitEocExt<Spi, Eoc, InternallyClockedInternallyTimedSerialInterface>; Max116xx10BitEocExt<Spi, Eoc, InternallyClockedInternallyTimedSerialInterface>;
pub type EocPin = Pin<PA14, Input<Floating>>;
pub const AN0_CHANNEL: u8 = 0; pub const AN0_CHANNEL: u8 = 0;
pub const AN1_CHANNEL: u8 = 1; pub const AN1_CHANNEL: u8 = 1;
@ -44,9 +43,9 @@ pub fn max11619_externally_clocked_with_wakeup<Spi: SpiDevice>(
pub fn max11619_internally_clocked<Spi: SpiDevice>( pub fn max11619_internally_clocked<Spi: SpiDevice>(
spi: Spi, spi: Spi,
eoc: EocPin, eoc: Input,
v_ref: VoltageRefMode, v_ref: VoltageRefMode,
) -> Result<Max11619InternallyClocked<Spi, EocPin>, Error<Spi::Error, Infallible>> { ) -> Result<Max11619InternallyClocked<Spi, Input>, Error<Spi::Error, Infallible>> {
let mut adc = Max116xx10Bit::max11619(spi)? let mut adc = Max116xx10Bit::max11619(spi)?
.into_int_clkd_int_timed_through_ser_if_without_wakeup(v_ref, eoc)?; .into_int_clkd_int_timed_through_ser_if_without_wakeup(v_ref, eoc)?;
adc.reset(false)?; adc.reset(false)?;

View File

@ -48,15 +48,10 @@ impl From<Error> for AdtInitError {
} }
impl Adt75TempSensor { impl Adt75TempSensor {
pub fn new( pub fn new(sys_clk: Hertz, i2ca: pac::I2ca) -> Result<Self, Error> {
sys_cfg: &mut pac::Sysconfig,
sys_clk: impl Into<Hertz> + Copy,
i2ca: pac::I2ca,
) -> Result<Self, Error> {
let mut sensor = Adt75TempSensor { let mut sensor = Adt75TempSensor {
// The master construction can not fail for regular I2C speed. // The master construction can not fail for regular I2C speed.
sensor_if: I2cMaster::new( sensor_if: I2cMaster::new(
sys_cfg,
sys_clk, sys_clk,
i2ca, i2ca,
MasterConfig::default(), MasterConfig::default(),

View File

@ -102,8 +102,7 @@ impl InputPinFuture {
) -> Self { ) -> Self {
let (waker_group, edge_detection_group) = let (waker_group, edge_detection_group) =
Self::pin_group_to_waker_and_edge_detection_group(pin.id().port()); Self::pin_group_to_waker_and_edge_detection_group(pin.id().port());
edge_detection_group[pin.id().offset() as usize] edge_detection_group[pin.id().offset()].store(false, core::sync::atomic::Ordering::Relaxed);
.store(false, core::sync::atomic::Ordering::Relaxed);
pin.configure_edge_interrupt(edge); pin.configure_edge_interrupt(edge);
#[cfg(feature = "vor1x")] #[cfg(feature = "vor1x")]
pin.enable_interrupt(InterruptConfig::new(irq, true, true)); pin.enable_interrupt(InterruptConfig::new(irq, true, true));
@ -128,7 +127,7 @@ impl Future for InputPinFuture {
self: core::pin::Pin<&mut Self>, self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>, cx: &mut core::task::Context<'_>,
) -> core::task::Poll<Self::Output> { ) -> core::task::Poll<Self::Output> {
let idx = self.id.offset() as usize; let idx = self.id.offset();
self.waker_group[idx].register(cx.waker()); self.waker_group[idx].register(cx.waker());
if self.edge_detection_group[idx].swap(false, core::sync::atomic::Ordering::Relaxed) { if self.edge_detection_group[idx].swap(false, core::sync::atomic::Ordering::Relaxed) {
return core::task::Poll::Ready(()); return core::task::Poll::Ready(());

View File

@ -1,5 +1,7 @@
pub use embedded_hal::digital::PinState; pub use embedded_hal::digital::PinState;
use crate::ioconfig::FilterClkSel;
use crate::ioconfig::FilterType;
#[cfg(feature = "vor1x")] #[cfg(feature = "vor1x")]
use crate::{PeripheralSelect, sysconfig::enable_peripheral_clock}; use crate::{PeripheralSelect, sysconfig::enable_peripheral_clock};
@ -27,15 +29,28 @@ pub enum InterruptLevel {
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PinId { pub struct PinId {
port: Port, port: Port,
offset: usize, offset: u8,
} }
impl PinId { impl PinId {
pub const fn new_unchecked(port: Port, offset: usize) -> Self {
if offset >= port.max_offset() {
panic!("Pin ID construction: offset is out of range");
}
PinId {
port,
offset: offset as u8,
}
}
pub const fn new(port: Port, offset: usize) -> Result<Self, InvalidOffsetError> { pub const fn new(port: Port, offset: usize) -> Result<Self, InvalidOffsetError> {
if offset >= port.max_offset() { if offset >= port.max_offset() {
return Err(InvalidOffsetError { offset, port }); return Err(InvalidOffsetError { offset, port });
} }
Ok(PinId { port, offset }) Ok(PinId {
port,
offset: offset as u8,
})
} }
pub const fn port(&self) -> Port { pub const fn port(&self) -> Port {
@ -43,7 +58,7 @@ impl PinId {
} }
pub const fn offset(&self) -> usize { pub const fn offset(&self) -> usize {
self.offset self.offset as usize
} }
} }
@ -53,6 +68,15 @@ pub struct LowLevelGpio {
id: PinId, id: PinId,
} }
impl core::fmt::Debug for LowLevelGpio {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("LowLevelGpio")
.field("gpio", &self.gpio.port())
.field("id", &self.id)
.finish()
}
}
impl LowLevelGpio { impl LowLevelGpio {
pub fn new(id: PinId) -> Self { pub fn new(id: PinId) -> Self {
LowLevelGpio { LowLevelGpio {
@ -78,23 +102,17 @@ impl LowLevelGpio {
} }
pub fn configure_as_input_floating(&mut self) { pub fn configure_as_input_floating(&mut self) {
unsafe { self.ioconfig.modify_pin_config(self.id, |mut config| {
self.ioconfig.modify_pin_config_unchecked( config.set_funsel(FunSel::Sel0);
self.id.port(), config.set_io_disable(false);
self.id.offset(), config.set_invert_input(false);
|mut config| { config.set_open_drain(false);
config.set_funsel(FunSel::Sel0); config.set_pull_enable(false);
config.set_io_disable(false); config.set_pull_when_output_active(false);
config.set_invert_input(false); config.set_invert_output(false);
config.set_open_drain(false); config.set_input_enable_when_output(false);
config.set_pull_enable(false); config
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| { self.gpio.modify_dir(|mut dir| {
dir &= !(1 << self.id.offset()); dir &= !(1 << self.id.offset());
dir dir
@ -102,24 +120,18 @@ impl LowLevelGpio {
} }
pub fn configure_as_input_with_pull(&mut self, pull: Pull) { pub fn configure_as_input_with_pull(&mut self, pull: Pull) {
unsafe { self.ioconfig.modify_pin_config(self.id, |mut config| {
self.ioconfig.modify_pin_config_unchecked( config.set_funsel(FunSel::Sel0);
self.id.port(), config.set_io_disable(false);
self.id.offset(), config.set_invert_input(false);
|mut config| { config.set_open_drain(false);
config.set_funsel(FunSel::Sel0); config.set_pull_enable(true);
config.set_io_disable(false); config.set_pull_dir(pull);
config.set_invert_input(false); config.set_pull_when_output_active(false);
config.set_open_drain(false); config.set_invert_output(false);
config.set_pull_enable(true); config.set_input_enable_when_output(false);
config.set_pull_dir(pull); config
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| { self.gpio.modify_dir(|mut dir| {
dir &= !(1 << self.id.offset()); dir &= !(1 << self.id.offset());
dir dir
@ -127,23 +139,17 @@ impl LowLevelGpio {
} }
pub fn configure_as_output_push_pull(&mut self, init_level: PinState) { pub fn configure_as_output_push_pull(&mut self, init_level: PinState) {
unsafe { self.ioconfig.modify_pin_config(self.id, |mut config| {
self.ioconfig.modify_pin_config_unchecked( config.set_funsel(FunSel::Sel0);
self.id.port(), config.set_io_disable(false);
self.id.offset(), config.set_invert_input(false);
|mut config| { config.set_open_drain(false);
config.set_funsel(FunSel::Sel0); config.set_pull_enable(false);
config.set_io_disable(false); config.set_pull_when_output_active(false);
config.set_invert_input(false); config.set_invert_output(false);
config.set_open_drain(false); config.set_input_enable_when_output(true);
config.set_pull_enable(false); config
config.set_pull_when_output_active(false); });
config.set_invert_output(false);
config.set_input_enable_when_output(true);
config
},
);
}
match init_level { match init_level {
PinState::Low => self.gpio.write_clr_out(self.mask_32()), PinState::Low => self.gpio.write_clr_out(self.mask_32()),
PinState::High => self.gpio.write_set_out(self.mask_32()), PinState::High => self.gpio.write_set_out(self.mask_32()),
@ -155,24 +161,18 @@ impl LowLevelGpio {
} }
pub fn configure_as_output_open_drain(&mut self, init_level: PinState) { pub fn configure_as_output_open_drain(&mut self, init_level: PinState) {
unsafe { self.ioconfig.modify_pin_config(self.id, |mut config| {
self.ioconfig.modify_pin_config_unchecked( config.set_funsel(FunSel::Sel0);
self.id.port(), config.set_io_disable(false);
self.id.offset(), config.set_invert_input(false);
|mut config| { config.set_open_drain(true);
config.set_funsel(FunSel::Sel0); config.set_pull_enable(true);
config.set_io_disable(false); config.set_pull_dir(Pull::Up);
config.set_invert_input(false); config.set_pull_when_output_active(false);
config.set_open_drain(true); config.set_invert_output(false);
config.set_pull_enable(true); config.set_input_enable_when_output(true);
config.set_pull_dir(Pull::Up); config
config.set_pull_when_output_active(false); });
config.set_invert_output(false);
config.set_input_enable_when_output(true);
config
},
);
}
let mask32 = self.mask_32(); let mask32 = self.mask_32();
match init_level { match init_level {
PinState::Low => self.gpio.write_clr_out(mask32), PinState::Low => self.gpio.write_clr_out(mask32),
@ -185,22 +185,16 @@ impl LowLevelGpio {
} }
pub fn configure_as_peripheral_pin(&mut self, fun_sel: FunSel, pull: Option<Pull>) { pub fn configure_as_peripheral_pin(&mut self, fun_sel: FunSel, pull: Option<Pull>) {
unsafe { self.ioconfig.modify_pin_config(self.id, |mut config| {
self.ioconfig.modify_pin_config_unchecked( config.set_funsel(fun_sel);
self.id.port(), config.set_io_disable(false);
self.id.offset(), config.set_invert_input(false);
|mut config| { config.set_open_drain(false);
config.set_funsel(fun_sel); config.set_pull_enable(pull.is_some());
config.set_io_disable(false); config.set_pull_dir(pull.unwrap_or(Pull::Up));
config.set_invert_input(false); config.set_invert_output(false);
config.set_open_drain(false); config
config.set_pull_enable(pull.is_some()); });
config.set_pull_dir(pull.unwrap_or(Pull::Up));
config.set_invert_output(false);
config
},
);
}
} }
#[inline] #[inline]
@ -295,6 +289,79 @@ impl LowLevelGpio {
} }
} }
/// Configure which edge or level type triggers an interrupt
#[inline]
pub fn configure_level_interrupt(&mut self, level: InterruptLevel) {
let mask32 = self.mask_32();
self.gpio.modify_irq_sen(|mut value| {
value |= mask32;
value
});
if level == InterruptLevel::Low {
self.gpio.modify_irq_evt(|mut value| {
value &= !mask32;
value
});
} else {
self.gpio.modify_irq_evt(|mut value| {
value |= mask32;
value
});
}
}
/// Only useful for input pins
#[inline]
pub fn configure_filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
self.ioconfig.modify_pin_config(self.id, |mut config| {
config.set_filter_type(filter);
config.set_filter_clk_sel(clksel);
config
});
}
/// Only useful for output pins.
#[inline]
pub fn configure_pulse_mode(&mut self, enable: bool, default_state: PinState) {
self.gpio.modify_pulse(|mut value| {
if enable {
value |= 1 << self.id.offset;
} else {
value &= !(1 << self.id.offset);
}
value
});
self.gpio.modify_pulsebase(|mut value| {
if default_state == PinState::High {
value |= 1 << self.id.offset;
} else {
value &= !(1 << self.id.offset);
}
value
});
}
/// Only useful for output pins
#[inline]
pub fn configure_delay(&mut self, delay_1: bool, delay_2: bool) {
self.gpio.modify_delay1(|mut value| {
if delay_1 {
value |= 1 << self.id.offset;
} else {
value &= !(1 << self.id.offset);
}
value
});
self.gpio.modify_delay2(|mut value| {
if delay_2 {
value |= 1 << self.id.offset;
} else {
value &= !(1 << self.id.offset);
}
value
});
}
#[cfg(feature = "vor1x")] #[cfg(feature = "vor1x")]
/// Configure the IRQSEL peripheral for this particular pin with the given interrupt ID. /// Configure the IRQSEL peripheral for this particular pin with the given interrupt ID.
pub fn configure_irqsel(&mut self, id: va108xx::Interrupt) { pub fn configure_irqsel(&mut self, id: va108xx::Interrupt) {
@ -304,12 +371,12 @@ impl LowLevelGpio {
// Set the correct interrupt number in the IRQSEL register // Set the correct interrupt number in the IRQSEL register
super::Port::A => { super::Port::A => {
irqsel irqsel
.porta0(self.id().offset() as usize) .porta0(self.id().offset())
.write(|w| unsafe { w.bits(id as u32) }); .write(|w| unsafe { w.bits(id as u32) });
} }
super::Port::B => { super::Port::B => {
irqsel irqsel
.portb0(self.id().offset() as usize) .portb0(self.id().offset())
.write(|w| unsafe { w.bits(id as u32) }); .write(|w| unsafe { w.bits(id as u32) });
} }
} }
@ -324,12 +391,12 @@ impl LowLevelGpio {
// Set the correct interrupt number in the IRQSEL register // Set the correct interrupt number in the IRQSEL register
super::Port::A => { super::Port::A => {
irqsel irqsel
.porta0(self.id().offset() as usize) .porta0(self.id().offset())
.write(|w| unsafe { w.bits(u32::MAX) }); .write(|w| unsafe { w.bits(u32::MAX) });
} }
super::Port::B => { super::Port::B => {
irqsel irqsel
.portb0(self.id().offset() as usize) .portb0(self.id().offset())
.write(|w| unsafe { w.bits(u32::MAX) }); .write(|w| unsafe { w.bits(u32::MAX) });
} }
} }

View File

@ -1,24 +1,22 @@
use core::convert::Infallible; use core::convert::Infallible;
pub use crate::ioconfig::{FilterClkSel, FilterType, regs::FunSel};
pub use embedded_hal::digital::PinState; pub use embedded_hal::digital::PinState;
pub use ll::PinId; pub use ll::{InterruptEdge, InterruptLevel, PinId, Port, Pull};
pub use ll::{Port, Pull};
use crate::ioconfig::regs::FunSel;
pub mod asynch; pub mod asynch;
pub mod ll; pub mod ll;
pub mod regs; pub mod regs;
pub trait PinMarker { pub trait PinIdProvider {
const ID: ll::PinId; const ID: ll::PinId;
} }
pub struct Pin<I: PinMarker> { pub struct Pin<I: PinIdProvider> {
phantom: core::marker::PhantomData<I>, phantom: core::marker::PhantomData<I>,
} }
impl<I: PinMarker> Pin<I> { impl<I: PinIdProvider> Pin<I> {
#[allow(clippy::new_without_default)] #[allow(clippy::new_without_default)]
pub const fn new() -> Self { pub const fn new() -> Self {
Self { Self {
@ -27,10 +25,11 @@ impl<I: PinMarker> Pin<I> {
} }
} }
#[derive(Debug)]
pub struct Output(ll::LowLevelGpio); pub struct Output(ll::LowLevelGpio);
impl Output { impl Output {
pub fn new<I: PinMarker>(_pin: Pin<I>, init_level: PinState) -> Self { pub fn new<I: PinIdProvider>(_pin: Pin<I>, init_level: PinState) -> Self {
let mut ll = ll::LowLevelGpio::new(I::ID); let mut ll = ll::LowLevelGpio::new(I::ID);
ll.configure_as_output_push_pull(init_level); ll.configure_as_output_push_pull(init_level);
Output(ll) Output(ll)
@ -65,6 +64,12 @@ impl Output {
pub fn is_set_low(&self) -> bool { pub fn is_set_low(&self) -> bool {
self.0.is_set_low() self.0.is_set_low()
} }
/// Toggle pin output with dedicated HW feature.
#[inline]
pub fn toggle(&mut self) {
self.0.toggle();
}
} }
impl embedded_hal::digital::ErrorType for Output { impl embedded_hal::digital::ErrorType for Output {
@ -99,16 +104,17 @@ impl embedded_hal::digital::StatefulOutputPin for Output {
} }
} }
#[derive(Debug)]
pub struct Input(ll::LowLevelGpio); pub struct Input(ll::LowLevelGpio);
impl Input { impl Input {
pub fn new_floating<I: PinMarker>(_pin: Pin<I>) -> Self { pub fn new_floating<I: PinIdProvider>(_pin: Pin<I>) -> Self {
let mut ll = ll::LowLevelGpio::new(I::ID); let mut ll = ll::LowLevelGpio::new(I::ID);
ll.configure_as_input_floating(); ll.configure_as_input_floating();
Input(ll) Input(ll)
} }
pub fn new_with_pull<I: PinMarker>(_pin: Pin<I>, pull: Pull) -> Self { pub fn new_with_pull<I: PinIdProvider>(_pin: Pin<I>, pull: Pull) -> Self {
let mut ll = ll::LowLevelGpio::new(I::ID); let mut ll = ll::LowLevelGpio::new(I::ID);
ll.configure_as_input_with_pull(pull); ll.configure_as_input_with_pull(pull);
Input(ll) Input(ll)
@ -126,10 +132,25 @@ impl Input {
} }
#[inline] #[inline]
pub fn configure_edge_interrupt(&mut self, edge: ll::InterruptEdge) { pub fn configure_edge_interrupt(&mut self, edge: InterruptEdge) {
self.0.configure_edge_interrupt(edge); self.0.configure_edge_interrupt(edge);
} }
#[inline]
pub fn configure_level_interrupt(&mut self, edge: InterruptLevel) {
self.0.configure_level_interrupt(edge);
}
#[inline]
pub fn configure_delay(&mut self, delay_1: bool, delay_2: bool) {
self.0.configure_delay(delay_1, delay_2);
}
#[inline]
pub fn configure_filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
self.0.configure_filter_type(filter, clksel);
}
#[inline] #[inline]
pub fn is_low(&self) -> bool { pub fn is_low(&self) -> bool {
self.0.is_low() self.0.is_low()
@ -155,6 +176,7 @@ impl embedded_hal::digital::InputPin for Input {
} }
} }
#[derive(Debug)]
pub enum PinMode { pub enum PinMode {
InputFloating, InputFloating,
InputWithPull(Pull), InputWithPull(Pull),
@ -172,13 +194,14 @@ impl PinMode {
} }
} }
#[derive(Debug)]
pub struct Flex { pub struct Flex {
ll: ll::LowLevelGpio, ll: ll::LowLevelGpio,
mode: PinMode, mode: PinMode,
} }
impl Flex { impl Flex {
pub fn new<I: PinMarker>(_pin: Pin<I>) -> Self { pub fn new<I: PinIdProvider>(_pin: Pin<I>) -> Self {
let mut ll = ll::LowLevelGpio::new(I::ID); let mut ll = ll::LowLevelGpio::new(I::ID);
ll.configure_as_input_floating(); ll.configure_as_input_floating();
Flex { Flex {
@ -287,12 +310,22 @@ pub struct IoPeriphPin {
} }
impl IoPeriphPin { impl IoPeriphPin {
pub fn new<I: PinMarker>(_pin: Pin<I>, fun_sel: FunSel, pull: Option<Pull>) -> Self { pub fn new_with_pin<I: PinIdProvider>(
_pin: Pin<I>,
fun_sel: FunSel,
pull: Option<Pull>,
) -> Self {
let mut ll = ll::LowLevelGpio::new(I::ID); let mut ll = ll::LowLevelGpio::new(I::ID);
ll.configure_as_peripheral_pin(fun_sel, pull); ll.configure_as_peripheral_pin(fun_sel, pull);
IoPeriphPin { ll, fun_sel } IoPeriphPin { ll, fun_sel }
} }
pub fn new(pin_id: PinId, fun_sel: FunSel, pull: Option<Pull>) -> Self {
let mut ll = ll::LowLevelGpio::new(pin_id);
ll.configure_as_peripheral_pin(fun_sel, pull);
IoPeriphPin { ll, fun_sel }
}
pub fn port(&self) -> Port { pub fn port(&self) -> Port {
self.ll.port() self.ll.port()
} }

View File

@ -1 +1,3 @@
pub use regs::{FilterClkSel, FilterType};
pub mod regs; pub mod regs;

View File

@ -1,6 +1,6 @@
use core::marker::PhantomData; use core::marker::PhantomData;
use crate::{InvalidOffsetError, NUM_PORT_A, NUM_PORT_B}; use crate::{NUM_PORT_A, NUM_PORT_B, gpio::PinId};
#[cfg(feature = "vor4x")] #[cfg(feature = "vor4x")]
use crate::{NUM_PORT_DEFAULT, NUM_PORT_G}; use crate::{NUM_PORT_DEFAULT, NUM_PORT_G};
@ -73,7 +73,7 @@ pub struct Config {
#[bit(6, rw)] #[bit(6, rw)]
invert_input: bool, invert_input: bool,
#[bits(3..=5, rw)] #[bits(3..=5, rw)]
filter_sel: FilterClkSel, filter_clk_sel: FilterClkSel,
#[bits(0..=2, rw)] #[bits(0..=2, rw)]
filter_type: Option<FilterType>, filter_type: Option<FilterType>,
} }
@ -134,24 +134,9 @@ impl IoConfig {
} }
impl MmioIoConfig<'_> { impl MmioIoConfig<'_> {
pub fn read_pin_config( pub fn read_pin_config(&self, id: PinId) -> Config {
&self, let offset = id.offset();
port: crate::Port, match id.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::A => unsafe { self.read_port_a_unchecked(offset) },
crate::Port::B => unsafe { self.read_port_b_unchecked(offset) }, crate::Port::B => unsafe { self.read_port_b_unchecked(offset) },
#[cfg(feature = "vor4x")] #[cfg(feature = "vor4x")]
@ -167,63 +152,14 @@ impl MmioIoConfig<'_> {
} }
} }
pub fn modify_pin_config<F: FnOnce(Config) -> Config>( pub fn modify_pin_config<F: FnOnce(Config) -> Config>(&mut self, id: PinId, f: F) {
&mut self, let config = self.read_pin_config(id);
port: crate::Port, self.write_pin_config(id, f(config))
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. pub fn write_pin_config(&mut self, id: PinId, config: Config) {
/// let offset = id.offset();
/// # Safety match id.port() {
///
/// Calling this function with an invalid offset can lead to undefined behaviour.
pub unsafe fn modify_pin_config_unchecked<F: FnOnce(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::A => unsafe { self.write_port_a_unchecked(offset, config) },
crate::Port::B => unsafe { self.write_port_b_unchecked(offset, config) }, crate::Port::B => unsafe { self.write_port_b_unchecked(offset, config) },
#[cfg(feature = "vor4x")] #[cfg(feature = "vor4x")]

View File

View File

@ -15,3 +15,29 @@ pub fn disable_peripheral_clock(clock: crate::PeripheralSelect) {
.peripheral_clk_enable() .peripheral_clk_enable()
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << clock as u8)) }); .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << clock as u8)) });
} }
#[cfg(feature = "vor1x")]
#[inline]
pub fn assert_peripheral_reset(periph_sel: crate::PeripheralSelect) {
let syscfg = unsafe { va108xx::Sysconfig::steal() };
syscfg
.peripheral_reset()
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << periph_sel as u8)) });
}
#[cfg(feature = "vor1x")]
#[inline]
pub fn deassert_peripheral_reset(periph_sel: crate::PeripheralSelect) {
let syscfg = unsafe { va108xx::Sysconfig::steal() };
syscfg
.peripheral_reset()
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << periph_sel as u8)) });
}
#[cfg(feature = "vor1x")]
#[inline]
pub fn reset_peripheral_for_cycles(periph_sel: crate::PeripheralSelect, cycles: u32) {
assert_peripheral_reset(periph_sel);
cortex_m::asm::delay(cycles);
deassert_peripheral_reset(periph_sel);
}