Skip to content

Instantly share code, notes, and snippets.

@nmenon
Last active August 17, 2023 11:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nmenon/ff7d8d9d0a2ddaad6bd01902fe25f660 to your computer and use it in GitHub Desktop.
Save nmenon/ff7d8d9d0a2ddaad6bd01902fe25f660 to your computer and use it in GitHub Desktop.
Rust baremetal code on beagleplay / AM62x M4F

Objectives

  • Focus on M4F on AM625.
  • Entirely done on target board: BeaglePlay, NO HOST TOOLS ALLOWED :)
  • Basic Hello world
  • Loads with remoteproc
  • Loads with self hosted openocd
  • Integrate with vscode to allow self hosted development and debug and reload

⚠️ Beagleplay: These steps require decent amount of disk space, which you might find the onboard emmc lacking.. I used a 64GB sdcard entirely formatted as ext4fs as my workarea for this development. Helps extend emmc further to my needs

  • Chapter 1: Watch the debug in action

Rust references:

Hardware references:

Installation of basic tools

Relatively fast - gets you cargo and rust basics.

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

fast step - install toolchain for M4F

rustup target add thumbv7em-none-eabihf

cargo generate - this step takes a bunch of time.

cargo install cargo-generate

Additional stuff

cargo install cargo-binutils
rustup component add llvm-tools-preview

The Project

Initializing the default project:

cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart
Appname: meapp

Building the default app

Follow instructions from https://github.com/rust-embedded/cortex-m-quickstart

cd meapp

Modify cargo/config.toml to point to the correct platform

vim cargo/config.toml and update to use:

[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)
# target = "thumbv8m.base-none-eabi"   # Cortex-M23
# target = "thumbv8m.main-none-eabi"   # Cortex-M33 (no FPU)
# target = "thumbv8m.main-none-eabihf" # Cortex-M33 (with FPU)

Modify memory.x to point to the correct memory map

Lets next modify the memory map to point to the AM62x memory map for M4f. As per (AM62 TRM)[https://www.ti.com/lit/pdf/spruiv7] (see Table 2-4 MCU M4F memory map view)

  • 0x0 is MCU M4F Instruction RAM
  • 0x3000_0000 MCU M4F's Data RAM.

we really dont have on-board flash, so it is a bit easy to kinda map things this way.

  • DDR memory map actually should be parsed from devicetree, but for the moment, lets hack it. this memory is'nt visible till we map things with RAT (Region Address Translation) module used to map SoC memory map back to M4F's view - think of it as a poor man's MMU - kinda..

⚠️ We have'nt yet added resource table - so remote proc still has'nt understood how to load this image.. we can tackle that problem next after we have "something" working..

cat memory.x 
MEMORY
{
  /* NOTE 1 K = 1 KiBi = 1024 bytes */
  /* FLASH : ORIGIN = 0x00000000, LENGTH = 256K */
  FLASH : ORIGIN = 0x00000000, LENGTH = 192K
  RAM : ORIGIN = 0x30000000, LENGTH = 64K
  DDR_MEM_REG : ORIGIN = 0x9cb00000, LENGTH = 1M
  DDR_DMA_MEM_REG : ORIGIN = 0x9cc00000, LENGTH = 13M
}

Build

cargo build

Modifying for enabling debug:

Modify openocd.gdb

Nothing special about the changes here -> Port maps to 3339 (more on this later).

target extended-remote :3339

All this does it to help gdb connect to the correct port that openOCD opens up. Full openocd.gdb:

target extended-remote :3339

# 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
# # 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

load

# start the process but immediately halt the processor
stepi

Modify .cargo/config.toml

Now we teach Cargo how to use openocd properly when we do cargo run. -> main thing here is:

 runner = "gdb-multiarch -q -x openocd.gdb"

Full .cargo/config.toml:

[target.thumbv7m-none-eabi]
# uncomment this to make `cargo run` execute programs on QEMU
# runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"

[target.'cfg(all(target_arch = "arm", target_os = "none"))']
# uncomment ONE of these three option to make `cargo run` start a GDB session
# which option to pick depends on your system
# runner = "arm-none-eabi-gdb -q -x openocd.gdb"
runner = "gdb-multiarch -q -x openocd.gdb"
# runner = "gdb -q -x openocd.gdb"

Building openocd

Installing package dependencies for building openocd

sudo apt-get install libhidapi-dev libtool libusb-1.0-0-dev

Build openocd

cd
git clone https://github.com/nmenon/openocd
cd openocd
./bootstrap
./configure --enable-dmem
make -j8

Run openOCD

  • dmem interface uses root access to get to the memory map to control M4F directly.. hence the sudo..
cd ~/openocd/tcl
sudo ../src/openocd -f ./board/ti_am625_swd_native.cfg 
[sudo] password for debian: 
Open On-Chip Debugger 0.12.0-rc1+dev-02505-g4abd25327 (2023-03-22-01:02)
Licensed under GNU GPL v2
For bug reports, read
	http://openocd.org/doc/doxygen/bugs.html
Info : only one transport option; autoselect 'dapdirect_swd'
adapter speed: 2500 kHz

Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : clock speed 2500 kHz
Info : starting gdb server for am625.cpu.sysctrl on 3333
Info : Listening on port 3333 for gdb connections
Info : starting gdb server for am625.cpu.a53.0 on 3334
Info : Listening on port 3334 for gdb connections
Info : starting gdb server for am625.cpu.a53.1 on 3335
Info : Listening on port 3335 for gdb connections
Info : starting gdb server for am625.cpu.a53.2 on 3336
Info : Listening on port 3336 for gdb connections
Info : starting gdb server for am625.cpu.a53.3 on 3337
Info : Listening on port 3337 for gdb connections
Info : starting gdb server for am625.cpu.main0_r5.0 on 3338
Info : Listening on port 3338 for gdb connections
Info : starting gdb server for am625.cpu.gp_mcu on 3339
Info : Listening on port 3339 for gdb connections
Info : accepting 'gdb' connection on tcp/3339

Connecting with cargo

cargo run
cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.16s
     Running `gdb-multiarch -q -x openocd.gdb target/thumbv7em-none-eabihf/debug/meapp`
Reading symbols from target/thumbv7em-none-eabihf/debug/meapp...
0x00000402 in cortex_m_rt::Reset ()
    at /home/debian/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.15/src/lib.rs:497
497	pub unsafe extern "C" fn Reset() -> ! {
Breakpoint 1 at 0x480: file /home/debian/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.15/src/lib.rs, line 570.
Breakpoint 2 at 0x7d6: file /home/debian/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.15/src/lib.rs, line 560.
Breakpoint 3 at 0x66a: file /home/debian/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-halt-0.2.0/src/lib.rs, line 32.
Breakpoint 4 at 0x454: file src/main.rs, line 13.
semihosting is enabled
Loading section .vector_table, size 0x400 lma 0x0
Loading section .text, size 0x3e8 lma 0x400
Loading section .rodata, size 0x228 lma 0x7e8
Start address 0x00000400, load size 2576
Transfer rate: 2515 KB/sec, 858 bytes/write.
0x00000402	497	pub unsafe extern "C" fn Reset() -> ! {
(gdb) info breakpoints
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x00000480 in cortex_m_rt::DefaultHandler_ 
                                           at /home/debian/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.15/src/lib.rs:570
2       breakpoint     keep y   0x000007d6 in cortex_m_rt::HardFault_ 
                                           at /home/debian/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.15/src/lib.rs:560
3       breakpoint     keep y   0x0000066a in panic_halt::panic 
                                           at /home/debian/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-halt-0.2.0/src/lib.rs:32
4       breakpoint     keep y   0x00000454 in meapp::__cortex_m_rt_main_trampoline 
                                           at src/main.rs:13
(gdb) 

Getting "fancy" with gdb dashboard

sudo python3 -m pip install pygments
wget -P ~ https://git.io/.gdbinit
cargo run
~
 0x00000400  cortex_m_rt::Reset+0  push	{r7, lr}
 0x00000402  cortex_m_rt::Reset+2  mov	r7, sp
 0x00000404  cortex_m_rt::Reset+4  bl	0x492 <cortex_m_rt::DefaultPreInit>
 0x00000408  cortex_m_rt::Reset+8  movw	r0, #0
 0x0000040c  cortex_m_rt::Reset+12 movt	r0, #12288	; 0x3000
 0x00000410  cortex_m_rt::Reset+16 movw	r1, #0
 0x00000414  cortex_m_rt::Reset+20 movt	r1, #12288	; 0x3000
─── Breakpoints ─────────────────────────────────────────────────────────────────────
[1] break at 0x00000480 in /home/debian/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.15/src/lib.rs:570 for DefaultHandler
[2] break at 0x000007d6 in /home/debian/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.15/src/lib.rs:560 for HardFault
[3] break at 0x0000066a in /home/debian/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-halt-0.2.0/src/lib.rs:32 for rust_begin_unwind
[4] break at 0x00000454 in src/main.rs:13 for main
─── Expressions ─────────────────────────────────────────────────────────────────────
─── History ─────────────────────────────────────────────────────────────────────────
─── Memory ──────────────────────────────────────────────────────────────────────────
─── Registers ───────────────────────────────────────────────────────────────────────
       r0 0xffffffff        r1 0x00000000         r2 0x0007a121       r3 0x00000000
       r4 0xa5a5a5a5        r5 0x0003e8fc         r6 0x0003e8f8       r7 0x00039fd0
       r8 0xe000ed04        r9 0x10000000        r10 0x0003b1b0      r11 0xa5a5a5a5
      r12 0x0003da87        sp 0x00039fd0         lr 0x00008d31       pc 0x00000404
     xPSR 0x81000000     fpscr 0x00000000        msp 0x00014e80      psp 0x00039fd0
  primask 0x00         basepri 0x00        faultmask 0x00        control 0x02      
─── Source ──────────────────────────────────────────────────────────────────────────
 513  
 514          // This symbol will be provided by the user via `#[pre_init]`
 515          fn __pre_init();
 516      }
 517  
 518      __pre_init();
 519  
 520      // Initialize RAM
 521      r0::zero_bss(&mut __sbss, &mut __ebss);
 522      r0::init_data(&mut __sdata, &mut __edata, &__sidata);
─── Stack ───────────────────────────────────────────────────────────────────────────
[0] from 0x00000404 in cortex_m_rt::Reset+4 at /home/debian/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.15/src/lib.rs:518
─── Threads ─────────────────────────────────────────────────────────────────────────
[1] id 0 from 0x00000404 in cortex_m_rt::Reset+4 at /home/debian/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.15/src/lib.rs:518
─── Variables ───────────────────────────────────────────────────────────────────────
─────────────────────────────────────────────────────────────────────────────────────
>>> 

Next Steps

  • Fix up resource_table for remoteproc load
  • integrate build and debug with vscode..
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment