Compare commits
No commits in common. "main" and "v0.3.1" have entirely different histories.
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@ -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() }}
|
||||||
|
59
CHANGELOG.md
59
CHANGELOG.md
@ -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
|
||||||
|
46
Cargo.toml
46
Cargo.toml
@ -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"]
|
||||||
|
@ -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).
|
||||||
|
@ -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
|
||||||
|
31
automation/Jenkinsfile
vendored
31
automation/Jenkinsfile
vendored
@ -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'
|
||||||
}
|
}
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
}
|
||||||
|
@ -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 {}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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,
|
||||||
|
@ -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();
|
||||||
|
@ -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 {
|
||||||
|
@ -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");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -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();
|
||||||
|
@ -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
|
||||||
|
@ -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),
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
24
src/i2c.rs
24
src/i2c.rs
@ -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 {
|
||||||
|
32
src/spi.rs
32
src/spi.rs
@ -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()
|
||||||
|
12
src/time.rs
12
src/time.rs
@ -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
|
||||||
|
74
src/timer.rs
74
src/timer.rs
@ -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() {
|
||||||
|
642
src/uart.rs
642
src/uart.rs
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -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) };
|
|
||||||
}
|
|
||||||
|
5
test/DueSerialTest/.gitignore
vendored
5
test/DueSerialTest/.gitignore
vendored
@ -1,5 +0,0 @@
|
|||||||
.pio
|
|
||||||
.vscode/.browse.c_cpp.db*
|
|
||||||
.vscode/c_cpp_properties.json
|
|
||||||
.vscode/launch.json
|
|
||||||
.vscode/ipch
|
|
7
test/DueSerialTest/.vscode/extensions.json
vendored
7
test/DueSerialTest/.vscode/extensions.json
vendored
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
|
||||||
// for the documentation about the extensions.json format
|
|
||||||
"recommendations": [
|
|
||||||
"platformio.platformio-ide"
|
|
||||||
]
|
|
||||||
}
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
|
||||||
}
|
|
@ -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
|
|
Reference in New Issue
Block a user