- Add embassy example - improve timer API - restructure examples - restructure and improve SPI - Add REB1 M95M01 NVM module
This commit is contained in:
33
examples/rtic/Cargo.toml
Normal file
33
examples/rtic/Cargo.toml
Normal file
@ -0,0 +1,33 @@
|
||||
[package]
|
||||
name = "rtic-example"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
|
||||
cortex-m-rt = "0.7"
|
||||
embedded-hal = "1"
|
||||
embedded-io = "0.6"
|
||||
rtt-target = { version = "0.5" }
|
||||
# Even though we do not use this directly, we need to activate this feature explicitely
|
||||
# so that RTIC compiles because thumv6 does not have CAS operations natively.
|
||||
portable-atomic = { version = "1", features = ["unsafe-assume-single-core"]}
|
||||
panic-rtt-target = { version = "0.1" }
|
||||
|
||||
[dependencies.va108xx-hal]
|
||||
path = "../../va108xx-hal"
|
||||
|
||||
[dependencies.vorago-reb1]
|
||||
path = "../../vorago-reb1"
|
||||
|
||||
[dependencies.rtic]
|
||||
version = "2"
|
||||
features = ["thumbv6-backend"]
|
||||
|
||||
[dependencies.rtic-monotonics]
|
||||
version = "2"
|
||||
features = ["cortex-m-systick"]
|
||||
|
||||
[dependencies.rtic-sync]
|
||||
version = "1.3"
|
||||
features = ["defmt-03"]
|
144
examples/rtic/src/bin/blinky-button-rtic.rs
Normal file
144
examples/rtic/src/bin/blinky-button-rtic.rs
Normal file
@ -0,0 +1,144 @@
|
||||
//! Blinky button application for the REB1 board using RTIC
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
#[rtic::app(device = pac)]
|
||||
mod app {
|
||||
use panic_rtt_target as _;
|
||||
use rtic_example::SYSCLK_FREQ;
|
||||
use rtt_target::{rprintln, rtt_init_default, set_print_channel};
|
||||
use va108xx_hal::{
|
||||
clock::{set_clk_div_register, FilterClkSel},
|
||||
gpio::{FilterType, InterruptEdge, PinsA},
|
||||
pac,
|
||||
prelude::*,
|
||||
timer::{default_ms_irq_handler, set_up_ms_tick, IrqCfg},
|
||||
};
|
||||
use vorago_reb1::button::Button;
|
||||
use vorago_reb1::leds::Leds;
|
||||
|
||||
rtic_monotonics::systick_monotonic!(Mono, 1_000);
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum PressMode {
|
||||
Toggle,
|
||||
Keep,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum CfgMode {
|
||||
Prompt,
|
||||
Fixed,
|
||||
}
|
||||
|
||||
const CFG_MODE: CfgMode = CfgMode::Fixed;
|
||||
// You can change the press mode here
|
||||
const DEFAULT_MODE: PressMode = PressMode::Toggle;
|
||||
|
||||
#[local]
|
||||
struct Local {
|
||||
leds: Leds,
|
||||
button: Button,
|
||||
mode: PressMode,
|
||||
}
|
||||
|
||||
#[shared]
|
||||
struct Shared {}
|
||||
|
||||
#[init]
|
||||
fn init(cx: init::Context) -> (Shared, Local) {
|
||||
let channels = rtt_init_default!();
|
||||
set_print_channel(channels.up.0);
|
||||
rprintln!("-- Vorago Button IRQ Example --");
|
||||
Mono::start(cx.core.SYST, SYSCLK_FREQ.raw());
|
||||
|
||||
let mode = match CFG_MODE {
|
||||
// Ask mode from user via RTT
|
||||
CfgMode::Prompt => prompt_mode(channels.down.0),
|
||||
// Use mode hardcoded in `DEFAULT_MODE`
|
||||
CfgMode::Fixed => DEFAULT_MODE,
|
||||
};
|
||||
rprintln!("Using {:?} mode", mode);
|
||||
|
||||
let mut dp = cx.device;
|
||||
let pinsa = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
|
||||
let edge_irq = match mode {
|
||||
PressMode::Toggle => InterruptEdge::HighToLow,
|
||||
PressMode::Keep => InterruptEdge::BothEdges,
|
||||
};
|
||||
|
||||
// Configure an edge interrupt on the button and route it to interrupt vector 15
|
||||
let mut button = Button::new(pinsa.pa11.into_floating_input()).edge_irq(
|
||||
edge_irq,
|
||||
IrqCfg::new(pac::interrupt::OC15, true, true),
|
||||
Some(&mut dp.sysconfig),
|
||||
Some(&mut dp.irqsel),
|
||||
);
|
||||
|
||||
if mode == PressMode::Toggle {
|
||||
// This filter debounces the switch for edge based interrupts
|
||||
button = button.filter_type(FilterType::FilterFourClockCycles, FilterClkSel::Clk1);
|
||||
set_clk_div_register(&mut dp.sysconfig, FilterClkSel::Clk1, 50_000);
|
||||
}
|
||||
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() {
|
||||
led.off();
|
||||
}
|
||||
set_up_ms_tick(
|
||||
IrqCfg::new(pac::Interrupt::OC0, true, true),
|
||||
&mut dp.sysconfig,
|
||||
Some(&mut dp.irqsel),
|
||||
50.MHz(),
|
||||
dp.tim0,
|
||||
);
|
||||
(Shared {}, Local { leds, button, mode })
|
||||
}
|
||||
|
||||
// `shared` cannot be accessed from this context
|
||||
#[idle]
|
||||
fn idle(_cx: idle::Context) -> ! {
|
||||
loop {
|
||||
cortex_m::asm::nop();
|
||||
}
|
||||
}
|
||||
|
||||
#[task(binds = OC15, local=[button, leds, mode])]
|
||||
fn button_task(cx: button_task::Context) {
|
||||
let leds = cx.local.leds;
|
||||
let button = cx.local.button;
|
||||
let mode = cx.local.mode;
|
||||
if *mode == PressMode::Toggle {
|
||||
leds[0].toggle();
|
||||
} else if button.released() {
|
||||
leds[0].off();
|
||||
} else {
|
||||
leds[0].on();
|
||||
}
|
||||
}
|
||||
|
||||
#[task(binds = OC0)]
|
||||
fn ms_tick(_cx: ms_tick::Context) {
|
||||
default_ms_irq_handler();
|
||||
}
|
||||
|
||||
fn prompt_mode(mut down_channel: rtt_target::DownChannel) -> PressMode {
|
||||
rprintln!("Using prompt mode");
|
||||
rprintln!("Please enter the mode [0: Toggle, 1: Keep]");
|
||||
let mut read_buf: [u8; 16] = [0; 16];
|
||||
let mut read;
|
||||
loop {
|
||||
read = down_channel.read(&mut read_buf);
|
||||
for &byte in &read_buf[..read] {
|
||||
match byte as char {
|
||||
'0' => return PressMode::Toggle,
|
||||
'1' => return PressMode::Keep,
|
||||
_ => continue, // Ignore other characters
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
30
examples/rtic/src/bin/rtic-empty.rs
Normal file
30
examples/rtic/src/bin/rtic-empty.rs
Normal file
@ -0,0 +1,30 @@
|
||||
//! Empty RTIC project template
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
#[rtic::app(device = pac)]
|
||||
mod app {
|
||||
use panic_rtt_target as _;
|
||||
use rtt_target::{rprintln, rtt_init_default};
|
||||
use va108xx_hal::pac;
|
||||
|
||||
#[local]
|
||||
struct Local {}
|
||||
|
||||
#[shared]
|
||||
struct Shared {}
|
||||
|
||||
#[init]
|
||||
fn init(_ctx: init::Context) -> (Shared, Local) {
|
||||
rtt_init_default!();
|
||||
rprintln!("-- Vorago RTIC template --");
|
||||
(Shared {}, Local {})
|
||||
}
|
||||
|
||||
// `shared` cannot be accessed from this context
|
||||
#[idle]
|
||||
fn idle(_cx: idle::Context) -> ! {
|
||||
#[allow(clippy::empty_loop)]
|
||||
loop {}
|
||||
}
|
||||
}
|
165
examples/rtic/src/bin/uart-rtic.rs
Normal file
165
examples/rtic/src/bin/uart-rtic.rs
Normal file
@ -0,0 +1,165 @@
|
||||
//! More complex UART application
|
||||
//!
|
||||
//! Uses the IRQ capabilities of the VA10820 peripheral and the RTIC framework to poll the UART in
|
||||
//! a non-blocking way. You can send variably sized strings to the VA10820 which will be echoed
|
||||
//! back to the sender.
|
||||
//!
|
||||
//! This script was tested with an Arduino Due. You can find the test script in the
|
||||
//! [`/test/DueSerialTest`](https://egit.irs.uni-stuttgart.de/rust/va108xx-hal/src/branch/main/test/DueSerialTest)
|
||||
//! folder.
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
#[rtic::app(device = pac, dispatchers = [OC4])]
|
||||
mod app {
|
||||
use embedded_io::Write;
|
||||
use panic_rtt_target as _;
|
||||
use rtic_example::SYSCLK_FREQ;
|
||||
use rtic_sync::make_channel;
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use va108xx_hal::{
|
||||
gpio::PinsB,
|
||||
pac,
|
||||
prelude::*,
|
||||
uart::{self, IrqCfg, IrqResult, UartWithIrqBase},
|
||||
};
|
||||
|
||||
#[local]
|
||||
struct Local {
|
||||
rx_info_tx: rtic_sync::channel::Sender<'static, RxInfo, 3>,
|
||||
rx_info_rx: rtic_sync::channel::Receiver<'static, RxInfo, 3>,
|
||||
}
|
||||
|
||||
#[shared]
|
||||
struct Shared {
|
||||
irq_uart: UartWithIrqBase<pac::Uartb>,
|
||||
rx_buf: [u8; 64],
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct RxInfo {
|
||||
pub bytes_read: usize,
|
||||
pub end_idx: usize,
|
||||
pub timeout: bool,
|
||||
}
|
||||
|
||||
rtic_monotonics::systick_monotonic!(Mono, 1_000);
|
||||
|
||||
#[init]
|
||||
fn init(cx: init::Context) -> (Shared, Local) {
|
||||
rtt_init_print!();
|
||||
rprintln!("-- VA108xx UART IRQ example application--");
|
||||
|
||||
Mono::start(cx.core.SYST, SYSCLK_FREQ.raw());
|
||||
|
||||
let mut dp = cx.device;
|
||||
let gpiob = PinsB::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.portb);
|
||||
let tx = gpiob.pb21.into_funsel_1();
|
||||
let rx = gpiob.pb20.into_funsel_1();
|
||||
|
||||
let irq_cfg = IrqCfg::new(pac::interrupt::OC3, true, true);
|
||||
let (mut irq_uart, _) =
|
||||
uart::Uart::new(&mut dp.sysconfig, 50.MHz(), dp.uartb, (tx, rx), 115200.Hz())
|
||||
.into_uart_with_irq(irq_cfg, Some(&mut dp.sysconfig), Some(&mut dp.irqsel))
|
||||
.downgrade();
|
||||
irq_uart
|
||||
.read_fixed_len_using_irq(64, true)
|
||||
.expect("Read initialization failed");
|
||||
|
||||
let (rx_info_tx, rx_info_rx) = make_channel!(RxInfo, 3);
|
||||
let rx_buf: [u8; 64] = [0; 64];
|
||||
(
|
||||
Shared { irq_uart, rx_buf },
|
||||
Local {
|
||||
rx_info_tx,
|
||||
rx_info_rx,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// `shared` cannot be accessed from this context
|
||||
#[idle]
|
||||
fn idle(_cx: idle::Context) -> ! {
|
||||
loop {
|
||||
cortex_m::asm::nop();
|
||||
}
|
||||
}
|
||||
|
||||
#[task(
|
||||
binds = OC3,
|
||||
shared = [irq_uart, rx_buf],
|
||||
local = [cnt: u32 = 0, result: IrqResult = IrqResult::new(), rx_info_tx],
|
||||
)]
|
||||
fn reception_task(cx: reception_task::Context) {
|
||||
let result = cx.local.result;
|
||||
let cnt: &mut u32 = cx.local.cnt;
|
||||
let irq_uart = cx.shared.irq_uart;
|
||||
let rx_buf = cx.shared.rx_buf;
|
||||
let (completed, end_idx) = (irq_uart, rx_buf).lock(|irq_uart, rx_buf| {
|
||||
match irq_uart.irq_handler(result, rx_buf) {
|
||||
Ok(_) => {
|
||||
if result.complete() {
|
||||
// Initiate next transfer immediately
|
||||
irq_uart
|
||||
.read_fixed_len_using_irq(64, true)
|
||||
.expect("Read operation init failed");
|
||||
|
||||
let mut end_idx = 0;
|
||||
for (idx, val) in rx_buf.iter().enumerate() {
|
||||
if (*val as char) == '\n' {
|
||||
end_idx = idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
(true, end_idx)
|
||||
} else {
|
||||
(false, 0)
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
rprintln!("reception error {:?}", e);
|
||||
(false, 0)
|
||||
}
|
||||
}
|
||||
});
|
||||
if completed {
|
||||
rprintln!("counter: {}", cnt);
|
||||
cx.local
|
||||
.rx_info_tx
|
||||
.try_send(RxInfo {
|
||||
bytes_read: result.bytes_read,
|
||||
end_idx,
|
||||
timeout: result.timeout(),
|
||||
})
|
||||
.expect("RX queue full");
|
||||
}
|
||||
*cnt += 1;
|
||||
}
|
||||
|
||||
#[task(shared = [irq_uart, rx_buf], local = [rx_info_rx], priority=1)]
|
||||
async fn reply_handler(cx: reply_handler::Context) {
|
||||
let mut irq_uart = cx.shared.irq_uart;
|
||||
let mut rx_buf = cx.shared.rx_buf;
|
||||
loop {
|
||||
match cx.local.rx_info_rx.recv().await {
|
||||
Ok(rx_info) => {
|
||||
rprintln!("reception success, {} bytes read", rx_info.bytes_read);
|
||||
if rx_info.timeout {
|
||||
rprintln!("timeout occurred");
|
||||
}
|
||||
rx_buf.lock(|rx_buf| {
|
||||
let string = core::str::from_utf8(&rx_buf[0..rx_info.end_idx])
|
||||
.expect("Invalid string format");
|
||||
rprintln!("read string: {}", string);
|
||||
irq_uart.lock(|uart| {
|
||||
writeln!(uart.uart, "{}", string).expect("Sending reply failed");
|
||||
});
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
rprintln!("error receiving RX info: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
4
examples/rtic/src/lib.rs
Normal file
4
examples/rtic/src/lib.rs
Normal file
@ -0,0 +1,4 @@
|
||||
#![no_std]
|
||||
use va108xx_hal::time::Hertz;
|
||||
|
||||
pub const SYSCLK_FREQ: Hertz = Hertz::from_raw(50_000_000);
|
71
examples/rtic/src/main.rs
Normal file
71
examples/rtic/src/main.rs
Normal file
@ -0,0 +1,71 @@
|
||||
//! RTIC minimal blinky
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
#[rtic::app(device = pac, dispatchers = [OC31, OC30, OC29])]
|
||||
mod app {
|
||||
use cortex_m::asm;
|
||||
use embedded_hal::digital::StatefulOutputPin;
|
||||
use panic_rtt_target as _;
|
||||
use rtic_example::SYSCLK_FREQ;
|
||||
use rtic_monotonics::systick::prelude::*;
|
||||
use rtic_monotonics::Monotonic;
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use va108xx_hal::{
|
||||
gpio::{OutputReadablePushPull, Pin, PinsA, PA10, PA6, PA7},
|
||||
pac,
|
||||
};
|
||||
|
||||
#[local]
|
||||
struct Local {
|
||||
led0: Pin<PA10, OutputReadablePushPull>,
|
||||
led1: Pin<PA7, OutputReadablePushPull>,
|
||||
led2: Pin<PA6, OutputReadablePushPull>,
|
||||
}
|
||||
|
||||
#[shared]
|
||||
struct Shared {}
|
||||
|
||||
rtic_monotonics::systick_monotonic!(Mono, 1_000);
|
||||
|
||||
#[init]
|
||||
fn init(mut cx: init::Context) -> (Shared, Local) {
|
||||
rtt_init_print!();
|
||||
rprintln!("-- Vorago VA108xx RTIC template --");
|
||||
|
||||
Mono::start(cx.core.SYST, SYSCLK_FREQ.raw());
|
||||
|
||||
let porta = PinsA::new(
|
||||
&mut cx.device.sysconfig,
|
||||
Some(cx.device.ioconfig),
|
||||
cx.device.porta,
|
||||
);
|
||||
let led0 = porta.pa10.into_readable_push_pull_output();
|
||||
let led1 = porta.pa7.into_readable_push_pull_output();
|
||||
let led2 = porta.pa6.into_readable_push_pull_output();
|
||||
blinky::spawn().ok();
|
||||
(Shared {}, Local { led0, led1, led2 })
|
||||
}
|
||||
|
||||
// `shared` cannot be accessed from this context
|
||||
#[idle]
|
||||
fn idle(_cx: idle::Context) -> ! {
|
||||
loop {
|
||||
asm::nop();
|
||||
}
|
||||
}
|
||||
|
||||
#[task(
|
||||
priority = 3,
|
||||
local=[led0, led1, led2],
|
||||
)]
|
||||
async fn blinky(cx: blinky::Context) {
|
||||
loop {
|
||||
rprintln!("toggling LEDs");
|
||||
cx.local.led0.toggle().ok();
|
||||
cx.local.led1.toggle().ok();
|
||||
cx.local.led2.toggle().ok();
|
||||
Mono::delay(1000.millis()).await;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user