Finished flashloader and bootloader implementation
Some checks are pending
Rust/va108xx-rs/pipeline/pr-main Build queued...
Some checks are pending
Rust/va108xx-rs/pipeline/pr-main Build queued...
This commit is contained in:
@ -9,16 +9,11 @@ cortex-m-rt = "0.7"
|
||||
embedded-hal = "1"
|
||||
embedded-io = "0.6"
|
||||
rtt-target = { version = "0.5" }
|
||||
panic-rtt-target = { version = "0.1" }
|
||||
|
||||
# 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"
|
||||
@ -31,3 +26,19 @@ features = ["cortex-m-systick"]
|
||||
[dependencies.rtic-sync]
|
||||
version = "1.3"
|
||||
features = ["defmt-03"]
|
||||
|
||||
[dependencies.once_cell]
|
||||
version = "1"
|
||||
default-features = false
|
||||
features = ["critical-section"]
|
||||
|
||||
[dependencies.ringbuf]
|
||||
version = "0.4.7"
|
||||
default-features = false
|
||||
features = ["portable-atomic"]
|
||||
|
||||
[dependencies.va108xx-hal]
|
||||
path = "../../va108xx-hal"
|
||||
|
||||
[dependencies.vorago-reb1]
|
||||
path = "../../vorago-reb1"
|
||||
|
143
examples/rtic/src/bin/uart-echo-rtic.rs
Normal file
143
examples/rtic/src/bin/uart-echo-rtic.rs
Normal file
@ -0,0 +1,143 @@
|
||||
//! 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. All received data will be sent back to the sender.
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use ringbuf::StaticRb;
|
||||
|
||||
// Larger buffer for TC to be able to hold the possibly large memory write packets.
|
||||
const RX_RING_BUF_SIZE: usize = 1024;
|
||||
|
||||
// Ring buffers to handling variable sized telemetry
|
||||
static mut RINGBUF: Lazy<StaticRb<u8, RX_RING_BUF_SIZE>> =
|
||||
Lazy::new(StaticRb::<u8, RX_RING_BUF_SIZE>::default);
|
||||
|
||||
#[rtic::app(device = pac, dispatchers = [OC4])]
|
||||
mod app {
|
||||
use super::*;
|
||||
use embedded_io::Write;
|
||||
use panic_rtt_target as _;
|
||||
use ringbuf::{
|
||||
traits::{Consumer, Observer, Producer, SplitRef},
|
||||
CachingCons, StaticProd,
|
||||
};
|
||||
use rtic_example::SYSCLK_FREQ;
|
||||
use rtic_monotonics::Monotonic;
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use va108xx_hal::{
|
||||
gpio::PinsA,
|
||||
pac,
|
||||
prelude::*,
|
||||
uart::{self, RxWithIrq, Tx},
|
||||
};
|
||||
|
||||
#[local]
|
||||
struct Local {
|
||||
data_producer: StaticProd<'static, u8, RX_RING_BUF_SIZE>,
|
||||
data_consumer: CachingCons<&'static StaticRb<u8, RX_RING_BUF_SIZE>>,
|
||||
rx: RxWithIrq<pac::Uarta>,
|
||||
tx: Tx<pac::Uarta>,
|
||||
}
|
||||
|
||||
#[shared]
|
||||
struct Shared {}
|
||||
|
||||
rtic_monotonics::systick_monotonic!(Mono, 1_000);
|
||||
|
||||
#[init]
|
||||
fn init(cx: init::Context) -> (Shared, Local) {
|
||||
rtt_init_print!();
|
||||
rprintln!("-- VA108xx UART Echo with IRQ example application--");
|
||||
|
||||
Mono::start(cx.core.SYST, SYSCLK_FREQ.raw());
|
||||
|
||||
let mut dp = cx.device;
|
||||
let gpioa = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
|
||||
let tx = gpioa.pa9.into_funsel_2();
|
||||
let rx = gpioa.pa8.into_funsel_2();
|
||||
|
||||
let irq_uart = uart::Uart::new(
|
||||
&mut dp.sysconfig,
|
||||
SYSCLK_FREQ,
|
||||
dp.uarta,
|
||||
(tx, rx),
|
||||
115200.Hz(),
|
||||
);
|
||||
let (tx, rx) = irq_uart.split();
|
||||
let mut rx = rx.into_rx_with_irq(&mut dp.sysconfig, &mut dp.irqsel, pac::interrupt::OC3);
|
||||
|
||||
rx.start();
|
||||
|
||||
let (data_producer, data_consumer) = unsafe { RINGBUF.split_ref() };
|
||||
echo_handler::spawn().unwrap();
|
||||
(
|
||||
Shared {},
|
||||
Local {
|
||||
data_producer,
|
||||
data_consumer,
|
||||
rx,
|
||||
tx,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// `shared` cannot be accessed from this context
|
||||
#[idle]
|
||||
fn idle(_cx: idle::Context) -> ! {
|
||||
loop {
|
||||
cortex_m::asm::nop();
|
||||
}
|
||||
}
|
||||
|
||||
#[task(
|
||||
binds = OC3,
|
||||
shared = [],
|
||||
local = [
|
||||
rx,
|
||||
data_producer
|
||||
],
|
||||
)]
|
||||
fn reception_task(cx: reception_task::Context) {
|
||||
let mut buf: [u8; 16] = [0; 16];
|
||||
let mut ringbuf_full = false;
|
||||
let result = cx.local.rx.irq_handler(&mut buf);
|
||||
if result.bytes_read > 0 && result.errors.is_none() {
|
||||
if cx.local.data_producer.vacant_len() < result.bytes_read {
|
||||
ringbuf_full = true;
|
||||
} else {
|
||||
cx.local
|
||||
.data_producer
|
||||
.push_slice(&buf[0..result.bytes_read]);
|
||||
}
|
||||
}
|
||||
if ringbuf_full {
|
||||
// Could also drop oldest data, but that would require the consumer to be shared.
|
||||
rprintln!("buffer full, data was dropped");
|
||||
}
|
||||
}
|
||||
|
||||
#[task(shared = [], local = [
|
||||
buf: [u8; RX_RING_BUF_SIZE] = [0; RX_RING_BUF_SIZE],
|
||||
data_consumer,
|
||||
tx
|
||||
], priority=1)]
|
||||
async fn echo_handler(cx: echo_handler::Context) {
|
||||
loop {
|
||||
let bytes_to_read = cx.local.data_consumer.occupied_len();
|
||||
if bytes_to_read > 0 {
|
||||
let actual_read_bytes = cx
|
||||
.local
|
||||
.data_consumer
|
||||
.pop_slice(&mut cx.local.buf[0..bytes_to_read]);
|
||||
cx.local
|
||||
.tx
|
||||
.write_all(&cx.local.buf[0..actual_read_bytes])
|
||||
.expect("Failed to write to TX");
|
||||
}
|
||||
Mono::delay(50.millis()).await;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,165 +0,0 @@
|
||||
//! 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -16,8 +16,8 @@ use va108xx_hal::{
|
||||
gpio::PinsA,
|
||||
pac::{self, interrupt},
|
||||
prelude::*,
|
||||
pwm::{default_ms_irq_handler, set_up_ms_tick, CountDownTimer},
|
||||
timer::DelayMs,
|
||||
timer::{default_ms_irq_handler, set_up_ms_tick, CountdownTimer},
|
||||
IrqCfg,
|
||||
};
|
||||
|
||||
@ -32,7 +32,7 @@ fn main() -> ! {
|
||||
dp.tim0,
|
||||
))
|
||||
.unwrap();
|
||||
let mut delay_tim1 = CountDownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim1);
|
||||
let mut delay_tim1 = CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim1);
|
||||
let porta = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
|
||||
let mut led1 = porta.pa10.into_readable_push_pull_output();
|
||||
let mut led2 = porta.pa7.into_readable_push_pull_output();
|
||||
|
@ -17,13 +17,13 @@ use va108xx_hal::{
|
||||
prelude::*,
|
||||
timer::{
|
||||
default_ms_irq_handler, set_up_ms_delay_provider, CascadeCtrl, CascadeSource,
|
||||
CountDownTimer, Event, IrqCfg,
|
||||
CountdownTimer, Event, IrqCfg,
|
||||
},
|
||||
};
|
||||
|
||||
static CSD_TGT_1: Mutex<RefCell<Option<CountDownTimer<pac::Tim4>>>> =
|
||||
static CSD_TGT_1: Mutex<RefCell<Option<CountdownTimer<pac::Tim4>>>> =
|
||||
Mutex::new(RefCell::new(None));
|
||||
static CSD_TGT_2: Mutex<RefCell<Option<CountDownTimer<pac::Tim5>>>> =
|
||||
static CSD_TGT_2: Mutex<RefCell<Option<CountdownTimer<pac::Tim5>>>> =
|
||||
Mutex::new(RefCell::new(None));
|
||||
|
||||
#[entry]
|
||||
@ -36,7 +36,7 @@ fn main() -> ! {
|
||||
|
||||
// Will be started periodically to trigger a cascade
|
||||
let mut cascade_triggerer =
|
||||
CountDownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim3).auto_disable(true);
|
||||
CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim3).auto_disable(true);
|
||||
cascade_triggerer.listen(
|
||||
Event::TimeOut,
|
||||
IrqCfg::new(pac::Interrupt::OC1, true, false),
|
||||
@ -46,7 +46,7 @@ fn main() -> ! {
|
||||
|
||||
// First target for cascade
|
||||
let mut cascade_target_1 =
|
||||
CountDownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim4).auto_deactivate(true);
|
||||
CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim4).auto_deactivate(true);
|
||||
cascade_target_1
|
||||
.cascade_0_source(CascadeSource::Tim(3))
|
||||
.expect("Configuring cascade source for TIM4 failed");
|
||||
@ -72,7 +72,7 @@ fn main() -> ! {
|
||||
|
||||
// Activated by first cascade target
|
||||
let mut cascade_target_2 =
|
||||
CountDownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim5).auto_deactivate(true);
|
||||
CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim5).auto_deactivate(true);
|
||||
// Set TIM4 as cascade source
|
||||
cascade_target_2
|
||||
.cascade_1_source(CascadeSource::Tim(4))
|
||||
|
@ -15,8 +15,8 @@ use va108xx_hal::{
|
||||
gpio::{PinsA, PinsB},
|
||||
pac::{self, interrupt},
|
||||
prelude::*,
|
||||
pwm::{default_ms_irq_handler, set_up_ms_tick},
|
||||
spi::{self, Spi, SpiBase, SpiClkConfig, TransferConfigWithHwcs},
|
||||
timer::{default_ms_irq_handler, set_up_ms_tick},
|
||||
IrqCfg,
|
||||
};
|
||||
|
||||
|
@ -12,7 +12,7 @@ use va108xx_hal::{
|
||||
pac::{self, interrupt},
|
||||
prelude::*,
|
||||
time::Hertz,
|
||||
timer::{default_ms_irq_handler, set_up_ms_tick, CountDownTimer, Event, IrqCfg, MS_COUNTER},
|
||||
timer::{default_ms_irq_handler, set_up_ms_tick, CountdownTimer, Event, IrqCfg, MS_COUNTER},
|
||||
};
|
||||
|
||||
#[allow(dead_code)]
|
||||
@ -72,7 +72,7 @@ fn main() -> ! {
|
||||
dp.tim0,
|
||||
);
|
||||
let mut second_timer =
|
||||
CountDownTimer::new(&mut dp.sysconfig, get_sys_clock().unwrap(), dp.tim1);
|
||||
CountdownTimer::new(&mut dp.sysconfig, get_sys_clock().unwrap(), dp.tim1);
|
||||
second_timer.listen(
|
||||
Event::TimeOut,
|
||||
IrqCfg::new(interrupt::OC1, true, true),
|
||||
|
Reference in New Issue
Block a user