diff --git a/.cargo/config b/.cargo/config index d5176c3..01b30cb 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,5 +1,4 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# runner = 'arm-none-eabi-gdb -x debug.gdb' rustflags = [ # LLD (shipped with the Rust toolchain) is used as the default linker "-C", "link-arg=-Tlink.x", @@ -16,23 +15,9 @@ rustflags = [ # "-C", "link-arg=-nostartfiles", ] -# work around rust-lang/cargo#5946 -[target.thumbv6m-none-eabi] -runner = 'arm-none-eabi-gdb -x debug.gdb' - -[target.thumbv7m-none-eabi] -runner = 'arm-none-eabi-gdb -x debug.gdb' - -[target.thumbv7em-none-eabi] -runner = 'arm-none-eabi-gdb -x debug.gdb' - -[target.thumbv7em-none-eabihf] -runner = 'arm-none-eabi-gdb -x debug.gdb' -# end of workaround - [build] -# Pick one of these compilation targets +# Pick ONE of these compilation targets # target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ -# target = "thumbv7m-none-eabi" # Cortex-M3 +target = "thumbv7m-none-eabi" # Cortex-M3 # target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU) # target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 08eb8d6..e4e5d8b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,7 @@ [package] -authors = ["Jorge Aparicio "] -categories = ["embedded", "no-std"] -description = "A template for building applications for ARM Cortex-M microcontrollers" -documentation = "https://rust-embedded.github.io/cortex-m-quickstart/cortex_m_quickstart" -keywords = ["arm", "cortex-m", "template"] -license = "MIT OR Apache-2.0" -name = "cortex-m-quickstart" -repository = "https://github.com/japaric/cortex-m-quickstart" -version = "0.3.4" +authors = ["{{authors}}"] +name = "{{project-name}}" +version = "0.1.0" [dependencies] cortex-m = "0.5.6" diff --git a/README.md b/README.md index b94edfe..3ce896f 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,493 @@ This project is developed and maintained by the [Cortex-M team][team]. # [Documentation](https://rust-embedded.github.io/cortex-m-quickstart/cortex_m_quickstart) +## Dependencies + +To build embedded programs using this template you'll need: + +- Nightly Rust toolchain from 2018-08-28 or newer: `rustup default nightly` +- The `cargo generate` subcommand: `cargo install cargo-generate` +- `rust-std` components (pre-compiled `core` crate) for the ARM Cortex-M + targets. Run: + +``` console +$ rustup target add thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabi thumbv7em-none-eabihf +``` + +## Non-dependencies + +This section list programs that are *not* required to build embedded programs +but are useful or necessary for embedded development. + +To flash (put the firmware on the target device) and debug embedded programs +you'll need these additional programs: + + + + +- GDB with ARM support or LLDB, for debugging. +- QEMU with ARM support, for running embedded programs on the build machine. +- OpenOCD and similar, which make debugging possible at all. + +To inspect the produced binaries you'll want [`cargo-binutils`]. + +[`cargo-binutils`]: https://crates.io/crates/cargo-binutils + +## Usage + +### First timers + +#### Building + +If you are already familiar with the process of building and debugging embedded +Rust programs feel free to skip this section! + +To get you familiar with building and debugging embedded Rust programs we'll use +the template with its default values to build a program for the LM3S6965, a +microcontroller with a Cortex-M3 core that QEMU can emulate. + +In this section we'll use a debugger (GDB or LLDB) and QEMU. Be sure to have +them installed! + +1. Initialize the template + +``` console +$ cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart +``` + +2. Build the example "Hello, world!" program + +``` rust +// example/hello.rs +#![no_main] +#![no_std] + +#[macro_use] +extern crate cortex_m_rt; +extern crate cortex_m_semihosting as sh; +extern crate panic_semihosting; + +use core::fmt::Write; + +use sh::hio; + +entry!(main); + +fn main() -> ! { + let mut stdout = hio::hstdout().unwrap(); + writeln!(stdout, "Hello, world!").unwrap(); + + loop {} +} +``` + +We'll cross compile the program for the `thumbv7m-none-eabi` target. This target +covers Cortex-M3 devices like the one we are targeting. + +``` console +$ cargo build --target thumbv7m-none-eabi --example hello +``` +You'll find the output binary in the following path: +`target/thumbv7m-none-eabi/debug/examples/hello`. The output is an ELF file. + +If you have `file` installed you can print the file type of the output to +confirm it's an ELF file: + +``` +$ ( cd target/thumbv7m-none-eabi/debug/examples && file hello ) +hello: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, with debug_info, not stripped +``` + +If you have `cargo-binutils` installed you can look at the ELF header of the +output: + +> NOTE `cargo-readelf` will be available in a *future* release of binutils +> (v0.1.3) + +``` console +$ cargo readelf --example hello -- --file-headers +``` + +``` text +ELF Header: + Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 + Class: ELF32 + Data: 2's complement, little endian + Version: 1 (current) + OS/ABI: UNIX - System V + ABI Version: 0x0 + Type: EXEC (Executable file) + Machine: ARM + Version: 0x1 + Entry point address: 0x23A3 + Start of program headers: 52 (bytes into file) + Start of section headers: 673340 (bytes into file) + Flags: 0x5000200 + Size of this header: 52 (bytes) + Size of program headers: 32 (bytes) + Number of program headers: 2 + Size of section headers: 40 (bytes) + Number of section headers: 21 + Section header string table index: 19 +``` + +If you look at the bottom of the Cargo configuration file (`.cargo/config`) +you'll see that the `thumbv7m-none-eabi` target has been set as the default +compilation target. This means that you do *not* need to pass the `--target` +flag to cross compile because it's already implied. So: + +``` console +$ cargo build --example hello +``` + +Does the same as before. + +3. There's no step 3! Your build is done, but for completeness let's look at how + to run this program on QEMU. + +#### Running the program on QEMU + +Execute this command and you are done. + +``` console +$ qemu-system-arm \ + -cpu cortex-m3 \ + -machine lm3s6965evb \ + -nographic \ + -semihosting-config enable=on,target=native \ + -kernel target/thumbv7m-none-eabi/debug/examples/hello +Hello, world! +``` + +The above command will block the terminal because the `hello` program never +ends! To terminate QEMU input this in your terminal: `Ctrl+A`, followed by `X`. + +Let me break down that long command for you: + +- `qemu-system-arm`. This is the QEMU emulator. There are a few variants of + these QEMU binaries; this one does full *system* emulation of *ARM* machines + -- hence the name. + +- `-cpu cortex-m3`. This tells QEMU to emulate a Cortex-M3 CPU. Specifying the + CPU model lets us catch some miscompilation errors: for example, running a + program compiled for the Cortex-M4F, which has a hardware FPU, will make QEMU + error during its execution. + +- `-machine lm3s6965evb`. This tells QEMU to emulate the LM3S6965EVB, a + evaluation board that contains a LM3S6965 microcontroller. + +- `-nographic`. This tells QEMU to not launch its GUI. + +- `-semihosting-config (..)`. This tells QEMU to enable semihosting. Semihosting + lets the emulated device, among other things, use the host stdout, stderr and + stdin and create files on the host. + +- `-kernel $file`. This tells QEMU which binary to flash (kind of) and run on + the emulated machine. + +#### Debugging + +First, we launch a QEMU instance: + +``` console +$ qemu-system-arm \ + -cpu cortex-m3 \ + -machine lm3s6965evb \ + -nographic \ + -semihosting-config enable=on,target=native \ + -gdb tcp::3333 \ + -S \ + -kernel target/thumbv7m-none-eabi/debug/examples/hello +``` + +Note that this command won't print anything to the console but will block the +terminal. We have passed two extra flags this time: + +- `-gdb tcp::3333`. This tells QEMU to wait for a GDB connection on TCP + port 3333. + +- `-S`. This tells QEMU to freeze the machine at startup. Without this the + program would have reached the end of `main` before we had a chance to launch + the debugger! + +Next, we start up LLDB in another terminal: + +``` console +$ lldb target/thumbv7m-none-eabi/debug/examples/hello +``` + +And tell it to connect to the GDB server that QEMU created: + +``` console +(lldb) gdb-remote 3333 +Process 1 stopped +* thread #1, stop reason = signal SIGTRAP + frame #0: 0x000023a2 hello`Reset at lib.rs:475 + 472 + 473 #[doc(hidden)] + 474 #[no_mangle] +-> 475 pub unsafe extern "C" fn Reset() -> ! { + 476 extern "C" { + 477 // This symbol will be provided by the user via the `entry!` macro + 478 fn main() -> !; +``` + +You'll see that the process is halted and that the program counter is pointing +to a function named `Reset`. That is the reset handler: what Cortex-M cores +execute upon booting. + +This reset handler will eventually call our `main` function. Let's skip all the +way there using a breakpoint and the `continue` command: + +``` console +(lldb) breakpoint set -name hello::main +Breakpoint 1: where = hello`hello::main::h9cf19a1378cbd1b8 + 2 at hello.rs:20, address = 0x000006a8 + +(lldb) continue +Process 1 resuming +Process 1 stopped +* thread #1, stop reason = breakpoint 1.1 + frame #0: 0x000006a8 hello`hello::main::h9cf19a1378cbd1b8 at hello.rs:20 + 17 entry!(main); + 18 + 19 fn main() -> ! { +-> 20 let mut stdout = hio::hstdout().unwrap(); + 21 writeln!(stdout, "Hello, world!").unwrap(); + 22 + 23 loop {} +``` + +We are now close to the code that prints "Hello, world!". Let's move the program +forward using the `next` command. + +``` console +(lldb) next +Process 1 stopped +* thread #1, stop reason = step over + frame #0: 0x000006be hello`hello::main::h9cf19a1378cbd1b8 at hello.rs:21 + 18 + 19 fn main() -> ! { + 20 let mut stdout = hio::hstdout().unwrap(); +-> 21 writeln!(stdout, "Hello, world!").unwrap(); + 22 + 23 loop {} + 24 } + +(lldb) next +Process 1 stopped +* thread #1, stop reason = step over + frame #0: 0x000006f6 hello`hello::main::h9cf19a1378cbd1b8 at hello.rs:23 + 20 let mut stdout = hio::hstdout().unwrap(); + 21 writeln!(stdout, "Hello, world!").unwrap(); + 22 +-> 23 loop {} + 24 } +``` + +At this point you should see "Hello, world!" printed on the terminal that's +running `qemu-system-arm`. + +``` console +$ qemu-system-arm (..) +Hello, world! +``` + +That's it! You can now exit `lldb`, which will also cause QEMU to terminate. + +``` +(lldb) exit +Quitting LLDB will kill one or more processes. Do you really want to proceed: [Y/n] y +``` + +### Not first timers + +#### Building + +This section explains how to configure this template to build programs for some +specific Cortex-M device. + +0. Before everything else, you need to know the characteristics of the target + device: + +- What's the ARM core? e.g. Cortex-M3. + +- Does the ARM core include an FPU? e.g. the Cortex-M4F does. + +- How much Flash memory and RAM does the target device has? e.g. 40 KB of RAM + +- Where is Flash memory and RAM mapped in the address space? e.g. `0x2000_0000` + is common for RAM. + +You should be able to find this information in the data sheet and / or reference +manual of your device. + +As an example, we'll use the [STM32F303VCT6] microcontroller. This device has: + +[STM32F303VCT6]: https://www.st.com/en/microcontrollers/stm32f303vc.html + +- a Cortex-M4F core that includes a single precision FPU + +- 256 KB of Flash located at address `0x0800_0000`. + +- 40 KB of RAM located at address `0x2000_0000`. (There's another RAM region but + for simplicity we'll ignore it). + +1. Initialize the template + +``` console +$ cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart +``` + +2. Set the default compilation target in `.cargo/config`. + +For the STM32F303VCT6, we pick the `thumbv7em-none-eabihf` target as that covers +the Cortex-M4F core. + +``` console +$ tail .cargo/config +``` + +``` toml +[build] +# Pick ONE of these compilation targets +# target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ +# target = "thumbv7m-none-eabi" # Cortex-M3 +# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU) +target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) +``` + +3. Enter the memory region information into `memory.x`. + +As we mentioned before the STM32F303VCT6 has 40 KB of RAM located at address +`0x2000_0000` and 256 KB of Flash memory located at address `0x0800_0000`. + +``` console +$ cat memory.x +``` + +``` text +MEMORY +{ + /* NOTE K = KiBi = 1024 bytes */ + FLASH : ORIGIN = 0x08000000, LENGTH = 256K + RAM : ORIGIN = 0x20000000, LENGTH = 40K +} +``` + +4. Build one of the examples: + +``` console +$ cargo build --example hello +``` + +You are done! You should be able to flash and run this example on your +device. + +#### Debugging + +Teaching you how to flash and debug this program on *your* device is out of +scope for this document due to the sheer variety of possible hardware / software +combinations. But the steps required to flash and debug this program on the +[STM32F3DISCOVERY] using OpenOCD are provided below as a reference. + +[STM32F3DISCOVERY]: https://www.st.com/en/evaluation-tools/stm32f3discovery.html + +On a terminal run `openocd` to connect to the ST-LINK on the discovery board. +Run this command from the root of the template; `openocd` will pick up the +`openocd.cfg` file which indicates which interface file and target file to use. + +``` console +$ cat openocd.cfg +``` + +``` text +source [find interface/stlink-v2-1.cfg] +source [find target/stm32f3x.cfg] +``` + +``` console +$ openocd +Open On-Chip Debugger 0.10.0 +Licensed under GNU GPL v2 +For bug reports, read + http://openocd.org/doc/doxygen/bugs.html +Info : auto-selecting first available session transport "hla_swd". To override use 'transport select '. +adapter speed: 1000 kHz +adapter_nsrst_delay: 100 +Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD +none separate +Info : Unable to match requested speed 1000 kHz, using 950 kHz +Info : Unable to match requested speed 1000 kHz, using 950 kHz +Info : clock speed 950 kHz +Info : STLINK v2 JTAG v27 API v2 SWIM v15 VID 0x0483 PID 0x374B +Info : using stlink api v2 +Info : Target voltage: 2.913879 +Info : stm32f3x.cpu: hardware has 6 breakpoints, 4 watchpoints +``` + +On another terminal run GDB, also from the root of the template. + +``` console +$ cat openocd.gdb +``` + +``` text +target remote :3333 + +# print demangled symbols +set print asm-demangle on + +# detect unhandled exceptions and hard faults +break DefaultHandler +break UserHardFault + +monitor arm semihosting enable + +load +``` + +``` console +$ arm-none-eabi-gdb -x openocd.gdb target/thumbv7em-none-eabihf/debug/examples/hello +(..) +Loading section .vector_table, size 0x400 lma 0x8000000 +Loading section .text, size 0x21dc lma 0x8000400 +Loading section .rodata, size 0x6a4 lma 0x80025e0 +Start address 0x800238c, load size 11392 +Transfer rate: 17 KB/sec, 3797 bytes/write. + +(gdb) list +470 #[no_mangle] +471 pub static __RESET_VECTOR: unsafe extern "C" fn() -> ! = Reset; +472 +473 #[doc(hidden)] +474 #[no_mangle] +475 pub unsafe extern "C" fn Reset() -> ! { +476 extern "C" { +477 // This symbol will be provided by the user via the `entry!` macro +478 fn main() -> !; +479 +``` + +The `openocd.gdb` script will connect GDB to OpenOCD and then flash the program +into the device. After that you can do a normal debugging session. + +If you `continue` the program past the semihosting write operation you'll see +"Hello, world" printed on the OpenOCD console. + +``` console +(gdb) continue +``` + +``` console +$ openocd +(..) +Hello, world! +``` + +## Next steps + +> TODO point the reader to embedded-hal, awesome-embedded-rust, etc. + # License Licensed under either of diff --git a/debug.gdb b/debug.gdb deleted file mode 100644 index f2bf090..0000000 --- a/debug.gdb +++ /dev/null @@ -1,21 +0,0 @@ -target remote :3333 - -# print demangled symbols by default -set print asm-demangle on - -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.fifo uart off 8000000 - -# # OR: make the microcontroller SWO pin output compatible with UART (8N1) -# # 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 - -load -step diff --git a/examples/hello.rs b/examples/hello.rs index 3c4b5ec..5537379 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -6,13 +6,12 @@ #![no_std] #[macro_use] -extern crate cortex_m_rt as rt; +extern crate cortex_m_rt; extern crate cortex_m_semihosting as sh; extern crate panic_semihosting; use core::fmt::Write; -use rt::ExceptionFrame; use sh::hio; entry!(main); @@ -23,15 +22,3 @@ fn main() -> ! { loop {} } - -exception!(HardFault, hard_fault); - -fn hard_fault(ef: &ExceptionFrame) -> ! { - panic!("HardFault at {:#?}", ef); -} - -exception!(*, default_handler); - -fn default_handler(irqn: i16) { - panic!("Unhandled exception (IRQn = {})", irqn); -} diff --git a/memory.x b/memory.x index 32879e1..ee7e8a8 100644 --- a/memory.x +++ b/memory.x @@ -2,8 +2,9 @@ MEMORY { /* NOTE K = KiBi = 1024 bytes */ /* TODO Adjust these memory regions to match your device memory layout */ - FLASH : ORIGIN = 0x000BAAD0, LENGTH = 0K - RAM : ORIGIN = 0xBAAD0000, LENGTH = 0K + /* These values correspond to the LM3S6965, one of the few devices QEMU can emulate */ + FLASH : ORIGIN = 0x00000000, LENGTH = 256K + RAM : ORIGIN = 0x20000000, LENGTH = 64K } /* This is where the call stack will be allocated. */ diff --git a/openocd.cfg b/openocd.cfg new file mode 100644 index 0000000..74c9af9 --- /dev/null +++ b/openocd.cfg @@ -0,0 +1,2 @@ +source [find interface/stlink-v2-1.cfg] +source [find target/stm32f3x.cfg] diff --git a/openocd.gdb b/openocd.gdb new file mode 100644 index 0000000..bacba86 --- /dev/null +++ b/openocd.gdb @@ -0,0 +1,12 @@ +target remote :3333 + +# print demangled symbols +set print asm-demangle on + +# detect unhandled exceptions and hard faults +break DefaultHandler +break UserHardFault + +monitor arm semihosting enable + +load \ No newline at end of file diff --git a/src/examples/_0_minimal.rs b/src/examples/_0_minimal.rs deleted file mode 100644 index 8926e23..0000000 --- a/src/examples/_0_minimal.rs +++ /dev/null @@ -1,67 +0,0 @@ -//! Minimal Cortex-M program -//! -//! When executed this program will hit the breakpoint set in `main`. -//! -//! All Cortex-M programs need to: -//! -//! - Contain the `#![no_main]` and `#![no_std]` attributes. Embedded programs don't use the -//! standard Rust `main` interface or the Rust standard (`std`) library. -//! -//! - Define their entry point using [`entry!`] macro. -//! -//! [`entry!`]: https://docs.rs/cortex-m-rt/~0.5/cortex_m_rt/macro.entry.html -//! -//! - Define their panicking behavior, i.e. what happens when `panic!` is called. The easiest way to -//! define a panicking behavior is to link to a [panic handler crate][0] -//! -//! [0]: https://crates.io/keywords/panic-impl -//! -//! - Define the `HardFault` handler using the [`exception!`] macro. This handler (function) is -//! called when a hard fault exception is raised by the hardware. -//! -//! [`exception!`]: https://docs.rs/cortex-m-rt/~0.5/cortex_m_rt/macro..html -//! -//! - Define a default handler using the [`exception!`] macro. This function will be used to handle -//! all interrupts and exceptions which have not been assigned a specific handler. -//! -//! ``` -//! -//! #![no_main] // <- IMPORTANT! -//! #![no_std] -//! -//! extern crate cortex_m; -//! -//! #[macro_use(entry, exception)] -//! extern crate cortex_m_rt as rt; -//! -//! // makes `panic!` print messages to the host stderr using semihosting -//! extern crate panic_semihosting; -//! -//! use cortex_m::asm; -//! use rt::ExceptionFrame; -//! -//! // the program entry point is ... -//! entry!(main); -//! -//! // ... this never ending function -//! fn main() -> ! { -//! loop { -//! asm::bkpt(); -//! } -//! } -//! -//! // define the hard fault handler -//! exception!(HardFault, hard_fault); -//! -//! fn hard_fault(ef: &ExceptionFrame) -> ! { -//! panic!("HardFault at {:#?}", ef); -//! } -//! -//! // define the default exception handler -//! exception!(*, default_handler); -//! -//! fn default_handler(irqn: i16) { -//! panic!("Unhandled exception (IRQn = {})", irqn); -//! } -//! ``` -// Auto-generated. Do not modify. diff --git a/src/examples/_1_hello.rs b/src/examples/_1_hello.rs deleted file mode 100644 index 413c4fb..0000000 --- a/src/examples/_1_hello.rs +++ /dev/null @@ -1,41 +0,0 @@ -//! Prints "Hello, world!" on the OpenOCD console using semihosting -//! -//! --- -//! -//! ``` -//! -//! #![no_main] -//! #![no_std] -//! -//! #[macro_use] -//! extern crate cortex_m_rt as rt; -//! extern crate cortex_m_semihosting as sh; -//! extern crate panic_semihosting; -//! -//! use core::fmt::Write; -//! -//! use rt::ExceptionFrame; -//! use sh::hio; -//! -//! entry!(main); -//! -//! fn main() -> ! { -//! let mut stdout = hio::hstdout().unwrap(); -//! writeln!(stdout, "Hello, world!").unwrap(); -//! -//! loop {} -//! } -//! -//! exception!(HardFault, hard_fault); -//! -//! fn hard_fault(ef: &ExceptionFrame) -> ! { -//! panic!("HardFault at {:#?}", ef); -//! } -//! -//! exception!(*, default_handler); -//! -//! fn default_handler(irqn: i16) { -//! panic!("Unhandled exception (IRQn = {})", irqn); -//! } -//! ``` -// Auto-generated. Do not modify. diff --git a/src/examples/_2_itm.rs b/src/examples/_2_itm.rs deleted file mode 100644 index 568a467..0000000 --- a/src/examples/_2_itm.rs +++ /dev/null @@ -1,58 +0,0 @@ -//! Sends "Hello, world!" through the ITM port 0 -//! -//! ITM is much faster than semihosting. Like 4 orders of magnitude or so. -//! -//! **NOTE** Cortex-M0 chips don't support ITM. -//! -//! You'll have to connect the microcontroller's SWO pin to the SWD interface. Note that some -//! development boards don't provide this option. -//! -//! You'll need [`itmdump`] to receive the message on the host plus you'll need to uncomment two -//! `monitor` commands in the `.gdbinit` file. -//! -//! [`itmdump`]: https://docs.rs/itm/0.2.1/itm/ -//! -//! --- -//! -//! ``` -//! -//! #![no_main] -//! #![no_std] -//! -//! #[macro_use] -//! extern crate cortex_m; -//! #[macro_use] -//! extern crate cortex_m_rt as rt; -//! extern crate panic_semihosting; -//! -//! use cortex_m::{asm, Peripherals}; -//! use rt::ExceptionFrame; -//! -//! entry!(main); -//! -//! fn main() -> ! { -//! let mut p = Peripherals::take().unwrap(); -//! let stim = &mut p.ITM.stim[0]; -//! -//! iprintln!(stim, "Hello, world!"); -//! -//! loop { -//! asm::bkpt(); -//! } -//! } -//! -//! // define the hard fault handler -//! exception!(HardFault, hard_fault); -//! -//! fn hard_fault(ef: &ExceptionFrame) -> ! { -//! panic!("HardFault at {:#?}", ef); -//! } -//! -//! // define the default exception handler -//! exception!(*, default_handler); -//! -//! fn default_handler(irqn: i16) { -//! panic!("Unhandled exception (IRQn = {})", irqn); -//! } -//! ``` -// Auto-generated. Do not modify. diff --git a/src/examples/_3_panic.rs b/src/examples/_3_panic.rs deleted file mode 100644 index 4d6a7dd..0000000 --- a/src/examples/_3_panic.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! Changing the panic handler -//! -//! The easiest way to change the panic handler is to use a different [panic handler crate][0]. -//! -//! [0]: https://crates.io/keywords/panic-impl -//! -//! --- -//! -//! ``` -//! -//! #![no_main] -//! #![no_std] -//! -//! #[macro_use] -//! extern crate cortex_m_rt as rt; -//! -//! // Pick one of these two panic handlers: -//! -//! // Reports panic messages to the host stderr using semihosting -//! extern crate panic_semihosting; -//! -//! // Logs panic messages using the ITM (Instrumentation Trace Macrocell) -//! // extern crate panic_itm; -//! -//! use rt::ExceptionFrame; -//! -//! entry!(main); -//! -//! fn main() -> ! { -//! panic!("Oops") -//! } -//! -//! // define the hard fault handler -//! exception!(HardFault, hard_fault); -//! -//! fn hard_fault(ef: &ExceptionFrame) -> ! { -//! panic!("HardFault at {:#?}", ef); -//! } -//! -//! // define the default exception handler -//! exception!(*, default_handler); -//! -//! fn default_handler(irqn: i16) { -//! panic!("Unhandled exception (IRQn = {})", irqn); -//! } -//! ``` -// Auto-generated. Do not modify. diff --git a/src/examples/_4_crash.rs b/src/examples/_4_crash.rs deleted file mode 100644 index f3957d1..0000000 --- a/src/examples/_4_crash.rs +++ /dev/null @@ -1,118 +0,0 @@ -//! Debugging a crash (exception) -//! -//! Most crash conditions trigger a hard fault exception, whose handler is defined via -//! `exception!(HardFault, ..)`. The `HardFault` handler has access to the exception frame, a -//! snapshot of the CPU registers at the moment of the exception. -//! -//! This program crashes and the `HardFault` handler prints to the console the contents of the -//! `ExceptionFrame` and then triggers a breakpoint. From that breakpoint one can see the backtrace -//! that led to the exception. -//! -//! ``` text -//! (gdb) continue -//! Program received signal SIGTRAP, Trace/breakpoint trap. -//! __bkpt () at asm/bkpt.s:3 -//! 3 bkpt -//! -//! (gdb) backtrace -//! #0 __bkpt () at asm/bkpt.s:3 -//! #1 0x080030b4 in cortex_m::asm::bkpt () at $$/cortex-m-0.5.0/src/asm.rs:19 -//! #2 rust_begin_unwind (args=..., file=..., line=99, col=5) at $$/panic-semihosting-0.2.0/src/lib.rs:87 -//! #3 0x08001d06 in core::panicking::panic_fmt () at libcore/panicking.rs:71 -//! #4 0x080004a6 in crash::hard_fault (ef=0x20004fa0) at examples/crash.rs:99 -//! #5 0x08000548 in UserHardFault (ef=0x20004fa0) at :10 -//! #6 0x0800093a in HardFault () at asm.s:5 -//! Backtrace stopped: previous frame identical to this frame (corrupt stack?) -//! ``` -//! -//! In the console output one will find the state of the Program Counter (PC) register at the time -//! of the exception. -//! -//! ``` text -//! panicked at 'HardFault at ExceptionFrame { -//! r0: 0x2fffffff, -//! r1: 0x2fffffff, -//! r2: 0x080051d4, -//! r3: 0x080051d4, -//! r12: 0x20000000, -//! lr: 0x08000435, -//! pc: 0x08000ab6, -//! xpsr: 0x61000000 -//! }', examples/crash.rs:106:5 -//! ``` -//! -//! This register contains the address of the instruction that caused the exception. In GDB one can -//! disassemble the program around this address to observe the instruction that caused the -//! exception. -//! -//! ``` text -//! (gdb) disassemble/m 0x08000ab6 -//! Dump of assembler code for function core::ptr::read_volatile: -//! 451 pub unsafe fn read_volatile(src: *const T) -> T { -//! 0x08000aae <+0>: sub sp, #16 -//! 0x08000ab0 <+2>: mov r1, r0 -//! 0x08000ab2 <+4>: str r0, [sp, #8] -//! -//! 452 intrinsics::volatile_load(src) -//! 0x08000ab4 <+6>: ldr r0, [sp, #8] -//! -> 0x08000ab6 <+8>: ldr r0, [r0, #0] -//! 0x08000ab8 <+10>: str r0, [sp, #12] -//! 0x08000aba <+12>: ldr r0, [sp, #12] -//! 0x08000abc <+14>: str r1, [sp, #4] -//! 0x08000abe <+16>: str r0, [sp, #0] -//! 0x08000ac0 <+18>: b.n 0x8000ac2 -//! -//! 453 } -//! 0x08000ac2 <+20>: ldr r0, [sp, #0] -//! 0x08000ac4 <+22>: add sp, #16 -//! 0x08000ac6 <+24>: bx lr -//! -//! End of assembler dump. -//! ``` -//! -//! `ldr r0, [r0, #0]` caused the exception. This instruction tried to load (read) a 32-bit word -//! from the address stored in the register `r0`. Looking again at the contents of `ExceptionFrame` -//! we see that the `r0` contained the address `0x2FFF_FFFF` when this instruction was executed. -//! -//! --- -//! -//! ``` -//! -//! #![no_main] -//! #![no_std] -//! -//! extern crate cortex_m; -//! #[macro_use] -//! extern crate cortex_m_rt as rt; -//! extern crate panic_semihosting; -//! -//! use core::ptr; -//! -//! use rt::ExceptionFrame; -//! -//! entry!(main); -//! -//! fn main() -> ! { -//! unsafe { -//! // read an address outside of the RAM region; causes a HardFault exception -//! ptr::read_volatile(0x2FFF_FFFF as *const u32); -//! } -//! -//! loop {} -//! } -//! -//! // define the hard fault handler -//! exception!(HardFault, hard_fault); -//! -//! fn hard_fault(ef: &ExceptionFrame) -> ! { -//! panic!("HardFault at {:#?}", ef); -//! } -//! -//! // define the default exception handler -//! exception!(*, default_handler); -//! -//! fn default_handler(irqn: i16) { -//! panic!("Unhandled exception (IRQn = {})", irqn); -//! } -//! ``` -// Auto-generated. Do not modify. diff --git a/src/examples/_5_exception.rs b/src/examples/_5_exception.rs deleted file mode 100644 index f2a65f3..0000000 --- a/src/examples/_5_exception.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! Overriding an exception handler -//! -//! You can override an exception handler using the [`exception!`][1] macro. -//! -//! [1]: https://docs.rs/cortex-m-rt/0.5.0/cortex_m_rt/macro.exception.html -//! -//! --- -//! -//! ``` -//! -//! #![deny(unsafe_code)] -//! #![no_main] -//! #![no_std] -//! -//! extern crate cortex_m; -//! #[macro_use] -//! extern crate cortex_m_rt as rt; -//! extern crate cortex_m_semihosting as sh; -//! extern crate panic_semihosting; -//! -//! use core::fmt::Write; -//! -//! use cortex_m::peripheral::syst::SystClkSource; -//! use cortex_m::Peripherals; -//! use rt::ExceptionFrame; -//! use sh::hio::{self, HStdout}; -//! -//! entry!(main); -//! -//! fn main() -> ! { -//! let p = Peripherals::take().unwrap(); -//! let mut syst = p.SYST; -//! -//! // configures the system timer to trigger a SysTick exception every second -//! syst.set_clock_source(SystClkSource::Core); -//! syst.set_reload(8_000_000); // period = 1s -//! syst.enable_counter(); -//! syst.enable_interrupt(); -//! -//! loop {} -//! } -//! -//! // try commenting out this line: you'll end in `default_handler` instead of in `sys_tick` -//! exception!(SysTick, sys_tick, state: Option = None); -//! -//! fn sys_tick(state: &mut Option) { -//! if state.is_none() { -//! *state = Some(hio::hstdout().unwrap()); -//! } -//! -//! if let Some(hstdout) = state.as_mut() { -//! hstdout.write_str(".").unwrap(); -//! } -//! } -//! -//! exception!(HardFault, hard_fault); -//! -//! fn hard_fault(ef: &ExceptionFrame) -> ! { -//! panic!("HardFault at {:#?}", ef); -//! } -//! -//! exception!(*, default_handler); -//! -//! fn default_handler(irqn: i16) { -//! panic!("Unhandled exception (IRQn = {})", irqn); -//! } -//! ``` -// Auto-generated. Do not modify. diff --git a/src/examples/_6_allocator.rs b/src/examples/_6_allocator.rs deleted file mode 100644 index c7bddcc..0000000 --- a/src/examples/_6_allocator.rs +++ /dev/null @@ -1,79 +0,0 @@ -//! How to use the heap and a dynamic memory allocator -//! -//! This example depends on the alloc-cortex-m crate so you'll have to add it to your Cargo.toml: -//! -//! ``` text -//! # or edit the Cargo.toml file manually -//! $ cargo add alloc-cortex-m -//! ``` -//! -//! --- -//! -//! ``` -//! -//! #![feature(alloc)] -//! #![feature(global_allocator)] -//! #![feature(lang_items)] -//! #![no_main] -//! #![no_std] -//! -//! // This is the allocator crate; you can use a different one -//! extern crate alloc_cortex_m; -//! #[macro_use] -//! extern crate alloc; -//! extern crate cortex_m; -//! #[macro_use] -//! extern crate cortex_m_rt as rt; -//! extern crate cortex_m_semihosting as sh; -//! extern crate panic_semihosting; -//! -//! use core::fmt::Write; -//! -//! use alloc_cortex_m::CortexMHeap; -//! use cortex_m::asm; -//! use rt::ExceptionFrame; -//! use sh::hio; -//! -//! // this is the allocator the application will use -//! #[global_allocator] -//! static ALLOCATOR: CortexMHeap = CortexMHeap::empty(); -//! -//! const HEAP_SIZE: usize = 1024; // in bytes -//! -//! entry!(main); -//! -//! fn main() -> ! { -//! // Initialize the allocator BEFORE you use it -//! unsafe { ALLOCATOR.init(rt::heap_start() as usize, HEAP_SIZE) } -//! -//! // Growable array allocated on the heap -//! let xs = vec![0, 1, 2]; -//! -//! let mut stdout = hio::hstdout().unwrap(); -//! writeln!(stdout, "{:?}", xs).unwrap(); -//! -//! loop {} -//! } -//! -//! // define what happens in an Out Of Memory (OOM) condition -//! #[lang = "oom"] -//! #[no_mangle] -//! pub fn rust_oom() -> ! { -//! asm::bkpt(); -//! -//! loop {} -//! } -//! -//! exception!(HardFault, hard_fault); -//! -//! fn hard_fault(ef: &ExceptionFrame) -> ! { -//! panic!("HardFault at {:#?}", ef); -//! } -//! -//! exception!(*, default_handler); -//! -//! fn default_handler(irqn: i16) { -//! panic!("Unhandled exception (IRQn = {})", irqn); -//! } -//! ``` -// Auto-generated. Do not modify. diff --git a/src/examples/_7_device.rs b/src/examples/_7_device.rs deleted file mode 100644 index 7564284..0000000 --- a/src/examples/_7_device.rs +++ /dev/null @@ -1,93 +0,0 @@ -//! Using a device crate -//! -//! Crates generated using [`svd2rust`] are referred to as device crates. These crates provide an -//! API to access the peripherals of a device. -//! -//! [`svd2rust`]: https://crates.io/crates/svd2rust -//! -//! Device crates also provide an `interrupt!` macro (behind the "rt" feature) to register interrupt -//! handlers. -//! -//! This example depends on the [`stm32f103xx`] crate so you'll have to add it to your Cargo.toml. -//! -//! [`stm32f103xx`]: https://crates.io/crates/stm32f103xx -//! -//! ``` -//! $ edit Cargo.toml && tail $_ -//! [dependencies.stm32f103xx] -//! features = ["rt"] -//! version = "0.10.0" -//! ``` -//! -//! --- -//! -//! ``` -//! -//! #![no_main] -//! #![no_std] -//! -//! extern crate cortex_m; -//! #[macro_use] -//! extern crate cortex_m_rt as rt; -//! extern crate cortex_m_semihosting as sh; -//! #[macro_use] -//! extern crate stm32f103xx; -//! extern crate panic_semihosting; -//! -//! use core::fmt::Write; -//! -//! use cortex_m::peripheral::syst::SystClkSource; -//! use rt::ExceptionFrame; -//! use sh::hio::{self, HStdout}; -//! use stm32f103xx::Interrupt; -//! -//! entry!(main); -//! -//! fn main() -> ! { -//! let p = cortex_m::Peripherals::take().unwrap(); -//! -//! let mut syst = p.SYST; -//! let mut nvic = p.NVIC; -//! -//! nvic.enable(Interrupt::EXTI0); -//! -//! // configure the system timer to wrap around every second -//! syst.set_clock_source(SystClkSource::Core); -//! syst.set_reload(8_000_000); // 1s -//! syst.enable_counter(); -//! -//! loop { -//! // busy wait until the timer wraps around -//! while !syst.has_wrapped() {} -//! -//! // trigger the `EXTI0` interrupt -//! nvic.set_pending(Interrupt::EXTI0); -//! } -//! } -//! -//! // try commenting out this line: you'll end in `default_handler` instead of in `exti0` -//! interrupt!(EXTI0, exti0, state: Option = None); -//! -//! fn exti0(state: &mut Option) { -//! if state.is_none() { -//! *state = Some(hio::hstdout().unwrap()); -//! } -//! -//! if let Some(hstdout) = state.as_mut() { -//! hstdout.write_str(".").unwrap(); -//! } -//! } -//! -//! exception!(HardFault, hard_fault); -//! -//! fn hard_fault(ef: &ExceptionFrame) -> ! { -//! panic!("HardFault at {:#?}", ef); -//! } -//! -//! exception!(*, default_handler); -//! -//! fn default_handler(irqn: i16) { -//! panic!("Unhandled exception (IRQn = {})", irqn); -//! } -//! ``` -// Auto-generated. Do not modify. diff --git a/src/examples/mod.rs b/src/examples/mod.rs deleted file mode 100644 index 0358d78..0000000 --- a/src/examples/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! Examples sorted in increasing degree of complexity -// Auto-generated. Do not modify. -pub mod _0_minimal; -pub mod _1_hello; -pub mod _2_itm; -pub mod _3_panic; -pub mod _4_crash; -pub mod _5_exception; -pub mod _6_allocator; -pub mod _7_device; diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index f85c4c6..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,342 +0,0 @@ -//! A template for building applications for ARM Cortex-M microcontrollers -//! -//! # Dependencies -//! -//! - Nightly Rust toolchain from 2018-08-28 or newer: `rustup default nightly` -//! - Cargo `clone` subcommand: `cargo install cargo-clone` -//! - GDB: `sudo apt-get install gdb-arm-none-eabi` (on Ubuntu) -//! - OpenOCD: `sudo apt-get install OpenOCD` (on Ubuntu) -//! - [Optional] Cargo `add` subcommand: `cargo install cargo-edit` -//! -//! # Usage -//! -//! 0) Figure out the cross compilation *target* to use. -//! -//! - Use `thumbv6m-none-eabi` for ARM Cortex-M0 and Cortex-M0+ -//! - Use `thumbv7m-none-eabi` for ARM Cortex-M3 -//! - Use `thumbv7em-none-eabi` for ARM Cortex-M4 and Cortex-M7 (*no* FPU support) -//! - Use `thumbv7em-none-eabihf` for ARM Cortex-M4**F** and Cortex-M7**F** (*with* FPU support) -//! -//! 1) Install the `rust-std` component for your target, if you haven't done so already -//! -//! ``` console -//! $ rustup target add thumbv7em-none-eabihf -//! ``` -//! -//! 2) Clone this crate -//! -//! ``` text -//! $ cargo clone cortex-m-quickstart --vers 0.3.4 -//! ``` -//! -//! 3) Change the crate name, author and version -//! -//! ``` text -//! $ edit Cargo.toml && head $_ -//! [package] -//! authors = ["Jorge Aparicio "] -//! name = "demo" -//! version = "0.1.0" -//! ``` -//! -//! 4) Specify the memory layout of the target device -//! -//! **NOTE** board support crates sometimes provide this file for you (check the crate -//! documentation). If you are using one that does then remove *both* `memory.x` and `build.rs` from -//! the root of this crate. -//! -//! ``` text -//! $ cat >memory.x <<'EOF' -//! MEMORY -//! { -//! /* NOTE K = KiBi = 1024 bytes */ -//! FLASH : ORIGIN = 0x08000000, LENGTH = 256K -//! RAM : ORIGIN = 0x20000000, LENGTH = 40K -//! } -//! EOF -//! ``` -//! -//! 5) Optionally, set a default build target. This way you don't have to pass `--target` to each -//! Cargo invocation. -//! -//! ``` text -//! $ cat >>.cargo/config <<'EOF' -//! [build] -//! target = "thumbv7em-none-eabihf" -//! EOF -//! ``` -//! -//! 6) Optionally, depend on a device, HAL implementation or a board support crate. -//! -//! ``` text -//! $ # add a device crate, OR -//! $ cargo add stm32f30x -//! -//! $ # add a HAL implementation crate, OR -//! $ cargo add stm32f30x-hal -//! -//! $ # add a board support crate -//! $ cargo add f3 -//! ``` -//! -//! 7) Write the application or start from one of the examples -//! -//! ``` text -//! $ rm -r src/* && cp examples/hello.rs src/main.rs -//! ``` -//! -//! 8) Build the application -//! -//! ``` text -//! $ cargo build --release -//! -//! $ # sanity check -//! $ arm-none-eabi-readelf -A target/thumbv7em-none-eabihf/release/demo -//! Attribute Section: aeabi -//! File Attributes -//! Tag_conformance: "2.09" -//! Tag_CPU_arch: v7E-M -//! Tag_CPU_arch_profile: Microcontroller -//! Tag_THUMB_ISA_use: Thumb-2 -//! Tag_FP_arch: VFPv4-D16 -//! Tag_ABI_PCS_GOT_use: direct -//! Tag_ABI_FP_denormal: Needed -//! Tag_ABI_FP_exceptions: Needed -//! Tag_ABI_FP_number_model: IEEE 754 -//! Tag_ABI_align_needed: 8-byte -//! Tag_ABI_align_preserved: 8-byte, except leaf SP -//! Tag_ABI_HardFP_use: SP only -//! Tag_ABI_VFP_args: VFP registers -//! Tag_ABI_optimization_goals: Aggressive Speed -//! Tag_CPU_unaligned_access: v6 -//! Tag_FP_HP_extension: Allowed -//! Tag_ABI_FP_16bit_format: IEEE 754 -//! ``` -//! -//! 9) Flash and debug the program -//! -//! ``` text -//! $ # Launch OpenOCD on a terminal -//! $ openocd -f (..) -//! ``` -//! -//! ``` text -//! $ # Start a debug session in another terminal -//! $ arm-none-eabi-gdb target/thumbv7em-none-eabihf/release/demo -//! ``` -//! -//! Alternatively, you can use `cargo run` to build, flash and debug the program in a single step. -//! -//! ``` text -//! $ cargo run --example hello -//! > # drops you into a GDB session -//! ``` -//! -//! # Examples -//! -//! Check the [examples module][examples] -//! -//! [examples]: ./examples/index.html -//! -//! # Troubleshooting -//! -//! This section contains fixes for common errors encountered when the -//! `cortex-m-quickstart` template is misused. -//! -//! ## Used the standard `main` interface -//! -//! Error message: -//! -//! ``` text -//! $ cargo build -//! Compiling demo v0.1.0 (file:///home/japaric/tmp/demo) -//! -//! error: requires `start` lang_item -//! ``` -//! -//! Solution: Use `#![no_main]` and `entry!` as shown in the [examples]. -//! -//! ## Forgot to launch an OpenOCD instance -//! -//! Error message: -//! -//! ``` text -//! $ arm-none-eabi-gdb target/.. -//! Reading symbols from hello...done. -//! .gdbinit:1: Error in sourced command file: -//! :3333: Connection timed out. -//! ``` -//! -//! Solution: Launch OpenOCD on other terminal. See [Usage] section. -//! -//! [Usage]: ./index.html#usage -//! -//! ## Didn't modify the `memory.x` linker script -//! -//! Error message: -//! -//! ``` text -//! $ cargo build -//! Compiling demo v0.1.0 (file:///home/japaric/tmp/demo) -//! error: linking with `rust-lld` failed: exit code: 1 -//! | -//! = note: "rust-lld" "-flavor" "gnu" "-L" (..) -//! (..) -//! = note: rust-lld: error: section '.vector_table' will not fit in region 'FLASH': overflowed by X bytes -//! rust-lld: error: section '.vector_table' will not fit in region 'FLASH': overflowed by Y bytes -//! (..) -//! ``` -//! -//! Solution: Specify your device memory layout in the `memory.x` linker script. See [Usage] -//! section. -//! -//! ## Didn't set a default build target and forgot to pass `--target` to Cargo -//! -//! Error message: -//! -//! ``` text -//! $ cargo build -//! (..) -//! error: language item required, but not found: `eh_personality` -//! -//! error: aborting due to previous error -//! ``` -//! -//! Solution: Set a default build target in the `.cargo/config` file (see [Usage] section), or call -//! Cargo with `--target` flag: `cargo build --target thumbv7em-none-eabi`. -//! -//! ## Overwrote the original `.cargo/config` file -//! -//! You won't get an error message but the output binary will be empty -//! -//! ``` text -//! $ cargo build && echo OK -//! OK -//! -//! $ size target/thumbv7m-none-eabi/debug/app -//! text data bss dec hex filename -//! 0 0 0 0 0 target/thumbv7m-none-eabi/debug/app -//! ``` -//! -//! Solution: You probably overwrote the original `.cargo/config` instead of appending the default -//! build target (e.g. `cat >` instead of `cat >>`). The less error prone way to fix this is to -//! remove the `.cargo` directory, clone a new copy of the template and then copy the `.cargo` -//! directory from that fresh template into your current project. Don't forget to *append* the -//! default build target to `.cargo/config`. -//! -//! ## Called OpenOCD with wrong arguments -//! -//! Error message: -//! -//! ``` text -//! $ openocd -f .. -//! (..) -//! Error: open failed -//! in procedure 'init' -//! in procedure 'ocd_bouncer' -//! ``` -//! -//! Solution: Correct the OpenOCD arguments. Check the `/usr/share/openocd/scripts` directory (exact -//! location varies per distribution / OS) for a list of scripts that can be used. -//! -//! ## Forgot to install the `rust-std` component -//! -//! Error message: -//! -//! ``` text -//! $ cargo build -//! error[E0463]: can't find crate for `core` -//! | -//! = note: the `thumbv7m-none-eabi` target may not be installed -//! ``` -//! -//! Solution: call `rustup target add thumbv7m-none-eabi` but with the name of your target -//! -//! ## Used an old nightly -//! -//! Error message: -//! -//! ``` text -//! $ cargo build -//! Compiling cortex-m-rt v0.2.0 -//! error[E0463]: can't find crate for `core` -//! | -//! = note: the `thumbv7em-none-eabihf` target may not be installed -//! -//! error: aborting due to previous error -//! ``` -//! -//! Solution: Use a more recent nightly -//! -//! ## Used the stable toolchain -//! -//! Error message: -//! -//! ``` text -//! $ cargo build -//! error[E0463]: can't find crate for `core` -//! | -//! = note: the `thumbv7em-none-eabihf` target may not be installed -//! ``` -//! -//! Solution: We are not there yet! Switch to the nightly toolchain with `rustup default nightly`. -//! -//! ## Used `gdb` instead of `arm-none-eabi-gdb` -//! -//! Error message: -//! -//! ``` text -//! $ gdb target/.. -//! Reading symbols from hello...done. -//! warning: Architecture rejected target-supplied description -//! warning: Cannot convert floating-point register value to .. -//! value has been optimized out -//! Cannot write the dashboard -//! Traceback (most recent call last): -//! File "", line 353, in render -//! File "", line 846, in lines -//! gdb.error: Frame is invalid. -//! 0x00000000 in ?? () -//! semihosting is enabled -//! Loading section .text, size 0xd88 lma 0x8000000 -//! Start address 0x8000000, load size 3464 -//! .gdbinit:6: Error in sourced command file: -//! Remote connection closed -//! ``` -//! -//! Solution: Use `arm-none-eabi-gdb target/..` -//! -//! # Used a named piped for `itm.fifo` -//! -//! Error message: -//! -//! ``` text -//! $ cargo run [--example ..] -//! -//! Reading symbols from target/thumbv7em-none-eabihf/debug/cortex-m-quickstart...done. -//! cortex_m_rt::reset_handler () -//! at $REGISTRY/cortex-m-rt-0.3.12/src/lib.rs:330 -//! 330 unsafe extern "C" fn reset_handler() -> ! { -//! semihosting is enabled -//! Ignoring packet error, continuing... -//! Ignoring packet error, continuing... -//! ``` -//! -//! Note that when you reach this point OpenOCD will become unresponsive and you'll have to kill it -//! and start a new OpenOCD process before you can invoke `cargo run` / start GDB. -//! -//! Cause: You uncommented the `monitor tpiu ..` line in `.gdbinit` and are using a named pipe to -//! receive the ITM data (i.e. you ran `mkfifo itm.fifo`). This error occurs when `itmdump -f -//! itm.fifo` (or equivalent, e.g. `cat itm.fifo`) is not running. -//! -//! Solution: Run `itmdump -f itm.fifo` (or equivalently `cat itm.fifo`) *before* invoking `cargo -//! run` / starting GDB. Note that sometimes `itmdump` will exit when the GDB session ends. In that -//! case you'll have to run `itmdump` before you start the next GDB session. -//! -//! Alternative solution: Use a plain text file instead of a named pipe. In this scenario you omit -//! the `mkfifo itm.dump` command. You can use `itmdump`'s *follow* mode (-F) to get named pipe like -//! output. - -#![no_std] - -pub mod examples; diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..23646c3 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,19 @@ +#![no_main] +#![no_std] + +extern crate cortex_m; +#[macro_use] +extern crate cortex_m_rt; + +// TODO pick a panicking behavior +// extern crate panic_abort; // requires nightly +// extern crate panic_itm; // requires ITM support +// extern crate panic_semihosting; // requires a debugger + +entry!(main); + +fn main() -> ! { + loop { + // TODO your code goes here + } +}