라즈베리 파이 재단이 출시한 4$ MCU인 Pico를 구입했다. 하드웨어 디버깅을 하기에 마땅한 장비가 없어서, 가지고 있던 라즈베리 파이 3을 이용해보기로 했다. 최대한 미니멀한 환경을 원했기 때문에 예전과 같이 Buildroot을 사용하여 구성하였다.

시작하기 전에

Buildroot에 관한 초기 세팅은 여기를 참고하자. 이 포스트는 최신 안정 버전인 Buildroot 2021.11.x 버전을 기준으로 하여 작성되었다.

Buildroot 환경 구성

Defconfig: Raspberry Pi 3 (64-bit)

make raspberrypi3_64_defconfig

Toolchain

Toolchain type에서 External toolchain, Toolchain에서 Arm AArch64 2021.07을 선택했다. Buildroot toolchain을 써도 큰 문제는 없겠지만 컴파일 시간을 줄이기 위해 pre-built ARM 툴체인을 사용한다.

System configuration

  • /dev management: devtmpfs + mdev. 장치 추가를 자동으로 해 주니 편해진다.
  • Root password: 적절히 설정해준다.
  • Install timezone info: 활성화하고 기본 시간대를 Asia/Seoul로 설정해줬다.
  • Root filesystem overlay directories: 파일시스템 오버레이가 필요하면 넣는다. (내 경우에는 /etc/network/interfacessshd_config를 이걸로 설정했다.)

Kernel

Defconfig에서 추가로 건드릴 사항 없었다.

Target Packages

위의 Pi Zero Headless 셋업에서 추가한 패키지와 더불어, Hardware Handling -> openocd 패키지를 추가하고 두 어댑터를 추가해야 한다.

  • bitbanging on BCM2835
  • programming via sysfs gpios

문제는 위의 bitbanging on BCM2837BR2_arm config가 활성화되어 있을 때만 사용 가능하고, 이는 BR2_aarch64와 별개이기 때문에 64비트 라즈베리 파이 3 시스템에서는 보이지 않는다. 이를 위해 다음과 같은 패치를 임시로 적용하였다.

diff --git a/package/openocd/Config.in b/package/openocd/Config.in
index b14f940b27..bdc6794123 100644
--- a/package/openocd/Config.in
+++ b/package/openocd/Config.in
@@ -190,13 +190,17 @@ config BR2_PACKAGE_OPENOCD_AT91RM
        help
          Enable building support for AT91RM9200 based SBCs

+endif # BR2_arm
+
+if (BR2_arm || BR2_aarch64)
+
 config BR2_PACKAGE_OPENOCD_BCM2835
        bool "bitbanging on BCM2835"
        help
          Enable building support for bitbanging on BCM2835
          (as found in Raspberry Pi)

-endif # BR2_arm
+endif # BR2_arm || BR2_aarch64

 config BR2_PACKAGE_OPENOCD_GW16012
        bool "Gateworks GW16012 JTAG Programmer"

(사용 방법: 해당 파일을 Buildroot 최상단 디렉토리에 openocd.patch라는 이름으로 저장해두고, patch -p1 < openocd.patch로 적용한다.)

다시 명시하지만 이 패치는 Buildroot 2021.11.x 기준으로 작성되었기 때문에 추후 버전에서는 conflict가 발생할 수도 있다.

추가로, RP2040 타겟을 위해 라즈베리 파이 재단이 OpenOCD를 포크하여 관련 드라이버를 구현한 것으로 보인다. Buildroot가 다운로드하는 OpenOCD에는 이것이 반영되어 있지 않으므로 해당 포크의 base version인 0.11.0과 포크 버전의 diff를 만들어서 패키지 패치 목록에 추가하였다. 패치 내역이 기므로 Github Gist로 갈음한다. https://gist.github.com/cr0sh/1920833b7b7ecd40f3c605f49dd32c84

해당 파일을 package/openocd/ 안에 동일한 파일명으로 집어넣으면 알아서 빌드 시에 패치가 적용된다.

(사실 정공법은 openocd.mk를 수정해서 소스 tarball을 다운로드받는 경로를 수정하는 것이었겠지만, 귀찮아서 이런 방식으로 우회했다. 앞으로 OpenOCD 버전이 0.11.0 위로 업그레이드되면 이 diff가 깨질 확률이 높으므로 알아서 수정 바람)

빌드

make

이후 output/images/sdcard.img를 플래싱한다.

OpenOCD 핀 세팅

Pico의 SWD 핀을 라즈베리 파이의 GPIO 핀에 연결해야 한다. (Pico와 파이 모두 전원을 뽑고 진행해야 한다. 안 그럼 오작동한다고 한다.) SWD 핀은 피코의 전원 플러그와 정반대에 위치해 있고, pre-soldered version을 구매해도 납땜이 되지 않은 상태로 오기 때문에 따로 납땜해야 한다.

  • 나는 납땜기가 없어서 Pimoroni사의 GPIO Hammer Header를 가위로 잘라서 꽂았다. (핀 수가 적기 때문에 망치질을 하지 않고 가위 끝 등으로 힘을 적당히 주면 하나씩 들어간다. 너무 많이 들어가면 반대방향으로 핀이 빠지므로 힘조절에 주의)

핀 연결은 다음과 같다.

Pico Pi
SWDIO GPIO24
SWDGND GND
SWDCLK GPIO25

세 핀의 순서가 양 기기에서 똑같기 때문에 점퍼선을 많이 조각내도 되지 않아서 좋았다. 다 염두에 두고 핀을 구성한건가?

OpenOCD 시작

이제 파이를 켜고, 루트 쉘에 접속해서(시리얼, SSH 등…) 다음과 같이 입력한다.

# openocd -f interface/raspberrypi-swd.cfg -f target/rp2040.cfg -c 'bindto 0.0.0.0'
Open On-Chip Debugger 0.11.0
Licensed under GNU GPL v2
For bug reports, read
	http://openocd.org/doc/doxygen/bugs.html
adapter speed: 1000 kHz

Info : Hardware thread awareness created
Info : Hardware thread awareness created
Info : RP2040 Flash Bank Command
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : BCM2835 GPIO JTAG/SWD bitbang driver
Info : clock speed 1001 kHz
Info : SWD DPIDR 0x0bc12477
Info : SWD DLPIDR 0x00000001
Info : SWD DPIDR 0x0bc12477
Info : SWD DLPIDR 0x10000001
Info : rp2040.core0: hardware has 4 breakpoints, 2 watchpoints
Info : rp2040.core1: hardware has 4 breakpoints, 2 watchpoints
Info : starting gdb server for rp2040.core0 on 3333
Info : Listening on port 3333 for gdb connections
Info : accepting 'gdb' connection on tcp/3333

-c 'bindto 0.0.0.0'은 파이 외부에서 GDB 서버에 접속하기 위해 필요하다(기본적으로 localhost에 바인드되어 외부에서 접근할 수 없다). OpenOCD가 정상적으로 실행되었고 SWD 인터페이스와의 연결도 잘 이루어졌음을 확인할 수 있다.

Info : Read incorrect DLIPDR 00000000 (possibly CTRL/STAT value) when selecting coreid 0
Info : DAP init failed


Info : Read incorrect DLIPDR 00000000 (possibly CTRL/STAT value) when selecting coreid 0

이런 오류가 발생하고 중지된다면 아마 핀 연결이 잘못되었거나 Pico의 전원을 넣어야 동작하는 것일 수도 있다.

arm-none-eabi GCC 툴체인 설치

https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads 여기서 호스트 시스템에 맞게 최신 버전을 설치한다.

샘플 프로젝트 빌드 & GDB remote target 연결

cargo install flip-link
cargo install probe-run
rustup target add thumbv6m-none-eabi
git clone https://github.com/rp-rs/rp2040-project-template && cd rp2040-project-template

cargo build --release
arm-none-eabi-gdb target/thumbv6m-none-eabi/release/rp2040-project-template

GDB가 열리면 target remote <address to pi>:3333 으로 연결 후 load 명령으로 로드한다. 이후 일반적인 GDB처럼 사용할 수 있다.

Happy hacking!

References