Merge pull request 'start switching to defmt' (#67) from add-defmt-support into main
Reviewed-on: #67
This commit is contained in:
commit
d641f3943f
@ -2,18 +2,15 @@
|
||||
# runner = "gdb-multiarch -q -x jlink/jlink.gdb"
|
||||
# runner = "arm-none-eabi-gdb -q -x jlink/jlink-reva.gdb"
|
||||
# runner = "gdb-multiarch -q -x jlink/jlink-reva.gdb"
|
||||
|
||||
# Probe-rs is currently problematic, possibly because of the
|
||||
# ROM protection?
|
||||
runner = "probe-rs run --chip VA416xx_RAM --protocol swd"
|
||||
|
||||
rustflags = [
|
||||
"-C",
|
||||
"link-arg=-Tlink.x",
|
||||
# "-C",
|
||||
# "linker=flip-link",
|
||||
# "-C",
|
||||
# "link-arg=-Tdefmt.x",
|
||||
"-C",
|
||||
"linker=flip-link",
|
||||
"-C",
|
||||
"link-arg=-Tdefmt.x",
|
||||
# This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x
|
||||
# See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
|
||||
"-C",
|
||||
@ -37,4 +34,4 @@ ut = "test --target=x86_64-unknown-linux-gnu"
|
||||
genbin = "objcopy --release -- -O binary app.bin"
|
||||
|
||||
[env]
|
||||
DEFMT_LOG = "info"
|
||||
DEFMT_LOG = "debug"
|
||||
|
28
README.md
28
README.md
@ -74,8 +74,8 @@ probe-rs run --chip VA416xx_RAM --protocol jtag target/thumbv7em-none-eabihf/deb
|
||||
to flash and run the blinky program on the RAM. There is also a `VA416xx` chip target
|
||||
available for persistent flashing.
|
||||
|
||||
Runner configuration avilable in the `.cargo/def-config.toml` file to use `probe-rs` for
|
||||
convenience.
|
||||
Runner configuration is available in the `.cargo/def-config.toml` file to use `probe-rs` for
|
||||
convenience. `probe-rs` is also able to process and display `defmt` strings directly.
|
||||
|
||||
### Pre-Requisites
|
||||
|
||||
@ -123,16 +123,25 @@ You can build the blinky example application with the following command
|
||||
cargo build --example blinky
|
||||
```
|
||||
|
||||
Start the GDB server first. The server needs to be started with a certain configuration and with
|
||||
a JLink script to disable ROM protection.
|
||||
Start the GDB server first. Depending on whether the application is flashed to RAM or the NVM
|
||||
flash memory, the server needs to be started with a different configuration
|
||||
For example, on Debian based system the following command can be used to do this (this command
|
||||
is also run when running the `jlink-gdb.sh` script)
|
||||
|
||||
**RAM Flash**
|
||||
|
||||
```sh
|
||||
JLinkGDBServer -select USB -device Cortex-M4 -endian little -if SWD -speed 2000 \
|
||||
-LocalhostOnly -vd -jlinkscriptfile ./jlink/JLinkSettings.JLinkScript
|
||||
```
|
||||
|
||||
**NVM Flash**
|
||||
|
||||
```sh
|
||||
JLinkGDBServer -select USB -device VA416xx -endian little -if SWD -speed 2000 \
|
||||
-LocalhostOnly -vd
|
||||
```
|
||||
|
||||
After this, you can flash and debug the application with the following command
|
||||
|
||||
```sh
|
||||
@ -144,7 +153,7 @@ runner configuration, for example with the following lines in your `.cargo/confi
|
||||
|
||||
```toml
|
||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||
runner = "gdb-multiarch -q -x jlink/jlink.gdb"
|
||||
runner = "gdb-multiarch -q -x jlink/jlink.gdb -tui"
|
||||
```
|
||||
|
||||
After that, you can simply use `cargo run --example blinky` to flash the blinky
|
||||
@ -156,6 +165,15 @@ The Segger RTT viewer can be used to display log messages received from the targ
|
||||
address for the RTT block placement is 0x1fff8000. It is recommended to use a search range of
|
||||
0x1000 around that base address when using the RTT viewer.
|
||||
|
||||
The RTT viewer will not be able to process `defmt` printouts. However, you can view the defmt
|
||||
logs by [installing defmt-print](https://crates.io/crates/defmt-print) first and then running
|
||||
|
||||
```sh
|
||||
defmt-print -e <pathToElfFile> tcp
|
||||
```
|
||||
|
||||
The path of the ELF file which is being debugged needs to be specified for this to work.
|
||||
|
||||
## Learning (Embedded) Rust
|
||||
|
||||
If you are unfamiliar with Rust on Embedded Systems or Rust in general, the following resources
|
||||
|
@ -7,16 +7,12 @@ edition = "2021"
|
||||
cortex-m = "0.7"
|
||||
cortex-m-rt = "0.7"
|
||||
embedded-hal = "1"
|
||||
panic-rtt-target = { version = "0.2" }
|
||||
panic-halt = { version = "1" }
|
||||
rtt-target = { version = "0.6" }
|
||||
defmt-rtt = "0.4"
|
||||
defmt = "1"
|
||||
panic-probe = { version = "1", features = ["defmt"] }
|
||||
crc = "3"
|
||||
static_assertions = "1"
|
||||
|
||||
[dependencies.va416xx-hal]
|
||||
version = "0.5"
|
||||
features = ["va41630"]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
rtt-panic = []
|
||||
features = ["va41630", "defmt"]
|
||||
|
@ -7,11 +7,8 @@
|
||||
|
||||
use cortex_m_rt::entry;
|
||||
use crc::{Crc, CRC_32_ISO_HDLC};
|
||||
#[cfg(not(feature = "rtt-panic"))]
|
||||
use panic_halt as _;
|
||||
#[cfg(feature = "rtt-panic")]
|
||||
use panic_rtt_target as _;
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use defmt_rtt as _;
|
||||
use panic_probe as _;
|
||||
use va416xx_hal::{
|
||||
clock::{pll_setup_delay, ClkDivSel, ClkselSys},
|
||||
edac,
|
||||
@ -35,7 +32,7 @@ const DEBUG_PRINTOUTS: bool = true;
|
||||
const FLASH_SELF: bool = false;
|
||||
// Useful for debugging and see what the bootloader is doing. Enabled currently, because
|
||||
// the binary stays small enough.
|
||||
const RTT_PRINTOUT: bool = true;
|
||||
const DEFMT_PRINTOUTS: bool = true;
|
||||
|
||||
// Important bootloader addresses and offsets, vector table information.
|
||||
|
||||
@ -76,7 +73,7 @@ pub const RESET_VECTOR_OFFSET: u32 = 0x4;
|
||||
|
||||
const CRC_ALGO: Crc<u32> = Crc::<u32>::new(&CRC_32_ISO_HDLC);
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, defmt::Format)]
|
||||
enum AppSel {
|
||||
A,
|
||||
B,
|
||||
@ -98,9 +95,8 @@ impl WdtInterface for OptWdt {
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
if RTT_PRINTOUT {
|
||||
rtt_init_print!();
|
||||
rprintln!("-- VA416xx bootloader --");
|
||||
if DEFMT_PRINTOUTS {
|
||||
defmt::println!("-- VA416xx bootloader --");
|
||||
}
|
||||
let mut dp = pac::Peripherals::take().unwrap();
|
||||
let cp = cortex_m::Peripherals::take().unwrap();
|
||||
@ -145,20 +141,20 @@ fn main() -> ! {
|
||||
nvm.write_data(0x0, &first_four_bytes);
|
||||
nvm.write_data(0x4, bootloader_data);
|
||||
if let Err(e) = nvm.verify_data(0x0, &first_four_bytes) {
|
||||
if RTT_PRINTOUT {
|
||||
rprintln!("verification of self-flash to NVM failed: {:?}", e);
|
||||
if DEFMT_PRINTOUTS {
|
||||
defmt::error!("verification of self-flash to NVM failed: {:?}", e);
|
||||
}
|
||||
}
|
||||
if let Err(e) = nvm.verify_data(0x4, bootloader_data) {
|
||||
if RTT_PRINTOUT {
|
||||
rprintln!("verification of self-flash to NVM failed: {:?}", e);
|
||||
if DEFMT_PRINTOUTS {
|
||||
defmt::error!("verification of self-flash to NVM failed: {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
nvm.write_data(BOOTLOADER_CRC_ADDR, &bootloader_crc.to_be_bytes());
|
||||
if let Err(e) = nvm.verify_data(BOOTLOADER_CRC_ADDR, &bootloader_crc.to_be_bytes()) {
|
||||
if RTT_PRINTOUT {
|
||||
rprintln!(
|
||||
if DEFMT_PRINTOUTS {
|
||||
defmt::error!(
|
||||
"error: CRC verification for bootloader self-flash failed: {:?}",
|
||||
e
|
||||
);
|
||||
@ -174,8 +170,8 @@ fn main() -> ! {
|
||||
} else if check_app_crc(AppSel::B, &opt_wdt) {
|
||||
boot_app(AppSel::B, &cp)
|
||||
} else {
|
||||
if DEBUG_PRINTOUTS && RTT_PRINTOUT {
|
||||
rprintln!("both images corrupt! booting image A");
|
||||
if DEBUG_PRINTOUTS && DEFMT_PRINTOUTS {
|
||||
defmt::println!("both images corrupt! booting image A");
|
||||
}
|
||||
// TODO: Shift a CCSDS packet out to inform host/OBC about image corruption.
|
||||
// Both images seem to be corrupt. Boot default image A.
|
||||
@ -202,8 +198,8 @@ fn check_own_crc(wdt: &OptWdt, nvm: &Nvm, cp: &cortex_m::Peripherals) {
|
||||
let crc_calc = digest.finalize();
|
||||
wdt.feed();
|
||||
if crc_exp == 0x0000 || crc_exp == 0xffff {
|
||||
if DEBUG_PRINTOUTS && RTT_PRINTOUT {
|
||||
rprintln!("BL CRC blank - prog new CRC");
|
||||
if DEBUG_PRINTOUTS && DEFMT_PRINTOUTS {
|
||||
defmt::info!("BL CRC blank - prog new CRC");
|
||||
}
|
||||
// Blank CRC, write it to NVM.
|
||||
nvm.write_data(BOOTLOADER_CRC_ADDR, &crc_calc.to_be_bytes());
|
||||
@ -212,8 +208,8 @@ fn check_own_crc(wdt: &OptWdt, nvm: &Nvm, cp: &cortex_m::Peripherals) {
|
||||
// cortex_m::peripheral::SCB::sys_reset();
|
||||
} else if crc_exp != crc_calc {
|
||||
// Bootloader is corrupted. Try to run App A.
|
||||
if DEBUG_PRINTOUTS && RTT_PRINTOUT {
|
||||
rprintln!(
|
||||
if DEBUG_PRINTOUTS && DEFMT_PRINTOUTS {
|
||||
defmt::info!(
|
||||
"bootloader CRC corrupt, read {} and expected {}. booting image A immediately",
|
||||
crc_calc,
|
||||
crc_exp
|
||||
@ -235,8 +231,8 @@ fn read_four_bytes_at_addr_zero(buf: &mut [u8; 4]) {
|
||||
}
|
||||
}
|
||||
fn check_app_crc(app_sel: AppSel, wdt: &OptWdt) -> bool {
|
||||
if DEBUG_PRINTOUTS && RTT_PRINTOUT {
|
||||
rprintln!("Checking image {:?}", app_sel);
|
||||
if DEBUG_PRINTOUTS && DEFMT_PRINTOUTS {
|
||||
defmt::info!("Checking image {:?}", app_sel);
|
||||
}
|
||||
if app_sel == AppSel::A {
|
||||
check_app_given_addr(APP_A_CRC_ADDR, APP_A_START_ADDR, APP_A_SIZE_ADDR, wdt)
|
||||
@ -255,8 +251,8 @@ fn check_app_given_addr(
|
||||
let image_size = unsafe { (image_size_addr as *const u32).read_unaligned().to_be() };
|
||||
// Sanity check.
|
||||
if image_size > APP_A_END_ADDR - APP_A_START_ADDR - 8 {
|
||||
if RTT_PRINTOUT {
|
||||
rprintln!("detected invalid app size {}", image_size);
|
||||
if DEFMT_PRINTOUTS {
|
||||
defmt::info!("detected invalid app size {}", image_size);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -272,8 +268,8 @@ fn check_app_given_addr(
|
||||
}
|
||||
|
||||
fn boot_app(app_sel: AppSel, cp: &cortex_m::Peripherals) -> ! {
|
||||
if DEBUG_PRINTOUTS && RTT_PRINTOUT {
|
||||
rprintln!("booting app {:?}", app_sel);
|
||||
if DEBUG_PRINTOUTS && DEFMT_PRINTOUTS {
|
||||
defmt::info!("booting app {:?}", app_sel);
|
||||
}
|
||||
let clkgen = unsafe { pac::Clkgen::steal() };
|
||||
clkgen
|
||||
|
@ -12,9 +12,10 @@ embedded-io = "0.6"
|
||||
embedded-hal-async = "1"
|
||||
embedded-io-async = "0.6"
|
||||
|
||||
rtt-target = { version = "0.6" }
|
||||
heapless = "0.8"
|
||||
panic-rtt-target = { version = "0.2" }
|
||||
defmt-rtt = "0.4"
|
||||
defmt = "1"
|
||||
panic-probe = { version = "1", features = ["defmt"] }
|
||||
static_cell = "2"
|
||||
critical-section = "1"
|
||||
once_cell = { version = "1", default-features = false, features = ["critical-section"] }
|
||||
@ -28,7 +29,7 @@ embassy-executor = { version = "0.7", features = [
|
||||
"executor-interrupt"
|
||||
]}
|
||||
|
||||
va416xx-hal = { version = "0.5" }
|
||||
va416xx-hal = { version = "0.5", features = ["defmt"] }
|
||||
va416xx-embassy = { version = "0.1", default-features = false }
|
||||
|
||||
[features]
|
||||
|
@ -5,6 +5,10 @@
|
||||
//! [CHECK_XXX_TO_XXX] constants to true.
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
// Import panic provider.
|
||||
use panic_probe as _;
|
||||
// Import logger.
|
||||
use defmt_rtt as _;
|
||||
|
||||
use embassy_example::EXTCLK_FREQ;
|
||||
use embassy_executor::Spawner;
|
||||
@ -12,8 +16,6 @@ use embassy_sync::channel::{Receiver, Sender};
|
||||
use embassy_sync::{blocking_mutex::raw::ThreadModeRawMutex, channel::Channel};
|
||||
use embassy_time::{Duration, Instant, Timer};
|
||||
use embedded_hal_async::digital::Wait;
|
||||
use panic_rtt_target as _;
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use va416xx_hal::clock::ClkgenExt;
|
||||
use va416xx_hal::gpio::{
|
||||
on_interrupt_for_async_gpio_for_port, InputDynPinAsync, InputPinAsync, PinsB, PinsC, PinsD,
|
||||
@ -66,8 +68,7 @@ static CHANNEL_PF0_TO_PF1: Channel<ThreadModeRawMutex, GpioCmd, 3> = Channel::ne
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(spawner: Spawner) {
|
||||
rtt_init_print!();
|
||||
rprintln!("-- VA416xx Async GPIO Demo --");
|
||||
defmt::println!("-- VA416xx Async GPIO Demo --");
|
||||
|
||||
let mut dp = pac::Peripherals::take().unwrap();
|
||||
|
||||
@ -114,7 +115,7 @@ async fn main(spawner: Spawner) {
|
||||
))
|
||||
.unwrap();
|
||||
check_pin_to_pin_async_ops("PA0 to PA1", CHANNEL_PA0_TO_PA1.sender(), in_pin).await;
|
||||
rprintln!("Example PA0 to PA1 done");
|
||||
defmt::info!("Example PA0 to PA1 done");
|
||||
}
|
||||
|
||||
if CHECK_PB0_TO_PB1 {
|
||||
@ -131,7 +132,7 @@ async fn main(spawner: Spawner) {
|
||||
))
|
||||
.unwrap();
|
||||
check_pin_to_pin_async_ops("PB0 to PB1", CHANNEL_PB0_TO_PB1.sender(), in_pin).await;
|
||||
rprintln!("Example PB0 to PB1 done");
|
||||
defmt::info!("Example PB0 to PB1 done");
|
||||
}
|
||||
|
||||
if CHECK_PC14_TO_PC15 {
|
||||
@ -147,7 +148,7 @@ async fn main(spawner: Spawner) {
|
||||
))
|
||||
.unwrap();
|
||||
check_pin_to_pin_async_ops("PC14 to PC15", CHANNEL_PC14_TO_PC15.sender(), in_pin).await;
|
||||
rprintln!("Example PC14 to PC15 done");
|
||||
defmt::info!("Example PC14 to PC15 done");
|
||||
}
|
||||
|
||||
if CHECK_PD2_TO_PD3 {
|
||||
@ -163,7 +164,7 @@ async fn main(spawner: Spawner) {
|
||||
))
|
||||
.unwrap();
|
||||
check_pin_to_pin_async_ops("PD2 to PD3", CHANNEL_PD2_TO_PD3.sender(), in_pin).await;
|
||||
rprintln!("Example PD2 to PD3 done");
|
||||
defmt::info!("Example PD2 to PD3 done");
|
||||
}
|
||||
|
||||
if CHECK_PE0_TO_PE1 {
|
||||
@ -179,7 +180,7 @@ async fn main(spawner: Spawner) {
|
||||
))
|
||||
.unwrap();
|
||||
check_pin_to_pin_async_ops("PE0 to PE1", CHANNEL_PE0_TO_PE1.sender(), in_pin).await;
|
||||
rprintln!("Example PE0 to PE1 done");
|
||||
defmt::info!("Example PE0 to PE1 done");
|
||||
}
|
||||
|
||||
if CHECK_PF0_TO_PF1 {
|
||||
@ -195,10 +196,10 @@ async fn main(spawner: Spawner) {
|
||||
))
|
||||
.unwrap();
|
||||
check_pin_to_pin_async_ops("PF0 to PF1", CHANNEL_PF0_TO_PF1.sender(), in_pin).await;
|
||||
rprintln!("Example PF0 to PF1 done");
|
||||
defmt::info!("Example PF0 to PF1 done");
|
||||
}
|
||||
|
||||
rprintln!("Example done, toggling LED0");
|
||||
defmt::info!("Example done, toggling LED0");
|
||||
loop {
|
||||
led.toggle();
|
||||
Timer::after(Duration::from_millis(500)).await;
|
||||
@ -210,46 +211,46 @@ async fn check_pin_to_pin_async_ops(
|
||||
sender: Sender<'static, ThreadModeRawMutex, GpioCmd, 3>,
|
||||
mut async_input: impl Wait,
|
||||
) {
|
||||
rprintln!(
|
||||
defmt::info!(
|
||||
"{}: sending SetHigh command ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
);
|
||||
sender.send(GpioCmd::new(GpioCmdType::SetHigh, 20)).await;
|
||||
async_input.wait_for_high().await.unwrap();
|
||||
rprintln!(
|
||||
defmt::info!(
|
||||
"{}: Input pin is high now ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
);
|
||||
|
||||
rprintln!(
|
||||
defmt::info!(
|
||||
"{}: sending SetLow command ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
);
|
||||
sender.send(GpioCmd::new(GpioCmdType::SetLow, 20)).await;
|
||||
async_input.wait_for_low().await.unwrap();
|
||||
rprintln!(
|
||||
defmt::info!(
|
||||
"{}: Input pin is low now ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
);
|
||||
|
||||
rprintln!(
|
||||
defmt::info!(
|
||||
"{}: 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!(
|
||||
defmt::info!(
|
||||
"{}: input pin had rising edge ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
);
|
||||
|
||||
rprintln!(
|
||||
defmt::info!(
|
||||
"{}: sending Falling command ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
@ -258,13 +259,13 @@ async fn check_pin_to_pin_async_ops(
|
||||
.send(GpioCmd::new(GpioCmdType::FallingEdge, 20))
|
||||
.await;
|
||||
async_input.wait_for_falling_edge().await.unwrap();
|
||||
rprintln!(
|
||||
defmt::info!(
|
||||
"{}: input pin had a falling edge ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
);
|
||||
|
||||
rprintln!(
|
||||
defmt::info!(
|
||||
"{}: sending Falling command ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
@ -273,20 +274,20 @@ async fn check_pin_to_pin_async_ops(
|
||||
.send(GpioCmd::new(GpioCmdType::FallingEdge, 20))
|
||||
.await;
|
||||
async_input.wait_for_any_edge().await.unwrap();
|
||||
rprintln!(
|
||||
defmt::info!(
|
||||
"{}: input pin had a falling (any) edge ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
);
|
||||
|
||||
rprintln!(
|
||||
defmt::info!(
|
||||
"{}: sending Falling command ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
);
|
||||
sender.send(GpioCmd::new(GpioCmdType::RisingEdge, 20)).await;
|
||||
async_input.wait_for_any_edge().await.unwrap();
|
||||
rprintln!(
|
||||
defmt::info!(
|
||||
"{}: input pin had a rising (any) edge ({} ms)",
|
||||
ctx,
|
||||
Instant::now().as_millis()
|
||||
@ -305,29 +306,29 @@ async fn output_task(
|
||||
Timer::after(Duration::from_millis(next_cmd.after_delay.into())).await;
|
||||
match next_cmd.cmd_type {
|
||||
GpioCmdType::SetHigh => {
|
||||
rprintln!("{}: Set output high", ctx);
|
||||
defmt::info!("{}: Set output high", ctx);
|
||||
out.set_high().unwrap();
|
||||
}
|
||||
GpioCmdType::SetLow => {
|
||||
rprintln!("{}: Set output low", ctx);
|
||||
defmt::info!("{}: Set output low", ctx);
|
||||
out.set_low().unwrap();
|
||||
}
|
||||
GpioCmdType::RisingEdge => {
|
||||
rprintln!("{}: Rising edge", ctx);
|
||||
defmt::info!("{}: Rising edge", ctx);
|
||||
if !out.is_low().unwrap() {
|
||||
out.set_low().unwrap();
|
||||
}
|
||||
out.set_high().unwrap();
|
||||
}
|
||||
GpioCmdType::FallingEdge => {
|
||||
rprintln!("{}: Falling edge", ctx);
|
||||
defmt::info!("{}: Falling edge", ctx);
|
||||
if !out.is_high().unwrap() {
|
||||
out.set_high().unwrap();
|
||||
}
|
||||
out.set_low().unwrap();
|
||||
}
|
||||
GpioCmdType::CloseTask => {
|
||||
rprintln!("{}: Closing task", ctx);
|
||||
defmt::info!("{}: Closing task", ctx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,12 @@
|
||||
//! RTT logs to see received data.
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
// Import panic provider.
|
||||
use panic_probe as _;
|
||||
// Import logger.
|
||||
use core::cell::RefCell;
|
||||
use defmt_rtt as _;
|
||||
use defmt_rtt as _;
|
||||
|
||||
use critical_section::Mutex;
|
||||
use embassy_example::EXTCLK_FREQ;
|
||||
@ -21,8 +26,6 @@ use embassy_time::Instant;
|
||||
use embedded_io::Write;
|
||||
use embedded_io_async::Read;
|
||||
use heapless::spsc::{Producer, Queue};
|
||||
use panic_rtt_target as _;
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use va416xx_hal::{
|
||||
gpio::PinsG,
|
||||
pac::{self, interrupt},
|
||||
@ -41,8 +44,7 @@ static PRODUCER_UART_A: Mutex<RefCell<Option<Producer<u8, 256>>>> = Mutex::new(R
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
rtt_init_print!();
|
||||
rprintln!("-- VA108xx Async UART RX Demo --");
|
||||
defmt::println!("-- VA108xx Async UART RX Demo --");
|
||||
|
||||
let mut dp = pac::Peripherals::take().unwrap();
|
||||
|
||||
@ -84,11 +86,11 @@ async fn main(_spawner: Spawner) {
|
||||
let mut async_uart_rx = RxAsync::new(rx_uart_a, cons_uart_a);
|
||||
let mut buf = [0u8; 256];
|
||||
loop {
|
||||
rprintln!("Current time UART A: {}", Instant::now().as_secs());
|
||||
defmt::info!("Current time UART A: {}", Instant::now().as_secs());
|
||||
led.toggle();
|
||||
let read_bytes = async_uart_rx.read(&mut buf).await.unwrap();
|
||||
let read_str = core::str::from_utf8(&buf[..read_bytes]).unwrap();
|
||||
rprintln!(
|
||||
defmt::info!(
|
||||
"Read {} bytes asynchronously on UART A: {:?}",
|
||||
read_bytes,
|
||||
read_str
|
||||
@ -106,6 +108,6 @@ fn UART0_RX() {
|
||||
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.
|
||||
if let Err(errors) = errors {
|
||||
rprintln!("UART A errors: {:?}", errors);
|
||||
defmt::info!("UART A errors: {:?}", errors);
|
||||
}
|
||||
}
|
||||
|
@ -11,12 +11,15 @@
|
||||
//! RTT logs to see received data.
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
// Import panic provider.
|
||||
use panic_probe as _;
|
||||
// Import logger.
|
||||
use defmt_rtt as _;
|
||||
|
||||
use embassy_example::EXTCLK_FREQ;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_time::{Duration, Instant, Ticker};
|
||||
use embedded_io_async::Write;
|
||||
use panic_rtt_target as _;
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use va416xx_hal::{
|
||||
gpio::PinsG,
|
||||
pac::{self, interrupt},
|
||||
@ -39,8 +42,7 @@ const STR_LIST: &[&str] = &[
|
||||
// main is itself an async function.
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
rtt_init_print!();
|
||||
rprintln!("-- VA108xx Async UART TX Demo --");
|
||||
defmt::println!("-- VA108xx Async UART TX Demo --");
|
||||
|
||||
let mut dp = pac::Peripherals::take().unwrap();
|
||||
|
||||
@ -75,7 +77,7 @@ async fn main(_spawner: Spawner) {
|
||||
let mut ticker = Ticker::every(Duration::from_secs(1));
|
||||
let mut idx = 0;
|
||||
loop {
|
||||
rprintln!("Current time: {}", Instant::now().as_secs());
|
||||
defmt::println!("Current time: {}", Instant::now().as_secs());
|
||||
led.toggle();
|
||||
let _written = async_tx
|
||||
.write(STR_LIST[idx].as_bytes())
|
||||
|
@ -9,6 +9,11 @@
|
||||
//! on the UART without requiring polling.
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
// Import panic provider.
|
||||
use panic_probe as _;
|
||||
// Import logger.
|
||||
use defmt_rtt as _;
|
||||
|
||||
use core::cell::RefCell;
|
||||
|
||||
use embassy_example::EXTCLK_FREQ;
|
||||
@ -17,12 +22,10 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::blocking_mutex::Mutex;
|
||||
use embassy_time::{Duration, Ticker};
|
||||
use embedded_io::Write;
|
||||
use panic_rtt_target as _;
|
||||
use ringbuf::{
|
||||
traits::{Consumer, Observer, Producer},
|
||||
StaticRb,
|
||||
};
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use va416xx_hal::{
|
||||
gpio::{OutputReadablePushPull, Pin, PinsG, PG5},
|
||||
pac::{self, interrupt},
|
||||
@ -49,8 +52,7 @@ static RINGBUF: SharedRingBuf = Mutex::new(RefCell::new(None));
|
||||
// a peripheral with embassy.
|
||||
#[embassy_executor::main]
|
||||
async fn main(spawner: Spawner) {
|
||||
rtt_init_print!();
|
||||
rprintln!("VA416xx UART-Embassy Example");
|
||||
defmt::println!("VA416xx UART-Embassy Example");
|
||||
|
||||
let mut dp = pac::Peripherals::take().unwrap();
|
||||
|
||||
@ -153,9 +155,9 @@ fn UART0_RX() {
|
||||
}
|
||||
|
||||
if errors.is_some() {
|
||||
rprintln!("UART error: {:?}", errors);
|
||||
defmt::info!("UART error: {:?}", errors);
|
||||
}
|
||||
if ringbuf_full {
|
||||
rprintln!("ringbuffer is full, deleted oldest data");
|
||||
defmt::info!("ringbuffer is full, deleted oldest data");
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
// Import panic provider.
|
||||
use panic_probe as _;
|
||||
// Import logger.
|
||||
use defmt_rtt as _;
|
||||
|
||||
use embassy_example::EXTCLK_FREQ;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_time::{Duration, Instant, Ticker};
|
||||
use panic_rtt_target as _;
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use va416xx_hal::{gpio::PinsG, pac, prelude::*, time::Hertz};
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
@ -17,8 +20,7 @@ cfg_if::cfg_if! {
|
||||
// main is itself an async function.
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
rtt_init_print!();
|
||||
rprintln!("VA416xx Embassy Demo");
|
||||
defmt::println!("VA416xx Embassy Demo");
|
||||
|
||||
let mut dp = pac::Peripherals::take().unwrap();
|
||||
|
||||
@ -57,7 +59,7 @@ async fn main(_spawner: Spawner) {
|
||||
let mut ticker = Ticker::every(Duration::from_secs(1));
|
||||
loop {
|
||||
ticker.next().await;
|
||||
rprintln!("Current time: {}", Instant::now().as_secs());
|
||||
defmt::info!("Current time: {}", Instant::now().as_secs());
|
||||
led.toggle();
|
||||
}
|
||||
}
|
||||
|
@ -7,9 +7,10 @@ edition = "2021"
|
||||
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
|
||||
cortex-m-rt = "0.7"
|
||||
embedded-hal = "1"
|
||||
rtt-target = { version = "0.6" }
|
||||
defmt-rtt = "0.4"
|
||||
defmt = "1"
|
||||
panic-probe = { version = "1", features = ["defmt"] }
|
||||
rtic-sync = { version = "1.3", features = ["defmt-03"] }
|
||||
panic-rtt-target = { version = "0.2" }
|
||||
|
||||
va416xx-hal = { version = "0.5", features = ["va41630"] }
|
||||
|
||||
|
@ -4,8 +4,10 @@
|
||||
|
||||
#[rtic::app(device = pac)]
|
||||
mod app {
|
||||
use panic_rtt_target as _;
|
||||
use rtt_target::{rprintln, rtt_init_default};
|
||||
// Import panic provider.
|
||||
use panic_probe as _;
|
||||
// Import logger.
|
||||
use defmt_rtt as _;
|
||||
use va416xx_hal::pac;
|
||||
|
||||
#[local]
|
||||
@ -16,8 +18,7 @@ mod app {
|
||||
|
||||
#[init]
|
||||
fn init(_ctx: init::Context) -> (Shared, Local) {
|
||||
rtt_init_default!();
|
||||
rprintln!("-- Vorago RTIC template --");
|
||||
defmt::println!("-- Vorago RTIC template --");
|
||||
(Shared {}, Local {})
|
||||
}
|
||||
|
||||
|
@ -9,11 +9,13 @@ const EXTCLK_FREQ: Hertz = Hertz::from_raw(40_000_000);
|
||||
#[rtic::app(device = pac, dispatchers = [U1, U2, U3])]
|
||||
mod app {
|
||||
use super::*;
|
||||
// Import panic provider.
|
||||
use panic_probe as _;
|
||||
// Import logger.
|
||||
use cortex_m::asm;
|
||||
use panic_rtt_target as _;
|
||||
use defmt_rtt as _;
|
||||
use rtic_monotonics::systick::prelude::*;
|
||||
use rtic_monotonics::Monotonic;
|
||||
use rtt_target::{rprintln, rtt_init_default};
|
||||
use va416xx_hal::{
|
||||
gpio::{OutputReadablePushPull, Pin, PinsG, PG5},
|
||||
pac,
|
||||
@ -32,8 +34,7 @@ mod app {
|
||||
|
||||
#[init]
|
||||
fn init(mut cx: init::Context) -> (Shared, Local) {
|
||||
rtt_init_default!();
|
||||
rprintln!("-- Vorago RTIC example application --");
|
||||
defmt::println!("-- Vorago RTIC example application --");
|
||||
// Use the external clock connected to XTAL_N.
|
||||
let clocks = cx
|
||||
.device
|
||||
|
@ -7,8 +7,9 @@ edition = "2021"
|
||||
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
|
||||
cortex-m-rt = "0.7"
|
||||
critical-section = "1"
|
||||
panic-rtt-target = { version = "0.2" }
|
||||
rtt-target = { version = "0.6" }
|
||||
defmt-rtt = "0.4"
|
||||
defmt = "1"
|
||||
panic-probe = { version = "1", features = ["defmt"] }
|
||||
embedded-hal = "1"
|
||||
embedded-hal-nb = "1"
|
||||
nb = "1"
|
||||
@ -16,7 +17,7 @@ embedded-io = "0.6"
|
||||
panic-halt = "1"
|
||||
accelerometer = "0.12"
|
||||
|
||||
va416xx-hal = { version = "0.5", features = ["va41630"] }
|
||||
va416xx-hal = { version = "0.5", features = ["va41630", "defmt"] }
|
||||
|
||||
[dependencies.vorago-peb1]
|
||||
path = "../../vorago-peb1"
|
||||
|
@ -2,10 +2,13 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
// Import panic provider.
|
||||
use panic_probe as _;
|
||||
// Import logger.
|
||||
use defmt_rtt as _;
|
||||
|
||||
use cortex_m_rt::entry;
|
||||
use embedded_hal::delay::DelayNs;
|
||||
use panic_rtt_target as _;
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use simple_examples::peb1;
|
||||
use va416xx_hal::{
|
||||
adc::{Adc, ChannelSelect, ChannelValue, MultiChannelSelect},
|
||||
@ -19,8 +22,7 @@ const ENABLE_BUF_PRINTOUT: bool = false;
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
rtt_init_print!();
|
||||
rprintln!("VA416xx ADC example");
|
||||
defmt::println!("VA416xx ADC example");
|
||||
|
||||
let mut dp = pac::Peripherals::take().unwrap();
|
||||
// Use the external clock connected to XTAL_N.
|
||||
@ -38,7 +40,7 @@ fn main() -> ! {
|
||||
let single_value = adc
|
||||
.trigger_and_read_single_channel(va416xx_hal::adc::ChannelSelect::TempSensor)
|
||||
.expect("reading single channel value failed");
|
||||
rprintln!(
|
||||
defmt::info!(
|
||||
"Read single ADC value on temperature sensor channel: {:?}",
|
||||
single_value
|
||||
);
|
||||
@ -46,8 +48,8 @@ fn main() -> ! {
|
||||
.sweep_and_read_range(0, 7, &mut read_buf)
|
||||
.expect("ADC range read failed");
|
||||
if ENABLE_BUF_PRINTOUT {
|
||||
rprintln!("ADC Range Read (0-8) read {} values", read_num);
|
||||
rprintln!("ADC Range Read (0-8): {:?}", read_buf);
|
||||
defmt::info!("ADC Range Read (0-8) read {} values", read_num);
|
||||
defmt::info!("ADC Range Read (0-8): {:?}", read_buf);
|
||||
}
|
||||
assert_eq!(read_num, 8);
|
||||
for (idx, ch_val) in read_buf.iter().enumerate() {
|
||||
@ -63,7 +65,7 @@ fn main() -> ! {
|
||||
)
|
||||
.expect("ADC multiselect read failed");
|
||||
if ENABLE_BUF_PRINTOUT {
|
||||
rprintln!("ADC Multiselect Read(0, 2 and 10): {:?}", &read_buf[0..3]);
|
||||
defmt::info!("ADC Multiselect Read(0, 2 and 10): {:?}", &read_buf[0..3]);
|
||||
}
|
||||
assert_eq!(read_buf[0].channel(), ChannelSelect::AnIn0);
|
||||
assert_eq!(read_buf[1].channel(), ChannelSelect::AnIn2);
|
||||
|
@ -2,15 +2,17 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
// Import panic provider.
|
||||
use panic_probe as _;
|
||||
// Import logger.
|
||||
use defmt_rtt as _;
|
||||
|
||||
use cortex_m_rt::entry;
|
||||
use panic_rtt_target as _;
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use va416xx_hal::{gpio::PinsG, pac};
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
rtt_init_print!();
|
||||
rprintln!("VA416xx HAL blinky example");
|
||||
defmt::println!("VA416xx HAL blinky example");
|
||||
|
||||
let mut dp = pac::Peripherals::take().unwrap();
|
||||
let portg = PinsG::new(&mut dp.sysconfig, dp.portg);
|
||||
|
@ -2,10 +2,13 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
// Import panic provider.
|
||||
use panic_probe as _;
|
||||
// Import logger.
|
||||
use defmt_rtt as _;
|
||||
|
||||
use cortex_m_rt::entry;
|
||||
use embedded_hal::delay::DelayNs;
|
||||
use panic_rtt_target as _;
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use simple_examples::peb1;
|
||||
use va416xx_hal::{adc::Adc, dac::Dac, pac, prelude::*, timer::CountdownTimer};
|
||||
|
||||
@ -25,8 +28,7 @@ const APP_MODE: AppMode = AppMode::DacAndAdc;
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
rtt_init_print!();
|
||||
rprintln!("VA416xx DAC/ADC example");
|
||||
defmt::println!("VA416xx DAC/ADC example");
|
||||
|
||||
let mut dp = pac::Peripherals::take().unwrap();
|
||||
// Use the external clock connected to XTAL_N.
|
||||
@ -53,7 +55,7 @@ fn main() -> ! {
|
||||
let mut current_val = 0;
|
||||
loop {
|
||||
if let Some(dac) = &dac {
|
||||
rprintln!("loading DAC with value {}", current_val);
|
||||
defmt::info!("loading DAC with value {}", current_val);
|
||||
dac.load_and_trigger_manually(current_val)
|
||||
.expect("loading DAC value failed");
|
||||
if current_val + DAC_INCREMENT >= 4096 {
|
||||
@ -70,7 +72,7 @@ fn main() -> ! {
|
||||
let ch_value = adc
|
||||
.trigger_and_read_single_channel(va416xx_hal::adc::ChannelSelect::AnIn0)
|
||||
.expect("reading ADC channel 0 failed");
|
||||
rprintln!("Received channel value {:?}", ch_value);
|
||||
defmt::info!("Received channel value {:?}", ch_value);
|
||||
}
|
||||
|
||||
delay_provider.delay_ms(500);
|
||||
|
@ -2,13 +2,16 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
// Import panic provider.
|
||||
use panic_probe as _;
|
||||
// Import logger.
|
||||
use defmt_rtt as _;
|
||||
|
||||
use core::cell::Cell;
|
||||
|
||||
use cortex_m_rt::entry;
|
||||
use critical_section::Mutex;
|
||||
use embedded_hal::delay::DelayNs;
|
||||
use panic_rtt_target as _;
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use simple_examples::peb1;
|
||||
use va416xx_hal::dma::{Dma, DmaCfg, DmaChannel, DmaCtrlBlock};
|
||||
use va416xx_hal::irq_router::enable_and_init_irq_router;
|
||||
@ -35,8 +38,7 @@ static mut DMA_DEST_BUF: [u16; 36] = [0; 36];
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
rtt_init_print!();
|
||||
rprintln!("VA416xx DMA example");
|
||||
defmt::println!("VA416xx DMA example");
|
||||
|
||||
let mut dp = pac::Peripherals::take().unwrap();
|
||||
// Use the external clock connected to XTAL_N.
|
||||
@ -119,7 +121,7 @@ fn transfer_example_8_bit(
|
||||
let mut dma_done = false;
|
||||
critical_section::with(|cs| {
|
||||
if DMA_ACTIVE_FLAG.borrow(cs).get() {
|
||||
rprintln!("DMA0 is active with 8 bit transfer");
|
||||
defmt::info!("DMA0 is active with 8 bit transfer");
|
||||
DMA_ACTIVE_FLAG.borrow(cs).set(false);
|
||||
}
|
||||
if DMA_DONE_FLAG.borrow(cs).get() {
|
||||
@ -127,7 +129,7 @@ fn transfer_example_8_bit(
|
||||
}
|
||||
});
|
||||
if dma_done {
|
||||
rprintln!("8-bit transfer done");
|
||||
defmt::info!("8-bit transfer done");
|
||||
break;
|
||||
}
|
||||
delay_ms.delay_ms(1);
|
||||
@ -177,7 +179,7 @@ fn transfer_example_16_bit(dma0: &mut DmaChannel, delay_ms: &mut CountdownTimer<
|
||||
let mut dma_done = false;
|
||||
critical_section::with(|cs| {
|
||||
if DMA_ACTIVE_FLAG.borrow(cs).get() {
|
||||
rprintln!("DMA0 is active with 16-bit transfer");
|
||||
defmt::info!("DMA0 is active with 16-bit transfer");
|
||||
DMA_ACTIVE_FLAG.borrow(cs).set(false);
|
||||
}
|
||||
if DMA_DONE_FLAG.borrow(cs).get() {
|
||||
@ -185,7 +187,7 @@ fn transfer_example_16_bit(dma0: &mut DmaChannel, delay_ms: &mut CountdownTimer<
|
||||
}
|
||||
});
|
||||
if dma_done {
|
||||
rprintln!("16-bit transfer done");
|
||||
defmt::info!("16-bit transfer done");
|
||||
break;
|
||||
}
|
||||
delay_ms.delay_ms(1);
|
||||
@ -237,7 +239,7 @@ fn transfer_example_32_bit(
|
||||
let mut dma_done = false;
|
||||
critical_section::with(|cs| {
|
||||
if DMA_ACTIVE_FLAG.borrow(cs).get() {
|
||||
rprintln!("DMA0 is active with 32-bit transfer");
|
||||
defmt::info!("DMA0 is active with 32-bit transfer");
|
||||
DMA_ACTIVE_FLAG.borrow(cs).set(false);
|
||||
}
|
||||
if DMA_DONE_FLAG.borrow(cs).get() {
|
||||
@ -245,7 +247,7 @@ fn transfer_example_32_bit(
|
||||
}
|
||||
});
|
||||
if dma_done {
|
||||
rprintln!("32-bit transfer done");
|
||||
defmt::info!("32-bit transfer done");
|
||||
break;
|
||||
}
|
||||
delay_ms.delay_ms(1);
|
||||
|
@ -2,11 +2,14 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
// Import panic provider.
|
||||
use panic_probe as _;
|
||||
// Import logger.
|
||||
use defmt_rtt as _;
|
||||
|
||||
use accelerometer::{Accelerometer, RawAccelerometer};
|
||||
use cortex_m_rt::entry;
|
||||
use embedded_hal::delay::DelayNs;
|
||||
use panic_rtt_target as _;
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use simple_examples::peb1;
|
||||
use va416xx_hal::{
|
||||
i2c,
|
||||
@ -25,9 +28,8 @@ const DISPLAY_MODE: DisplayMode = DisplayMode::Normalized;
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
rtt_init_print!();
|
||||
let mut dp = pac::Peripherals::take().unwrap();
|
||||
rprintln!("-- Vorago PEB1 accelerometer example --");
|
||||
defmt::println!("-- Vorago PEB1 accelerometer example --");
|
||||
// Use the external clock connected to XTAL_N.
|
||||
let clocks = dp
|
||||
.clkgen
|
||||
|
@ -4,8 +4,10 @@
|
||||
|
||||
use cortex_m_rt::entry;
|
||||
use embedded_hal::{delay::DelayNs, pwm::SetDutyCycle};
|
||||
use panic_rtt_target as _;
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
// Import panic provider.
|
||||
use panic_probe as _;
|
||||
// Import logger.
|
||||
use defmt_rtt as _;
|
||||
use simple_examples::peb1;
|
||||
use va416xx_hal::{
|
||||
gpio::PinsA,
|
||||
@ -17,8 +19,7 @@ use va416xx_hal::{
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
rtt_init_print!();
|
||||
rprintln!("-- VA108xx PWM example application--");
|
||||
defmt::println!("-- VA108xx PWM example application--");
|
||||
let mut dp = pac::Peripherals::take().unwrap();
|
||||
|
||||
// Use the external clock connected to XTAL_N.
|
||||
@ -52,7 +53,7 @@ fn main() -> ! {
|
||||
current_duty_cycle += 0.02;
|
||||
counter += 1;
|
||||
if counter % 10 == 0 {
|
||||
rprintln!("current duty cycle: {}", current_duty_cycle);
|
||||
defmt::info!("current duty cycle: {}", current_duty_cycle);
|
||||
}
|
||||
|
||||
reduced_pin
|
||||
@ -74,8 +75,8 @@ fn main() -> ! {
|
||||
upper_limit -= 0.01;
|
||||
pwmb.set_pwmb_lower_limit(get_duty_from_percent(lower_limit));
|
||||
pwmb.set_pwmb_upper_limit(get_duty_from_percent(upper_limit));
|
||||
rprintln!("Lower limit: {}", pwmb.pwmb_lower_limit());
|
||||
rprintln!("Upper limit: {}", pwmb.pwmb_upper_limit());
|
||||
defmt::info!("Lower limit: {}", pwmb.pwmb_lower_limit());
|
||||
defmt::info!("Upper limit: {}", pwmb.pwmb_upper_limit());
|
||||
}
|
||||
reduced_pin = ReducedPwmPin::<PwmA>::from(pwmb);
|
||||
}
|
||||
|
@ -2,9 +2,12 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
// Import panic provider.
|
||||
use panic_probe as _;
|
||||
// Import logger.
|
||||
use defmt_rtt as _;
|
||||
|
||||
use cortex_m_rt::entry;
|
||||
use panic_rtt_target as _;
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use va416xx_hal::pac;
|
||||
|
||||
// Mask for the LED
|
||||
@ -12,6 +15,7 @@ const LED_PG5: u32 = 1 << 5;
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
defmt::println!("VA416xx RTT Demo");
|
||||
let dp = pac::Peripherals::take().unwrap();
|
||||
// Enable all peripheral clocks
|
||||
dp.sysconfig
|
||||
@ -22,11 +26,9 @@ fn main() -> ! {
|
||||
.datamask()
|
||||
.modify(|_, w| unsafe { w.bits(LED_PG5) });
|
||||
|
||||
rtt_init_print!();
|
||||
rprintln!("VA416xx RTT Demo");
|
||||
let mut counter = 0;
|
||||
loop {
|
||||
rprintln!("{}: Hello, world!", counter);
|
||||
defmt::info!("{}: Hello, world!", counter);
|
||||
// Still toggle LED. If there are issues with the RTT log, the LED
|
||||
// blinking ensures that the application is actually running.
|
||||
dp.portg.togout().write(|w| unsafe { w.bits(LED_PG5) });
|
||||
|
@ -3,10 +3,13 @@
|
||||
//! If you do not use the loopback mode, MOSI and MISO need to be tied together on the board.
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
// Import panic provider.
|
||||
use panic_probe as _;
|
||||
// Import logger.
|
||||
use defmt_rtt as _;
|
||||
|
||||
use cortex_m_rt::entry;
|
||||
use embedded_hal::spi::{Mode, SpiBus, MODE_0};
|
||||
use panic_rtt_target as _;
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use simple_examples::peb1;
|
||||
use va416xx_hal::spi::{Spi, SpiClkConfig};
|
||||
use va416xx_hal::{
|
||||
@ -33,8 +36,7 @@ const FILL_WORD: u8 = 0x0f;
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
rtt_init_print!();
|
||||
rprintln!("-- VA108xx SPI example application--");
|
||||
defmt::println!("-- VA108xx SPI example application--");
|
||||
let cp = cortex_m::Peripherals::take().unwrap();
|
||||
let mut dp = pac::Peripherals::take().unwrap();
|
||||
// Use the external clock connected to XTAL_N.
|
||||
|
@ -1,13 +1,15 @@
|
||||
//! MS and Second counter implemented using the TIM0 and TIM1 peripheral
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
// Import panic provider.
|
||||
use panic_probe as _;
|
||||
// Import logger.
|
||||
use defmt_rtt as _;
|
||||
|
||||
use core::cell::Cell;
|
||||
use cortex_m::asm;
|
||||
use cortex_m_rt::entry;
|
||||
use critical_section::Mutex;
|
||||
use panic_rtt_target as _;
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use simple_examples::peb1;
|
||||
use va416xx_hal::{
|
||||
irq_router::enable_and_init_irq_router,
|
||||
@ -26,10 +28,9 @@ static SEC_COUNTER: Mutex<Cell<u32>> = Mutex::new(Cell::new(0));
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
rtt_init_print!();
|
||||
let mut dp = pac::Peripherals::take().unwrap();
|
||||
let mut last_ms = 0;
|
||||
rprintln!("-- Vorago system ticks using timers --");
|
||||
defmt::println!("-- Vorago system ticks using timers --");
|
||||
// Use the external clock connected to XTAL_N.
|
||||
let clocks = dp
|
||||
.clkgen
|
||||
@ -47,9 +48,9 @@ fn main() -> ! {
|
||||
if current_ms >= last_ms + 1000 {
|
||||
// To prevent drift.
|
||||
last_ms += 1000;
|
||||
rprintln!("MS counter: {}", current_ms);
|
||||
defmt::info!("MS counter: {}", current_ms);
|
||||
let second = critical_section::with(|cs| SEC_COUNTER.borrow(cs).get());
|
||||
rprintln!("Second counter: {}", second);
|
||||
defmt::info!("Second counter: {}", second);
|
||||
}
|
||||
asm::delay(1000);
|
||||
}
|
||||
|
@ -2,12 +2,14 @@
|
||||
// echo mode
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
// Import panic provider.
|
||||
use panic_probe as _;
|
||||
// Import logger.
|
||||
use defmt_rtt as _;
|
||||
|
||||
use cortex_m_rt::entry;
|
||||
use embedded_hal_nb::serial::Read;
|
||||
use embedded_io::Write;
|
||||
use panic_rtt_target as _;
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use simple_examples::peb1;
|
||||
use va416xx_hal::clock::ClkgenExt;
|
||||
use va416xx_hal::time::Hertz;
|
||||
@ -15,8 +17,7 @@ use va416xx_hal::{gpio::PinsG, pac, uart};
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
rtt_init_print!();
|
||||
rprintln!("-- VA416xx UART example application--");
|
||||
defmt::println!("-- VA416xx UART example application--");
|
||||
|
||||
let mut dp = pac::Peripherals::take().unwrap();
|
||||
|
||||
@ -45,12 +46,11 @@ fn main() -> ! {
|
||||
// Echo what is received on the serial link.
|
||||
match nb::block!(rx.read()) {
|
||||
Ok(recvd) => {
|
||||
if let Err(e) = embedded_hal_nb::serial::Write::write(&mut tx, recvd) {
|
||||
rprintln!("UART TX error: {:?}", e);
|
||||
}
|
||||
// Infallible operation.
|
||||
embedded_hal_nb::serial::Write::write(&mut tx, recvd).unwrap();
|
||||
}
|
||||
Err(e) => {
|
||||
rprintln!("UART RX error {:?}", e);
|
||||
defmt::info!("UART RX error {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,14 @@
|
||||
// Code to test the watchdog timer.
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
// Import panic provider.
|
||||
use panic_probe as _;
|
||||
// Import logger.
|
||||
use defmt_rtt as _;
|
||||
|
||||
use core::cell::Cell;
|
||||
use cortex_m_rt::entry;
|
||||
use critical_section::Mutex;
|
||||
use panic_rtt_target as _;
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use simple_examples::peb1;
|
||||
use va416xx_hal::irq_router::enable_and_init_irq_router;
|
||||
use va416xx_hal::pac::{self, interrupt};
|
||||
@ -29,8 +31,7 @@ const WDT_ROLLOVER_MS: u32 = 100;
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
rtt_init_print!();
|
||||
rprintln!("-- VA416xx WDT example application--");
|
||||
defmt::println!("-- VA416xx WDT example application--");
|
||||
let cp = cortex_m::Peripherals::take().unwrap();
|
||||
let mut dp = pac::Peripherals::take().unwrap();
|
||||
|
||||
@ -53,7 +54,7 @@ fn main() -> ! {
|
||||
}
|
||||
let interrupt_counter = critical_section::with(|cs| WDT_INTRPT_COUNT.borrow(cs).get());
|
||||
if interrupt_counter > last_interrupt_counter {
|
||||
rprintln!("interrupt counter has increased to {}", interrupt_counter);
|
||||
defmt::info!("interrupt counter has increased to {}", interrupt_counter);
|
||||
last_interrupt_counter = interrupt_counter;
|
||||
}
|
||||
match TEST_MODE {
|
||||
|
@ -3,7 +3,7 @@
|
||||
#![no_std]
|
||||
|
||||
use cortex_m_rt::entry;
|
||||
use panic_rtt_target as _;
|
||||
use panic_halt as _;
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
|
@ -9,9 +9,9 @@ cortex-m-rt = "0.7"
|
||||
embedded-hal = "1"
|
||||
embedded-hal-nb = "1"
|
||||
embedded-io = "0.6"
|
||||
panic-rtt-target = { version = "0.2" }
|
||||
rtt-target = { version = "0.6" }
|
||||
rtt-log = "0.5"
|
||||
defmt-rtt = "0.4"
|
||||
defmt = "1"
|
||||
panic-probe = { version = "1", features = ["defmt"] }
|
||||
log = "0.4"
|
||||
crc = "3"
|
||||
rtic-sync = "1"
|
||||
@ -19,10 +19,10 @@ static_cell = "2"
|
||||
satrs = { version = "0.3.0-alpha.0", default-features = false }
|
||||
ringbuf = { version = "0.4", default-features = false }
|
||||
once_cell = { version = "1", default-features = false, features = ["critical-section"] }
|
||||
spacepackets = { version = "0.13", default-features = false }
|
||||
spacepackets = { version = "0.13", default-features = false, features = ["defmt"] }
|
||||
cobs = { version = "0.3", default-features = false }
|
||||
|
||||
va416xx-hal = { version = "0.5", features = ["va41630"] }
|
||||
va416xx-hal = { version = "0.5", features = ["va41630", "defmt"] }
|
||||
|
||||
rtic = { version = "2", features = ["thumbv7-backend"] }
|
||||
rtic-monotonics = { version = "2", features = ["cortex-m-systick"] }
|
||||
|
@ -2,16 +2,15 @@
|
||||
from typing import List, Tuple
|
||||
from spacepackets.ecss.defs import PusService
|
||||
from spacepackets.ecss.tm import PusTm
|
||||
from tmtccmd.com import ComInterface
|
||||
from com_interface import ComInterface
|
||||
import toml
|
||||
import struct
|
||||
import logging
|
||||
import argparse
|
||||
import time
|
||||
import enum
|
||||
from tmtccmd.com.serial_base import SerialCfg
|
||||
from tmtccmd.com.serial_cobs import SerialCobsComIF
|
||||
from tmtccmd.com.ser_utils import prompt_com_port
|
||||
from com_interface.serial_base import SerialCfg
|
||||
from com_interface.serial_cobs import SerialCobsComIF
|
||||
from crcmod.predefined import PredefinedCrc
|
||||
from spacepackets.ecss.tc import PusTc
|
||||
from spacepackets.ecss.pus_verificator import PusVerificator, StatusField
|
||||
@ -58,6 +57,7 @@ PING_PAYLOAD_SIZE = 0
|
||||
class ActionId(enum.IntEnum):
|
||||
CORRUPT_APP_A = 128
|
||||
CORRUPT_APP_B = 129
|
||||
SET_BOOT_SLOT = 130
|
||||
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@ -78,11 +78,29 @@ class Target(enum.Enum):
|
||||
APP_B = 2
|
||||
|
||||
|
||||
class AppSel(enum.IntEnum):
|
||||
APP_A = 0
|
||||
APP_B = 1
|
||||
|
||||
|
||||
class ImageLoader:
|
||||
def __init__(self, com_if: ComInterface, verificator: PusVerificator) -> None:
|
||||
self.com_if = com_if
|
||||
self.verificator = verificator
|
||||
|
||||
def handle_boot_sel_cmd(self, target: AppSel):
|
||||
_LOGGER.info("Sending ping command")
|
||||
action_tc = PusTc(
|
||||
apid=0x00,
|
||||
service=PusService.S8_FUNC_CMD,
|
||||
subservice=ActionId.SET_BOOT_SLOT,
|
||||
seq_count=SEQ_PROVIDER.get_and_increment(),
|
||||
app_data=bytes([target]),
|
||||
)
|
||||
self.verificator.add_tc(action_tc)
|
||||
self.com_if.send(bytes(action_tc.pack()))
|
||||
self.await_for_command_copletion("boot image selection command")
|
||||
|
||||
def handle_ping_cmd(self):
|
||||
_LOGGER.info("Sending ping command")
|
||||
ping_tc = PusTc(
|
||||
@ -94,19 +112,9 @@ class ImageLoader:
|
||||
)
|
||||
self.verificator.add_tc(ping_tc)
|
||||
self.com_if.send(bytes(ping_tc.pack()))
|
||||
|
||||
data_available = self.com_if.data_available(0.4)
|
||||
if not data_available:
|
||||
_LOGGER.warning("no ping reply received")
|
||||
for reply in self.com_if.receive():
|
||||
result = self.verificator.add_tm(
|
||||
Service1Tm.from_tm(PusTm.unpack(reply, 0), UnpackParams(0))
|
||||
)
|
||||
if result is not None and result.completed:
|
||||
_LOGGER.info("received ping completion reply")
|
||||
self.await_for_command_copletion("ping command")
|
||||
|
||||
def handle_corruption_cmd(self, target: Target):
|
||||
|
||||
if target == Target.BOOTLOADER:
|
||||
_LOGGER.error("can not corrupt bootloader")
|
||||
if target == Target.APP_A:
|
||||
@ -126,6 +134,25 @@ class ImageLoader:
|
||||
),
|
||||
)
|
||||
|
||||
def await_for_command_copletion(self, context: str):
|
||||
done = False
|
||||
now = time.time()
|
||||
while time.time() - now < 2.0:
|
||||
if not self.com_if.data_available():
|
||||
time.sleep(0.2)
|
||||
continue
|
||||
for reply in self.com_if.receive():
|
||||
result = self.verificator.add_tm(
|
||||
Service1Tm.from_tm(PusTm.unpack(reply, 0), UnpackParams(0))
|
||||
)
|
||||
if result is not None and result.completed:
|
||||
_LOGGER.info(f"received {context} reply")
|
||||
done = True
|
||||
if done:
|
||||
break
|
||||
if not done:
|
||||
_LOGGER.warning(f"no {context} reply received")
|
||||
|
||||
def handle_flash_cmd(self, target: Target, file_path: Path) -> int:
|
||||
loadable_segments = []
|
||||
_LOGGER.info("Parsing ELF file for loadable sections")
|
||||
@ -269,12 +296,12 @@ def main() -> int:
|
||||
if "serial_port" in parsed_toml:
|
||||
serial_port = parsed_toml["serial_port"]
|
||||
if serial_port is None:
|
||||
serial_port = prompt_com_port()
|
||||
serial_port = input("Please specify the serial port manually: ")
|
||||
serial_cfg = SerialCfg(
|
||||
com_if_id="ser_cobs",
|
||||
serial_port=serial_port,
|
||||
baud_rate=BAUD_RATE,
|
||||
serial_timeout=0.1,
|
||||
polling_frequency=0.1,
|
||||
)
|
||||
verificator = PusVerificator()
|
||||
com_if = SerialCobsComIF(serial_cfg)
|
||||
|
@ -1,5 +1,5 @@
|
||||
spacepackets == 0.24
|
||||
tmtccmd == 8.0.2
|
||||
spacepackets == 0.28
|
||||
com-interface == 0.1.0
|
||||
toml == 0.10
|
||||
pyelftools == 0.31
|
||||
crcmod == 1.7
|
||||
|
@ -1,9 +0,0 @@
|
||||
#![no_std]
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn simple() {
|
||||
assert_eq!(1 + 1, 2);
|
||||
}
|
||||
}
|
@ -19,7 +19,6 @@
|
||||
#![no_std]
|
||||
|
||||
use once_cell::sync::OnceCell;
|
||||
use panic_rtt_target as _;
|
||||
use va416xx_hal::{clock::Clocks, edac, pac, time::Hertz, wdt::Wdt};
|
||||
|
||||
const EXTCLK_FREQ: u32 = 40_000_000;
|
||||
@ -95,10 +94,12 @@ mod app {
|
||||
use super::*;
|
||||
use cortex_m::asm;
|
||||
use embedded_io::Write;
|
||||
use panic_rtt_target as _;
|
||||
// Import panic provider.
|
||||
use panic_probe as _;
|
||||
// Import logger.
|
||||
use defmt_rtt as _;
|
||||
use rtic::Mutex;
|
||||
use rtic_monotonics::systick::prelude::*;
|
||||
use rtt_target::rprintln;
|
||||
use satrs::pus::verification::VerificationReportCreator;
|
||||
use spacepackets::ecss::PusServiceId;
|
||||
use spacepackets::ecss::{
|
||||
@ -150,9 +151,7 @@ mod app {
|
||||
|
||||
#[init]
|
||||
fn init(mut cx: init::Context) -> (Shared, Local) {
|
||||
//rtt_init_default!();
|
||||
rtt_log::init();
|
||||
rprintln!("-- Vorago flashloader --");
|
||||
defmt::println!("-- Vorago flashloader --");
|
||||
// Initialize the systick interrupt & obtain the token to prove that we did
|
||||
// Use the external clock connected to XTAL_N.
|
||||
let clocks = cx
|
||||
@ -272,7 +271,7 @@ mod app {
|
||||
let decoded_size =
|
||||
cobs::decode_in_place(&mut cx.local.rx_buf[1..result.bytes_read]);
|
||||
if decoded_size.is_err() {
|
||||
log::warn!("COBS decoding failed");
|
||||
defmt::warn!("COBS decoding failed");
|
||||
} else {
|
||||
let decoded_size = decoded_size.unwrap();
|
||||
if cx.local.tc_prod.sizes_prod.vacant_len() >= 1
|
||||
@ -285,11 +284,13 @@ mod app {
|
||||
.buf_prod
|
||||
.push_slice(&cx.local.rx_buf[1..1 + decoded_size]);
|
||||
} else {
|
||||
log::warn!("COBS TC queue full");
|
||||
defmt::warn!("COBS TC queue full");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::warn!("COBS frame with invalid format, start and end bytes are not 0");
|
||||
defmt::warn!(
|
||||
"COBS frame with invalid format, start and end bytes are not 0"
|
||||
);
|
||||
}
|
||||
|
||||
// Initiate next transfer.
|
||||
@ -299,11 +300,11 @@ mod app {
|
||||
.expect("read operation failed");
|
||||
}
|
||||
if result.has_errors() {
|
||||
log::warn!("UART error: {:?}", result.errors.unwrap());
|
||||
defmt::warn!("UART error: {:?}", result.errors.unwrap());
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("UART error: {:?}", e);
|
||||
defmt::warn!("UART error: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -346,7 +347,7 @@ mod app {
|
||||
fn handle_valid_pus_tc(cx: &mut pus_tc_handler::Context) {
|
||||
let pus_tc = PusTcReader::new(cx.local.tc_buf);
|
||||
if pus_tc.is_err() {
|
||||
log::warn!("PUS TC error: {}", pus_tc.unwrap_err());
|
||||
defmt::warn!("PUS TC error: {}", pus_tc.unwrap_err());
|
||||
return;
|
||||
}
|
||||
let (pus_tc, _) = pus_tc.unwrap();
|
||||
@ -396,11 +397,11 @@ mod app {
|
||||
write_and_send(&tm);
|
||||
};
|
||||
if pus_tc.subservice() == ActionId::CorruptImageA as u8 {
|
||||
rprintln!("corrupting App Image A");
|
||||
defmt::info!("corrupting App Image A");
|
||||
corrupt_image(APP_A_START_ADDR);
|
||||
}
|
||||
if pus_tc.subservice() == ActionId::CorruptImageB as u8 {
|
||||
rprintln!("corrupting App Image B");
|
||||
defmt::info!("corrupting App Image B");
|
||||
corrupt_image(APP_B_START_ADDR);
|
||||
}
|
||||
}
|
||||
@ -430,23 +431,21 @@ mod app {
|
||||
if pus_tc.subservice() == 2 {
|
||||
let app_data = pus_tc.app_data();
|
||||
if app_data.len() < 10 {
|
||||
log::warn!(
|
||||
target: "TC Handler",
|
||||
defmt::warn!(
|
||||
"app data for raw memory write is too short: {}",
|
||||
app_data.len()
|
||||
);
|
||||
}
|
||||
let memory_id = app_data[0];
|
||||
if memory_id != BOOT_NVM_MEMORY_ID {
|
||||
log::warn!(target: "TC Handler", "memory ID {} not supported", memory_id);
|
||||
defmt::warn!("memory ID {} not supported", memory_id);
|
||||
// TODO: Error reporting
|
||||
return;
|
||||
}
|
||||
let offset = u32::from_be_bytes(app_data[2..6].try_into().unwrap());
|
||||
let data_len = u32::from_be_bytes(app_data[6..10].try_into().unwrap());
|
||||
if 10 + data_len as usize > app_data.len() {
|
||||
log::warn!(
|
||||
target: "TC Handler",
|
||||
defmt::warn!(
|
||||
"invalid data length {} for raw mem write detected",
|
||||
data_len
|
||||
);
|
||||
|
5
jlink-gdb-ram.sh
Executable file
5
jlink-gdb-ram.sh
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
# Start the JLinkGDBServer while also specifying the JLinkScript file. The JLinkScript is necessary
|
||||
# to disable ROM protection to allow flashing
|
||||
JLinkGDBServer -select USB -device Cortex-M4 -endian little -if SWD -speed 2000 \
|
||||
-LocalhostOnly -vd -jlinkscriptfile ./jlink/JLinkSettings.JLinkScript
|
@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
# Start the JLinkGDBServer while also specifying the JLinkScript file. The JLinkScript is necessary
|
||||
# to disable ROM protection to allow flashing
|
||||
JLinkGDBServer -select USB -device Cortex-M4 -endian little -if SWD -speed 2000 \
|
||||
-LocalhostOnly -vd -jlinkscriptfile ./jlink/JLinkSettings.JLinkScript
|
||||
JLinkGDBServer -select USB -device VA416xx -endian little -if SWD -speed 2000 \
|
||||
-LocalhostOnly -vd
|
||||
|
1
memory.x
1
memory.x
@ -18,6 +18,5 @@ _stack_start = ORIGIN(RAM) + LENGTH(RAM);
|
||||
SECTIONS {
|
||||
.sram1 (NOLOAD) : ALIGN(8) {
|
||||
*(.sram1 .sram1.*);
|
||||
. = ALIGN(4);
|
||||
} > SRAM_1
|
||||
};
|
||||
|
18
scripts/defmt-telnet.sh
Executable file
18
scripts/defmt-telnet.sh
Executable file
@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Check if binary path was provided
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "Usage: $0 <path-to-binary>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BINARY="$1"
|
||||
|
||||
# Check if file exists
|
||||
if [ ! -f "$BINARY" ]; then
|
||||
echo "Error: File '$BINARY' not found."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run the command
|
||||
defmt-print -e "$BINARY" tcp
|
Loading…
x
Reference in New Issue
Block a user