Compare commits
1 Commits
1cbadeffb9
...
b751cb7d48
Author | SHA1 | Date | |
---|---|---|---|
b751cb7d48 |
@ -44,8 +44,8 @@ fn main() -> ! {
|
||||
rprintln!("-- VA108xx Test Application --");
|
||||
let mut dp = pac::Peripherals::take().unwrap();
|
||||
let cp = cortex_m::Peripherals::take().unwrap();
|
||||
let pinsa = PinsA::new(&mut dp.sysconfig, None, dp.porta);
|
||||
let pinsb = PinsB::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.portb);
|
||||
let pinsa = PinsA::new(&mut dp.sysconfig, dp.porta);
|
||||
let pinsb = PinsB::new(&mut dp.sysconfig, dp.portb);
|
||||
let mut led1 = pinsa.pa10.into_readable_push_pull_output();
|
||||
let test_case = TestCase::DelayMs;
|
||||
|
||||
|
@ -1,10 +1,16 @@
|
||||
//! This example demonstrates the usage of async GPIO operations on VA108xx.
|
||||
//!
|
||||
//! You need to tie the PA0 to the PA1 pin for this example to work. You can optionally tie the PB22 to PB23 pins well
|
||||
//! and then set the `CHECK_PB22_TO_PB23` to true to also test async operations on Port B.
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_sync::channel::{Receiver, Sender};
|
||||
use embassy_sync::{blocking_mutex::raw::ThreadModeRawMutex, channel::Channel};
|
||||
use embassy_time::{Duration, Instant, Timer};
|
||||
use embedded_hal::digital::{InputPin, OutputPin, StatefulOutputPin};
|
||||
use embedded_hal_async::digital::Wait;
|
||||
use panic_rtt_target as _;
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use va108xx_embassy::embassy;
|
||||
@ -17,6 +23,12 @@ use va108xx_hal::{
|
||||
|
||||
const SYSCLK_FREQ: Hertz = Hertz::from_raw(50_000_000);
|
||||
|
||||
const CHECK_PA0_TO_PA1: bool = true;
|
||||
const CHECK_PB22_TO_PB23: bool = false;
|
||||
|
||||
// Can also be set to OC10 and works as well.
|
||||
const PB22_TO_PB23_IRQ: pac::Interrupt = pac::Interrupt::OC11;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct GpioCmd {
|
||||
cmd_type: GpioCmdType,
|
||||
@ -44,9 +56,6 @@ pub enum GpioCmdType {
|
||||
static CHANNEL_PA0_PA1: Channel<ThreadModeRawMutex, GpioCmd, 3> = Channel::new();
|
||||
static CHANNEL_PB22_TO_PB23: Channel<ThreadModeRawMutex, GpioCmd, 3> = Channel::new();
|
||||
|
||||
const CHECK_PA0_TO_PA1: bool = true;
|
||||
const CHECK_PB22_TO_PB23: bool = true;
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(spawner: Spawner) {
|
||||
rtt_init_print!();
|
||||
@ -65,26 +74,42 @@ async fn main(spawner: Spawner) {
|
||||
)
|
||||
};
|
||||
|
||||
let porta = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
|
||||
let portb = PinsB::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.portb);
|
||||
let led0 = porta.pa10.into_readable_push_pull_output();
|
||||
let porta = PinsA::new(&mut dp.sysconfig, dp.porta);
|
||||
let portb = PinsB::new(&mut dp.sysconfig, dp.portb);
|
||||
let mut led0 = porta.pa10.into_readable_push_pull_output();
|
||||
let out_pa0 = porta.pa0.into_readable_push_pull_output();
|
||||
let in_pa1 = porta.pa1.into_floating_input();
|
||||
let out_pb22 = portb.pb22.into_readable_push_pull_output();
|
||||
let in_pb23 = portb.pb23.into_floating_input();
|
||||
|
||||
let mut 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 mut in_pb23_async = InputPinAsync::new(in_pb23, pac::Interrupt::OC10);
|
||||
let in_pb23_async = InputDynPinAsync::new(in_pb23.downgrade(), PB22_TO_PB23_IRQ).unwrap();
|
||||
let out_pb22_dyn = out_pb22.downgrade();
|
||||
|
||||
spawner.spawn(output_task(out_pa0_dyn)).unwrap();
|
||||
spawner
|
||||
.spawn(output_task(
|
||||
"PA0 to PA1",
|
||||
out_pa0_dyn,
|
||||
CHANNEL_PA0_PA1.receiver(),
|
||||
))
|
||||
.unwrap();
|
||||
spawner
|
||||
.spawn(output_task(
|
||||
"PB22 to PB23",
|
||||
out_pb22_dyn,
|
||||
CHANNEL_PB22_TO_PB23.receiver(),
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
if CHECK_PA0_TO_PA1 {
|
||||
check_pin_to_pin_async_ops(&CHANNEL_PA0_PA1, in_pa1_async);
|
||||
check_pin_to_pin_async_ops("PA0 to PA1", CHANNEL_PA0_PA1.sender(), in_pa1_async).await;
|
||||
rprintln!("Example PA0 to PA1 done");
|
||||
}
|
||||
if CHECK_PB22_TO_PB23 {
|
||||
check_pin_to_pin_async_ops(&CHANNEL_PB22_TO_PB23, in_pb23_async);
|
||||
check_pin_to_pin_async_ops("PB22 to PB23", CHANNEL_PB22_TO_PB23.sender(), in_pb23_async)
|
||||
.await;
|
||||
rprintln!("Example PB22 to PB23 done");
|
||||
}
|
||||
|
||||
rprintln!("Example done, toggling LED0");
|
||||
@ -95,113 +120,139 @@ async fn main(spawner: Spawner) {
|
||||
}
|
||||
|
||||
async fn check_pin_to_pin_async_ops(
|
||||
ch: &'static Channel<ThreadModeRawMutex, GpioCmd, 3>,
|
||||
async_input: InputDynPinAsync,
|
||||
ctx: &'static str,
|
||||
sender: Sender<'static, ThreadModeRawMutex, GpioCmd, 3>,
|
||||
mut async_input: impl Wait,
|
||||
) {
|
||||
rprintln!(
|
||||
"sending SetHigh command ({} ms)",
|
||||
"{}: sending SetHigh command ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
);
|
||||
CHANNEL_PA0_PA1
|
||||
.send(GpioCmd::new(GpioCmdType::SetHigh, 20))
|
||||
.await;
|
||||
async_input.wait_for_high().await;
|
||||
rprintln!("Input pin is high now ({} ms)", Instant::now().as_millis());
|
||||
|
||||
rprintln!("sending SetLow command ({} ms)", Instant::now().as_millis());
|
||||
CHANNEL_PA0_PA1
|
||||
.send(GpioCmd::new(GpioCmdType::SetLow, 20))
|
||||
.await;
|
||||
async_input.wait_for_low().await;
|
||||
rprintln!("Input pin is low now ({} ms)", Instant::now().as_millis());
|
||||
|
||||
sender.send(GpioCmd::new(GpioCmdType::SetHigh, 20)).await;
|
||||
async_input.wait_for_high().await.unwrap();
|
||||
rprintln!(
|
||||
"sending RisingEdge command ({} ms)",
|
||||
Instant::now().as_millis()
|
||||
);
|
||||
CHANNEL_PA0_PA1
|
||||
.send(GpioCmd::new(GpioCmdType::RisingEdge, 20))
|
||||
.await;
|
||||
async_input.wait_for_rising_edge().await;
|
||||
rprintln!(
|
||||
"input pin had rising edge ({} ms)",
|
||||
"{}: Input pin is high now ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
);
|
||||
|
||||
rprintln!(
|
||||
"sending Falling command ({} ms)",
|
||||
"{}: sending SetLow command ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
);
|
||||
CHANNEL_PA0_PA1
|
||||
sender.send(GpioCmd::new(GpioCmdType::SetLow, 20)).await;
|
||||
async_input.wait_for_low().await.unwrap();
|
||||
rprintln!(
|
||||
"{}: Input pin is low now ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
);
|
||||
|
||||
rprintln!(
|
||||
"{}: sending RisingEdge command ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
);
|
||||
sender.send(GpioCmd::new(GpioCmdType::RisingEdge, 20)).await;
|
||||
async_input.wait_for_rising_edge().await.unwrap();
|
||||
rprintln!(
|
||||
"{}: input pin had rising edge ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
);
|
||||
|
||||
rprintln!(
|
||||
"{}: sending Falling command ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
);
|
||||
sender
|
||||
.send(GpioCmd::new(GpioCmdType::FallingEdge, 20))
|
||||
.await;
|
||||
async_input.wait_for_falling_edge().await;
|
||||
async_input.wait_for_falling_edge().await.unwrap();
|
||||
rprintln!(
|
||||
"input pin had a falling edge ({} ms)",
|
||||
"{}: input pin had a falling edge ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
);
|
||||
|
||||
rprintln!(
|
||||
"sending Falling command ({} ms)",
|
||||
"{}: sending Falling command ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
);
|
||||
CHANNEL_PA0_PA1
|
||||
sender
|
||||
.send(GpioCmd::new(GpioCmdType::FallingEdge, 20))
|
||||
.await;
|
||||
async_input.wait_for_any_edge().await;
|
||||
async_input.wait_for_any_edge().await.unwrap();
|
||||
rprintln!(
|
||||
"input pin had a falling (any) edge ({} ms)",
|
||||
"{}: input pin had a falling (any) edge ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
);
|
||||
|
||||
rprintln!(
|
||||
"sending Falling command ({} ms)",
|
||||
"{}: sending Falling command ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
);
|
||||
CHANNEL_PA0_PA1
|
||||
.send(GpioCmd::new(GpioCmdType::RisingEdge, 20))
|
||||
.await;
|
||||
async_input.wait_for_any_edge().await;
|
||||
sender.send(GpioCmd::new(GpioCmdType::RisingEdge, 20)).await;
|
||||
async_input.wait_for_any_edge().await.unwrap();
|
||||
rprintln!(
|
||||
"input pin had a rising (any) edge ({} ms)",
|
||||
"{}: input pin had a rising (any) edge ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
);
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn output_task(mut out: DynPin) {
|
||||
#[embassy_executor::task(pool_size = 2)]
|
||||
async fn output_task(
|
||||
ctx: &'static str,
|
||||
mut out: DynPin,
|
||||
receiver: Receiver<'static, ThreadModeRawMutex, GpioCmd, 3>,
|
||||
) {
|
||||
loop {
|
||||
let next_cmd = CHANNEL_PA0_PA1.receive().await;
|
||||
let next_cmd = receiver.receive().await;
|
||||
Timer::after(Duration::from_millis(next_cmd.after_delay.into())).await;
|
||||
match next_cmd.cmd_type {
|
||||
GpioCmdType::SetHigh => {
|
||||
rprintln!("Set output high");
|
||||
rprintln!("{}: Set output high", ctx);
|
||||
out.set_high().unwrap();
|
||||
}
|
||||
GpioCmdType::SetLow => {
|
||||
rprintln!("Set output low");
|
||||
rprintln!("{}: Set output low", ctx);
|
||||
out.set_low().unwrap();
|
||||
}
|
||||
GpioCmdType::RisingEdge => {
|
||||
rprintln!("{}: Rising edge", ctx);
|
||||
if !out.is_low().unwrap() {
|
||||
out.set_low().unwrap();
|
||||
}
|
||||
rprintln!("Rising edge");
|
||||
out.set_high().unwrap();
|
||||
}
|
||||
GpioCmdType::FallingEdge => {
|
||||
rprintln!("{}: Falling edge", ctx);
|
||||
if !out.is_high().unwrap() {
|
||||
out.set_high().unwrap();
|
||||
}
|
||||
rprintln!("Falling edge");
|
||||
out.set_low().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PB22 to PB23 can be handled by both OC10 and OC11 depending on configuration.
|
||||
|
||||
#[interrupt]
|
||||
#[allow(non_snake_case)]
|
||||
fn OC10() {
|
||||
handle_interrupt_for_async_gpio();
|
||||
}
|
||||
|
||||
#[interrupt]
|
||||
#[allow(non_snake_case)]
|
||||
fn OC11() {
|
||||
handle_interrupt_for_async_gpio();
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ async fn main(_spawner: Spawner) {
|
||||
}
|
||||
}
|
||||
|
||||
let porta = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
|
||||
let porta = PinsA::new(&mut dp.sysconfig, 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();
|
||||
|
@ -110,7 +110,7 @@ mod app {
|
||||
let mut dp = cx.device;
|
||||
let nvm = M95M01::new(&mut dp.sysconfig, SYSCLK_FREQ, dp.spic);
|
||||
|
||||
let gpioa = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
|
||||
let gpioa = PinsA::new(&mut dp.sysconfig, dp.porta);
|
||||
let tx = gpioa.pa9.into_funsel_2();
|
||||
let rx = gpioa.pa8.into_funsel_2();
|
||||
|
||||
|
@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- `InvalidPinTypeError` now wraps the pin mode.
|
||||
- I2C `TimingCfg` constructor now returns explicit error instead of generic Error.
|
||||
Removed the timing configuration error type from the generic I2C error enumeration.
|
||||
- `PinsA` and `PinsB` constructor do not expect an optional `pac::Ioconfig` argument anymore.
|
||||
|
||||
## Added
|
||||
|
||||
|
@ -110,7 +110,7 @@ impl InputPinFuture {
|
||||
irq_sel: &mut Irqsel,
|
||||
) -> Result<Self, InvalidPinTypeError> {
|
||||
if !pin.is_input_pin() {
|
||||
return Err(InvalidPinTypeError);
|
||||
return Err(InvalidPinTypeError(pin.mode()));
|
||||
}
|
||||
|
||||
EDGE_DETECTION[pin_id_to_offset(pin.id())]
|
||||
@ -204,7 +204,7 @@ impl InputDynPinAsync {
|
||||
/// the asynchronous functionality to work.
|
||||
pub fn new(pin: DynPin, irq: pac::Interrupt) -> Result<Self, InvalidPinTypeError> {
|
||||
if !pin.is_input_pin() {
|
||||
return Err(InvalidPinTypeError);
|
||||
return Err(InvalidPinTypeError(pin.mode()));
|
||||
}
|
||||
Ok(Self { pin, irq })
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ pub type DynAlternate = FunSel;
|
||||
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[error("Invalid pin type for operation: {0:?}")]
|
||||
pub struct InvalidPinTypeError(DynPinMode);
|
||||
pub struct InvalidPinTypeError(pub DynPinMode);
|
||||
|
||||
impl embedded_hal::digital::Error for InvalidPinTypeError {
|
||||
fn kind(&self) -> embedded_hal::digital::ErrorKind {
|
||||
|
@ -742,7 +742,6 @@ macro_rules! pins {
|
||||
paste!(
|
||||
/// Collection of all the individual [`Pin`]s for a given port (PORTA or PORTB)
|
||||
pub struct $PinsName {
|
||||
iocfg: Option<va108xx::Ioconfig>,
|
||||
port: $Port,
|
||||
$(
|
||||
#[doc = "Pin " $Id]
|
||||
@ -757,7 +756,6 @@ macro_rules! pins {
|
||||
#[inline]
|
||||
pub fn new(
|
||||
syscfg: &mut va108xx::Sysconfig,
|
||||
iocfg: Option<va108xx::Ioconfig>,
|
||||
port: $Port
|
||||
) -> $PinsName {
|
||||
syscfg.peripheral_clk_enable().modify(|_, w| {
|
||||
@ -766,7 +764,7 @@ macro_rules! pins {
|
||||
w.ioconfig().set_bit()
|
||||
});
|
||||
$PinsName {
|
||||
iocfg,
|
||||
//iocfg,
|
||||
port,
|
||||
// Safe because we only create one `Pin` per `PinId`
|
||||
$(
|
||||
@ -783,8 +781,8 @@ macro_rules! pins {
|
||||
}
|
||||
|
||||
/// Consumes the Pins struct and returns the port definitions
|
||||
pub fn release(self) -> (Option<va108xx::Ioconfig>, $Port) {
|
||||
(self.iocfg, self.port)
|
||||
pub fn release(self) -> $Port {
|
||||
self.port
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -73,13 +73,6 @@ impl From<DynPinMode> for ModeFields {
|
||||
//==================================================================================================
|
||||
|
||||
pub type PortReg = ioconfig::Porta;
|
||||
/*
|
||||
pub type IocfgPort = ioconfig::Porta;
|
||||
#[repr(C)]
|
||||
pub(super) struct IocfgPortGroup {
|
||||
port: [IocfgPort; 32],
|
||||
}
|
||||
*/
|
||||
|
||||
/// Provide a safe register interface for pin objects
|
||||
///
|
||||
|
Loading…
x
Reference in New Issue
Block a user