🌻

GDBをつかって、microbitのレジスタへ値を書き込む

2021/01/03に公開

はじめに

GDBを使ってレジスタの読み書きを行い、microbitのLEDの点灯をしてみます。
使用するmicrobitはV1.5です。

利用するコード

いきなりすべてのレジスタをgdbを使って設定するのはさすがに面倒なので
1個のレジスタの読み書きだけをしてみます。
丁度いいコードがどこかないか探してみたところ、
以下のようなものがありましたので、こちらを利用します。

https://github.com/dwelch67/microbit

上記の
https://github.com/dwelch67/microbit/tree/master/blinker01
を利用します。これはLEDのひとつを点滅させるだけの単純なものです。

Debug用に修正

Makefileを以下のように修正します。
-g -O0を付け、makeを実行します。そうすると
notmain.elfが作成されます。

diff --git a/blinker01/Makefile b/blinker01/Makefile
index 404cb37..26611c6 100644
--- a/blinker01/Makefile
+++ b/blinker01/Makefile
@@ -2,8 +2,8 @@
 ARMGNU = arm-none-eabi
 #ARMGNU = arm-linux-gnueabi
 
-AOPS = --warn --fatal-warnings -mcpu=cortex-m0
-COPS = -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding  -mcpu=cortex-m0
+AOPS = -g --warn --fatal-warnings -mcpu=cortex-m0
+COPS = -Wall -Werror -g -O0 -nostdlib -nostartfiles -ffreestanding  -mcpu=cortex-m0

pyocd-gdbserverの起動

microbitをPCに接続し pyocd-gdbserverを起動します。

$ pyocd-gdbserver -t nrf51 -bh -r
0000988:WARNING:gdb_server:pyocd-gdbserver is deprecated; please use the new combined pyocd tool.
0001102:INFO:board:Target type is nrf51
0001356:INFO:dap:DP IDR = 0x0bb11477 (v1 MINDP rev0)
0001906:INFO:ap:AHB-AP#0 IDR = 0x04770021 (AHB-AP var2 rev0)
0002092:INFO:rom_table:AHB-AP#0 Class 0x1 ROM table #0 @ 0xf0000000 (designer=244 part=001)
0002110:INFO:rom_table:[0]<e00ff000:ROM class=1 designer=43b part=471>
0002111:INFO:rom_table:  AHB-AP#0 Class 0x1 ROM table #1 @ 0xe00ff000 (designer=43b part=471)
0002142:INFO:rom_table:  [0]<e000e000:SCS-M0+ class=14 designer=43b part=008>
0002159:INFO:rom_table:  [1]<e0001000:DWT-M0+ class=14 designer=43b part=00a>
0002170:INFO:rom_table:  [2]<e0002000:BPU class=14 designer=43b part=00b>
0002180:INFO:rom_table:[1]<f0002000:MTB-M0 class=9 designer=43b part=9a3 devtype=13 archid=0000 devid=0:0:0>
0002186:INFO:cortex_m:CPU core #0 is Cortex-M0 r0p0
0002196:INFO:dwt:2 hardware watchpoints
0002201:INFO:fpb:4 hardware breakpoints, 0 literal comparators
0002225:INFO:server:Semihost server started on port 4444 (core 0)
0002241:INFO:gdbserver:GDB server started on port 3333 (core 0)

gdbの起動

pyocd-gdbserverを起動した terminal画面とは別の画面を起動し、そこから
arm-none-eabi-gdbを起動します。

$ arm-none-eabi-gdb
GNU gdb (GNU Arm Embedded Toolchain 10-2020-q4-major) 10.1.90.20201028-git
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
<省略>
(gdb) 

起動後、gdb serverに接続しnomain.elfをloadします。

(gdb) target remote localhost:3333
Remote debugging using localhost:3333
warning: No executable has been specified and target does not support
determining executable automatically.  Try using the "file" command.
0x000000b6 in ?? ()
(gdb) file notmain.elf 
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
Reading symbols from notmain.elf...
(gdb) load notmain.elf 
Loading section .text, size 0xdc lma 0x0
Start address 0x00000000, load size 220
Transfer rate: 450 bytes/sec, 220 bytes/write.
(gdb) 

tuiを使用

必須では無いですが、TUI(Text User Interface)モードというものがあるので(最近知った)、
こちらを利用して、コード、レジスタ情報を1画面に表示します。

(gdb) tui enable
(gdb) tui new-layout example {-horizontal src 1 asm 1 regs 1} 2 status 0 cmd 1
(gdb) layout example 
(gdb) focus cmd 

上記コマンドで、以下のように表示されます。

詳しくは以下。
https://sourceware.org/gdb/download/onlinedocs/gdb/TUI.html#TUI

LED点灯直前の処理まで処理をすすめる。

以下のようにして、
LED点灯直前まで処理を進めます。

(gdb) b notmain.c:33
Breakpoint 1 at 0xa0: file notmain.c, line 33.
Note: automatically using hardware breakpoints for read-only addresses.
(gdb) c
Continuing.

Breakpoint 1, notmain () at notmain.c:33
(gdb) s
PUT32 () at flash.s:38

画面は以下のようになります。

現在、以下の命令のところで停止しています。

str r1,[r0]

レジスタR0とR1の値はそれぞれ以下のようになっています

r0             0x50000508
r1             0x2000

アドレス、0x50000508に0x2000を書いているようです。
gdbのsetコマンドで設定をしてみます。

(gdb) set *((int *) 0x50000508) = 0x2000
Cannot access memory at address 0x50000508

出来ないよ、とメッセージが出てしまいました。
調べると同じような症状で困っている人がいました。

https://answers.launchpad.net/gcc-arm-embedded/+question/232090

gdbのドキュメントでは以下に記載がありました。

https://sourceware.org/gdb/download/onlinedocs/gdb/Memory-Region-Attributes.html#Memory-Access-Checking

set mem inaccessible-by-default offを入力してから
setコマンドを入力してみます。

(gdb) set mem inaccessible-by-default off
(gdb) set *((int *) 0x50000508) = 0x2000
(gdb) 

先程の、Cannot access memory at ...は表示されず
LEDが点灯しました。

参考

レジスタの情報については以下を参照

https://infocenter.nordicsemi.com/topic/struct_nrf51/struct/nrf51_refmanual.html

Discussion