[previous section on QEMU]: qemu.md
-``` console
+``` text
$ cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart
Project Name: app
Creating project called `app`...
Done! New project created /tmp/app
- $ cd app
+$ cd app
```
-Step number one is to set a default compilation target in `.cargo/config`.
+Step number one is to set a default compilation target in `.cargo/config.toml`.
``` console
-$ tail -n5 .cargo/config
+tail -n5 .cargo/config.toml
```
``` toml
The second step is to enter the memory region information into the `memory.x`
file.
-``` console
+``` text
$ cat memory.x
/* Linker script for the STM32F303VCT6 */
MEMORY
RAM : ORIGIN = 0x20000000, LENGTH = 40K
}
```
+> **NOTE**: If you for some reason changed the `memory.x` file after you had made
+> the first build of a specific build target, then do `cargo clean` before
+> `cargo build`, because `cargo build` may not track updates of `memory.x`.
+
+We'll start with the hello example again, but first we have to make a small
+change.
-Make sure the `debug::exit()` call is commented out or removed, it is used
-only for running in QEMU.
+In `examples/hello.rs`, make sure the `debug::exit()` call is commented out or
+removed. It is used only for running in QEMU.
-``` rust
+```rust,ignore
#[entry]
fn main() -> ! {
hprintln!("Hello, world!").unwrap();
as helpfully, pretty much all Cortex-M CPUs boot in the same fashion.
``` console
-$ cargo build --example hello
+cargo build --example hello
```
## Debugging
`openocd.cfg` file which indicates which interface file and target file to use.
``` console
-$ cat openocd.cfg
+cat openocd.cfg
```
``` text
# interfaces. At any time only one interface should be commented out.
# Revision C (newer revision)
-source [find interface/stlink-v2-1.cfg]
+source [find interface/stlink.cfg]
# Revision A and B (older revisions)
# source [find interface/stlink-v2.cfg]
> board during the [verify] section then you should modify the `openocd.cfg`
> file at this point to use `interface/stlink-v2.cfg`.
-``` console
+``` text
$ openocd
Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
On another terminal run GDB, also from the root of the template.
-``` console
-$ <gdb> -q target/thumbv7em-none-eabihf/debug/examples/hello
+``` text
+gdb-multiarch -q target/thumbv7em-none-eabihf/debug/examples/hello
```
+**NOTE**: like before you might need another version of gdb instead of `gdb-multiarch` depending
+on which one you installed in the installation chapter. This could also be
+`arm-none-eabi-gdb` or just `gdb`.
+
Next connect GDB to OpenOCD, which is waiting for a TCP connection on port 3333.
``` console
``` console
(gdb) load
Loading section .vector_table, size 0x400 lma 0x8000000
-Loading section .text, size 0x1e70 lma 0x8000400
-Loading section .rodata, size 0x61c lma 0x8002270
-Start address 0x800144e, load size 10380
-Transfer rate: 17 KB/sec, 3460 bytes/write.
+Loading section .text, size 0x1518 lma 0x8000400
+Loading section .rodata, size 0x414 lma 0x8001918
+Start address 0x08000400, load size 7468
+Transfer rate: 13 KB/sec, 2489 bytes/write.
```
The program is now loaded. This program uses semihosting so before we do any
``` console
(gdb) break main
-Breakpoint 1 at 0x8000d18: file examples/hello.rs, line 15.
+Breakpoint 1 at 0x8000490: file examples/hello.rs, line 11.
+Note: automatically using hardware breakpoints for read-only addresses.
(gdb) continue
Continuing.
-Note: automatically using hardware breakpoints for read-only addresses.
-Breakpoint 1, main () at examples/hello.rs:15
-15 let mut stdout = hio::hstdout().unwrap();
+Breakpoint 1, hello::__cortex_m_rt_main_trampoline () at examples/hello.rs:11
+11 #[entry]
```
-Advancing the program with `next` should produce the same results as before.
+> **NOTE** If GDB blocks the terminal instead of hitting the breakpoint after
+> you issue the `continue` command above, you might want to double check that
+> the memory region information in the `memory.x` file is correctly set up
+> for your device (both the starts *and* lengths).
-``` console
-(gdb) next
-16 writeln!(stdout, "Hello, world!").unwrap();
+Step into the main function with `step`.
-(gdb) next
-19 debug::exit(debug::EXIT_SUCCESS);
+``` console
+(gdb) step
+halted: PC: 0x08000496
+hello::__cortex_m_rt_main () at examples/hello.rs:13
+13 hprintln!("Hello, world!").unwrap();
```
-At this point you should see "Hello, world!" printed on the OpenOCD console,
+After advancing the program with `next` you should see "Hello, world!" printed on the OpenOCD console,
among other stuff.
``` console
$ openocd
(..)
-Info : halted: PC: 0x08000e6c
+Info : halted: PC: 0x08000502
Hello, world!
-Info : halted: PC: 0x08000d62
-Info : halted: PC: 0x08000d64
-Info : halted: PC: 0x08000d66
-Info : halted: PC: 0x08000d6a
-Info : halted: PC: 0x08000a0c
-Info : halted: PC: 0x08000d70
-Info : halted: PC: 0x08000d72
+Info : halted: PC: 0x080004ac
+Info : halted: PC: 0x080004ae
+Info : halted: PC: 0x080004b0
+Info : halted: PC: 0x080004b4
+Info : halted: PC: 0x080004b8
+Info : halted: PC: 0x080004bc
```
-
-Issuing another `next` will make the processor execute `debug::exit`. This acts
-as a breakpoint and halts the process:
-
-``` console
-(gdb) next
-
-Program received signal SIGTRAP, Trace/breakpoint trap.
-0x0800141a in __syscall ()
-```
-
-It also causes this to be printed to the OpenOCD console:
-
-``` console
-$ openocd
-(..)
-Info : halted: PC: 0x08001188
-semihosting: *** application exited ***
-Warn : target not halted
-Warn : target not halted
-target halted due to breakpoint, current mode: Thread
-xPSR: 0x21000000 pc: 0x08000d76 msp: 0x20009fc0, semihosting
-```
-
-However, the process running on the microcontroller has not terminated and you
-can resume it using `continue` or a similar command.
+The message is only displayed once as the program is about to enter the infinite loop defined in line 19: `loop {}`
You can now exit GDB using the `quit` command.
``` console
(gdb) quit
+A debugging session is active.
+
+ Inferior 1 [Remote target] will be detached.
+
+Quit anyway? (y or n)
```
Debugging now requires a few more steps so we have packed all those steps into a
-single GDB script named `openocd.gdb`.
+single GDB script named `openocd.gdb`. The file was created during the `cargo generate` step, and should work without any modifications. Let's have a peek:
``` console
-$ cat openocd.gdb
+cat openocd.gdb
```
``` text
-target remote :3333
+target extended-remote :3333
# print demangled symbols
set print asm-demangle on
stepi
```
-Now running `<gdb> -x openocd.gdb $program` will immediately connect GDB to
+Now running `<gdb> -x openocd.gdb target/thumbv7em-none-eabihf/debug/examples/hello` will immediately connect GDB to
OpenOCD, enable semihosting, load the program and start the process.
Alternatively, you can turn `<gdb> -x openocd.gdb` into a custom runner to make
`cargo run` build a program *and* start a GDB session. This runner is included
-in `.cargo/config` but it's commented out.
+in `.cargo/config.toml` but it's commented out.
``` console
-$ head -n10 .cargo/config
+head -n10 .cargo/config.toml
```
``` toml
# runner = "gdb -x openocd.gdb"
```
-``` console
+``` text
$ cargo run --example hello
(..)
Loading section .vector_table, size 0x400 lma 0x8000000