Open10

Rust + nRF52 で自作キーボードファームウェアを作ろうとしている履歴

🐰🐰

買ったもの

ISP1807搭載Microボード(Pro Microピン互換)

  • https://www.switch-science.com/catalog/6939/
  • ISP1807 (nRF52840 パッケージ) が動作する Pro Micro とピン配置に互換性のあるボード
  • ブートローダは UF2 が入ってる
    • 最新が0.6.3なのに対し、やたらとバージョンが低い。またSoftDeviceは7系じゃなく6系。
UF2 Bootloader 0.3.2-114-gb5fab63-dirty lib/nrfx (v2.0.0) lib/tinyusb (0.6.0-272-g4e6aa0d8) lib/uf2 (remotes/origin/configupdate-9-gadbb8c7)
Model: ISP1807 Micro Board
Board-ID: ISP1807 Micro Board Rev.A
SoftDevice: S140 version 6.1.1
Date: Feb 15 2021

nRF52840 MDK USB Dongle

澤田と和解せよボード

  • 下記でSWDに苦しんでたら見かねたフォロワーさんが設計したものを安く譲っていただけた
  • AE-LPC11U35-MB (DAPLink役) と MS88SF2(nRF52840パッケージ)がSWDで繋がるよう実装されている。
  • 電源は3.3Vではなく5V(VDDH)を使うようになっている。
  • ブートローダは UF2 の BOARD=pca10056 互換との事なので自分で S140 v7.2.0 とあわせてビルドして使用。
🐰🐰

ブートローダーってなに

  • マイコンが起動したら真っ先に呼び出されるやつ
    • メインプログラムを起動したり
    • メインプログラムを書き込めるようにしたり
  • ボードだとこれだけは書き込まれて出荷されることが多い
    • まっさらな状態からブートローダーを書き込むのは大変
    • ブートローダーの提供する書き込み機能でブートローダー自体も更新可能
      • ブートローダーが破損するとまっさらな状態と変わらなくなるので修理は大変
      • SWD(後述)などを使ってブートローダを復旧することは可能
  • nRF52の場合、ブートローダーは主に2種類

Open Bootloader (nordic公式のもの)

  • nRF connect をはじめとしたアプリとの連携機能
    • USB-CDC
    • ホストと通信するデバイスとして認識される

UF2 Bootloader (adafruitのもの)

(ブートローダを使用しない)

  • 実はブートローダは必須ではない
  • USBからの書き込みをやめ、SWDで書くことにしてしまえばブートローダの機能はいらない
  • 起動したら直接メインプログラムを起動するだけ
🐰🐰

SoftDevice ってなに

🐰🐰

Rust から BLE を使う

C から nRF で BLE を扱う、つまり SoftDevice を使用するには一般的に Nordic SDK を使用するが、Rust にはその用意がない。
Rust からのアクセスは SoftDevice へのバインディングである nrf-softdevice を使うか、あるいはいくつかの方法がある。

nrf-softdevice

https://github.com/embassy-rs/nrf-softdevice

  • SoftDevice のバインディング
  • Embassy (Embedded Rust 向けの非同期ライブラリ) の一部として提供される
    • 現在開発中。crate.io からでなく github から拾ってくる必要がある
  • SoftDevice 7.x 系が必要

rubble

https://github.com/jonas-schievink/rubble

  • いちからRustで実装されたBLEスタック
  • SoftDevice を使用しない
  • 認証を通していないので 技適NG

CのプロジェクトからRustを呼ぶ

  • Nordic SDK を使用する C プロジェクトを記載し、グルーコードを実装した上で Rust アプリを呼ぶ
  • 一部で C を必要とする
  • 一番現実的だが一番つまんない

ということで、今回は nrf-softdevice を使用することにした。

🐰🐰

nrf-softdevice を使うための準備 (SWD環境作成、ブートローダ更新)

まずは examples の ble_bas_peripheral を走らせることを目指す。

ブートローダの更新および SoftDevice S140 の v7.x 化

まずは Adafruit のブートローダをビルドする。澤田と和解しろボードを使うので、BOARD=pca10056 とした。他のボードを使用する場合は適宜変更する必要がある。また存在しない場合はボード定義を書く必要がある。ここらへんはまだよくわかっていない。

$ git clone https://github.com/adafruit/Adafruit_nRF52_Bootloader
$ cd Adafruit_nRF52_Bootloader                        
$ git submodule update --init
$ make BOARD=pca10056 SD_VERSION=7.2.0

ここで作られた _build/build-pca10056/pca10056_bootloader-0.6.3-48-gcc8ea2b_s140_7.2.0.hex を焼く必要がある。

SWDを使ってブートローダを焼く

ブートローダを焼くには SWD での書き込みが必要となる。J-Linkの書き込み器とか持ってればそれに越したことはないんだろうけど、そんな金はないので安く済む書き込み器を求めて秋月の AE-LPC11U35-MB に行きついた。

以下記事などを参考にDAPLinkファーム焼いて結線してみる。

具体的には

  1. DAPLinkのreleases から v0254 ( 0254_release_package_f499eb6e.zip ) をダウンロード
  2. 展開して、 0254_lpc11u35_mtb_laird_bl654_0x0000.bin を AE-LPC11U35-MB に書き込み
  3. 以下の通り配線
ピン AE-LPC11U35-MB ISP1807 micro
GND 1: GND SWD-4: GND
3V3 29: +3.3V SWD-1: 3.3V
SWCLK 5:0_9 SWD-2: SWDI
SWDIO 4:0_8 SWD-3: SWDC
  1. AE-LPC11U35-MB 側のUSBポートをPCと接続
    • nRF52側のUSBポートではない

Segger Embedded Studio から書き込む

最初に知ったのがこの方法。

Segger Embedded Studio for ARM をインストールし、 Target → Connect J-Link から接続、Erase All で全消去して Download file → Download Intel Hex File からブートローダの *.hex ファイルを焼く。

うまくいったら Disconnect し、nRF52 側の USBポートをPCと接続すると USB メモリのように外部ボリュームとしてマウントできるようになる。
マウントしたあと INFO_UF2.txt を開くとブートローダの構成情報が確認できる。

probe-rs-cli を使う

Segger でもいいんだけど、GUI を毎回使うのはめんどくさい。ということで CLI から使えるものを探して probe-rs-cli をみつけた。cargo で probe-rs-cli をインストールして使用する。た

$ probe-rs-cli erase --chip nrf52840
$ probe-rs-cli download --chip nrf52840 --format hex /path/to/***.hex
saotosaoto

大変参考にさせていただきました。ありがとうございます。
一つご質問があります。
AE-LPC11U35-MBのピン配においてSWCLKを0_9ピンとされていますが、DAPLinkのソースを見ると0_7のように見えます。0_9でよろしかったでしょうか?

🐰🐰

probe-run を使う

https://github.com/knurling-rs/probe-run

$ sudo apt install -y libusb-1.0-0-dev libudev-dev
$ cargo install --version 0.2.0 -f probe-run
  • ターゲットボードと SWD で接続した probe をにUSB 接続して操作する
  • 実際の通信部分は probe-rs

probe-rs を使う

https://probe.rs/

SWDが必要。

秋月のLPC11U35マイコンボードキット が格安ながら DAPLINK という SWD での書き込み器になるとの噂を聞いたのでそれを試してみる。

SWDと戦う

ここらへんでTwitterではSWDを澤田と呼びはじめ「澤田と和解せよ」とかいうネタが流行りはじめていた。

それはさておき以下記事などを参考にファーム焼いて結線などしてみた。

具体的には

  1. DAPLinkのreleases から v0254 ( 0254_release_package_f499eb6e.zip ) をダウンロード
  2. 展開して、 0254_lpc11u35_mtb_laird_bl654_0x0000.bin を AE-LPC11U35-MB に書き込み
  3. 以下の通り配線
ピン AE-LPC11U35-MB ISP1807 micro
GND 1: GND SWD-4: GND
3V3 29: +3.3V SWD-1: 3.3V
SWCLK 5:0_9 SWD-2: SWDI
SWDIO 4:0_8 SWD-3: SWDC
  1. nrf-softdevice の example を cargo run
$ vi memory.x
FLASH : ORIGIN = 0x00026000 と書き換える。(SoftDevice6.1.1を使用するため。7系を使うなら修正不要)
$ cargo run --bin ble_bas_peripheral
:
Error: An error with the usage of the probe occured

Caused by:
    Didn't receive any answer during batch processing: [Read(DebugPort, 0)]

あれ・・・

$ cargo run --bin ble_bas_peripheral
:
Error: no probe was found

結線の接点不良?LPC11U35ハズレボード掴んだ?いろいろ努力してみたがちょっとよくわかんなかったので一旦あきらめ。

uf2conv を使う

cargo run するには probe-run が必要だが、cargo build したバイナリを uf2 ファイルに変換してしまえば Adafruit ブートローダの MSD 機能によってUSBつないでマウントしてコピペするだけでバイナリ自体は焼ける。

ということで変換ツールを含むリポジトリを clone しておく。

https://github.com/microsoft/uf2

$  cd nrf-softdevice/example
$ vi memory.x
FLASH : ORIGIN = 0x00026000 と書き換える。(SoftDevice6.1.1を使用するため。7系を使うなら修正不要)
$  cargo build --bin ble_bas_peripheral
$  arm-none-eabi-objcopy -Oihex ../target/thumbv7em-none-eabihf/debug/ble_bas_peripheral ble_bas_peripheral.hex
$  python3 path/to/uf2conv.py ble_bas_peripheral.hex -c -b 0x26000 -f 0xADA52840
$  cp flash.uf2 /media/illness072/NRF52BOOT/

適当なBluetooth スキャンアプリなどで見てみると HelloRust というデバイスが見つかる。

🐰🐰

memo: あとで整理する

env

rustup update
rustup install nightly
rustup component add llvm-tools-preview
rustup target add thumbv7em-none-eabihf --toolchain nightly
cargo install cargo-binutils
sudo apt install -y pkg-config libusb-1.0-0-dev libudev-dev
cargo install probe-run
DEFMT_LOG=info cargo run --bin ble_bas_peripheral

Linux

$ cat  50-daplink.rules
# 0d28:0204 DAPLink
SUBSYSTEM=="usb", ATTR{idVendor}=="0d28", ATTR{idProduct}=="0204", MODE:="666"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", MODE="0664", GROUP="plugdev"
$ sudo mv 50-daplink.rules /etc/udev/rules.d/
$ sudo udevadm control --reload
$ sudo udevadm trigger