Compare commits

..

No commits in common. "main" and "v0.3.1" have entirely different histories.
main ... v0.3.1

34 changed files with 272 additions and 1383 deletions

View File

@ -16,11 +16,14 @@ jobs:
override: true override: true
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
use-cross: true
command: check command: check
args: --target thumbv6m-none-eabi
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
use-cross: true
command: check command: check
args: --examples args: --examples --target thumbv6m-none-eabi
fmt: fmt:
name: Rustfmt name: Rustfmt
@ -52,8 +55,9 @@ jobs:
- run: rustup component add clippy - run: rustup component add clippy
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
use-cross: true
command: clippy command: clippy
args: -- -D warnings args: --target thumbv6m-none-eabi -- -D warnings
ci: ci:
if: ${{ success() }} if: ${{ success() }}

View File

@ -6,65 +6,6 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/) The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/). and this project adheres to [Semantic Versioning](http://semver.org/).
## [v0.5.2] 2024-06-16
## Fixed
- Replaced usage to `ptr::write_volatile` in UART module which is denied on more recent Rust
compilers.
## [v0.5.1]
### Changes
- Updated dependencies:
- `cortex-m-rtic` (dev-depencency) to 1.1.2
- `once_cell` to 1.12.0
- Other dependencies: Only revision has changed
## [v0.5.0]
### Added
- Reactored IRQ handling, so that `unmask` operations can be moved to HAL
- Added UART IRQ handler. Right now, can only perform reception, TX still needs to be done in
a blocking manner
- Added RTIC template and RTIC UART IRQ application
### Fixed
- Bugfix in UART code where RX and TX could not be enabled or disabled independently
## [v0.4.3]
- Various smaller fixes for READMEs, update of links in documentation
- Simplified CI for github, do not use `cross`
- New `blinky-pac` example
- Use HAL delay in `blinky` example
## [v0.4.2]
### Added
- `port_mux` function to set pin function select manually
### Changed
- Clear TX and RX FIFO in SPI transfer function
## [v0.4.1]
### Fixed
- Initial blockmode setting was not set in SPI constructor
## [v0.4.0]
### Changed
- Replaced `Hertz` by `impl Into<Hertz>` completely and removed
`+ Copy` where not necessary
## [v0.3.1] ## [v0.3.1]
- Updated all links to point to new repository - Updated all links to point to new repository

View File

@ -1,6 +1,6 @@
[package] [package]
name = "va108xx-hal" name = "va108xx-hal"
version = "0.5.2" version = "0.3.1"
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"] authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
edition = "2021" edition = "2021"
description = "HAL for the Vorago VA108xx family of microcontrollers" description = "HAL for the Vorago VA108xx family of microcontrollers"
@ -8,58 +8,38 @@ homepage = "https://egit.irs.uni-stuttgart.de/rust/va108xx-hal"
repository = "https://egit.irs.uni-stuttgart.de/rust/va108xx-hal" repository = "https://egit.irs.uni-stuttgart.de/rust/va108xx-hal"
license = "Apache-2.0" license = "Apache-2.0"
keywords = ["no-std", "hal", "cortex-m", "vorago", "va108xx"] keywords = ["no-std", "hal", "cortex-m", "vorago", "va108xx"]
categories = ["aerospace", "embedded", "no-std", "hardware-support"] categories = ["embedded", "no-std", "hardware-support"]
[dependencies] [dependencies]
va108xx = "0.2.4"
cortex-m = "0.7" cortex-m = "0.7"
cortex-m-rt = "0.7" cortex-m-rt = "0.7"
nb = "1" nb = "1"
paste = "1.0" paste = "1.0"
libm = "0.2" embedded-hal = { features = ["unproven"], version = "0.2.6" }
void = { version = "1.0", default-features = false }
once_cell = { version = "1.8.0", default-features = false }
libm = "0.2.1"
[dependencies.embedded-hal] [dependencies.va108xx]
version = "0.2.7" version = "0.2.4"
features = ["unproven"]
[dependencies.void]
version = "1.0"
default-features = false
[dependencies.once_cell]
version = "1.14"
default-features = false
[features] [features]
rt = ["va108xx/rt"] rt = ["va108xx/rt"]
[dev-dependencies] [dev-dependencies]
cortex-m-rtic = "1.1.2" panic-rtt-target = { version = "0.1", features = ["cortex-m"] }
rtt-target = { version = "0.3", features = ["cortex-m"] }
panic-halt = "0.2" panic-halt = "0.2"
[dev-dependencies.rtt-target]
version = "0.3"
features = ["cortex-m"]
[dev-dependencies.panic-rtt-target]
version = "0.1"
features = ["cortex-m"]
[profile.dev] [profile.dev]
debug = true debug = true
lto = false lto = false
[profile.release] [profile.release]
# Problematic because RTT won't work lto = true
lto = false
debug = true debug = true
opt-level = "s" opt-level = "s"
# Commented until named-profiles feature is stabilized
# [profile.release-lto]
# inherits = "release"
# lto = true
[[example]] [[example]]
name = "timer-ticks" name = "timer-ticks"
required-features = ["rt"] required-features = ["rt"]
@ -69,9 +49,9 @@ name = "tests"
required-features = ["rt"] required-features = ["rt"]
[[example]] [[example]]
name = "cascade" name = "pwm"
required-features = ["rt"] required-features = ["rt"]
[[example]] [[example]]
name = "uart-irq-rtic" name = "cascade"
required-features = ["rt"] required-features = ["rt"]

View File

@ -1,5 +1,5 @@
[![Crates.io](https://img.shields.io/crates/v/va108xx-hal)](https://crates.io/crates/va108xx-hal) [![Crates.io](https://img.shields.io/crates/v/va108xx-hal)](https://crates.io/crates/va108xx-hal)
[![ci](https://github.com/us-irs/va108xx-hal-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/us-irs/va108xx-hal-rs/actions/workflows/ci.yml) [![ci](https://github.com/robamu-org/va108xx-hal-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/robamu-org/va108xx-hal-rs/actions/workflows/ci.yml)
[![docs.rs](https://img.shields.io/docsrs/va108xx-hal)](https://docs.rs/va108xx-hal) [![docs.rs](https://img.shields.io/docsrs/va108xx-hal)](https://docs.rs/va108xx-hal)
# HAL for the Vorago VA108xx MCU family # HAL for the Vorago VA108xx MCU family
@ -63,7 +63,7 @@ is contained within the
1. Set up your Rust cross-compiler if you have not done so yet. See more in the [build chapter](#Building) 1. Set up your Rust cross-compiler if you have not done so yet. See more in the [build chapter](#Building)
2. Create a new binary crate with `cargo init` 2. Create a new binary crate with `cargo init`
3. To ensure that `cargo build` cross-compiles, it is recommended to create a `.cargo/config.toml` 3. To ensure that `cargo build` cross-compiles, it is recommended to create a `cargo/config.toml`
file. A sample `.cargo/config.toml` file is provided in this repository as well file. A sample `.cargo/config.toml` file is provided in this repository as well
4. Copy the `memory.x` file into your project. This file contains information required by the linker. 4. Copy the `memory.x` file into your project. This file contains information required by the linker.
5. Copy the `blinky.rs` file to the `src/main.rs` file in your binary crate 5. Copy the `blinky.rs` file to the `src/main.rs` file in your binary crate
@ -85,4 +85,4 @@ is contained within the
7. Flashing the board might work differently for different boards and there is usually 7. Flashing the board might work differently for different boards and there is usually
more than one way. You can find example instructions for the REB1 development board more than one way. You can find example instructions for the REB1 development board
[here](https://egit.irs.uni-stuttgart.de/rust/vorago-reb1). [here](https://github.com/robamu-org/vorago-reb1-rs).

View File

@ -7,7 +7,5 @@ RUN apt-get --yes upgrade
# tzdata is a dependency, won't install otherwise # tzdata is a dependency, won't install otherwise
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive
RUN rustup install nightly && \ RUN rustup target add thumbv6m-none-eabi && \
rustup target add thumbv6m-none-eabi && \
rustup +nightly target add thumbv6m-none-eabi && \
rustup component add rustfmt clippy rustup component add rustfmt clippy

View File

@ -1,34 +1,47 @@
pipeline { pipeline {
agent any
stages {
stage('Clippy') {
agent { agent {
dockerfile { dockerfile {
dir 'automation' dir 'automation'
reuseNode true reuseNode true
} }
} }
stages {
stage('Clippy') {
steps { steps {
sh 'cargo clippy' sh 'cargo clippy'
} }
} }
stage('Rustfmt') { stage('Rustfmt') {
agent {
dockerfile {
dir 'automation'
reuseNode true
}
}
steps { steps {
sh 'cargo fmt' sh 'cargo fmt'
} }
} }
stage('Docs') {
steps {
sh 'cargo +nightly doc'
}
}
stage('Check') { stage('Check') {
agent {
dockerfile {
dir 'automation'
reuseNode true
}
}
steps { steps {
sh 'cargo check --target thumbv6m-none-eabi' sh 'cargo check --target thumbv6m-none-eabi'
} }
} }
stage('Check Examples') { stage('Check Examples') {
agent {
dockerfile {
dir 'automation'
reuseNode true
}
}
steps { steps {
sh 'cargo check --target thumbv6m-none-eabi --examples' sh 'cargo check --target thumbv6m-none-eabi --examples'
} }

View File

@ -1,47 +0,0 @@
//! Blinky examples using only the PAC
//!
//! Additional note on LEDs:
//! Pulling the GPIOs low makes the LEDs blink. See REB1
//! schematic for more details.
#![no_main]
#![no_std]
use cortex_m_rt::entry;
use panic_halt as _;
use va108xx as pac;
// REB LED pin definitions. All on port A
const LED_D2: u32 = 1 << 10;
const LED_D3: u32 = 1 << 7;
const LED_D4: u32 = 1 << 6;
#[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.PORTA
.dir()
.modify(|_, w| unsafe { w.bits(LED_D2 | LED_D3 | LED_D4) });
dp.PORTA
.datamask()
.modify(|_, w| unsafe { w.bits(LED_D2 | LED_D3 | LED_D4) });
for _ in 0..10 {
dp.PORTA
.clrout()
.write(|w| unsafe { w.bits(LED_D2 | LED_D3 | LED_D4) });
cortex_m::asm::delay(5_000_000);
dp.PORTA
.setout()
.write(|w| unsafe { w.bits(LED_D2 | LED_D3 | LED_D4) });
cortex_m::asm::delay(5_000_000);
}
loop {
dp.PORTA
.togout()
.write(|w| unsafe { w.bits(LED_D2 | LED_D3 | LED_D4) });
cortex_m::asm::delay(25_000_000);
}
}

View File

@ -9,7 +9,7 @@
use cortex_m_rt::entry; use cortex_m_rt::entry;
use embedded_hal::digital::v2::ToggleableOutputPin; use embedded_hal::digital::v2::ToggleableOutputPin;
use panic_halt as _; use panic_halt as _;
use va108xx_hal::{gpio::PinsA, pac, prelude::*, timer::CountDownTimer}; use va108xx_hal::{gpio::PinsA, pac, prelude::*};
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
@ -18,23 +18,22 @@ fn main() -> ! {
let mut led1 = porta.pa10.into_push_pull_output(); let mut led1 = porta.pa10.into_push_pull_output();
let mut led2 = porta.pa7.into_push_pull_output(); let mut led2 = porta.pa7.into_push_pull_output();
let mut led3 = porta.pa6.into_push_pull_output(); let mut led3 = porta.pa6.into_push_pull_output();
let mut delay = CountDownTimer::new(&mut dp.SYSCONFIG, 50.mhz(), dp.TIM0);
for _ in 0..10 { for _ in 0..10 {
led1.set_low().ok(); led1.set_low().ok();
led2.set_low().ok(); led2.set_low().ok();
led3.set_low().ok(); led3.set_low().ok();
delay.delay_ms(200_u16); cortex_m::asm::delay(5_000_000);
led1.set_high().ok(); led1.set_high().ok();
led2.set_high().ok(); led2.set_high().ok();
led3.set_high().ok(); led3.set_high().ok();
delay.delay_ms(200_u16); cortex_m::asm::delay(5_000_000);
} }
loop { loop {
led1.toggle().ok(); led1.toggle().ok();
delay.delay_ms(200_u16); cortex_m::asm::delay(5_000_000);
led2.toggle().ok(); led2.toggle().ok();
delay.delay_ms(200_u16); cortex_m::asm::delay(5_000_000);
led3.toggle().ok(); led3.toggle().ok();
delay.delay_ms(200_u16); cortex_m::asm::delay(5_000_000);
} }
} }

View File

@ -14,8 +14,8 @@ use va108xx_hal::{
pac::{self, interrupt, TIM4, TIM5}, pac::{self, interrupt, TIM4, TIM5},
prelude::*, prelude::*,
timer::{ timer::{
default_ms_irq_handler, set_up_ms_delay_provider, CascadeCtrl, CascadeSource, default_ms_irq_handler, set_up_ms_timer, CascadeCtrl, CascadeSource, CountDownTimer, Delay,
CountDownTimer, Event, IrqCfg, Event,
}, },
}; };
@ -28,16 +28,23 @@ fn main() -> ! {
rprintln!("-- VA108xx Cascade example application--"); rprintln!("-- VA108xx Cascade example application--");
let mut dp = pac::Peripherals::take().unwrap(); let mut dp = pac::Peripherals::take().unwrap();
let mut delay = set_up_ms_delay_provider(&mut dp.SYSCONFIG, 50.mhz(), dp.TIM0); let timer = set_up_ms_timer(
&mut dp.SYSCONFIG,
&mut dp.IRQSEL,
50.mhz().into(),
dp.TIM0,
pac::Interrupt::OC0,
);
let mut delay = Delay::new(timer);
// Will be started periodically to trigger a cascade // Will be started periodically to trigger a cascade
let mut cascade_triggerer = 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( cascade_triggerer.listen(
Event::TimeOut, Event::TimeOut,
IrqCfg::new(va108xx::Interrupt::OC1, true, false), &mut dp.SYSCONFIG,
Some(&mut dp.IRQSEL), &mut dp.IRQSEL,
Some(&mut dp.SYSCONFIG), va108xx::Interrupt::OC1,
); );
// First target for cascade // First target for cascade
@ -56,9 +63,9 @@ fn main() -> ! {
// the timer expires // the timer expires
cascade_target_1.listen( cascade_target_1.listen(
Event::TimeOut, Event::TimeOut,
IrqCfg::new(va108xx::Interrupt::OC2, true, false), &mut dp.SYSCONFIG,
Some(&mut dp.IRQSEL), &mut dp.IRQSEL,
Some(&mut dp.SYSCONFIG), va108xx::Interrupt::OC2,
); );
// The counter will only activate when the cascade signal is coming in so // The counter will only activate when the cascade signal is coming in so
// it is okay to call start here to set the reset value // it is okay to call start here to set the reset value
@ -82,9 +89,9 @@ fn main() -> ! {
// the timer expires // the timer expires
cascade_target_2.listen( cascade_target_2.listen(
Event::TimeOut, Event::TimeOut,
IrqCfg::new(va108xx::Interrupt::OC3, true, false), &mut dp.SYSCONFIG,
Some(&mut dp.IRQSEL), &mut dp.IRQSEL,
Some(&mut dp.SYSCONFIG), va108xx::Interrupt::OC3,
); );
// The counter will only activate when the cascade signal is coming in so // The counter will only activate when the cascade signal is coming in so
// it is okay to call start here to set the reset value // it is okay to call start here to set the reset value
@ -105,7 +112,7 @@ fn main() -> ! {
loop { loop {
rprintln!("-- Triggering cascade in 0.5 seconds --"); rprintln!("-- Triggering cascade in 0.5 seconds --");
cascade_triggerer.start(2.hz()); cascade_triggerer.start(2.hz());
delay.delay_ms(5000_u16); delay.delay_ms(5000);
} }
} }

View File

@ -8,10 +8,10 @@ use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print}; use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{ use va108xx_hal::{
gpio::PinsA, gpio::PinsA,
pac, pac::{self, interrupt},
prelude::*, prelude::*,
pwm::{self, get_duty_from_percent, ReducedPwmPin, PWMA, PWMB}, pwm::{self, get_duty_from_percent, ReducedPwmPin, PWMA, PWMB},
timer::set_up_ms_delay_provider, timer::{default_ms_irq_handler, set_up_ms_timer, Delay},
}; };
#[entry] #[entry]
@ -26,7 +26,17 @@ fn main() -> ! {
&mut dp.SYSCONFIG, &mut dp.SYSCONFIG,
10.hz(), 10.hz(),
); );
let mut delay = set_up_ms_delay_provider(&mut dp.SYSCONFIG, 50.mhz(), dp.TIM0); let timer = set_up_ms_timer(
&mut dp.SYSCONFIG,
&mut dp.IRQSEL,
50.mhz().into(),
dp.TIM0,
pac::Interrupt::OC0,
);
let mut delay = Delay::new(timer);
unsafe {
cortex_m::peripheral::NVIC::unmask(pac::Interrupt::OC0);
}
let mut current_duty_cycle = 0.0; let mut current_duty_cycle = 0.0;
PwmPin::set_duty(&mut pwm, get_duty_from_percent(current_duty_cycle)); PwmPin::set_duty(&mut pwm, get_duty_from_percent(current_duty_cycle));
PwmPin::enable(&mut pwm); PwmPin::enable(&mut pwm);
@ -36,7 +46,7 @@ fn main() -> ! {
loop { loop {
// Increase duty cycle continuously // Increase duty cycle continuously
while current_duty_cycle < 1.0 { while current_duty_cycle < 1.0 {
delay.delay_ms(200_u16); delay.delay_ms(200);
current_duty_cycle += 0.02; current_duty_cycle += 0.02;
PwmPin::set_duty(&mut reduced_pin, get_duty_from_percent(current_duty_cycle)); PwmPin::set_duty(&mut reduced_pin, get_duty_from_percent(current_duty_cycle));
} }
@ -50,7 +60,7 @@ fn main() -> ! {
pwmb.set_pwmb_lower_limit(get_duty_from_percent(lower_limit)); pwmb.set_pwmb_lower_limit(get_duty_from_percent(lower_limit));
pwmb.set_pwmb_upper_limit(get_duty_from_percent(upper_limit)); pwmb.set_pwmb_upper_limit(get_duty_from_percent(upper_limit));
while lower_limit < 0.5 { while lower_limit < 0.5 {
delay.delay_ms(200_u16); delay.delay_ms(200);
lower_limit += 0.01; lower_limit += 0.01;
upper_limit -= 0.01; upper_limit -= 0.01;
pwmb.set_pwmb_lower_limit(get_duty_from_percent(lower_limit)); pwmb.set_pwmb_lower_limit(get_duty_from_percent(lower_limit));
@ -61,3 +71,8 @@ fn main() -> ! {
reduced_pin = ReducedPwmPin::<PWMA>::from(pwmb); reduced_pin = ReducedPwmPin::<PWMA>::from(pwmb);
} }
} }
#[interrupt]
fn OC0() {
default_ms_irq_handler()
}

View File

@ -1,29 +0,0 @@
//! 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, init::Monotonics) {
rtt_init_default!();
rprintln!("-- Vorago RTIC template --");
(Shared {}, Local {}, init::Monotonics())
}
// `shared` cannot be accessed from this context
#[idle]
fn idle(_cx: idle::Context) -> ! {
loop {}
}
}

View File

@ -114,8 +114,12 @@ fn main() -> ! {
match SPI_BUS_SEL { match SPI_BUS_SEL {
SpiBusSelect::SpiAPortA | SpiBusSelect::SpiAPortB => { SpiBusSelect::SpiAPortA | SpiBusSelect::SpiAPortB => {
if let Some(ref mut spi) = *spia_ref.borrow_mut() { if let Some(ref mut spi) = *spia_ref.borrow_mut() {
let transfer_cfg = let transfer_cfg = TransferConfig::new_no_hw_cs(
TransferConfig::new_no_hw_cs(SPI_SPEED_KHZ.khz(), SPI_MODE, BLOCKMODE, false); SPI_SPEED_KHZ.khz().into(),
SPI_MODE,
BLOCKMODE,
false,
);
spi.cfg_transfer(&transfer_cfg); spi.cfg_transfer(&transfer_cfg);
} }
} }
@ -123,7 +127,7 @@ fn main() -> ! {
if let Some(ref mut spi) = *spib_ref.borrow_mut() { if let Some(ref mut spi) = *spib_ref.borrow_mut() {
let hw_cs_pin = pinsb.pb2.into_funsel_1(); let hw_cs_pin = pinsb.pb2.into_funsel_1();
let transfer_cfg = TransferConfig::new( let transfer_cfg = TransferConfig::new(
SPI_SPEED_KHZ.khz(), SPI_SPEED_KHZ.khz().into(),
SPI_MODE, SPI_MODE,
Some(hw_cs_pin), Some(hw_cs_pin),
BLOCKMODE, BLOCKMODE,

View File

@ -14,7 +14,7 @@ use va108xx_hal::{
pac::{self, interrupt}, pac::{self, interrupt},
prelude::*, prelude::*,
time::Hertz, time::Hertz,
timer::{default_ms_irq_handler, set_up_ms_timer, CountDownTimer, Delay, IrqCfg}, timer::{default_ms_irq_handler, set_up_ms_timer, CountDownTimer, Delay},
}; };
#[allow(dead_code)] #[allow(dead_code)]
@ -146,12 +146,15 @@ fn main() -> ! {
} }
TestCase::DelayMs => { TestCase::DelayMs => {
let ms_timer = set_up_ms_timer( let ms_timer = set_up_ms_timer(
IrqCfg::new(pac::Interrupt::OC0, true, true),
&mut dp.SYSCONFIG, &mut dp.SYSCONFIG,
Some(&mut dp.IRQSEL), &mut dp.IRQSEL,
50.mhz(), 50.mhz().into(),
dp.TIM0, dp.TIM0,
pac::Interrupt::OC0,
); );
unsafe {
cortex_m::peripheral::NVIC::unmask(pac::Interrupt::OC0);
}
let mut delay = Delay::new(ms_timer); let mut delay = Delay::new(ms_timer);
for _ in 0..5 { for _ in 0..5 {
led1.toggle().ok(); led1.toggle().ok();
@ -160,7 +163,7 @@ fn main() -> ! {
delay.delay_ms(500); delay.delay_ms(500);
} }
let mut delay_timer = CountDownTimer::new(&mut dp.SYSCONFIG, 50.mhz(), dp.TIM1); let mut delay_timer = CountDownTimer::new(&mut dp.SYSCONFIG, 50.mhz().into(), dp.TIM1);
let mut pa0 = pinsa.pa0.into_push_pull_output(); let mut pa0 = pinsa.pa0.into_push_pull_output();
for _ in 0..5 { for _ in 0..5 {
led1.toggle().ok(); led1.toggle().ok();

View File

@ -12,7 +12,7 @@ use va108xx_hal::{
pac::{self, interrupt}, pac::{self, interrupt},
prelude::*, prelude::*,
time::Hertz, time::Hertz,
timer::{default_ms_irq_handler, set_up_ms_timer, CountDownTimer, Event, IrqCfg, MS_COUNTER}, timer::{default_ms_irq_handler, set_up_ms_timer, CountDownTimer, Event, MS_COUNTER},
}; };
#[allow(dead_code)] #[allow(dead_code)]
@ -65,21 +65,22 @@ fn main() -> ! {
} }
LibType::Hal => { LibType::Hal => {
set_up_ms_timer( set_up_ms_timer(
IrqCfg::new(interrupt::OC0, true, true),
&mut dp.SYSCONFIG, &mut dp.SYSCONFIG,
Some(&mut dp.IRQSEL), &mut dp.IRQSEL,
50.mhz(), 50.mhz().into(),
dp.TIM0, dp.TIM0,
interrupt::OC0,
); );
let mut second_timer = 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( second_timer.listen(
Event::TimeOut, Event::TimeOut,
IrqCfg::new(interrupt::OC1, true, true), &mut dp.SYSCONFIG,
Some(&mut dp.IRQSEL), &mut dp.IRQSEL,
Some(&mut dp.SYSCONFIG), interrupt::OC1,
); );
second_timer.start(1.hz()); second_timer.start(1.hz());
unmask_irqs();
} }
} }
loop { loop {

View File

@ -1,126 +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 core::fmt::Write;
use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_default, set_print_channel};
use va108xx_hal::{
gpio::PinsB,
pac,
prelude::*,
uart::{self, IrqCfg, IrqResult, UartWithIrqBase},
};
#[local]
struct Local {}
#[shared]
struct Shared {
irq_uart: UartWithIrqBase<pac::UARTB>,
rx_buf: [u8; 64],
}
#[init]
fn init(ctx: init::Context) -> (Shared, Local, init::Monotonics) {
let channels = rtt_init_default!();
set_print_channel(channels.up.0);
rprintln!("-- VA108xx UART IRQ example application--");
let mut dp = ctx.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::uartb(
dp.UARTB,
(tx, rx),
115200.bps(),
&mut dp.SYSCONFIG,
50.mhz(),
)
.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_buf: [u8; 64] = [0; 64];
(Shared { irq_uart, rx_buf }, Local {}, init::Monotonics())
}
// `shared` cannot be accessed from this context
#[idle]
fn idle(_cx: idle::Context) -> ! {
loop {}
}
#[task(
binds = OC3,
shared = [irq_uart, rx_buf],
local = [cnt: u32 = 0, result: IrqResult = IrqResult::new()],
priority = 4
)]
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 in 0..rx_buf.len() {
if (rx_buf[idx] 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);
reply_handler::spawn(result.bytes_read, end_idx, result.timeout()).unwrap();
}
*cnt += 1;
}
#[task(shared = [irq_uart, rx_buf], priority = 3)]
fn reply_handler(cx: reply_handler::Context, bytes_read: usize, end_idx: usize, timeout: bool) {
let irq_uart = cx.shared.irq_uart;
let rx_buf = cx.shared.rx_buf;
(irq_uart, rx_buf).lock(|irq_uart, rx_buf| {
rprintln!("Reception success, {} bytes read", bytes_read);
if timeout {
rprintln!("Timeout occured");
}
let string = core::str::from_utf8(&rx_buf[0..end_idx]).expect("Invalid string format");
rprintln!("Read string: {}", string);
writeln!(irq_uart.uart, "{}", string).expect("Sending reply failed");
});
}
}

View File

@ -25,7 +25,7 @@ fn main() -> ! {
(tx, rx), (tx, rx),
115200.bps(), 115200.bps(),
&mut dp.SYSCONFIG, &mut dp.SYSCONFIG,
50.mhz(), 50.mhz().into(),
); );
let (mut tx, mut rx) = uartb.split(); let (mut tx, mut rx) = uartb.split();
writeln!(tx, "Hello World\r").unwrap(); writeln!(tx, "Hello World\r").unwrap();

View File

@ -11,7 +11,7 @@ static SYS_CLOCK: Mutex<OnceCell<Hertz>> = Mutex::new(OnceCell::new());
pub type PeripheralClocks = PeripheralSelect; pub type PeripheralClocks = PeripheralSelect;
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq)]
pub enum FilterClkSel { pub enum FilterClkSel {
SysClk = 0, SysClk = 0,
Clk1 = 1, Clk1 = 1,
@ -50,14 +50,12 @@ pub fn set_clk_div_register(syscfg: &mut SYSCONFIG, clk_sel: FilterClkSel, div:
} }
} }
#[inline]
pub fn enable_peripheral_clock(syscfg: &mut SYSCONFIG, clock: PeripheralClocks) { pub fn enable_peripheral_clock(syscfg: &mut SYSCONFIG, clock: PeripheralClocks) {
syscfg syscfg
.peripheral_clk_enable .peripheral_clk_enable
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << clock as u8)) }); .modify(|r, w| unsafe { w.bits(r.bits() | (1 << clock as u8)) });
} }
#[inline]
pub fn disable_peripheral_clock(syscfg: &mut SYSCONFIG, clock: PeripheralClocks) { pub fn disable_peripheral_clock(syscfg: &mut SYSCONFIG, clock: PeripheralClocks) {
syscfg syscfg
.peripheral_clk_enable .peripheral_clk_enable

View File

@ -57,17 +57,14 @@
//! operation, the trait functions will return //! operation, the trait functions will return
//! [`InvalidPinType`](PinError::InvalidPinType). //! [`InvalidPinType`](PinError::InvalidPinType).
use super::{ use super::pins::{
pins::{
common_reg_if_functions, FilterType, InterruptEdge, InterruptLevel, Pin, PinError, PinId, common_reg_if_functions, FilterType, InterruptEdge, InterruptLevel, Pin, PinError, PinId,
PinMode, PinState, PinMode, PinState,
},
reg::RegisterInterface,
}; };
use super::reg::RegisterInterface;
use crate::{ use crate::{
clock::FilterClkSel, clock::FilterClkSel,
pac::{IRQSEL, SYSCONFIG}, pac::{self, IRQSEL, SYSCONFIG},
utility::{Funsel, IrqCfg},
}; };
use embedded_hal::digital::v2::{InputPin, OutputPin, ToggleableOutputPin}; use embedded_hal::digital::v2::{InputPin, OutputPin, ToggleableOutputPin};
use paste::paste; use paste::paste;
@ -101,7 +98,13 @@ pub enum DynOutput {
ReadableOpenDrain, ReadableOpenDrain,
} }
pub type DynAlternate = Funsel; /// Value-level `enum` for alternate peripheral function configurations
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum DynAlternate {
Funsel1,
Funsel2,
Funsel3,
}
//================================================================================================== //==================================================================================================
// DynPinMode // DynPinMode
@ -143,14 +146,14 @@ pub const DYN_ALT_FUNC_3: DynPinMode = DynPinMode::Alternate(DynAlternate::Funse
//================================================================================================== //==================================================================================================
/// Value-level `enum` for pin groups /// Value-level `enum` for pin groups
#[derive(PartialEq, Eq, Clone, Copy)] #[derive(PartialEq, Clone, Copy)]
pub enum DynGroup { pub enum DynGroup {
A, A,
B, B,
} }
/// Value-level `struct` representing pin IDs /// Value-level `struct` representing pin IDs
#[derive(PartialEq, Eq, Clone, Copy)] #[derive(PartialEq, Clone, Copy)]
pub struct DynPinId { pub struct DynPinId {
pub group: DynGroup, pub group: DynGroup,
pub num: u8, pub num: u8,
@ -344,14 +347,14 @@ impl DynPin {
pub fn interrupt_edge( pub fn interrupt_edge(
mut self, mut self,
edge_type: InterruptEdge, edge_type: InterruptEdge,
irq_cfg: IrqCfg,
syscfg: Option<&mut SYSCONFIG>, syscfg: Option<&mut SYSCONFIG>,
irqsel: Option<&mut IRQSEL>, irqsel: &mut IRQSEL,
interrupt: pac::Interrupt,
) -> Result<Self, PinError> { ) -> Result<Self, PinError> {
match self.mode { match self.mode {
DynPinMode::Input(_) | DynPinMode::Output(_) => { DynPinMode::Input(_) | DynPinMode::Output(_) => {
self._irq_enb(syscfg, irqsel, interrupt);
self.regs.interrupt_edge(edge_type); self.regs.interrupt_edge(edge_type);
self.irq_enb(irq_cfg, syscfg, irqsel);
Ok(self) Ok(self)
} }
_ => Err(PinError::InvalidPinType), _ => Err(PinError::InvalidPinType),
@ -361,14 +364,14 @@ impl DynPin {
pub fn interrupt_level( pub fn interrupt_level(
mut self, mut self,
level_type: InterruptLevel, level_type: InterruptLevel,
irq_cfg: IrqCfg,
syscfg: Option<&mut SYSCONFIG>, syscfg: Option<&mut SYSCONFIG>,
irqsel: Option<&mut IRQSEL>, irqsel: &mut IRQSEL,
interrupt: crate::pac::Interrupt,
) -> Result<Self, PinError> { ) -> Result<Self, PinError> {
match self.mode { match self.mode {
DynPinMode::Input(_) | DynPinMode::Output(_) => { DynPinMode::Input(_) | DynPinMode::Output(_) => {
self._irq_enb(syscfg, irqsel, interrupt);
self.regs.interrupt_level(level_type); self.regs.interrupt_level(level_type);
self.irq_enb(irq_cfg, syscfg, irqsel);
Ok(self) Ok(self)
} }
_ => Err(PinError::InvalidPinType), _ => Err(PinError::InvalidPinType),

View File

@ -92,9 +92,8 @@
use super::dynpins::{DynAlternate, DynGroup, DynInput, DynOutput, DynPinId, DynPinMode}; use super::dynpins::{DynAlternate, DynGroup, DynInput, DynOutput, DynPinId, DynPinMode};
use super::reg::RegisterInterface; use super::reg::RegisterInterface;
use crate::{ use crate::{
pac::{IOCONFIG, IRQSEL, PORTA, PORTB, SYSCONFIG}, pac::{self, IOCONFIG, IRQSEL, PORTA, PORTB, SYSCONFIG},
typelevel::Is, typelevel::Is,
utility::IrqCfg,
Sealed, Sealed,
}; };
use core::convert::Infallible; use core::convert::Infallible;
@ -106,27 +105,27 @@ use paste::paste;
// Errors and Definitions // Errors and Definitions
//================================================================================================== //==================================================================================================
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq)]
pub enum InterruptEdge { pub enum InterruptEdge {
HighToLow, HighToLow,
LowToHigh, LowToHigh,
BothEdges, BothEdges,
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq)]
pub enum InterruptLevel { pub enum InterruptLevel {
Low = 0, Low = 0,
High = 1, High = 1,
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq)]
pub enum PinState { pub enum PinState {
Low = 0, Low = 0,
High = 1, High = 1,
} }
/// GPIO error type /// GPIO error type
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq)]
pub enum PinError { pub enum PinError {
/// The pin did not have the correct ID or mode for the requested operation. /// The pin did not have the correct ID or mode for the requested operation.
/// [`DynPin`](crate::gpio::DynPin)s are not tracked and verified at compile-time, so run-time /// [`DynPin`](crate::gpio::DynPin)s are not tracked and verified at compile-time, so run-time
@ -182,7 +181,7 @@ pub struct Input<C: InputConfig> {
impl<C: InputConfig> Sealed for Input<C> {} impl<C: InputConfig> Sealed for Input<C> {}
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq)]
pub enum FilterType { pub enum FilterType {
SystemClock = 0, SystemClock = 0,
DirectInputWithSynchronization = 1, DirectInputWithSynchronization = 1,
@ -398,11 +397,11 @@ macro_rules! common_reg_if_functions {
self.regs.write_pin_masked(false) self.regs.write_pin_masked(false)
} }
fn irq_enb( fn _irq_enb(
&mut self, &mut self,
irq_cfg: crate::utility::IrqCfg,
syscfg: Option<&mut va108xx::SYSCONFIG>, syscfg: Option<&mut va108xx::SYSCONFIG>,
irqsel: Option<&mut va108xx::IRQSEL>, irqsel: &mut va108xx::IRQSEL,
interrupt: va108xx::Interrupt,
) { ) {
if syscfg.is_some() { if syscfg.is_some() {
crate::clock::enable_peripheral_clock( crate::clock::enable_peripheral_clock(
@ -411,19 +410,15 @@ macro_rules! common_reg_if_functions {
); );
} }
self.regs.enable_irq(); self.regs.enable_irq();
if let Some(irqsel) = irqsel {
if irq_cfg.route {
match self.regs.id().group { match self.regs.id().group {
// Set the correct interrupt number in the IRQSEL register // Set the correct interrupt number in the IRQSEL register
DynGroup::A => { DynGroup::A => {
irqsel.porta[self.regs.id().num as usize] irqsel.porta[self.regs.id().num as usize]
.write(|w| unsafe { w.bits(irq_cfg.irq as u32) }); .write(|w| unsafe { w.bits(interrupt as u32) });
} }
DynGroup::B => { DynGroup::B => {
irqsel.portb[self.regs.id().num as usize] irqsel.portb[self.regs.id().num as usize]
.write(|w| unsafe { w.bits(irq_cfg.irq as u32) }); .write(|w| unsafe { w.bits(interrupt as u32) });
}
}
} }
} }
} }
@ -582,24 +577,24 @@ impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
pub fn interrupt_edge( pub fn interrupt_edge(
mut self, mut self,
edge_type: InterruptEdge, edge_type: InterruptEdge,
irq_cfg: IrqCfg,
syscfg: Option<&mut SYSCONFIG>, syscfg: Option<&mut SYSCONFIG>,
irqsel: Option<&mut IRQSEL>, irqsel: &mut IRQSEL,
interrupt: pac::Interrupt,
) -> Self { ) -> Self {
self._irq_enb(syscfg, irqsel, interrupt);
self.regs.interrupt_edge(edge_type); self.regs.interrupt_edge(edge_type);
self.irq_enb(irq_cfg, syscfg, irqsel);
self self
} }
pub fn interrupt_level( pub fn interrupt_level(
mut self, mut self,
level_type: InterruptLevel, level_type: InterruptLevel,
irq_cfg: IrqCfg,
syscfg: Option<&mut SYSCONFIG>, syscfg: Option<&mut SYSCONFIG>,
irqsel: Option<&mut IRQSEL>, irqsel: &mut IRQSEL,
interrupt: pac::Interrupt,
) -> Self { ) -> Self {
self._irq_enb(syscfg, irqsel, interrupt);
self.regs.interrupt_level(level_type); self.regs.interrupt_level(level_type);
self.irq_enb(irq_cfg, syscfg, irqsel);
self self
} }
} }
@ -627,24 +622,24 @@ impl<I: PinId, C: OutputConfig> Pin<I, Output<C>> {
pub fn interrupt_edge( pub fn interrupt_edge(
mut self, mut self,
edge_type: InterruptEdge, edge_type: InterruptEdge,
irq_cfg: IrqCfg,
syscfg: Option<&mut SYSCONFIG>, syscfg: Option<&mut SYSCONFIG>,
irqsel: Option<&mut IRQSEL>, irqsel: &mut IRQSEL,
interrupt: pac::Interrupt,
) -> Self { ) -> Self {
self._irq_enb(syscfg, irqsel, interrupt);
self.regs.interrupt_edge(edge_type); self.regs.interrupt_edge(edge_type);
self.irq_enb(irq_cfg, syscfg, irqsel);
self self
} }
pub fn interrupt_level( pub fn interrupt_level(
mut self, mut self,
level_type: InterruptLevel, level_type: InterruptLevel,
irq_cfg: IrqCfg,
syscfg: Option<&mut SYSCONFIG>, syscfg: Option<&mut SYSCONFIG>,
irqsel: Option<&mut IRQSEL>, irqsel: &mut IRQSEL,
interrupt: pac::Interrupt,
) -> Self { ) -> Self {
self._irq_enb(syscfg, irqsel, interrupt);
self.regs.interrupt_level(level_type); self.regs.interrupt_level(level_type);
self.irq_enb(irq_cfg, syscfg, irqsel);
self self
} }
} }

View File

@ -60,7 +60,18 @@ impl From<DynPinMode> for ModeFields {
} }
} }
Alternate(config) => { Alternate(config) => {
fields.funsel = config as u8; use dynpins::DynAlternate::*;
match config {
Funsel1 => {
fields.funsel = 1;
}
Funsel2 => {
fields.funsel = 2;
}
Funsel3 => {
fields.funsel = 3;
}
}
} }
} }
fields fields

View File

@ -2,7 +2,7 @@
//! //!
//! ## Examples //! ## Examples
//! //!
//! - [REB1 I2C temperature sensor example](https://egit.irs.uni-stuttgart.de/rust/vorago-reb1/src/branch/main/examples/adt75-temp-sensor.rs) //! - [REB1 I2C temperature sensor example](https://github.com/robamu-org/vorago-reb1-rs/blob/main/examples/temp-sensor.rs)
use crate::{ use crate::{
clock::{enable_peripheral_clock, PeripheralClocks}, clock::{enable_peripheral_clock, PeripheralClocks},
pac::{I2CA, I2CB, SYSCONFIG}, pac::{I2CA, I2CB, SYSCONFIG},
@ -18,13 +18,13 @@ pub use embedded_hal::blocking::i2c::{SevenBitAddress, TenBitAddress};
// Defintions // Defintions
//================================================================================================== //==================================================================================================
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
pub enum FifoEmptyMode { pub enum FifoEmptyMode {
Stall = 0, Stall = 0,
EndTransaction = 1, EndTransaction = 1,
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq)]
pub enum Error { pub enum Error {
InvalidTimingParams, InvalidTimingParams,
ArbitrationLost, ArbitrationLost,
@ -46,19 +46,19 @@ enum I2cCmd {
Cancel = 0b100, Cancel = 0b100,
} }
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
pub enum I2cSpeed { pub enum I2cSpeed {
Regular100khz = 0, Regular100khz = 0,
Fast400khz = 1, Fast400khz = 1,
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq)]
pub enum I2cDirection { pub enum I2cDirection {
Send = 0, Send = 0,
Read = 1, Read = 1,
} }
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
pub enum I2cAddress { pub enum I2cAddress {
Regular(u8), Regular(u8),
TenBit(u16), TenBit(u16),
@ -119,14 +119,14 @@ impl TimingCfg {
} }
pub fn reg(&self) -> u32 { pub fn reg(&self) -> u32 {
(self.tbuf as u32) << 28 ((self.tbuf as u32) << 28
| (self.thd_sta as u32) << 24 | (self.thd_sta as u32) << 24
| (self.tsu_sta as u32) << 20 | (self.tsu_sta as u32) << 20
| (self.tsu_sto as u32) << 16 | (self.tsu_sto as u32) << 16
| (self.tlow as u32) << 12 | (self.tlow as u32) << 12
| (self.thigh as u32) << 8 | (self.thigh as u32) << 8
| (self.tf as u32) << 4 | (self.tf as u32) << 4
| (self.tr as u32) | (self.tr as u32)) as u32
} }
} }
@ -231,7 +231,7 @@ macro_rules! i2c_base {
impl I2cBase<$I2CX> { impl I2cBase<$I2CX> {
pub fn $i2cx( pub fn $i2cx(
i2c: $I2CX, i2c: $I2CX,
sys_clk: impl Into<Hertz>, sys_clk: impl Into<Hertz> + Copy,
speed_mode: I2cSpeed, speed_mode: I2cSpeed,
ms_cfg: Option<&MasterConfig>, ms_cfg: Option<&MasterConfig>,
sl_cfg: Option<&SlaveConfig>, sl_cfg: Option<&SlaveConfig>,
@ -740,7 +740,7 @@ macro_rules! i2c_slave {
fn $i2cx_slave( fn $i2cx_slave(
i2c: $I2CX, i2c: $I2CX,
cfg: SlaveConfig, cfg: SlaveConfig,
sys_clk: impl Into<Hertz>, sys_clk: impl Into<Hertz> + Copy,
speed_mode: I2cSpeed, speed_mode: I2cSpeed,
sys_cfg: Option<&mut SYSCONFIG>, sys_cfg: Option<&mut SYSCONFIG>,
) -> Self { ) -> Self {
@ -897,7 +897,7 @@ macro_rules! i2c_slave {
pub fn i2ca( pub fn i2ca(
i2c: $I2CX, i2c: $I2CX,
cfg: SlaveConfig, cfg: SlaveConfig,
sys_clk: impl Into<Hertz>, sys_clk: impl Into<Hertz> + Copy,
speed_mode: I2cSpeed, speed_mode: I2cSpeed,
sys_cfg: Option<&mut SYSCONFIG>, sys_cfg: Option<&mut SYSCONFIG>,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
@ -912,7 +912,7 @@ macro_rules! i2c_slave {
pub fn $i2cx( pub fn $i2cx(
i2c: $I2CX, i2c: $I2CX,
cfg: SlaveConfig, cfg: SlaveConfig,
sys_clk: impl Into<Hertz>, sys_clk: impl Into<Hertz> + Copy,
speed_mode: I2cSpeed, speed_mode: I2cSpeed,
sys_cfg: Option<&mut SYSCONFIG>, sys_cfg: Option<&mut SYSCONFIG>,
) -> Self { ) -> Self {

View File

@ -25,7 +25,7 @@ use embedded_hal::{
// Defintions // Defintions
//================================================================================================== //==================================================================================================
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
pub enum HwChipSelectId { pub enum HwChipSelectId {
Id0 = 0, Id0 = 0,
Id1 = 1, Id1 = 1,
@ -38,7 +38,7 @@ pub enum HwChipSelectId {
Invalid = 0xff, Invalid = 0xff,
} }
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
pub enum WordSize { pub enum WordSize {
OneBit = 0x00, OneBit = 0x00,
FourBits = 0x03, FourBits = 0x03,
@ -218,9 +218,9 @@ pub struct ReducedTransferConfig {
} }
impl TransferConfig<NoneT> { impl TransferConfig<NoneT> {
pub fn new_no_hw_cs(spi_clk: impl Into<Hertz>, mode: Mode, blockmode: bool, sod: bool) -> Self { pub fn new_no_hw_cs(spi_clk: Hertz, mode: Mode, blockmode: bool, sod: bool) -> Self {
TransferConfig { TransferConfig {
spi_clk: spi_clk.into(), spi_clk,
mode, mode,
hw_cs: None, hw_cs: None,
sod, sod,
@ -231,14 +231,14 @@ impl TransferConfig<NoneT> {
impl<HWCS: HwCs> TransferConfig<HWCS> { impl<HWCS: HwCs> TransferConfig<HWCS> {
pub fn new( pub fn new(
spi_clk: impl Into<Hertz>, spi_clk: Hertz,
mode: Mode, mode: Mode,
hw_cs: Option<HWCS>, hw_cs: Option<HWCS>,
blockmode: bool, blockmode: bool,
sod: bool, sod: bool,
) -> Self { ) -> Self {
TransferConfig { TransferConfig {
spi_clk: spi_clk.into(), spi_clk,
mode, mode,
hw_cs, hw_cs,
sod, sod,
@ -428,7 +428,6 @@ macro_rules! spi {
w.sod().bit(sod); w.sod().bit(sod);
w.ms().bit(ms); w.ms().bit(ms);
w.mdlycap().bit(mdlycap); w.mdlycap().bit(mdlycap);
w.blockmode().bit(init_blockmode);
unsafe { w.ss().bits(ss) } unsafe { w.ss().bits(ss) }
}); });
@ -453,7 +452,7 @@ macro_rules! spi {
} }
#[inline] #[inline]
pub fn cfg_clock(&mut self, spi_clk: impl Into<Hertz>) { pub fn cfg_clock(&mut self, spi_clk: Hertz) {
self.spi_base.cfg_clock(spi_clk); self.spi_base.cfg_clock(spi_clk);
} }
@ -483,8 +482,8 @@ macro_rules! spi {
impl<WORD: Word> SpiBase<$SPIX, WORD> { impl<WORD: Word> SpiBase<$SPIX, WORD> {
#[inline] #[inline]
pub fn cfg_clock(&mut self, spi_clk: impl Into<Hertz>) { pub fn cfg_clock(&mut self, spi_clk: Hertz) {
let clk_prescale = self.sys_clk.0 / (spi_clk.into().0 * (self.cfg.scrdv as u32 + 1)); let clk_prescale = self.sys_clk.0 / (spi_clk.0 * (self.cfg.scrdv as u32 + 1));
self.spi self.spi
.clkprescale .clkprescale
.write(|w| unsafe { w.bits(clk_prescale) }); .write(|w| unsafe { w.bits(clk_prescale) });
@ -504,16 +503,6 @@ macro_rules! spi {
}); });
} }
#[inline]
pub fn clear_tx_fifo(&self) {
self.spi.fifo_clr.write(|w| w.txfifo().set_bit());
}
#[inline]
pub fn clear_rx_fifo(&self) {
self.spi.fifo_clr.write(|w| w.rxfifo().set_bit());
}
#[inline] #[inline]
pub fn perid(&self) -> u32 { pub fn perid(&self) -> u32 {
self.spi.perid.read().bits() self.spi.perid.read().bits()
@ -650,9 +639,6 @@ macro_rules! spi {
// FIFO has a depth of 16. // FIFO has a depth of 16.
const FILL_DEPTH: usize = 12; const FILL_DEPTH: usize = 12;
self.clear_tx_fifo();
self.clear_rx_fifo();
if self.blockmode { if self.blockmode {
self.spi.ctrl1.modify(|_, w| { self.spi.ctrl1.modify(|_, w| {
w.mtxpause().set_bit() w.mtxpause().set_bit()

View File

@ -6,7 +6,7 @@
//! allowing it to be converted into frequencies. //! allowing it to be converted into frequencies.
/// Bits per second /// Bits per second
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Debug)] #[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct Bps(pub u32); pub struct Bps(pub u32);
/// Hertz /// Hertz
@ -25,7 +25,7 @@ pub struct Bps(pub u32);
/// ///
/// let freq = 60.hz(); /// let freq = 60.hz();
/// ``` /// ```
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Debug)] #[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct Hertz(pub u32); pub struct Hertz(pub u32);
/// Kilohertz /// Kilohertz
@ -47,7 +47,7 @@ pub struct Hertz(pub u32);
/// ///
/// let freq = 100.khz(); /// let freq = 100.khz();
/// ``` /// ```
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Debug)] #[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct KiloHertz(pub u32); pub struct KiloHertz(pub u32);
/// Megahertz /// Megahertz
@ -68,14 +68,14 @@ pub struct KiloHertz(pub u32);
/// ///
/// let freq = 8.mhz(); /// let freq = 8.mhz();
/// ``` /// ```
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Debug)] #[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct MegaHertz(pub u32); pub struct MegaHertz(pub u32);
/// Time unit /// Time unit
#[derive(PartialEq, Eq, PartialOrd, Clone, Copy)] #[derive(PartialEq, PartialOrd, Clone, Copy)]
pub struct MilliSeconds(pub u32); pub struct MilliSeconds(pub u32);
#[derive(PartialEq, Eq, PartialOrd, Clone, Copy)] #[derive(PartialEq, PartialOrd, Clone, Copy)]
pub struct MicroSeconds(pub u32); pub struct MicroSeconds(pub u32);
/// Extension trait that adds convenience methods to the `u32` type /// Extension trait that adds convenience methods to the `u32` type

View File

@ -4,7 +4,6 @@
//! //!
//! - [MS and second tick implementation](https://egit.irs.uni-stuttgart.de/rust/va108xx-hal/src/branch/main/examples/timer-ticks.rs) //! - [MS and second tick implementation](https://egit.irs.uni-stuttgart.de/rust/va108xx-hal/src/branch/main/examples/timer-ticks.rs)
//! - [Cascade feature example](https://egit.irs.uni-stuttgart.de/rust/va108xx-hal/src/branch/main/examples/cascade.rs) //! - [Cascade feature example](https://egit.irs.uni-stuttgart.de/rust/va108xx-hal/src/branch/main/examples/cascade.rs)
pub use crate::utility::IrqCfg;
use crate::{ use crate::{
clock::{enable_peripheral_clock, PeripheralClocks}, clock::{enable_peripheral_clock, PeripheralClocks},
gpio::{ gpio::{
@ -21,7 +20,6 @@ use crate::{
private::Sealed, private::Sealed,
time::Hertz, time::Hertz,
timer, timer,
utility::unmask_irq,
}; };
use core::cell::Cell; use core::cell::Cell;
use cortex_m::interrupt::Mutex; use cortex_m::interrupt::Mutex;
@ -29,7 +27,7 @@ use embedded_hal::{
blocking::delay, blocking::delay,
timer::{Cancel, CountDown, Periodic}, timer::{Cancel, CountDown, Periodic},
}; };
use va108xx::{IRQSEL, SYSCONFIG}; use va108xx::{Interrupt, IRQSEL, SYSCONFIG};
use void::Void; use void::Void;
const IRQ_DST_NONE: u32 = 0xffffffff; const IRQ_DST_NONE: u32 = 0xffffffff;
@ -45,7 +43,7 @@ pub enum Event {
TimeOut, TimeOut,
} }
#[derive(Default, Debug, PartialEq, Eq, Copy, Clone)] #[derive(Default, Debug, PartialEq, Copy, Clone)]
pub struct CascadeCtrl { pub struct CascadeCtrl {
/// Enable Cascade 0 signal active as a requirement for counting /// Enable Cascade 0 signal active as a requirement for counting
pub enb_start_src_csd0: bool, pub enb_start_src_csd0: bool,
@ -74,7 +72,7 @@ pub struct CascadeCtrl {
pub trg_csd2: bool, pub trg_csd2: bool,
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq)]
pub enum CascadeSel { pub enum CascadeSel {
Csd0 = 0, Csd0 = 0,
Csd1 = 1, Csd1 = 1,
@ -82,7 +80,7 @@ pub enum CascadeSel {
} }
/// The numbers are the base numbers for bundles like PORTA, PORTB or TIM /// The numbers are the base numbers for bundles like PORTA, PORTB or TIM
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq)]
pub enum CascadeSource { pub enum CascadeSource {
PortABase = 0, PortABase = 0,
PortBBase = 32, PortBBase = 32,
@ -95,7 +93,7 @@ pub enum CascadeSource {
ClockDividerBase = 120, ClockDividerBase = 120,
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq)]
pub enum TimerErrors { pub enum TimerErrors {
Canceled, Canceled,
/// Invalid input for Cascade source /// Invalid input for Cascade source
@ -388,7 +386,6 @@ unsafe impl TimPinInterface for TimDynRegister {
pub struct CountDownTimer<TIM: ValidTim> { pub struct CountDownTimer<TIM: ValidTim> {
tim: TimRegister<TIM>, tim: TimRegister<TIM>,
curr_freq: Hertz, curr_freq: Hertz,
irq_cfg: Option<IrqCfg>,
sys_clk: Hertz, sys_clk: Hertz,
rst_val: u32, rst_val: u32,
last_cnt: u32, last_cnt: u32,
@ -485,7 +482,6 @@ impl<TIM: ValidTim> CountDownTimer<TIM> {
let cd_timer = CountDownTimer { let cd_timer = CountDownTimer {
tim: unsafe { TimRegister::new(tim) }, tim: unsafe { TimRegister::new(tim) },
sys_clk: sys_clk.into(), sys_clk: sys_clk.into(),
irq_cfg: None,
rst_val: 0, rst_val: 0,
curr_freq: 0.hz(), curr_freq: 0.hz(),
listening: false, listening: false,
@ -495,28 +491,21 @@ impl<TIM: ValidTim> CountDownTimer<TIM> {
cd_timer cd_timer
} }
/// Listen for events. Depending on the IRQ configuration, this also activates the IRQ in the /// Listen for events. This also actives the IRQ in the IRQSEL register
/// IRQSEL peripheral for the provided interrupt and unmasks the interrupt /// for the provided interrupt. It also actives the peripheral clock for
/// IRQSEL
pub fn listen( pub fn listen(
&mut self, &mut self,
event: Event, event: Event,
irq_cfg: IrqCfg, syscfg: &mut SYSCONFIG,
irq_sel: Option<&mut IRQSEL>, irqsel: &mut IRQSEL,
sys_cfg: Option<&mut SYSCONFIG>, interrupt: Interrupt,
) { ) {
match event { match event {
Event::TimeOut => { Event::TimeOut => {
cortex_m::peripheral::NVIC::mask(irq_cfg.irq); enable_peripheral_clock(syscfg, PeripheralClocks::Irqsel);
self.irq_cfg = Some(irq_cfg); irqsel.tim[TIM::TIM_ID as usize].write(|w| unsafe { w.bits(interrupt as u32) });
if irq_cfg.route { self.enable_interrupt();
if let Some(sys_cfg) = sys_cfg {
enable_peripheral_clock(sys_cfg, PeripheralClocks::Irqsel);
}
if let Some(irq_sel) = irq_sel {
irq_sel.tim[TIM::TIM_ID as usize]
.write(|w| unsafe { w.bits(irq_cfg.irq as u32) });
}
}
self.listening = true; self.listening = true;
} }
} }
@ -565,12 +554,6 @@ impl<TIM: ValidTim> CountDownTimer<TIM> {
#[inline(always)] #[inline(always)]
pub fn enable(&mut self) { pub fn enable(&mut self) {
self.tim.reg().ctrl.modify(|_, w| w.enable().set_bit()); self.tim.reg().ctrl.modify(|_, w| w.enable().set_bit());
if let Some(irq_cfg) = self.irq_cfg {
self.enable_interrupt();
if irq_cfg.enable {
unmask_irq(irq_cfg.irq);
}
}
} }
#[inline(always)] #[inline(always)]
@ -737,29 +720,19 @@ impl<TIM: ValidTim> embedded_hal::blocking::delay::DelayMs<u8> for CountDownTime
// Set up a millisecond timer on TIM0. Please note that you still need to unmask the related IRQ // Set up a millisecond timer on TIM0. Please note that you still need to unmask the related IRQ
// and provide an IRQ handler yourself // and provide an IRQ handler yourself
pub fn set_up_ms_timer<TIM: ValidTim>( pub fn set_up_ms_timer(
irq_cfg: IrqCfg, syscfg: &mut pac::SYSCONFIG,
sys_cfg: &mut pac::SYSCONFIG, irqsel: &mut pac::IRQSEL,
irq_sel: Option<&mut pac::IRQSEL>, sys_clk: Hertz,
sys_clk: impl Into<Hertz>, tim0: TIM0,
tim0: TIM, irq: pac::Interrupt,
) -> CountDownTimer<TIM> { ) -> CountDownTimer<TIM0> {
let mut ms_timer = CountDownTimer::new(sys_cfg, sys_clk, tim0); let mut ms_timer = CountDownTimer::new(syscfg, sys_clk, tim0);
ms_timer.listen(timer::Event::TimeOut, irq_cfg, irq_sel, Some(sys_cfg)); ms_timer.listen(timer::Event::TimeOut, syscfg, irqsel, irq);
ms_timer.start(1000.hz()); ms_timer.start(1000.hz());
ms_timer ms_timer
} }
pub fn set_up_ms_delay_provider<TIM: ValidTim>(
sys_cfg: &mut pac::SYSCONFIG,
sys_clk: impl Into<Hertz>,
tim: TIM,
) -> CountDownTimer<TIM> {
let mut provider = CountDownTimer::new(sys_cfg, sys_clk, tim);
provider.start(1000.hz());
provider
}
/// This function can be called in a specified interrupt handler to increment /// This function can be called in a specified interrupt handler to increment
/// the MS counter /// the MS counter
pub fn default_ms_irq_handler() { pub fn default_ms_irq_handler() {
@ -790,7 +763,6 @@ impl Delay {
} }
/// This assumes that the user has already set up a MS tick timer in TIM0 as a system tick /// This assumes that the user has already set up a MS tick timer in TIM0 as a system tick
/// with [`set_up_ms_delay_provider`]
impl embedded_hal::blocking::delay::DelayMs<u32> for Delay { impl embedded_hal::blocking::delay::DelayMs<u32> for Delay {
fn delay_ms(&mut self, ms: u32) { fn delay_ms(&mut self, ms: u32) {
if self.cd_tim.curr_freq() != 1000.hz() || !self.cd_tim.listening() { if self.cd_tim.curr_freq() != 1000.hz() || !self.cd_tim.listening() {

View File

@ -2,31 +2,25 @@
//! //!
//! ## Examples //! ## Examples
//! //!
//! - [UART simple example](https://egit.irs.uni-stuttgart.de/rust/va108xx-hal/src/branch/main/examples/uart.rs) //! - [UART example](https://egit.irs.uni-stuttgart.de/rust/va108xx-hal/src/branch/main/examples/uart.rs)
//! - [UART with IRQ and RTIC](https://egit.irs.uni-stuttgart.de/rust/va108xx-hal/src/branch/main/examples/uart-irq-rtic.rs)
use core::{convert::Infallible, ptr}; use core::{convert::Infallible, ptr};
use core::{marker::PhantomData, ops::Deref}; use core::{marker::PhantomData, ops::Deref};
use libm::floorf; use libm::floorf;
pub use crate::utility::IrqCfg; use crate::clock::enable_peripheral_clock;
use crate::{ use crate::{
clock::{self, enable_peripheral_clock, PeripheralClocks}, clock,
gpio::pins::{ gpio::pins::{
AltFunc1, AltFunc2, AltFunc3, Pin, PA16, PA17, PA18, PA19, PA2, PA26, PA27, PA3, PA30, AltFunc1, AltFunc2, AltFunc3, Pin, PA16, PA17, PA18, PA19, PA2, PA26, PA27, PA3, PA30,
PA31, PA8, PA9, PB18, PB19, PB20, PB21, PB22, PB23, PB6, PB7, PB8, PB9, PA31, PA8, PA9, PB18, PB19, PB20, PB21, PB22, PB23, PB6, PB7, PB8, PB9,
}, },
pac::{uarta as uart_base, IRQSEL, SYSCONFIG, UARTA, UARTB}, pac::{uarta as uart_base, SYSCONFIG, UARTA, UARTB},
prelude::*, prelude::*,
time::{Bps, Hertz}, time::{Bps, Hertz},
utility::unmask_irq,
}; };
use embedded_hal::{blocking, serial}; use embedded_hal::{blocking, serial};
//==================================================================================================
// Type-Level support
//==================================================================================================
pub trait Pins<UART> {} pub trait Pins<UART> {}
impl Pins<UARTA> for (Pin<PA9, AltFunc2>, Pin<PA8, AltFunc2>) {} impl Pins<UARTA> for (Pin<PA9, AltFunc2>, Pin<PA8, AltFunc2>) {}
@ -44,23 +38,15 @@ impl Pins<UARTB> for (Pin<PB7, AltFunc1>, Pin<PB6, AltFunc1>) {}
impl Pins<UARTB> for (Pin<PB19, AltFunc2>, Pin<PB18, AltFunc2>) {} impl Pins<UARTB> for (Pin<PB19, AltFunc2>, Pin<PB18, AltFunc2>) {}
impl Pins<UARTB> for (Pin<PB21, AltFunc1>, Pin<PB20, AltFunc1>) {} impl Pins<UARTB> for (Pin<PB21, AltFunc1>, Pin<PB20, AltFunc1>) {}
//==================================================================================================
// Regular Definitions
//==================================================================================================
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
Overrun, Overrun,
FramingError, FramingError,
ParityError, ParityError,
BreakCondition, BreakCondition,
TransferPending,
BufferTooShort,
/// Can be a combination of overrun, framing or parity error
IrqError,
} }
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
pub enum Event { pub enum Event {
// Receiver FIFO interrupt enable. Generates interrupt // Receiver FIFO interrupt enable. Generates interrupt
// when FIFO is at least half full. Half full is defined as FIFO // when FIFO is at least half full. Half full is defined as FIFO
@ -84,20 +70,20 @@ pub enum Event {
TxCts, TxCts,
} }
#[derive(Copy, Clone, PartialEq, Eq)] #[derive(Copy, Clone, PartialEq)]
pub enum Parity { pub enum Parity {
None, None,
Odd, Odd,
Even, Even,
} }
#[derive(Copy, Clone, PartialEq, Eq)] #[derive(Copy, Clone, PartialEq)]
pub enum StopBits { pub enum StopBits {
One = 0, One = 0,
Two = 1, Two = 1,
} }
#[derive(Copy, Clone, PartialEq, Eq)] #[derive(Copy, Clone, PartialEq)]
pub enum WordSize { pub enum WordSize {
Five = 0, Five = 0,
Six = 1, Six = 1,
@ -174,144 +160,13 @@ impl From<Bps> for Config {
} }
} }
//================================================================================================== /// Serial abstraction
// IRQ Definitions pub struct Uart<UART, PINS> {
//==================================================================================================
struct IrqInfo {
rx_len: usize,
rx_idx: usize,
irq_cfg: IrqCfg,
mode: IrqReceptionMode,
}
pub enum IrqResultMask {
Complete = 0,
Overflow = 1,
FramingError = 2,
ParityError = 3,
Break = 4,
Timeout = 5,
Addr9 = 6,
/// Should not happen
Unknown = 7,
}
/// This struct is used to return the default IRQ handler result to the user
#[derive(Debug, Default)]
pub struct IrqResult {
raw_res: u32,
pub bytes_read: usize,
}
impl IrqResult {
pub const fn new() -> Self {
IrqResult {
raw_res: 0,
bytes_read: 0,
}
}
}
impl IrqResult {
#[inline]
pub fn raw_result(&self) -> u32 {
self.raw_res
}
#[inline]
pub(crate) fn clear_result(&mut self) {
self.raw_res = 0;
}
#[inline]
pub(crate) fn set_result(&mut self, flag: IrqResultMask) {
self.raw_res |= 1 << flag as u32;
}
#[inline]
pub fn complete(&self) -> bool {
if ((self.raw_res >> IrqResultMask::Complete as u32) & 0x01) == 0x01 {
return true;
}
false
}
#[inline]
pub fn error(&self) -> bool {
if self.overflow_error() || self.framing_error() || self.parity_error() {
return true;
}
false
}
#[inline]
pub fn overflow_error(&self) -> bool {
if ((self.raw_res >> IrqResultMask::Overflow as u32) & 0x01) == 0x01 {
return true;
}
false
}
#[inline]
pub fn framing_error(&self) -> bool {
if ((self.raw_res >> IrqResultMask::FramingError as u32) & 0x01) == 0x01 {
return true;
}
false
}
#[inline]
pub fn parity_error(&self) -> bool {
if ((self.raw_res >> IrqResultMask::ParityError as u32) & 0x01) == 0x01 {
return true;
}
false
}
#[inline]
pub fn timeout(&self) -> bool {
if ((self.raw_res >> IrqResultMask::Timeout as u32) & 0x01) == 0x01 {
return true;
}
false
}
}
#[derive(Debug, PartialEq)]
enum IrqReceptionMode {
Idle,
Pending,
}
//==================================================================================================
// UART implementation
//==================================================================================================
/// Type erased variant of a UART. Can be created with the [`Uart::downgrade`] function.
pub struct UartBase<UART> {
uart: UART, uart: UART,
pins: PINS,
tx: Tx<UART>, tx: Tx<UART>,
rx: Rx<UART>, rx: Rx<UART>,
} }
/// Serial abstraction. Entry point to create a new UART
pub struct Uart<UART, PINS> {
uart_base: UartBase<UART>,
pins: PINS,
}
/// UART using the IRQ capabilities of the peripheral. Can be created with the
/// [`Uart::into_uart_with_irq`] function.
pub struct UartWithIrq<UART, PINS> {
irq_base: UartWithIrqBase<UART>,
pins: PINS,
}
/// Type-erased UART using the IRQ capabilities of the peripheral. Can be created with the
/// [`UartWithIrq::downgrade`] function.
pub struct UartWithIrqBase<UART> {
pub uart: UartBase<UART>,
irq_info: IrqInfo,
}
/// Serial receiver /// Serial receiver
pub struct Rx<UART> { pub struct Rx<UART> {
@ -341,10 +196,12 @@ impl<UART> Tx<UART> {
pub trait Instance: Deref<Target = uart_base::RegisterBlock> { pub trait Instance: Deref<Target = uart_base::RegisterBlock> {
fn ptr() -> *const uart_base::RegisterBlock; fn ptr() -> *const uart_base::RegisterBlock;
const IDX: u8;
} }
impl<UART: Instance> UartBase<UART> { impl<UART, PINS> Uart<UART, PINS>
where
UART: Instance,
{
/// This function assumes that the peripheral clock was alredy enabled /// This function assumes that the peripheral clock was alredy enabled
/// in the SYSCONFIG register /// in the SYSCONFIG register
fn init(self, config: Config, sys_clk: Hertz) -> Self { fn init(self, config: Config, sys_clk: Hertz) -> Self {
@ -354,7 +211,7 @@ impl<UART: Instance> UartBase<UART> {
}; };
let x = sys_clk.0 as f32 / (config.baudrate.0 * baud_multiplier) as f32; let x = sys_clk.0 as f32 / (config.baudrate.0 * baud_multiplier) as f32;
let integer_part = floorf(x) as u32; let integer_part = floorf(x) as u32;
let frac = floorf(64.0 * (x - integer_part as f32) + 0.5) as u32; let frac = floorf((64.0 * (x - integer_part as f32) + 0.5) as f32) as u32;
self.uart self.uart
.clkscale .clkscale
.write(|w| unsafe { w.bits(integer_part * 64 + frac) }); .write(|w| unsafe { w.bits(integer_part * 64 + frac) });
@ -390,47 +247,7 @@ impl<UART: Instance> UartBase<UART> {
self self
} }
#[inline] pub fn listen(self, event: Event) -> Self {
pub fn enable_rx(&mut self) {
self.uart.enable.modify(|_, w| w.rxenable().set_bit());
}
#[inline]
pub fn disable_rx(&mut self) {
self.uart.enable.modify(|_, w| w.rxenable().clear_bit());
}
#[inline]
pub fn enable_tx(&mut self) {
self.uart.enable.modify(|_, w| w.txenable().set_bit());
}
#[inline]
pub fn disable_tx(&mut self) {
self.uart.enable.modify(|_, w| w.txenable().clear_bit());
}
#[inline]
pub fn clear_rx_fifo(&mut self) {
self.uart.fifo_clr.write(|w| w.rxfifo().set_bit());
}
#[inline]
pub fn clear_tx_fifo(&mut self) {
self.uart.fifo_clr.write(|w| w.txfifo().set_bit());
}
#[inline]
pub fn clear_rx_status(&mut self) {
self.uart.fifo_clr.write(|w| w.rxsts().set_bit());
}
#[inline]
pub fn clear_tx_status(&mut self) {
self.uart.fifo_clr.write(|w| w.txsts().set_bit());
}
pub fn listen(&self, event: Event) {
self.uart.irq_enb.modify(|_, w| match event { self.uart.irq_enb.modify(|_, w| match event {
Event::RxError => w.irq_rx_status().set_bit(), Event::RxError => w.irq_rx_status().set_bit(),
Event::RxFifoHalfFull => w.irq_rx().set_bit(), Event::RxFifoHalfFull => w.irq_rx().set_bit(),
@ -440,9 +257,10 @@ impl<UART: Instance> UartBase<UART> {
Event::TxFifoHalfFull => w.irq_tx().set_bit(), Event::TxFifoHalfFull => w.irq_tx().set_bit(),
Event::TxCts => w.irq_tx_cts().set_bit(), Event::TxCts => w.irq_tx_cts().set_bit(),
}); });
self
} }
pub fn unlisten(&self, event: Event) { pub fn unlisten(self, event: Event) -> Self {
self.uart.irq_enb.modify(|_, w| match event { self.uart.irq_enb.modify(|_, w| match event {
Event::RxError => w.irq_rx_status().clear_bit(), Event::RxError => w.irq_rx_status().clear_bit(),
Event::RxFifoHalfFull => w.irq_rx().clear_bit(), Event::RxFifoHalfFull => w.irq_rx().clear_bit(),
@ -452,9 +270,10 @@ impl<UART: Instance> UartBase<UART> {
Event::TxFifoHalfFull => w.irq_tx().clear_bit(), Event::TxFifoHalfFull => w.irq_tx().clear_bit(),
Event::TxCts => w.irq_tx_cts().clear_bit(), Event::TxCts => w.irq_tx_cts().clear_bit(),
}); });
self
} }
pub fn release(self) -> UART { pub fn release(self) -> (UART, PINS) {
// Clear the FIFO // Clear the FIFO
self.uart.fifo_clr.write(|w| { self.uart.fifo_clr.write(|w| {
w.rxfifo().set_bit(); w.rxfifo().set_bit();
@ -464,7 +283,7 @@ impl<UART: Instance> UartBase<UART> {
w.rxenable().clear_bit(); w.rxenable().clear_bit();
w.txenable().clear_bit() w.txenable().clear_bit()
}); });
self.uart (self.uart, self.pins)
} }
pub fn split(self) -> (Tx<UART>, Rx<UART>) { pub fn split(self) -> (Tx<UART>, Rx<UART>) {
@ -472,132 +291,14 @@ impl<UART: Instance> UartBase<UART> {
} }
} }
impl<UART, PINS> Uart<UART, PINS>
where
UART: Instance,
{
/// This function assumes that the peripheral clock was alredy enabled
/// in the SYSCONFIG register
fn init(mut self, config: Config, sys_clk: Hertz) -> Self {
self.uart_base = self.uart_base.init(config, sys_clk);
self
}
/// If the IRQ capabilities of the peripheral are used, the UART needs to be converted
/// with this function
pub fn into_uart_with_irq(
self,
irq_cfg: IrqCfg,
sys_cfg: Option<&mut SYSCONFIG>,
irq_sel: Option<&mut IRQSEL>,
) -> UartWithIrq<UART, PINS> {
let (uart, pins) = self.downgrade_internal();
UartWithIrq {
pins,
irq_base: UartWithIrqBase {
uart,
irq_info: IrqInfo {
rx_len: 0,
rx_idx: 0,
irq_cfg,
mode: IrqReceptionMode::Idle,
},
}
.init(sys_cfg, irq_sel),
}
}
#[inline]
pub fn enable_rx(&mut self) {
self.uart_base.enable_rx();
}
#[inline]
pub fn disable_rx(&mut self) {
self.uart_base.enable_rx();
}
#[inline]
pub fn enable_tx(&mut self) {
self.uart_base.enable_tx();
}
#[inline]
pub fn disable_tx(&mut self) {
self.uart_base.disable_tx();
}
#[inline]
pub fn clear_rx_fifo(&mut self) {
self.uart_base.clear_rx_fifo();
}
#[inline]
pub fn clear_tx_fifo(&mut self) {
self.uart_base.clear_tx_fifo();
}
#[inline]
pub fn clear_rx_status(&mut self) {
self.uart_base.clear_rx_status();
}
#[inline]
pub fn clear_tx_status(&mut self) {
self.uart_base.clear_tx_status();
}
pub fn listen(&self, event: Event) {
self.uart_base.listen(event);
}
pub fn unlisten(&self, event: Event) {
self.uart_base.unlisten(event);
}
pub fn release(self) -> (UART, PINS) {
(self.uart_base.release(), self.pins)
}
fn downgrade_internal(self) -> (UartBase<UART>, PINS) {
let base = UartBase {
uart: self.uart_base.uart,
tx: self.uart_base.tx,
rx: self.uart_base.rx,
};
(base, self.pins)
}
pub fn downgrade(self) -> UartBase<UART> {
UartBase {
uart: self.uart_base.uart,
tx: self.uart_base.tx,
rx: self.uart_base.rx,
}
}
pub fn split(self) -> (Tx<UART>, Rx<UART>) {
self.uart_base.split()
}
}
impl Instance for UARTA {
fn ptr() -> *const uart_base::RegisterBlock {
UARTA::ptr() as *const _
}
const IDX: u8 = 0;
}
impl Instance for UARTB {
fn ptr() -> *const uart_base::RegisterBlock {
UARTB::ptr() as *const _
}
const IDX: u8 = 1;
}
macro_rules! uart_impl { macro_rules! uart_impl {
($($UARTX:ident: ($uartx:ident, $clk_enb_enum:path),)+) => { ($($UARTX:ident: ($uartx:ident, $clk_enb_enum:path),)+) => {
$( $(
impl Instance for $UARTX {
fn ptr() -> *const uart_base::RegisterBlock {
$UARTX::ptr() as *const _
}
}
impl<PINS: Pins<$UARTX>> Uart<$UARTX, PINS> { impl<PINS: Pins<$UARTX>> Uart<$UARTX, PINS> {
pub fn $uartx( pub fn $uartx(
@ -605,260 +306,19 @@ macro_rules! uart_impl {
pins: PINS, pins: PINS,
config: impl Into<Config>, config: impl Into<Config>,
syscfg: &mut SYSCONFIG, syscfg: &mut SYSCONFIG,
sys_clk: impl Into<Hertz> sys_clk: Hertz
) -> Self ) -> Self
{ {
enable_peripheral_clock(syscfg, $clk_enb_enum); enable_peripheral_clock(syscfg, $clk_enb_enum);
Uart { Uart { uart, pins, tx: Tx::new(), rx: Rx::new() }.init(
uart_base: UartBase { config.into(), sys_clk
uart, )
tx: Tx::new(),
rx: Rx::new(),
},
pins,
}
.init(config.into(), sys_clk.into())
} }
} }
)+ )+
} }
} }
impl<UART: Instance> UartWithIrqBase<UART> {
fn init(self, sys_cfg: Option<&mut SYSCONFIG>, irq_sel: Option<&mut IRQSEL>) -> Self {
if let Some(sys_cfg) = sys_cfg {
enable_peripheral_clock(sys_cfg, PeripheralClocks::Irqsel)
}
if let Some(irq_sel) = irq_sel {
if self.irq_info.irq_cfg.route {
irq_sel.uart[UART::IDX as usize]
.write(|w| unsafe { w.bits(self.irq_info.irq_cfg.irq as u32) });
}
}
self
}
/// This initializes a non-blocking read transfer using the IRQ capabilities of the UART
/// peripheral.
///
/// The only required information is the maximum length for variable sized reception
/// or the expected length for fixed length reception. If variable sized packets are expected,
/// the timeout functionality of the IRQ should be enabled as well. After calling this function,
/// the [`irq_handler`](Self::irq_handler) function should be called in the user interrupt
/// handler to read the received packets and reinitiate another transfer if desired.
pub fn read_fixed_len_using_irq(
&mut self,
max_len: usize,
enb_timeout_irq: bool,
) -> Result<(), Error> {
if self.irq_info.mode != IrqReceptionMode::Idle {
return Err(Error::TransferPending);
}
self.irq_info.mode = IrqReceptionMode::Pending;
self.irq_info.rx_idx = 0;
self.irq_info.rx_len = max_len;
self.uart.enable_rx();
self.uart.enable_tx();
self.enable_rx_irq_sources(enb_timeout_irq);
if self.irq_info.irq_cfg.enable {
unmask_irq(self.irq_info.irq_cfg.irq);
}
Ok(())
}
#[inline]
fn enable_rx_irq_sources(&mut self, timeout: bool) {
self.uart.uart.irq_enb.modify(|_, w| {
if timeout {
w.irq_rx_to().set_bit();
}
w.irq_rx_status().set_bit();
w.irq_rx().set_bit()
});
}
#[inline]
fn disable_rx_irq_sources(&mut self) {
self.uart.uart.irq_enb.modify(|_, w| {
w.irq_rx_to().clear_bit();
w.irq_rx_status().clear_bit();
w.irq_rx().clear_bit()
});
}
#[inline]
pub fn enable_tx(&mut self) {
self.uart.enable_tx()
}
#[inline]
pub fn disable_tx(&mut self) {
self.uart.disable_tx()
}
pub fn cancel_transfer(&mut self) {
// Disable IRQ
cortex_m::peripheral::NVIC::mask(self.irq_info.irq_cfg.irq);
self.disable_rx_irq_sources();
self.uart.clear_tx_fifo();
self.irq_info.rx_idx = 0;
self.irq_info.rx_len = 0;
}
/// Default IRQ handler which can be used to read the packets arriving on the UART peripheral.
///
/// If passed buffer is equal to or larger than the specified maximum length, an
/// [`Error::BufferTooShort`] will be returned
pub fn irq_handler(&mut self, res: &mut IrqResult, buf: &mut [u8]) -> Result<(), Error> {
if buf.len() < self.irq_info.rx_len {
return Err(Error::BufferTooShort);
}
let irq_end = self.uart.uart.irq_end.read();
let enb_status = self.uart.uart.enable.read();
let rx_enabled = enb_status.rxenable().bit_is_set();
let _tx_enabled = enb_status.txenable().bit_is_set();
let read_handler =
|res: &mut IrqResult, read_res: nb::Result<u8, Error>| -> Result<Option<u8>, Error> {
match read_res {
Ok(byte) => Ok(Some(byte)),
Err(nb::Error::WouldBlock) => Ok(None),
Err(nb::Error::Other(e)) => match e {
Error::Overrun => {
res.set_result(IrqResultMask::Overflow);
Err(Error::IrqError)
}
Error::FramingError => {
res.set_result(IrqResultMask::FramingError);
Err(Error::IrqError)
}
Error::ParityError => {
res.set_result(IrqResultMask::ParityError);
Err(Error::IrqError)
}
_ => {
res.set_result(IrqResultMask::Unknown);
Err(Error::IrqError)
}
},
}
};
if irq_end.irq_rx().bit_is_set() {
// If this interrupt bit is set, the trigger level is available at the very least.
// Read everything as fast as possible
for _ in 0..core::cmp::min(
self.uart.uart.rxfifoirqtrg.read().bits() as usize,
self.irq_info.rx_len,
) {
buf[self.irq_info.rx_idx] = (self.uart.uart.data.read().bits() & 0xff) as u8;
self.irq_info.rx_idx += 1;
}
// While there is data in the FIFO, write it into the reception buffer
loop {
if self.irq_info.rx_idx == self.irq_info.rx_len {
self.irq_completion_handler(res);
return Ok(());
}
if let Some(byte) = read_handler(res, self.uart.read())? {
buf[self.irq_info.rx_idx] = byte;
self.irq_info.rx_idx += 1;
} else {
break;
}
}
}
// RX transfer not complete, check for RX errors
if (self.irq_info.rx_idx < self.irq_info.rx_len) && rx_enabled {
// Read status register again, might have changed since reading received data
let rx_status = self.uart.uart.rxstatus.read();
res.clear_result();
if rx_status.rxovr().bit_is_set() {
res.set_result(IrqResultMask::Overflow);
}
if rx_status.rxfrm().bit_is_set() {
res.set_result(IrqResultMask::FramingError);
}
if rx_status.rxpar().bit_is_set() {
res.set_result(IrqResultMask::ParityError);
}
if rx_status.rxbrk().bit_is_set() {
res.set_result(IrqResultMask::Break);
}
if rx_status.rxto().bit_is_set() {
// A timeout has occured but there might be some leftover data in the FIFO,
// so read that data as well
while let Some(byte) = read_handler(res, self.uart.read())? {
buf[self.irq_info.rx_idx] = byte;
self.irq_info.rx_idx += 1;
}
self.irq_completion_handler(res);
res.set_result(IrqResultMask::Timeout);
return Ok(());
}
// If it is not a timeout, it's an error
if res.raw_res != 0 {
self.disable_rx_irq_sources();
return Err(Error::IrqError);
}
}
// Clear the interrupt status bits
self.uart
.uart
.irq_clr
.write(|w| unsafe { w.bits(irq_end.bits()) });
Ok(())
}
fn irq_completion_handler(&mut self, res: &mut IrqResult) {
self.disable_rx_irq_sources();
self.uart.disable_rx();
res.bytes_read = self.irq_info.rx_idx;
res.clear_result();
res.set_result(IrqResultMask::Complete);
self.irq_info.mode = IrqReceptionMode::Idle;
self.irq_info.rx_idx = 0;
self.irq_info.rx_len = 0;
}
pub fn release(self) -> UART {
self.uart.release()
}
}
impl<UART: Instance, PINS> UartWithIrq<UART, PINS> {
/// See [`UartWithIrqBase::read_fixed_len_using_irq`] doc
pub fn read_fixed_len_using_irq(
&mut self,
max_len: usize,
enb_timeout_irq: bool,
) -> Result<(), Error> {
self.irq_base
.read_fixed_len_using_irq(max_len, enb_timeout_irq)
}
pub fn cancel_transfer(&mut self) {
self.irq_base.cancel_transfer()
}
/// See [`UartWithIrqBase::irq_handler`] doc
pub fn irq_handler(&mut self, res: &mut IrqResult, buf: &mut [u8]) -> Result<(), Error> {
self.irq_base.irq_handler(res, buf)
}
pub fn release(self) -> (UART, PINS) {
(self.irq_base.release(), self.pins)
}
pub fn downgrade(self) -> (UartWithIrqBase<UART>, PINS) {
(self.irq_base, self.pins)
}
}
uart_impl! { uart_impl! {
UARTA: (uarta, clock::PeripheralClocks::Uart0), UARTA: (uarta, clock::PeripheralClocks::Uart0),
UARTB: (uartb, clock::PeripheralClocks::Uart1), UARTB: (uartb, clock::PeripheralClocks::Uart1),
@ -866,26 +326,16 @@ uart_impl! {
impl<UART> Tx<UART> where UART: Instance {} impl<UART> Tx<UART> where UART: Instance {}
impl<UART: Instance> serial::Write<u8> for UartBase<UART> {
type Error = Infallible;
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
self.tx.write(word)
}
fn flush(&mut self) -> nb::Result<(), Self::Error> {
self.tx.flush()
}
}
impl<UART, PINS> serial::Write<u8> for Uart<UART, PINS> impl<UART, PINS> serial::Write<u8> for Uart<UART, PINS>
where where
UART: Instance, UART: Instance,
{ {
type Error = Infallible; type Error = Infallible;
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
self.uart_base.write(word) self.tx.write(word)
} }
fn flush(&mut self) -> nb::Result<(), Self::Error> { fn flush(&mut self) -> nb::Result<(), Self::Error> {
self.uart_base.flush() self.tx.flush()
} }
} }
@ -900,10 +350,11 @@ impl<UART: Instance> serial::Write<u8> for Tx<UART> {
return Err(nb::Error::WouldBlock); return Err(nb::Error::WouldBlock);
} else { } else {
// DPARITY bit not supported yet // DPARITY bit not supported yet
// NOTE(unsafe) atomic write to data register
unsafe { unsafe {
// NOTE(unsafe) atomic write to data register // NOTE(unsafe) atomic write to data register
(*UART::ptr()).data.write(|w| w.bits(word as u32)); // NOTE(write_volatile) 8-bit write that's not
// possible through the svd2rust API
ptr::write_volatile(&(*UART::ptr()).data as *const _ as *mut _, word);
} }
} }
Ok(()) Ok(())
@ -919,19 +370,11 @@ impl<UART: Instance> serial::Write<u8> for Tx<UART> {
} }
} }
impl<UART: Instance> serial::Read<u8> for UartBase<UART> {
type Error = Error;
fn read(&mut self) -> nb::Result<u8, Error> {
self.rx.read()
}
}
impl<UART: Instance, PINS> serial::Read<u8> for Uart<UART, PINS> { impl<UART: Instance, PINS> serial::Read<u8> for Uart<UART, PINS> {
type Error = Error; type Error = Error;
fn read(&mut self) -> nb::Result<u8, Error> { fn read(&mut self) -> nb::Result<u8, Error> {
self.uart_base.read() self.rx.read()
} }
} }
@ -966,7 +409,7 @@ impl<UART: Instance> serial::Read<u8> for Rx<UART> {
} }
} }
impl<UART: Instance> core::fmt::Write for Tx<UART> impl<UART> core::fmt::Write for Tx<UART>
where where
Tx<UART>: embedded_hal::serial::Write<u8>, Tx<UART>: embedded_hal::serial::Write<u8>,
{ {
@ -977,12 +420,3 @@ where
.map_err(|_| core::fmt::Error) .map_err(|_| core::fmt::Error)
} }
} }
impl<UART: Instance> core::fmt::Write for UartBase<UART>
where
UartBase<UART>: embedded_hal::serial::Write<u8>,
{
fn write_str(&mut self, s: &str) -> core::fmt::Result {
self.tx.write_str(s)
}
}

View File

@ -3,29 +3,14 @@
//! Some more information about the recommended scrub rates can be found on the //! Some more information about the recommended scrub rates can be found on the
//! [Vorago White Paper website](https://www.voragotech.com/resources) in the //! [Vorago White Paper website](https://www.voragotech.com/resources) in the
//! application note AN1212 //! application note AN1212
use crate::pac; use va108xx::SYSCONFIG;
use va108xx::{IOCONFIG, SYSCONFIG};
#[derive(PartialEq, Eq, Debug)] #[derive(PartialEq, Debug)]
pub enum UtilityError { pub enum UtilityError {
InvalidCounterResetVal, InvalidCounterResetVal,
InvalidPin,
} }
#[derive(Debug, Eq, Copy, Clone, PartialEq)] #[derive(Copy, Clone, PartialEq)]
pub enum Funsel {
Funsel1 = 0b01,
Funsel2 = 0b10,
Funsel3 = 0b11,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum PortSel {
PortA,
PortB,
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum PeripheralSelect { pub enum PeripheralSelect {
PortA = 0, PortA = 0,
PortB = 1, PortB = 1,
@ -42,26 +27,6 @@ pub enum PeripheralSelect {
Gpio = 24, Gpio = 24,
} }
/// Generic IRQ config which can be used to specify whether the HAL driver will
/// use the IRQSEL register to route an interrupt, and whether the IRQ will be unmasked in the
/// Cortex-M0 NVIC. Both are generally necessary for IRQs to work, but the user might perform
/// this steps themselves
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct IrqCfg {
/// Interrupt target vector. Should always be set, might be required for disabling IRQs
pub irq: pac::Interrupt,
/// Specfiy whether IRQ should be routed to an IRQ vector using the IRQSEL peripheral
pub route: bool,
/// Specify whether the IRQ is unmasked in the Cortex-M NVIC
pub enable: bool,
}
impl IrqCfg {
pub fn new(irq: pac::Interrupt, route: bool, enable: bool) -> Self {
IrqCfg { irq, route, enable }
}
}
/// Enable scrubbing for the ROM /// Enable scrubbing for the ROM
/// ///
/// Returns [`UtilityError::InvalidCounterResetVal`] if the scrub rate is 0 /// Returns [`UtilityError::InvalidCounterResetVal`] if the scrub rate is 0
@ -107,38 +72,3 @@ pub fn set_reset_bit(syscfg: &mut SYSCONFIG, periph_sel: PeripheralSelect) {
.peripheral_reset .peripheral_reset
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << periph_sel as u8)) }); .modify(|r, w| unsafe { w.bits(r.bits() | (1 << periph_sel as u8)) });
} }
/// Can be used to manually manipulate the function select of port pins
pub fn port_mux(
ioconfig: &mut IOCONFIG,
port: PortSel,
pin: u8,
funsel: Funsel,
) -> Result<(), UtilityError> {
match port {
PortSel::PortA => {
if pin > 31 {
return Err(UtilityError::InvalidPin);
}
ioconfig.porta[pin as usize].modify(|_, w| unsafe { w.funsel().bits(funsel as u8) });
Ok(())
}
PortSel::PortB => {
if pin > 23 {
return Err(UtilityError::InvalidPin);
}
ioconfig.portb[pin as usize].modify(|_, w| unsafe { w.funsel().bits(funsel as u8) });
Ok(())
}
}
}
/// Unmask and enable an IRQ with the given interrupt number
///
/// ## Safety
///
/// The unmask function can break mask-based critical sections
#[inline]
pub(crate) fn unmask_irq(irq: pac::Interrupt) {
unsafe { cortex_m::peripheral::NVIC::unmask(irq) };
}

View File

@ -1,5 +0,0 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

View File

@ -1,7 +0,0 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
]
}

View File

@ -1,2 +0,0 @@
This is a Platform IO test script for the Arduino Due which can be used to sent different kind
of strings via the serial interface (RX1 and TX1) to the Vorago board.

View File

@ -1,39 +0,0 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

View File

@ -1,46 +0,0 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in a an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

View File

@ -1,15 +0,0 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:due]
platform = atmelsam
board = due
framework = arduino
monitor_speed = 115200

View File

@ -1,78 +0,0 @@
#include <Arduino.h>
enum SendModes {
ECHO,
ONLY_WRITE,
ONLY_READ,
WRITE_READ
};
enum StringModes {
FIXED,
VARIABLE
};
// Configure the test application here
SendModes SEND_MODE = SendModes::WRITE_READ;
StringModes STRING_MODE = StringModes::VARIABLE;
uint8_t STRING_IDX = 0;
String STRINGS[4] = {
"$Hi\n",
"$Hello\n",
"$Hello World\n",
"$Hello and Merry Christmas to all of you!\n"
};
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("Starting Arduino Serial Test script..");
Serial1.begin(115200);
if(STRING_MODE == StringModes::VARIABLE) {
STRING_IDX = 0;
}
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
static byte ICOMING_BYTE = 0;
static uint32_t GLOBAL_IDX = 0;
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
// put your main code here, to run repeatedly:
// send data only when you receive data:
if (SEND_MODE == SendModes::ONLY_WRITE or SEND_MODE == SendModes::WRITE_READ) {
Serial.println("Sending string..");
Serial1.write(STRINGS[STRING_IDX].c_str());
if(STRING_MODE == StringModes::VARIABLE) {
STRING_IDX += 1;
if(STRING_IDX > 3) {
STRING_IDX = 0;
}
}
}
if(
SEND_MODE == SendModes::WRITE_READ or
SEND_MODE == SendModes::ONLY_READ or
SEND_MODE == SendModes::ECHO
) {
if (Serial1.available() > 0) {
// read the incoming byte:
String readString = Serial1.readStringUntil('\n');
Serial.print(GLOBAL_IDX);
Serial.print(" - ");
GLOBAL_IDX++;
// say what you got:
Serial.print("I received: ");
Serial.println(readString);
if(SEND_MODE == SendModes::ECHO) {
delay(200);
Serial.println("Sending back echo message");
String sendBack = readString + '\n';
Serial1.write(sendBack.c_str());
}
}
}
delay(3000);
}

View File

@ -1,11 +0,0 @@
This directory is intended for PlatformIO Unit Testing and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/page/plus/unit-testing.html