Compare commits

..

1 commit

Author SHA1 Message Date
ca9c9bae75 Upgrade to latest nrf52832-hal 2020-06-21 14:07:56 +02:00
14 changed files with 53 additions and 43290 deletions

View file

@ -1,5 +1,4 @@
[target.thumbv7em-none-eabihf] [target.thumbv7em-none-eabihf]
runner = "arm-none-eabi-gdb -x openocd.gdb -q"
rustflags = [ rustflags = [
"-C", "link-arg=-Tfixed-link.x", "-C", "link-arg=-Tfixed-link.x",
] ]

View file

@ -1 +0,0 @@
[]

View file

@ -1 +0,0 @@
[]

114
.vscode/launch.json vendored
View file

@ -1,114 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "PineTime Debug",
"device": "nRF52832",
"svdFile": ".vscode/nrf52.svd",
"cwd": "${workspaceRoot}",
"configFiles": [
// Tell OpenOCD to open the ST Link connection.
"scripts/swd-stlink.ocd",
// Tell OpenOCD to run our custom debug commands.
"scripts/debug.ocd"
],
"executable": "./target/thumbv7em-none-eabihf/debug/pinetime-rs",
"request": "launch",
"type": "cortex-debug",
"servertype": "openocd",
"preLaunchCommands": [
// Before loading the Application, run these gdb commands.
// Set timeout for executing openocd commands.
"set remotetimeout 60",
// This indicates that an unrecognized breakpoint location should automatically result in a pending breakpoint being created.
"set breakpoint pending on",
// Display the Arm instruction when hitting breakpoint.
// "display/i $pc",
// Load Bootloader symbols in case we jump to the Bootloader.
// "symbol-file bin/targets/bluepill_boot/app/apps/boot/boot.elf",
// Restore Application symbols.
// "symbol-file bin/targets/bluepill_my_sensor/app/apps/my_sensor_app/my_sensor_app.elf",
"monitor arm semihosting enable"
],
"postLaunchCommands": [
// After loading the Application, run these gdb commands. The Application ELF image does not contain a valid Image Header.
// If not using the Stub Bootloader boot_stub, we need to bypass the Bootloader and jump to the Application directly:
// "stepi", // Must step before setting PC
// "set $pc = Reset_Handler", // Prepare to jump to the Application's Reset Handler
// "stepi", // Execute the Reset Handler
//"break main", // Break at main()
"break __assert_func", // Break for any assert failures
"break os_default_irq", // Break for any unhandled interrupts
"break HardFault",
"break rust_begin_unwind"
]
},
{
"name": "PineTime Debug Release",
"device": "nRF52832",
"svdFile": ".vscode/nrf52.svd",
"cwd": "${workspaceRoot}",
"configFiles": [
// Tell OpenOCD to open the ST Link connection.
"scripts/swd-stlink.ocd",
// Tell OpenOCD to run our custom debug commands.
"scripts/debug.ocd"
],
"executable": "./target/thumbv7em-none-eabihf/release/pinetime-rs",
"request": "launch",
"type": "cortex-debug",
"servertype": "openocd",
// "swoConfig": {
// "enabled": true,
// "cpuFrequency": 16000000,
// "swoFrequency": 2000000,
// "source": "probe",
// "decoders": [
// {
// "type": "console",
// "label": "ITM",
// "port": 0
// }
// ]
// },
"preLaunchCommands": [
// Before loading the Application, run these gdb commands.
// Set timeout for executing openocd commands.
"set remotetimeout 60",
// This indicates that an unrecognized breakpoint location should automatically result in a pending breakpoint being created.
"set breakpoint pending on",
// Display the Arm instruction when hitting breakpoint.
// "display/i $pc",
// Load Bootloader symbols in case we jump to the Bootloader.
// "symbol-file bin/targets/bluepill_boot/app/apps/boot/boot.elf",
// Restore Application symbols.
// "symbol-file bin/targets/bluepill_my_sensor/app/apps/my_sensor_app/my_sensor_app.elf",
"set print asm-demangle on",
//"monitor semihosting ioclient 3",
"monitor arm semihosting enable"
],
"postLaunchCommands": [
// After loading the Application, run these gdb commands. The Application ELF image does not contain a valid Image Header.
// If not using the Stub Bootloader boot_stub, we need to bypass the Bootloader and jump to the Application directly:
// "stepi", // Must step before setting PC
// "set $pc = Reset_Handler", // Prepare to jump to the Application's Reset Handler
// "stepi", // Execute the Reset Handler
//"break main", // Break at main()
"break __assert_func", // Break for any assert failures
"break os_default_irq", // Break for any unhandled interrupts
"break HardFault"
]
}
]
}

42660
.vscode/nrf52.svd vendored

File diff suppressed because it is too large Load diff

41
.vscode/tasks.json vendored
View file

@ -1,41 +0,0 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "cargo release",
"type": "shell",
"problemMatcher": [
"$rustc"
],
"command": "cargo",
"args": [
"build",
"--release",
"-Zfeatures=build_dep"
]
},
{
"label": "flash release",
"type": "shell",
"problemMatcher": [
"$rustc"
],
"command": "cargo",
"args": [
"embed",
"--release"
]
},
{
"label": "flash debug",
"type": "shell",
"problemMatcher": [
"$rustc"
],
"command": "cargo",
"args": [
"embed"
]
}
]
}

77
Cargo.lock generated
View file

@ -59,6 +59,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "autocfg"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
[[package]] [[package]]
name = "bare-metal" name = "bare-metal"
version = "0.2.5" version = "0.2.5"
@ -98,12 +104,6 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "byte-slice-cast"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0a5e3906bcbf133e33c1d4d95afc664ad37fbdb9f6568d8043e7ea8c27d93d3"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.3.4" version = "1.3.4"
@ -198,18 +198,11 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "cortex-m-semihosting"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "113ef0ecffee2b62b58f9380f4469099b30e9f9cbee2804771b4203ba1762cfa"
dependencies = [
"cortex-m",
]
[[package]] [[package]]
name = "cst816s" name = "cst816s"
version = "0.1.4" version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "988624bfaeaa34565792f7badc33cd02e84ba51fff4bbc3cd76f59d4af5658e7"
dependencies = [ dependencies = [
"cortex-m", "cortex-m",
"embedded-hal", "embedded-hal",
@ -231,23 +224,6 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7313c0d620d0cb4dbd9d019e461a4beb501071ff46ec0ab933efb4daa76d73e3" checksum = "7313c0d620d0cb4dbd9d019e461a4beb501071ff46ec0ab933efb4daa76d73e3"
[[package]]
name = "display-interface"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da12a892db5cce95ae247e8803dc653b1a73da3b0450f7983eb518dd54f583cf"
[[package]]
name = "display-interface-spi"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94d08c3a1682b166cbcbb4fe009a31a1834ba46c16599bf7a9b3cc7bc31b38b0"
dependencies = [
"byte-slice-cast",
"display-interface",
"embedded-hal",
]
[[package]] [[package]]
name = "embedded-graphics" name = "embedded-graphics"
version = "0.6.2" version = "0.6.2"
@ -490,18 +466,32 @@ dependencies = [
"vcell", "vcell",
] ]
[[package]]
name = "num-derive"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c8b15b261814f992e33760b1fca9fe8b693d8a65299f20c9901688636cfb746"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "num-traits"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "numtoa" name = "numtoa"
version = "0.2.3" version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e521b6adefa0b2c1fa5d2abdf9a5216288686fe6146249215d884c0e5ab320b0" checksum = "e521b6adefa0b2c1fa5d2abdf9a5216288686fe6146249215d884c0e5ab320b0"
[[package]]
name = "panic-halt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812"
[[package]] [[package]]
name = "peeking_take_while" name = "peeking_take_while"
version = "0.1.2" version = "0.1.2"
@ -514,17 +504,13 @@ version = "0.1.0"
dependencies = [ dependencies = [
"cortex-m", "cortex-m",
"cortex-m-rt", "cortex-m-rt",
"cortex-m-semihosting",
"cst816s", "cst816s",
"cstr_core", "cstr_core",
"display-interface",
"display-interface-spi",
"embedded-graphics", "embedded-graphics",
"embedded-hal", "embedded-hal",
"lvgl", "lvgl",
"nrf52832-hal", "nrf52832-hal",
"numtoa", "numtoa",
"panic-halt",
"st7789", "st7789",
] ]
@ -620,15 +606,16 @@ checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
[[package]] [[package]]
name = "st7789" name = "st7789"
version = "0.5.0" version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9f2a309b876ab3ac011a437624b439ec22387db20c86e024b5aae8090428623" checksum = "5ccc7b7e79f9e578e981bfab45b502b72ca02717a4356df0478228a6ff7c47c4"
dependencies = [ dependencies = [
"display-interface",
"embedded-graphics", "embedded-graphics",
"embedded-hal", "embedded-hal",
"heapless", "heapless",
"nb", "nb",
"num-derive",
"num-traits",
] ]
[[package]] [[package]]

View file

@ -8,17 +8,13 @@ license = "BSD-3-Clause"
[dependencies] [dependencies]
cortex-m = "0.6" cortex-m = "0.6"
cortex-m-rt = "0.6" cortex-m-rt = "0.6"
cortex-m-semihosting = "0.3.5"
embedded-graphics = "0.6" embedded-graphics = "0.6"
embedded-hal = {version ="0.2.3", features = ["unproven"] } embedded-hal = {version ="0.2.3", features = ["unproven"] }
nrf52832-hal = { version = "0.10", default-features = false, features = ["xxAA-package", "rt"] } nrf52832-hal = { version = "0.10", default-features = false, features = ["xxAA-package", "rt"] }
st7789 = { version = "0.5.0", features = ["graphics", "batch", "buffer"], default-features = false } st7789 = { version = "0.2", features = ["graphics", "batch", "buffer"], default-features = false }
display-interface = "0.4"
display-interface-spi = "0.4"
panic-halt = "0.2.0"
cstr_core = "0.2.0" cstr_core = "0.2.0"
numtoa = "0.2.3" numtoa = "0.2.3"
cst816s = { path = "../cst816s" } cst816s = "0.1.4"
lvgl = { path = "../lvgl-rs/lvgl" } lvgl = { path = "../lvgl-rs/lvgl" }
[profile.dev] [profile.dev]

View file

@ -1,49 +0,0 @@
target extended-remote :3333
# print demangled symbols
set print asm-demangle on
# set backtrace limit to not have infinite backtrace loops
set backtrace limit 32
# detect unhandled exceptions, hard faults and panics
#break DefaultHandler
break HardFault
break rust_begin_unwind
#break panic
# # run the next few lines so the panic message is printed immediately
# # the number needs to be adjusted for your panic handler
# commands $bpnum
# next 4
# end
# *try* to stop at the user entry point (it might be gone due to inlining)
# break main
monitor arm semihosting enable
# # send captured ITM to the file itm.fifo
# # (the microcontroller SWO pin must be connected to the programmer SWO pin)
# # 8000000 must match the core clock frequency
# monitor tpiu config internal itm.txt uart off 8000000
# # OR: make the microcontroller SWO pin output compatible with UART (8N1)
# # 8000000 must match the core clock frequency
# # 2000000 is the frequency of the SWO pin
# monitor tpiu config external uart off 8000000 2000000
# # enable ITM port 0
# monitor itm port 0 on
# don't confirm when quitting debugger
define hook-quit
set confirm off
end
load
#monitor reset halt
# start the process but immediately halt the processor
# stepi
continue

View file

@ -1,10 +0,0 @@
# This is an OpenOCD script that connects to the nRF52 for Cortex Debug.
# Debug Level must be 2 or greater or gdb will fail.
debug_level 2
$_TARGETNAME configure -event reset-init {
# Arm Semihosting is used to show debug console output and may only be enabled after init event. We wait for the event and enable Arm Semihosting.
echo "Enable ARM Semihosting to show debug output"
arm semihosting enable
}

View file

@ -1,4 +0,0 @@
# This is an OpenOCD script that prepares the microcontroller before any flashing.
# Disable all openocd messages.
debug_level 0

View file

@ -1,14 +0,0 @@
# OpenOCD script for using ST-Link v2 as SWD Programmer for nRF52
# VSCode debugger searches this folder for OpenOCD scripts
add_script_search_dir openocd/scripts
# Set OpenOCD logging
source [find scripts/flash-init.ocd]
# Select the ST-Link v2 interface (SWD transport)
source [find interface/stlink-v2.cfg]
transport select hla_swd
# Select nRF52 as target
source [find target/nrf52.cfg]

View file

@ -1,18 +1,14 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
extern crate panic_halt;
mod backlight; mod backlight;
mod delay; mod delay;
mod monotonic_nrf52;
use nrf52832_hal::gpio::Level; use nrf52832_hal::gpio::Level;
use nrf52832_hal::{self as p_hal, pac}; use nrf52832_hal::{self as p_hal, pac};
use p_hal::{delay::Delay, spim, twim}; use p_hal::{delay::Delay, spim, twim};
use cortex_m_rt as rt; use cortex_m_rt as rt;
use cortex_m_semihosting::hprintln;
use cst816s::CST816S; use cst816s::CST816S;
use cstr_core::CStr; use cstr_core::CStr;
use embedded_graphics::prelude::*; use embedded_graphics::prelude::*;
@ -20,25 +16,21 @@ use embedded_hal::blocking::delay::{DelayMs, DelayUs};
use embedded_hal::digital::v2::OutputPin; use embedded_hal::digital::v2::OutputPin;
use numtoa::NumToA; use numtoa::NumToA;
use rt::entry; use rt::entry;
use st7789::{Orientation, ST7789}; use st7789::Orientation;
use lvgl::input_device::{InputData, Pointer}; use lvgl::input_device::{InputData, Pointer};
use lvgl::style::Style; use lvgl::style::Style;
use lvgl::widgets::{Btn, Label}; use lvgl::widgets::{Btn, Label};
use lvgl::{self, Align, Color, Part, State, Widget, UI}; use lvgl::{self, Align, Color, Part, State, Widget, UI};
use crate::monotonic_nrf52::Instant;
use core::panic::PanicInfo; use core::panic::PanicInfo;
use core::time::Duration; use core::time::Duration;
use display_interface_spi::SPIInterfaceNoCS;
/// ///
/// This example was written and tested for the PineTime smart watch /// This example was written and tested for the PineTime smart watch
/// ///
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
hprintln!("\nStarting...").unwrap();
let cp = pac::CorePeripherals::take().unwrap(); let cp = pac::CorePeripherals::take().unwrap();
let mut delay_source = Delay::new(cp.SYST); let mut delay_source = Delay::new(cp.SYST);
@ -46,14 +38,12 @@ fn main() -> ! {
// Optimize clock config // Optimize clock config
let dp = pac::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap();
//let lcd_delay = delay::TimerDelay::new(dp.TIMER0); let lcd_delay = delay::TimerDelay::new(dp.TIMER0);
// Initialize monotonic timer on TIMER1 (for RTFM)
monotonic_nrf52::Tim1::initialize(dp.TIMER1);
// Set up clocks. On reset, the high frequency clock is already used, // Set up clocks. On reset, the high frequency clock is already used,
// but we also need to switch to the external HF oscillator. This is // but we also need to switch to the external HF oscillator. This is
// needed for Bluetooth to work. // needed for Bluetooth to work.
let _clocks = p_hal::clocks::Clocks::new(dp.CLOCK).enable_ext_hfosc(); let _clocks = p_hal::clocks::Clocks::new(dp.CLOCK).enable_ext_hfosc();
let gpio = p_hal::gpio::p0::Parts::new(dp.P0); let gpio = p_hal::gpio::p0::Parts::new(dp.P0);
@ -61,9 +51,10 @@ fn main() -> ! {
// Set up SPI pins // Set up SPI pins
let spi_clk = gpio.p0_02.into_push_pull_output(Level::Low).degrade(); let spi_clk = gpio.p0_02.into_push_pull_output(Level::Low).degrade();
let spi_mosi = gpio.p0_03.into_push_pull_output(Level::Low).degrade(); let spi_mosi = gpio.p0_03.into_push_pull_output(Level::Low).degrade();
let spi_miso = gpio.p0_04.into_floating_input().degrade();
let spi_pins = spim::Pins { let spi_pins = spim::Pins {
sck: spi_clk, sck: spi_clk,
miso: None, miso: Some(spi_miso),
mosi: Some(spi_mosi), mosi: Some(spi_mosi),
}; };
@ -111,12 +102,9 @@ fn main() -> ! {
spim::Frequency::M8, spim::Frequency::M8,
// SPI must be used in mode 3. Mode 0 (the default) won't work. // SPI must be used in mode 3. Mode 0 (the default) won't work.
spim::MODE_3, spim::MODE_3,
122, 0,
); );
// display interface abstraction from SPI and DC
let di = SPIInterfaceNoCS::new(spi, lcd_dc);
// Chip select must be held low while driving the display. It must be high // Chip select must be held low while driving the display. It must be high
// when using other SPI devices on the same bus (such as external flash // when using other SPI devices on the same bus (such as external flash
// storage) so that the display controller won't respond to the wrong // storage) so that the display controller won't respond to the wrong
@ -124,17 +112,17 @@ fn main() -> ! {
lcd_cs.set_low().unwrap(); lcd_cs.set_low().unwrap();
// Initialize LCD // Initialize LCD
let mut lcd = ST7789::new( let mut lcd = st7789::ST7789::new(
di, spi,
lcd_dc,
lcd_rst, lcd_rst,
lvgl::HOR_RES_MAX as u16, lvgl::HOR_RES_MAX as u16,
lvgl::VER_RES_MAX as u16, lvgl::VER_RES_MAX as u16,
lcd_delay,
); );
lcd.init(&mut delay_source).unwrap(); lcd.init().unwrap();
lcd.set_orientation(Orientation::Portrait).unwrap(); lcd.set_orientation(&Orientation::Portrait).unwrap();
hprintln!("\nAll devices set!").unwrap();
// Initialize LVGL // Initialize LVGL
let mut ui = UI::init().unwrap(); let mut ui = UI::init().unwrap();
@ -187,17 +175,7 @@ fn main() -> ! {
}) })
.unwrap(); .unwrap();
let mut loop_time = Instant::now();
let mut total_time = Duration::from_secs(0);
let mut time_text_buf = [0u8; 20];
let mut last_update_time_secs = 0;
let mut last_inc_time_ms = 0;
hprintln!("\nLVGL widgets built!").unwrap();
loop { loop {
ui.task_handler();
if let Some(evt) = touchpad.read_one_touch_event(true) { if let Some(evt) = touchpad.read_one_touch_event(true) {
latest_touch_point = Point::new(evt.x, evt.y); latest_touch_point = Point::new(evt.x, evt.y);
// Pressed // Pressed
@ -211,32 +189,12 @@ fn main() -> ! {
.once(); .once();
delay_source.delay_us(1u32); delay_source.delay_us(1u32);
} }
ui.task_handler();
total_time += Duration::from_micros(loop_time.elapsed().as_cycles() as u64); ui.tick_inc(Duration::from_secs(1));
if total_time.as_secs() > last_update_time_secs {
last_update_time_secs = total_time.as_secs();
let text = (total_time.as_secs() as u32).numtoa(10, &mut time_text_buf);
let time_text = unsafe { CStr::from_bytes_with_nul_unchecked(&text) };
time_lbl.set_text(time_text).unwrap();
time_lbl
.set_align(&mut button, Align::OutTopMid, 0, -50)
.unwrap();
// Reset buffer
for p in time_text_buf.iter_mut() {
*p = '\0' as u8;
}
}
if total_time.as_millis() > last_inc_time_ms {
//let diff_ms = total_time.as_millis() - last_inc_time_ms;
last_inc_time_ms = total_time.as_millis();
}
ui.tick_inc(Duration::from_millis(50));
loop_time = Instant::now();
} }
} }
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}

View file

@ -1,283 +0,0 @@
//! Using NRF52 as monotonic timer
//!
//! Source:
//! https://github.com/rtfm-rs/rtfm-examples/blob/master/rtfm_v5/monotonic_nrf52/src/monotonic_nrf52.rs
use core::u32;
use core::{
cmp::Ordering,
convert::{Infallible, TryInto},
fmt, ops,
};
use nrf52832_hal::target;
/// A measurement of the counter. Opaque and useful only with `Duration`
///
/// # Correctness
///
/// Adding or subtracting a `Duration` of more than `(1 << 31)` cycles to an `Instant` effectively
/// makes it "wrap around" and creates an incorrect value. This is also true if the operation is
/// done in steps, e.g. `(instant + dur) + dur` where `dur` is `(1 << 30)` ticks.
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Instant {
inner: i32,
}
impl Instant {
/// Returns an instant corresponding to "now"
pub fn now() -> Self {
let now = {
let timer = unsafe { &*target::TIMER1::ptr() };
timer.tasks_capture[0].write(|w| unsafe { w.bits(1) });
timer.cc[0].read().bits()
};
Instant { inner: now as i32 }
}
/// Returns the amount of time elapsed since this instant was created.
pub fn elapsed(&self) -> Duration {
Instant::now() - *self
}
/// Returns the underlying count
pub fn counts(&self) -> u32 {
self.inner as u32
}
/// Returns the amount of time elapsed from another instant to this one.
pub fn duration_since(&self, earlier: Instant) -> Duration {
let diff = self.inner - earlier.inner;
assert!(diff >= 0, "second instant is later than self");
Duration { inner: diff as u32 }
}
}
impl fmt::Debug for Instant {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Instant")
.field(&(self.inner as u32))
.finish()
}
}
impl ops::AddAssign<Duration> for Instant {
fn add_assign(&mut self, dur: Duration) {
// NOTE this is a debug assertion because there's no foolproof way to detect a wrap around;
// the user may write `(instant + dur) + dur` where `dur` is `(1<<31)-1` ticks.
debug_assert!(dur.inner < (1 << 31));
self.inner = self.inner.wrapping_add(dur.inner as i32);
}
}
impl ops::Add<Duration> for Instant {
type Output = Self;
fn add(mut self, dur: Duration) -> Self {
self += dur;
self
}
}
impl ops::SubAssign<Duration> for Instant {
fn sub_assign(&mut self, dur: Duration) {
// NOTE see the NOTE in `<Instant as AddAssign<Duration>>::add_assign`
debug_assert!(dur.inner < (1 << 31));
self.inner = self.inner.wrapping_sub(dur.inner as i32);
}
}
impl ops::Sub<Duration> for Instant {
type Output = Self;
fn sub(mut self, dur: Duration) -> Self {
self -= dur;
self
}
}
impl ops::Sub<Instant> for Instant {
type Output = Duration;
fn sub(self, other: Instant) -> Duration {
self.duration_since(other)
}
}
impl Ord for Instant {
fn cmp(&self, rhs: &Self) -> Ordering {
self.inner.wrapping_sub(rhs.inner).cmp(&0)
}
}
impl PartialOrd for Instant {
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
Some(self.cmp(rhs))
}
}
/// A `Duration` type to represent a span of time.
///
/// This data type is only available on ARMv7-M
///
/// # Correctness
///
/// This type is *not* appropriate for representing time spans in the order of, or larger than,
/// seconds because it can hold a maximum of `(1 << 31)` "ticks" where each tick is the inverse of
/// the CPU frequency, which usually is dozens of MHz.
#[derive(Clone, Copy, Default, Eq, Ord, PartialEq, PartialOrd)]
pub struct Duration {
inner: u32,
}
impl Duration {
/// Creates a new `Duration` from the specified number of clock cycles
pub fn from_cycles(cycles: u32) -> Self {
Duration { inner: cycles }
}
/// Returns the total number of clock cycles contained by this `Duration`
pub fn as_cycles(&self) -> u32 {
self.inner
}
}
// Used internally by RTFM to convert the duration into a known type
impl TryInto<u32> for Duration {
type Error = Infallible;
fn try_into(self) -> Result<u32, Infallible> {
Ok(self.as_cycles())
}
}
impl ops::AddAssign for Duration {
fn add_assign(&mut self, dur: Duration) {
self.inner += dur.inner;
}
}
impl ops::Add<Duration> for Duration {
type Output = Self;
fn add(self, other: Self) -> Self {
Duration {
inner: self.inner + other.inner,
}
}
}
impl ops::Mul<u32> for Duration {
type Output = Self;
fn mul(self, other: u32) -> Self {
Duration {
inner: self.inner * other,
}
}
}
impl ops::MulAssign<u32> for Duration {
fn mul_assign(&mut self, other: u32) {
*self = *self * other;
}
}
impl ops::SubAssign for Duration {
fn sub_assign(&mut self, rhs: Duration) {
self.inner -= rhs.inner;
}
}
impl ops::Sub<Duration> for Duration {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
Duration {
inner: self.inner - rhs.inner,
}
}
}
/// Adds the `millis` and `micros` methods to the `u32` type
///
/// This trait is only available on ARMv7-M
pub trait U32Ext {
/// Converts the `u32` value as seconds into ticks
fn secs(self) -> Duration;
/// Converts the `u32` value as milliseconds into ticks
fn millis(self) -> Duration;
/// Converts the `u32` value as microseconds into ticks
fn micros(self) -> Duration;
/// Converts the `u32` value as hertz into ticks
fn hz(self) -> Duration;
}
impl U32Ext for u32 {
fn secs(self) -> Duration {
self.millis() * 1_000
}
fn millis(self) -> Duration {
self.micros() * 1_000
}
fn micros(self) -> Duration {
Duration { inner: self }
}
fn hz(self) -> Duration {
(1_000_000 / self).micros()
}
}
/// Implementor of the `rtfm::Monotonic` traits and used to consume the timer
/// to not allow for erroneous configuration.
///
/// The timer must be initialized through `initialize()`.
pub struct Tim1;
impl Tim1 {
pub fn initialize(timer: target::TIMER1) {
// Auto restart, make sure the entire timer won't stop for any event
timer.shorts.write(|w| {
w.compare0_clear()
.enabled()
.compare0_stop()
.disabled()
.compare1_clear()
.enabled()
.compare1_stop()
.disabled()
.compare2_clear()
.enabled()
.compare2_stop()
.disabled()
.compare3_clear()
.enabled()
.compare3_stop()
.disabled()
});
// 1 MHz mode
timer.prescaler.write(|w| unsafe { w.prescaler().bits(4) });
// 32 bit mode
timer.bitmode.write(|w| w.bitmode()._32bit());
// Set compare value to max, not sure if this is needed
timer.cc[0].write(|w| unsafe { w.cc().bits(u32::MAX) });
// Clear the counter value
timer.tasks_clear.write(|w| unsafe { w.bits(1) });
// Start the timer
timer.tasks_start.write(|w| unsafe { w.bits(1) });
// Throw away the timer, it is now setup and consumed
drop(timer);
}
}