feat: add display UI with splash screen, dashboard, and RSSI sparkline
Implement full SSD1306 OLED display support: - Splash screen on boot (1.5s) with project name, version, board - Dashboard showing radio state, config, counters, RSSI/SNR - RSSI history sparkline (64-sample ring buffer, 2px-wide bars) - DisplayOn/DisplayOff host commands routed via dedicated channel - Pure render functions against generic DrawTarget (no hardware coupling) - Display on/off control bypasses radio task entirely Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
17624 files changed
+4564928
-38
No files matched your search
Vendored
+448
@@ -0,0 +1,448 @@
|
||||
//! Inline assembly implementing the routines exposed in `cortex_m::asm`.
|
||||
//!
|
||||
//! If the `inline-asm` feature is enabled, these functions will be directly called by the
|
||||
//! `cortex-m` wrappers. Otherwise, `cortex-m` links against them via prebuilt archives.
|
||||
//!
|
||||
//! All of these functions should be blanket-`unsafe`. `cortex-m` provides safe wrappers where
|
||||
//! applicable.
|
||||
|
||||
use core::arch::asm;
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __bkpt() {
|
||||
asm!("bkpt", options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __control_r() -> u32 {
|
||||
let r;
|
||||
asm!("mrs {}, CONTROL", out(reg) r, options(nomem, nostack, preserves_flags));
|
||||
r
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __control_w(w: u32) {
|
||||
// ISB is required after writing to CONTROL,
|
||||
// per ARM architectural requirements (see Application Note 321).
|
||||
asm!(
|
||||
"msr CONTROL, {}",
|
||||
"isb",
|
||||
in(reg) w,
|
||||
options(nomem, nostack, preserves_flags),
|
||||
);
|
||||
|
||||
// Ensure memory accesses are not reordered around the CONTROL update.
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __cpsid() {
|
||||
asm!("cpsid i", options(nomem, nostack, preserves_flags));
|
||||
|
||||
// Ensure no subsequent memory accesses are reordered to before interrupts are disabled.
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __cpsie() {
|
||||
// Ensure no preceeding memory accesses are reordered to after interrupts are enabled.
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
asm!("cpsie i", options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __delay(cyc: u32) {
|
||||
// The loop will normally take 3 to 4 CPU cycles per iteration, but superscalar cores
|
||||
// (eg. Cortex-M7) can potentially do it in 2, so we use that as the lower bound, since delaying
|
||||
// for more cycles is okay.
|
||||
// Add 1 to prevent an integer underflow which would cause a long freeze
|
||||
let real_cyc = 1 + cyc / 2;
|
||||
asm!(
|
||||
// Use local labels to avoid R_ARM_THM_JUMP8 relocations which fail on thumbv6m.
|
||||
"1:",
|
||||
"subs {}, #1",
|
||||
"bne 1b",
|
||||
inout(reg) real_cyc => _,
|
||||
options(nomem, nostack),
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __dmb() {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
asm!("dmb", options(nomem, nostack, preserves_flags));
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __dsb() {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
asm!("dsb", options(nomem, nostack, preserves_flags));
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __isb() {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
asm!("isb", options(nomem, nostack, preserves_flags));
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __msp_r() -> u32 {
|
||||
let r;
|
||||
asm!("mrs {}, MSP", out(reg) r, options(nomem, nostack, preserves_flags));
|
||||
r
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __msp_w(val: u32) {
|
||||
// Technically is writing to the stack pointer "not pushing any data to the stack"?
|
||||
// In any event, if we don't set `nostack` here, this method is useless as the new
|
||||
// stack value is immediately mutated by returning. Really this is just not a good
|
||||
// method and its higher-level use is marked as deprecated in cortex-m.
|
||||
asm!("msr MSP, {}", in(reg) val, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
|
||||
// NOTE: No FFI shim, this requires inline asm.
|
||||
#[inline(always)]
|
||||
pub unsafe fn __apsr_r() -> u32 {
|
||||
let r;
|
||||
asm!("mrs {}, APSR", out(reg) r, options(nomem, nostack, preserves_flags));
|
||||
r
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __nop() {
|
||||
// NOTE: This is a `pure` asm block, but applying that option allows the compiler to eliminate
|
||||
// the nop entirely (or to collapse multiple subsequent ones). Since the user probably wants N
|
||||
// nops when they call `nop` N times, let's not add that option.
|
||||
asm!("nop", options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
|
||||
// NOTE: No FFI shim, this requires inline asm.
|
||||
#[inline(always)]
|
||||
pub unsafe fn __pc_r() -> u32 {
|
||||
let r;
|
||||
asm!("mov {}, pc", out(reg) r, options(nomem, nostack, preserves_flags));
|
||||
r
|
||||
}
|
||||
|
||||
// NOTE: No FFI shim, this requires inline asm.
|
||||
#[inline(always)]
|
||||
pub unsafe fn __pc_w(val: u32) {
|
||||
asm!("mov pc, {}", in(reg) val, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
|
||||
// NOTE: No FFI shim, this requires inline asm.
|
||||
#[inline(always)]
|
||||
pub unsafe fn __lr_r() -> u32 {
|
||||
let r;
|
||||
asm!("mov {}, lr", out(reg) r, options(nomem, nostack, preserves_flags));
|
||||
r
|
||||
}
|
||||
|
||||
// NOTE: No FFI shim, this requires inline asm.
|
||||
#[inline(always)]
|
||||
pub unsafe fn __lr_w(val: u32) {
|
||||
asm!("mov lr, {}", in(reg) val, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __primask_r() -> u32 {
|
||||
let r;
|
||||
asm!("mrs {}, PRIMASK", out(reg) r, options(nomem, nostack, preserves_flags));
|
||||
r
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __psp_r() -> u32 {
|
||||
let r;
|
||||
asm!("mrs {}, PSP", out(reg) r, options(nomem, nostack, preserves_flags));
|
||||
r
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __psp_w(val: u32) {
|
||||
// See comment on __msp_w. Unlike MSP, there are legitimate use-cases for modifying PSP
|
||||
// if MSP is currently being used as the stack pointer.
|
||||
asm!("msr PSP, {}", in(reg) val, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __sev() {
|
||||
asm!("sev", options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __udf() -> ! {
|
||||
asm!("udf #0", options(noreturn, nomem, nostack, preserves_flags));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __wfe() {
|
||||
asm!("wfe", options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __wfi() {
|
||||
asm!("wfi", options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
|
||||
/// Semihosting syscall.
|
||||
#[inline(always)]
|
||||
pub unsafe fn __sh_syscall(mut nr: u32, arg: u32) -> u32 {
|
||||
asm!("bkpt #0xab", inout("r0") nr, in("r1") arg, options(nomem, nostack, preserves_flags));
|
||||
nr
|
||||
}
|
||||
|
||||
/// Set CONTROL.SPSEL to 0, write `msp` to MSP, branch to `rv`.
|
||||
#[inline(always)]
|
||||
pub unsafe fn __bootstrap(msp: u32, rv: u32) -> ! {
|
||||
asm!(
|
||||
"mrs {tmp}, CONTROL",
|
||||
"bics {tmp}, {spsel}",
|
||||
"msr CONTROL, {tmp}",
|
||||
"isb",
|
||||
"msr MSP, {msp}",
|
||||
"bx {rv}",
|
||||
// `out(reg) _` is not permitted in a `noreturn` asm! call,
|
||||
// so instead use `in(reg) 0` and don't restore it afterwards.
|
||||
tmp = in(reg) 0,
|
||||
spsel = in(reg) 2,
|
||||
msp = in(reg) msp,
|
||||
rv = in(reg) rv,
|
||||
options(noreturn, nomem, nostack),
|
||||
);
|
||||
}
|
||||
|
||||
// v7m *AND* v8m.main, but *NOT* v8m.base
|
||||
#[cfg(any(armv7m, armv8m_main))]
|
||||
pub use self::v7m::*;
|
||||
#[cfg(any(armv7m, armv8m_main))]
|
||||
mod v7m {
|
||||
use core::arch::asm;
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __basepri_max(val: u8) {
|
||||
asm!("msr BASEPRI_MAX, {}", in(reg) val, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __basepri_r() -> u8 {
|
||||
let r;
|
||||
asm!("mrs {}, BASEPRI", out(reg) r, options(nomem, nostack, preserves_flags));
|
||||
r
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __basepri_w(val: u8) {
|
||||
asm!("msr BASEPRI, {}", in(reg) val, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __faultmask_r() -> u32 {
|
||||
let r;
|
||||
asm!("mrs {}, FAULTMASK", out(reg) r, options(nomem, nostack, preserves_flags));
|
||||
r
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __enable_icache() {
|
||||
asm!(
|
||||
"ldr {0}, =0xE000ED14", // CCR
|
||||
"mrs {2}, PRIMASK", // save critical nesting info
|
||||
"cpsid i", // mask interrupts
|
||||
"ldr {1}, [{0}]", // read CCR
|
||||
"orr.w {1}, {1}, #(1 << 17)", // Set bit 17, IC
|
||||
"str {1}, [{0}]", // write it back
|
||||
"dsb", // ensure store completes
|
||||
"isb", // synchronize pipeline
|
||||
"msr PRIMASK, {2}", // unnest critical section
|
||||
out(reg) _,
|
||||
out(reg) _,
|
||||
out(reg) _,
|
||||
options(nostack),
|
||||
);
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __enable_dcache() {
|
||||
asm!(
|
||||
"ldr {0}, =0xE000ED14", // CCR
|
||||
"mrs {2}, PRIMASK", // save critical nesting info
|
||||
"cpsid i", // mask interrupts
|
||||
"ldr {1}, [{0}]", // read CCR
|
||||
"orr.w {1}, {1}, #(1 << 16)", // Set bit 16, DC
|
||||
"str {1}, [{0}]", // write it back
|
||||
"dsb", // ensure store completes
|
||||
"isb", // synchronize pipeline
|
||||
"msr PRIMASK, {2}", // unnest critical section
|
||||
out(reg) _,
|
||||
out(reg) _,
|
||||
out(reg) _,
|
||||
options(nostack),
|
||||
);
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(armv7em)]
|
||||
pub use self::v7em::*;
|
||||
#[cfg(armv7em)]
|
||||
mod v7em {
|
||||
use core::arch::asm;
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __basepri_max_cm7_r0p1(val: u8) {
|
||||
asm!(
|
||||
"mrs {1}, PRIMASK",
|
||||
"cpsid i",
|
||||
"tst.w {1}, #1",
|
||||
"msr BASEPRI_MAX, {0}",
|
||||
"it ne",
|
||||
"bxne lr",
|
||||
"cpsie i",
|
||||
in(reg) val,
|
||||
out(reg) _,
|
||||
options(nomem, nostack, preserves_flags),
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __basepri_w_cm7_r0p1(val: u8) {
|
||||
asm!(
|
||||
"mrs {1}, PRIMASK",
|
||||
"cpsid i",
|
||||
"tst.w {1}, #1",
|
||||
"msr BASEPRI, {0}",
|
||||
"it ne",
|
||||
"bxne lr",
|
||||
"cpsie i",
|
||||
in(reg) val,
|
||||
out(reg) _,
|
||||
options(nomem, nostack, preserves_flags),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(armv8m)]
|
||||
pub use self::v8m::*;
|
||||
/// Baseline and Mainline.
|
||||
#[cfg(armv8m)]
|
||||
mod v8m {
|
||||
use core::arch::asm;
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __tt(mut target: u32) -> u32 {
|
||||
asm!(
|
||||
"tt {target}, {target}",
|
||||
target = inout(reg) target,
|
||||
options(nomem, nostack, preserves_flags),
|
||||
);
|
||||
target
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __ttt(mut target: u32) -> u32 {
|
||||
asm!(
|
||||
"ttt {target}, {target}",
|
||||
target = inout(reg) target,
|
||||
options(nomem, nostack, preserves_flags),
|
||||
);
|
||||
target
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __tta(mut target: u32) -> u32 {
|
||||
asm!(
|
||||
"tta {target}, {target}",
|
||||
target = inout(reg) target,
|
||||
options(nomem, nostack, preserves_flags),
|
||||
);
|
||||
target
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __ttat(mut target: u32) -> u32 {
|
||||
asm!(
|
||||
"ttat {target}, {target}",
|
||||
target = inout(reg) target,
|
||||
options(nomem, nostack, preserves_flags),
|
||||
);
|
||||
target
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __msp_ns_r() -> u32 {
|
||||
let r;
|
||||
asm!("mrs {}, MSP_NS", out(reg) r, options(nomem, nostack, preserves_flags));
|
||||
r
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __msp_ns_w(val: u32) {
|
||||
asm!("msr MSP_NS, {}", in(reg) val, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __bxns(val: u32) {
|
||||
asm!("BXNS {}", in(reg) val, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(armv8m_main)]
|
||||
pub use self::v8m_main::*;
|
||||
/// Mainline only.
|
||||
#[cfg(armv8m_main)]
|
||||
mod v8m_main {
|
||||
use core::arch::asm;
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __msplim_r() -> u32 {
|
||||
let r;
|
||||
asm!("mrs {}, MSPLIM", out(reg) r, options(nomem, nostack, preserves_flags));
|
||||
r
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __msplim_w(val: u32) {
|
||||
asm!("msr MSPLIM, {}", in(reg) val, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __psplim_r() -> u32 {
|
||||
let r;
|
||||
asm!("mrs {}, PSPLIM", out(reg) r, options(nomem, nostack, preserves_flags));
|
||||
r
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __psplim_w(val: u32) {
|
||||
asm!("msr PSPLIM, {}", in(reg) val, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(has_fpu)]
|
||||
pub use self::fpu::*;
|
||||
/// All targets with FPU.
|
||||
#[cfg(has_fpu)]
|
||||
mod fpu {
|
||||
use core::arch::asm;
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __fpscr_r() -> u32 {
|
||||
let r;
|
||||
asm!("vmrs {}, fpscr", out(reg) r, options(nomem, nostack, preserves_flags));
|
||||
r
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn __fpscr_w(val: u32) {
|
||||
asm!("vmsr fpscr, {}", in(reg) val, options(nomem, nostack));
|
||||
}
|
||||
}
|
||||
Vendored
+143
@@ -0,0 +1,143 @@
|
||||
//! FFI shim around the inline assembly in `inline.rs`.
|
||||
//!
|
||||
//! We use this file to precompile some assembly stubs into the static libraries you can find in
|
||||
//! `bin`. Apps using the `cortex-m` crate then link against those static libraries and don't need
|
||||
//! to build this file themselves.
|
||||
//!
|
||||
//! Nowadays the assembly stubs are no longer actual assembly files, but actually just this small
|
||||
//! Rust crate that uses unstable inline assembly, coupled with the `xtask` tool to invoke rustc
|
||||
//! and build the files.
|
||||
//!
|
||||
//! Precompiling this to a static lib allows users to call assembly routines from stable Rust, but
|
||||
//! also perform [linker plugin LTO] with the precompiled artifacts to completely inline the
|
||||
//! assembly routines into their code, which brings the "outline assembly" on par with "real" inline
|
||||
//! assembly.
|
||||
//!
|
||||
//! For developers and contributors to `cortex-m`, this setup means that they don't have to install
|
||||
//! any binutils, assembler, or C compiler to hack on the crate. All they need is to run `cargo
|
||||
//! xtask assemble` to rebuild the archives from this file.
|
||||
//!
|
||||
//! Cool, right?
|
||||
//!
|
||||
//! # Rust version management
|
||||
//!
|
||||
//! Since inline assembly is still unstable, and we want to ensure that the created blobs are
|
||||
//! up-to-date in CI, we have to pin the nightly version we use for this. The nightly toolchain is
|
||||
//! stored in `asm-toolchain`.
|
||||
//!
|
||||
//! The `cargo xtask` automation will automatically install the `asm-toolchain` as well as all
|
||||
//! Cortex-M targets needed to generate the blobs.
|
||||
//!
|
||||
//! [linker plugin LTO]: https://doc.rust-lang.org/stable/rustc/linker-plugin-lto.html
|
||||
|
||||
#![feature(asm)]
|
||||
#![no_std]
|
||||
#![crate_type = "staticlib"]
|
||||
#![deny(warnings)]
|
||||
// Don't warn about feature(asm) being stable on Rust >= 1.59.0
|
||||
#![allow(stable_features)]
|
||||
|
||||
mod inline;
|
||||
|
||||
macro_rules! shims {
|
||||
(
|
||||
$( fn $name:ident( $($arg:ident: $argty:ty),* ) $(-> $ret:ty)?; )+
|
||||
) => {
|
||||
$(
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn $name(
|
||||
$($arg: $argty),*
|
||||
) $(-> $ret)? {
|
||||
crate::inline::$name($($arg),*)
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
shims! {
|
||||
fn __bkpt();
|
||||
fn __control_r() -> u32;
|
||||
fn __control_w(w: u32);
|
||||
fn __cpsid();
|
||||
fn __cpsie();
|
||||
fn __delay(cyc: u32);
|
||||
fn __dmb();
|
||||
fn __dsb();
|
||||
fn __isb();
|
||||
fn __msp_r() -> u32;
|
||||
fn __msp_w(val: u32);
|
||||
fn __nop();
|
||||
fn __primask_r() -> u32;
|
||||
fn __psp_r() -> u32;
|
||||
fn __psp_w(val: u32);
|
||||
fn __sev();
|
||||
fn __udf() -> !;
|
||||
fn __wfe();
|
||||
fn __wfi();
|
||||
fn __sh_syscall(nr: u32, arg: u32) -> u32;
|
||||
fn __bootstrap(msp: u32, rv: u32) -> !;
|
||||
}
|
||||
|
||||
// v7m *AND* v8m.main, but *NOT* v8m.base
|
||||
#[cfg(any(armv7m, armv8m_main))]
|
||||
shims! {
|
||||
fn __basepri_max(val: u8);
|
||||
fn __basepri_r() -> u8;
|
||||
fn __basepri_w(val: u8);
|
||||
fn __faultmask_r() -> u32;
|
||||
fn __enable_icache();
|
||||
fn __enable_dcache();
|
||||
}
|
||||
|
||||
#[cfg(armv7em)]
|
||||
shims! {
|
||||
fn __basepri_max_cm7_r0p1(val: u8);
|
||||
fn __basepri_w_cm7_r0p1(val: u8);
|
||||
}
|
||||
|
||||
// Baseline and Mainline.
|
||||
#[cfg(armv8m)]
|
||||
shims! {
|
||||
fn __tt(target: u32) -> u32;
|
||||
fn __ttt(target: u32) -> u32;
|
||||
fn __tta(target: u32) -> u32;
|
||||
fn __ttat(target: u32) -> u32;
|
||||
fn __msp_ns_r() -> u32;
|
||||
fn __msp_ns_w(val: u32);
|
||||
fn __bxns(val: u32);
|
||||
}
|
||||
|
||||
// Mainline only.
|
||||
#[cfg(armv8m_main)]
|
||||
shims! {
|
||||
fn __msplim_r() -> u32;
|
||||
fn __msplim_w(val: u32);
|
||||
fn __psplim_r() -> u32;
|
||||
fn __psplim_w(val: u32);
|
||||
}
|
||||
|
||||
// All targets with FPU.
|
||||
#[cfg(has_fpu)]
|
||||
shims! {
|
||||
fn __fpscr_r() -> u32;
|
||||
fn __fpscr_w(val: u32);
|
||||
}
|
||||
|
||||
/// We *must* define a panic handler here, even though nothing here should ever be able to panic.
|
||||
///
|
||||
/// We prove that nothing will ever panic by calling a function that doesn't exist. If the panic
|
||||
/// handler gets linked in, this causes a linker error. We always build this file with optimizations
|
||||
/// enabled, but even without them the panic handler should never be linked in.
|
||||
#[panic_handler]
|
||||
#[link_section = ".text.asm_panic_handler"]
|
||||
fn panic(_: &core::panic::PanicInfo) -> ! {
|
||||
extern "C" {
|
||||
#[link_name = "cortex-m internal error: panic handler not optimized out, please file an \
|
||||
issue at https://github.com/rust-embedded/cortex-m"]
|
||||
fn __cortex_m_should_not_panic() -> !;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
__cortex_m_should_not_panic();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user