Init Commit
All checks were successful
Rust/va416xx-rs/pipeline/head This commit looks good

Monorepo for Rust support of VA416XX family of radiation hardened MCUs
This commit is contained in:
2021-12-07 00:31:51 +01:00
committed by Robin Mueller
commit 5d1740efea
606 changed files with 74678 additions and 0 deletions

View File

@ -0,0 +1,18 @@
[package]
name = "simple_examples"
version = "0.1.0"
edition = "2021"
[dependencies]
cortex-m-rt = "0.7"
va416xx-hal = { path = "../../va416xx-hal" }
panic-rtt-target = { version = "0.1.3" }
rtt-target = { version = "0.5" }
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
embedded-hal = "1"
embedded-hal-nb = "1"
nb = "1"
embedded-io = "0.6"
panic-halt = "0.2"
vorago-peb1 = { path = "../../vorago-peb1" }
accelerometer = "0.12"

View File

@ -0,0 +1,33 @@
//! Simple blinky example
#![no_main]
#![no_std]
use cortex_m_rt::entry;
use panic_halt as _;
use va416xx_hal::pac;
// Mask for the LED
const LED_PG5: u32 = 1 << 5;
#[entry]
fn main() -> ! {
let dp = pac::Peripherals::take().unwrap();
// Enable all peripheral clocks
dp.sysconfig
.peripheral_clk_enable()
.modify(|_, w| unsafe { w.bits(0xffffffff) });
dp.portg.dir().modify(|_, w| unsafe { w.bits(LED_PG5) });
dp.portg
.datamask()
.modify(|_, w| unsafe { w.bits(LED_PG5) });
for _ in 0..10 {
dp.portg.clrout().write(|w| unsafe { w.bits(LED_PG5) });
cortex_m::asm::delay(2_000_000);
dp.portg.setout().write(|w| unsafe { w.bits(LED_PG5) });
cortex_m::asm::delay(2_000_000);
}
loop {
dp.portg.togout().write(|w| unsafe { w.bits(LED_PG5) });
cortex_m::asm::delay(2_000_000);
}
}

View File

@ -0,0 +1,24 @@
//! Simple blinky example using the HAL
#![no_main]
#![no_std]
use cortex_m_rt::entry;
use embedded_hal::digital::StatefulOutputPin;
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");
let mut dp = pac::Peripherals::take().unwrap();
let portg = PinsG::new(&mut dp.sysconfig, dp.portg);
let mut led = portg.pg5.into_readable_push_pull_output();
//let mut delay = CountDownTimer::new(&mut dp.SYSCONFIG, 50.mhz(), dp.TIM0);
loop {
cortex_m::asm::delay(2_000_000);
led.toggle().ok();
}
}

View File

@ -0,0 +1,88 @@
//! Example code for the PEB1 development board accelerometer.
#![no_main]
#![no_std]
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,
pac::{self},
prelude::*,
pwm::CountdownTimer,
};
use vorago_peb1::lis2dh12::{self, detect_i2c_addr, FullScale, Odr};
pub enum DisplayMode {
Raw,
Normalized,
}
const DISPLAY_MODE: DisplayMode = DisplayMode::Normalized;
#[entry]
fn main() -> ! {
rtt_init_print!();
let mut dp = pac::Peripherals::take().unwrap();
rprintln!("-- Vorago PEB1 accelerometer example --");
// Use the external clock connected to XTAL_N.
let clocks = dp
.clkgen
.constrain()
.xtal_n_clk_with_src_freq(peb1::EXTCLK_FREQ)
.freeze(&mut dp.sysconfig)
.unwrap();
let mut i2c_master = i2c::I2cMaster::new(
dp.i2c0,
&mut dp.sysconfig,
i2c::MasterConfig::default(),
&clocks,
i2c::I2cSpeed::Regular100khz,
)
.expect("creating I2C master failed");
let mut delay_provider = CountdownTimer::new(&mut dp.sysconfig, dp.tim1, &clocks);
// Detect the I2C address of the accelerometer by scanning all possible values.
let slave_addr = detect_i2c_addr(&mut i2c_master).expect("detecting I2C address failed");
// Create the accelerometer driver using the PEB1 BSP.
let mut accelerometer = vorago_peb1::accelerometer::new_with_i2cm(i2c_master, slave_addr)
.expect("creating accelerometer driver failed");
let device_id = accelerometer.get_device_id().unwrap();
accelerometer
.set_mode(lis2dh12::reg::Mode::Normal)
.expect("setting mode failed");
accelerometer
.set_odr(Odr::Hz100)
.expect("setting ODR failed");
accelerometer
.set_fs(FullScale::G4)
.expect("setting full scale failed");
// This function also enabled BDU.
accelerometer
.enable_temp(true)
.expect("enabling temperature sensor failed");
rprintln!("Device ID: 0x{:02X}", device_id);
// Start reading the accelerometer periodically.
loop {
let temperature = accelerometer
.get_temp_outf()
.expect("reading temperature failed");
match DISPLAY_MODE {
DisplayMode::Normalized => {
let value = accelerometer
.accel_norm()
.expect("reading normalized accelerometer data failed");
rprintln!("Accel Norm F32x3: {:.06?} | Temp {} °C", value, temperature);
}
DisplayMode::Raw => {
let value_raw = accelerometer
.accel_raw()
.expect("reading raw accelerometer data failed");
rprintln!("Accel Raw F32x3: {:?} | Temp {} °C", value_raw, temperature);
}
}
delay_provider.delay_ms(100);
}
}

View File

@ -0,0 +1,81 @@
//! Simple PWM example
#![no_main]
#![no_std]
use cortex_m_rt::entry;
use embedded_hal::{delay::DelayNs, pwm::SetDutyCycle};
use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print};
use simple_examples::peb1;
use va416xx_hal::{
gpio::PinsA,
pac,
prelude::*,
pwm::{self, get_duty_from_percent, CountdownTimer, PwmA, PwmB, ReducedPwmPin},
};
#[entry]
fn main() -> ! {
rtt_init_print!();
rprintln!("-- VA108xx PWM example application--");
let mut dp = pac::Peripherals::take().unwrap();
// Use the external clock connected to XTAL_N.
let clocks = dp
.clkgen
.constrain()
.xtal_n_clk_with_src_freq(peb1::EXTCLK_FREQ)
.freeze(&mut dp.sysconfig)
.unwrap();
let pinsa = PinsA::new(&mut dp.sysconfig, dp.porta);
let mut pwm = pwm::PwmPin::new(
(pinsa.pa3.into_funsel_1(), dp.tim3),
&mut dp.sysconfig,
&clocks,
10.Hz(),
);
let mut delay_timer = CountdownTimer::new(&mut dp.sysconfig, dp.tim0, &clocks);
let mut current_duty_cycle = 0.0;
pwm.set_duty_cycle(get_duty_from_percent(current_duty_cycle))
.unwrap();
pwm.enable();
// Delete type information, increased code readibility for the rest of the code
let mut reduced_pin = ReducedPwmPin::from(pwm);
loop {
let mut counter = 0;
// Increase duty cycle continuously
while current_duty_cycle < 1.0 {
delay_timer.delay_ms(400);
current_duty_cycle += 0.02;
counter += 1;
if counter % 10 == 0 {
rprintln!("current duty cycle: {}", current_duty_cycle);
}
reduced_pin
.set_duty_cycle(get_duty_from_percent(current_duty_cycle))
.unwrap();
}
// Switch to PWMB and decrease the window with a high signal from 100 % to 0 %
// continously
current_duty_cycle = 0.0;
let mut upper_limit = 1.0;
let mut lower_limit = 0.0;
let mut pwmb: ReducedPwmPin<PwmB> = ReducedPwmPin::from(reduced_pin);
pwmb.set_pwmb_lower_limit(get_duty_from_percent(lower_limit));
pwmb.set_pwmb_upper_limit(get_duty_from_percent(upper_limit));
while lower_limit < 0.5 {
delay_timer.delay_ms(400);
lower_limit += 0.01;
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());
}
reduced_pin = ReducedPwmPin::<PwmA>::from(pwmb);
}
}

View File

@ -0,0 +1,36 @@
// Code to test RTT logger functionality.
#![no_main]
#![no_std]
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
const LED_PG5: u32 = 1 << 5;
#[entry]
fn main() -> ! {
let dp = pac::Peripherals::take().unwrap();
// Enable all peripheral clocks
dp.sysconfig
.peripheral_clk_enable()
.modify(|_, w| unsafe { w.bits(0xffffffff) });
dp.portg.dir().modify(|_, w| unsafe { w.bits(LED_PG5) });
dp.portg
.datamask()
.modify(|_, w| unsafe { w.bits(LED_PG5) });
rtt_init_print!();
rprintln!("VA416xx RTT Demo");
let mut counter = 0;
loop {
rprintln!("{}: 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) });
counter += 1;
cortex_m::asm::delay(10_000_000);
}
}

View File

@ -0,0 +1,96 @@
//! SPI example application.
//!
//! If you do not use the loopback mode, MOSI and MISO need to be tied together on the board.
#![no_main]
#![no_std]
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, TransferConfig};
use va416xx_hal::{
gpio::{PinsB, PinsC},
pac,
prelude::*,
spi::SpiConfig,
};
#[derive(PartialEq, Debug)]
pub enum ExampleSelect {
// Enter loopback mode. It is not necessary to tie MOSI/MISO together for this
Loopback,
// Send a test buffer and print everything received. You need to tie together MOSI/MISO in this
// mode.
TestBuffer,
}
const EXAMPLE_SEL: ExampleSelect = ExampleSelect::Loopback;
const SPI_SPEED_KHZ: u32 = 1000;
const SPI_MODE: Mode = MODE_0;
const BLOCKMODE: bool = true;
const FILL_WORD: u8 = 0x0f;
#[entry]
fn main() -> ! {
rtt_init_print!();
rprintln!("-- 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.
let clocks = dp
.clkgen
.constrain()
.xtal_n_clk_with_src_freq(peb1::EXTCLK_FREQ)
.freeze(&mut dp.sysconfig)
.unwrap();
let mut delay_sysclk = cortex_m::delay::Delay::new(cp.SYST, clocks.apb0().raw());
let pins_b = PinsB::new(&mut dp.sysconfig, dp.portb);
let pins_c = PinsC::new(&mut dp.sysconfig, dp.portc);
// Configure SPI1 pins.
let (sck, miso, mosi) = (
pins_b.pb15.into_funsel_1(),
pins_c.pc0.into_funsel_1(),
pins_c.pc1.into_funsel_1(),
);
let mut spi_cfg = SpiConfig::default();
if EXAMPLE_SEL == ExampleSelect::Loopback {
spi_cfg = spi_cfg.loopback(true)
}
let transfer_cfg =
TransferConfig::new_no_hw_cs(SPI_SPEED_KHZ.kHz(), SPI_MODE, BLOCKMODE, false);
// Create SPI peripheral.
let mut spi0 = Spi::new(
dp.spi0,
(sck, miso, mosi),
&clocks,
spi_cfg,
&mut dp.sysconfig,
Some(&transfer_cfg.downgrade()),
);
spi0.set_fill_word(FILL_WORD);
loop {
let mut tx_buf: [u8; 3] = [1, 2, 3];
let mut rx_buf: [u8; 3] = [0; 3];
// Can't really verify correct reply here.
spi0.write(&[0x42]).expect("write failed");
// Need small delay.. otherwise we will read back the sent byte (which we don't want here).
// The write function will return as soon as all bytes were shifted out, ignoring the
// reply bytes.
delay_sysclk.delay_us(50);
// Because of the loopback mode, we should get back the fill word here.
spi0.read(&mut rx_buf[0..1]).unwrap();
assert_eq!(rx_buf[0], FILL_WORD);
spi0.transfer_in_place(&mut tx_buf)
.expect("SPI transfer_in_place failed");
assert_eq!([1, 2, 3], tx_buf);
spi0.transfer(&mut rx_buf, &tx_buf)
.expect("SPI transfer failed");
assert_eq!(rx_buf, tx_buf);
delay_sysclk.delay_ms(500);
}
}

View File

@ -0,0 +1,68 @@
//! MS and Second counter implemented using the TIM0 and TIM1 peripheral
#![no_main]
#![no_std]
use core::cell::Cell;
use cortex_m::interrupt::Mutex;
use cortex_m_rt::entry;
use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print};
use simple_examples::peb1;
use va416xx_hal::{
pac::{self, interrupt},
prelude::*,
timer::{default_ms_irq_handler, set_up_ms_tick, CountdownTimer, MS_COUNTER},
};
#[allow(dead_code)]
enum LibType {
Pac,
Hal,
}
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 --");
// Use the external clock connected to XTAL_N.
let clocks = dp
.clkgen
.constrain()
.xtal_n_clk_with_src_freq(peb1::EXTCLK_FREQ)
.freeze(&mut dp.sysconfig)
.unwrap();
let _ = set_up_ms_tick(&mut dp.sysconfig, dp.tim0, &clocks);
let mut second_timer = CountdownTimer::new(&mut dp.sysconfig, dp.tim1, &clocks);
second_timer.start(1.Hz());
second_timer.listen();
loop {
let current_ms = cortex_m::interrupt::free(|cs| MS_COUNTER.borrow(cs).get());
if current_ms - last_ms >= 1000 {
last_ms = current_ms;
rprintln!("MS counter: {}", current_ms);
let second = cortex_m::interrupt::free(|cs| SEC_COUNTER.borrow(cs).get());
rprintln!("Second counter: {}", second);
}
cortex_m::asm::delay(10000);
}
}
#[interrupt]
#[allow(non_snake_case)]
fn TIM0() {
default_ms_irq_handler()
}
#[interrupt]
#[allow(non_snake_case)]
fn TIM1() {
cortex_m::interrupt::free(|cs| {
let mut sec = SEC_COUNTER.borrow(cs).get();
sec += 1;
SEC_COUNTER.borrow(cs).set(sec);
});
}

View File

@ -0,0 +1,57 @@
// UART example application. Sends a test string over a UART and then enters
// echo mode
#![no_main]
#![no_std]
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;
use va416xx_hal::{gpio::PinsG, pac, uart};
#[entry]
fn main() -> ! {
rtt_init_print!();
rprintln!("-- VA416xx UART example application--");
let mut dp = pac::Peripherals::take().unwrap();
// Use the external clock connected to XTAL_N.
let clocks = dp
.clkgen
.constrain()
.xtal_n_clk_with_src_freq(peb1::EXTCLK_FREQ)
.freeze(&mut dp.sysconfig)
.unwrap();
let gpiob = PinsG::new(&mut dp.sysconfig, dp.portg);
let tx = gpiob.pg0.into_funsel_1();
let rx = gpiob.pg1.into_funsel_1();
let uart0 = uart::Uart::new(
dp.uart0,
(tx, rx),
Hertz::from_raw(115200),
&mut dp.sysconfig,
&clocks,
);
let (mut tx, mut rx) = uart0.split();
writeln!(tx, "Hello World\n\r").unwrap();
loop {
// 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);
}
}
Err(e) => {
rprintln!("UART RX error {:?}", e);
}
}
}
}

View File

@ -0,0 +1,79 @@
// Code to test the watchdog timer.
#![no_main]
#![no_std]
use core::cell::Cell;
use cortex_m::interrupt::Mutex;
use cortex_m_rt::entry;
use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print};
use simple_examples::peb1;
use va416xx_hal::pac::{self, interrupt};
use va416xx_hal::prelude::*;
use va416xx_hal::wdt::WdtController;
static WDT_INTRPT_COUNT: Mutex<Cell<u32>> = Mutex::new(Cell::new(0));
#[derive(Debug, PartialEq, Eq)]
#[allow(dead_code)]
enum TestMode {
// Watchdog is fed by main loop, which runs with high period.
FedByMain,
// Watchdog is fed by watchdog IRQ.
FedByIrq,
AllowReset,
}
const TEST_MODE: TestMode = TestMode::FedByMain;
const WDT_ROLLOVER_MS: u32 = 100;
#[entry]
fn main() -> ! {
rtt_init_print!();
rprintln!("-- VA416xx WDT example application--");
let cp = cortex_m::Peripherals::take().unwrap();
let mut dp = pac::Peripherals::take().unwrap();
// Use the external clock connected to XTAL_N.
let clocks = dp
.clkgen
.constrain()
.xtal_n_clk_with_src_freq(peb1::EXTCLK_FREQ)
.freeze(&mut dp.sysconfig)
.unwrap();
let mut delay_sysclk = cortex_m::delay::Delay::new(cp.SYST, clocks.apb0().raw());
let mut last_interrupt_counter = 0;
let mut wdt_ctrl =
WdtController::start(&mut dp.sysconfig, dp.watch_dog, &clocks, WDT_ROLLOVER_MS);
wdt_ctrl.enable_reset();
loop {
if TEST_MODE != TestMode::AllowReset {
wdt_ctrl.feed();
}
let interrupt_counter = cortex_m::interrupt::free(|cs| WDT_INTRPT_COUNT.borrow(cs).get());
if interrupt_counter > last_interrupt_counter {
rprintln!("interrupt counter has increased to {}", interrupt_counter);
last_interrupt_counter = interrupt_counter;
}
match TEST_MODE {
TestMode::FedByMain => delay_sysclk.delay_ms(WDT_ROLLOVER_MS / 5),
TestMode::FedByIrq => delay_sysclk.delay_ms(WDT_ROLLOVER_MS),
_ => (),
}
}
}
#[interrupt]
#[allow(non_snake_case)]
fn WATCHDOG() {
cortex_m::interrupt::free(|cs| {
WDT_INTRPT_COUNT
.borrow(cs)
.set(WDT_INTRPT_COUNT.borrow(cs).get() + 1);
});
let wdt = unsafe { pac::WatchDog::steal() };
// Clear interrupt.
if TEST_MODE != TestMode::AllowReset {
wdt.wdogintclr().write(|w| unsafe { w.bits(1) });
}
}

View File

@ -0,0 +1,11 @@
#![no_std]
/// PEB1 board specific configuration.
pub mod peb1 {
use va416xx_hal::time::Hertz;
// The clock on the PEB1 board has a 20 MHz clock which is increased to 40 MHz with a configurable
// PLL by default.
pub const EXTCLK_FREQ: Hertz = Hertz::from_raw(40_000_000);
pub const XTAL_FREQ: Hertz = Hertz::from_raw(10_000_000);
}

View File

@ -0,0 +1,13 @@
//! Dummy app which does not do anything.
#![no_main]
#![no_std]
use cortex_m_rt::entry;
use panic_rtt_target as _;
#[entry]
fn main() -> ! {
loop {
cortex_m::asm::nop();
}
}