LC Technology STM32F103C8T6 開発ボードを使うまで

# この記事の目的
Amazonにて123円（2017/03/16現在）で販売されている[STM32F103C8T6開発ボード](https://www.amazon.co.jp/gp/product/B010RYH970/)を買ってみました。が、簡単には動かなかったので動かすまでの道のりを記録しました。一度理解すれば簡単です。

ちなみに[STM32duinoのwiki](http://wiki.stm32duino.com/index.php?title=STM32F103_boards)によれば、こいつの通称はUgly board（やっかいなボード）で、注釈で「買うな」と書いてあります。やー、買う前にそこまで調べないよー（汗。もう少し詳しく見ると、ロットによって半田がブリッジしてたり浮いてたりといった事があるようです。油断できませんね。

# 書き換え方法を探る
## USB
[STM32duino](http://wiki.stm32duino.com/)化が済めばUSB経由で書き込みできるようです。が、初期状態では特に凝ったファームウェア（ブートローダ）が入っておらず、USBは刺しても反応ありません。なので、まずは面倒でもファームを書き換える方法を探すことにします。

## UART（シリアル）
ラストリゾートかつ最も簡単な方法がUARTによる書き換えなのですが、ブートモードを切り替えるBOOT0/BOOT1のジャンパーが、あるにはあるのですがピンの極性がわかりません。基板上にはノーヒント。まぁ、たかだか4パタンなので全部試したのですが、~~どうも外側のピンが1、内側のピンが0みたいです。購入時はどちらも1側にブリッジされていました。~~

（2017/04/04追記）後ほどCPUのマニュアルを眺めていたら、システムメモリからの起動はCPU出荷時に焼かれたROMからで、UART/SWD/JTAG等からのブートが必ずサポートされているような事が書かれており、不審に思って再度確かめてみました。どうやら極性について勘違いしていたようです。__外側が0、内側が1__のようです。購入時は0側にジャンパーが刺さっているので、BOOT0を差し替えることでシステムメモリからの起動となり、UARTからの書き換えが可能となりました。

ちなみにジャンパーとBOOTモードの関係は、他の同チップ開発ボード（例えば[秋月で売ってるボード](http://akizukidenshi.com/catalog/g/gK-05819/)）と同じとすれば、参考資料から推測するに以下の通り。
（2017/04/04追記）AN2606に記載されている内容がBOOT0とnBOOT1となっていて紛らわしいのですが、nBOOT1はBOOT1の負論理のようです。という解釈の元で判断すると、以下の表は正しく、確認できた動作とも一致しています。

| BOOT0 | BOOT1 | BOOTモード             |
|-------|-------|------------------------|
| 0     | *     | ユーザーフラッシュメモリ |
| 1     | 0     | システムメモリ          |
| 1     | 1     | SRAM起動               |

という事で、少しわかりにくいですが設定は以下の写真のようになりました。USBは給電用。シリアルからはTX/RXをクロスで繋いだうえにGNDも繋いでます。同じUSBポートから分岐してればたいていGNDは共通なので繋げなくても動くんですが、今回は駄目だったので安定化措置。電源は繋ぎません。
（2017/04/04追記）ボード側のUSBポートを接続していなければ、UART用に出ている5Vを含めた4線でシリアルに繋げても大丈夫です。5Vを繋ぐ代わりに3.3Vを別のピンヘッダに出てる3V3に繋いでも大丈夫。5Vピンに3.3Vとかは試していません。USBポートと同時に繋ぐとたぶんショートすると思います（これも試してません＆調べてません）。

![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f31323834332f33323038653636642d613663362d666261332d653261302d3334643139623533633938332e6a706567.jpeg](https://qiita-image-store.s3.amazonaws.com/0/12843/51bd5e6c-8b4e-c16a-04b7-9472bcc8105b.jpeg)

~~で、この状態で[Flash Loader Demonstrator](http://www.st.com/content/st_com/en/products/development-tools/software-development-tools/stm32-software-development-tools/stm32-programmers/flasher-stm32.html)を使おうとした結果が以下の通り。~~

![Flash Loader Demonstrator  2017_03_16 2_18_25.png](https://qiita-image-store.s3.amazonaws.com/0/12843/7e7bf6a2-81b9-969a-4d5d-fd442e48adbe.png)

~~確認のためTeraTermから繋いでみたら、以下のような化けたデータが送られてきているようです。~~

![COM3 - Tera Term VT 2017_03_16 2_58_20.png](https://qiita-image-store.s3.amazonaws.com/0/12843/cd15d084-5cd7-4098-b948-54b90137e5d7.png)
~~[
AN2606](http://www.st.com/content/ccc/resource/technical/document/application_note/b9/9b/16/3a/12/1e/40/0c/CD00167594.pdf/files/CD00167594.pdf/jcr:content/translations/en.CD00167594.pdf)によれば0x7Fが送られてくるはずなのかな？どうもこのアプリは0x7F以外の値を受け取ると先ほどのスクリーンショットのようなエラーを出すらしい、という書き込みを海外でちらほら見かけました。ちょっとボードの不具合が不安になり始めます。~~

## SWD
幸い我が家には「備えあれば患いなし」という事で、一家に一台「STM32VL Discovery」が探せば出てきますので、これを使う事にします。まずは4ピンのヘッダに刺さっている2つのジャンパーを外して、SWDピンを使った外部デバイスの書き換え・デバッグを有効にします。この段階で[ST-Link Utility](http://www.st.com/ja/embedded-software/stsw-link004.html)を起動して設定を見ると

![STM32 ST-LINK Utility 2017_03_16 3_11_11.png](https://qiita-image-store.s3.amazonaws.com/0/12843/39445987-f086-af9c-ad7d-46e47f8d155b.png)

とりあえず認識はするものの、さすがは積まれていたデバイス。ファームウェアが古いと怒られてます。が、アップデートしようとすると

![ST-Link Upgrade 2017_03_16 3_11_45.png](https://qiita-image-store.s3.amazonaws.com/0/12843/6f168a4a-df23-27c1-6134-c11f7be4af4e.png)

うぐぅ。どうやら配布中のソフトで更新できないくらい古いファームウェアみたいです。いちいちサポートに連絡して対応を待ってもいられないので、無視して進めてみます。Discovery側のSWDのピンは上から順に

| Pin | Desc. |
|-----|-------|
| 0   | N/A   |
| 1   | SWCLK |
| 2   | GND   |
| 3   | SWDIO |

Ugly boardは[この辺](http://wiki.stm32duino.com/index.php?title=Ugly_board)の回路図を見ると

| Pin | Desc. |
|-----|-------|
| 7   | JTMS  |
| 9   | JTCK  |
| 4   | GND   |

となっているので、JTMS <=> SWDIO / JTCK <=> SWCLK / GND <=> GND あたりを繋いでみます。

![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f31323834332f66666461663435652d363064642d643932362d303834332d6632666330636666306538642e6a706567.jpeg](https://qiita-image-store.s3.amazonaws.com/0/12843/c3051f5c-1a65-1126-e9c2-db1b11fb1c9a.jpeg)

これでもう一度設定からデバイスの情報を取得すると……

![STM32 ST-LINK Utility 2017_03_16 3_31_35.png](https://qiita-image-store.s3.amazonaws.com/0/12843/16afdbbf-45a4-d431-bdbb-6c96c51232c9.png)

デバイスは認識してくれました。このままOKを押すと

![STM32 ST-LINK Utility 2017_03_16 3_25_22.png](https://qiita-image-store.s3.amazonaws.com/0/12843/d4363281-e58c-4fcd-cb3f-d13673560879.png)

メモリは読めてるようで一安心。このままProgram & Verifyで先ほどのSTM32duino wikiのUgly board用Bootloaderを書き込むと……

![STM32 ST-LINK Utility 2017_03_16 3_39_56.png](https://qiita-image-store.s3.amazonaws.com/0/12843/0611b958-a618-7597-b76a-f6b5ba9db902.png)

![STM32 ST-LINK Utility 2017_03_16 3_40_13.png](https://qiita-image-store.s3.amazonaws.com/0/12843/9784abf3-0ef2-aa12-ed2b-8a070c06e59a.png)

無事書き込めました。ジャンパーの位置を初期位置に戻してリセットをかけると、今度は無事にUSBデバイスとして認識、Maple 003という名前で見えるようになりました。

## JTAG
（追記：2017/04/05）残るJTAGについて少し試してみたのでメモ。基本的には書き込み目的じゃなくてデバッグ目的のテスト（むしろ入手したJTAGアダプタの動作確認としてやった）。

使ったJTAGアダプタは1000円ちょっとで手に入るAltera USB Blaster互換のJTAGアダプタ。openocdがUSB Blaster（互換機）経由でのARMのJTAGデバッグをサポートしているようなので、まずはこのボードで試してみた。おそらくメーカー等の制約なしで使えるARMのJTAGデバッグ環境としては最安値の類い？

一般ユーザから実行するためにudevの設定を入れておくと便利です。

```text:/etc/udev/rules.d/51-usb-blaster.rules
SUBSYSTEM=="usb", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6001", MODE="0666"
```

Ugly board側のJTAG接続で必要となるピン配置は以下の通り。

| Pin | Desc. |   | Pin | Desc. |
|-----|-------|---|-----|-------|
| 1   | 3V3   |   | 2   | 3V3   |
| 3   | -     |   | 4   | GND   |
| 5   | JTDI  |   | 6   | GND   |
| 7   | JTMS  |   | 8   | GND   |
| 9   | JTCK  |   | 10  | GND   |
| 11  | -     |   | 12  | GND   |
| 13  | JTDO  |   | 14  | GND   |
| 15  | -     |   | 16  | GND   |
| 17  | -     |   | 18  | GND   |
| 19  | -     |   | 20  | GND   |

USB Blaster側は以下の通り。

| Pin | Desc. |   | Pin | Desc. |
|-----|-------|---|-----|-------|
| 1   | JTCK  |   | 2   | GND   |
| 3   | JTDO  |   | 4   | VCC   |
| 5   | JTMS  |   | 6   | -     |
| 7   | -     |   | 8   | -     |
| 9   | JTDI  |   | 10  | GND   |

同じ名前のピンはどれを繋いでもOK。電源は供給するための線じゃなくてバッファ用のリファレンスなので、ターゲットは別途電源に繋いである必要があります。接続不要なピンは省略して「-」と表記してありますが、かならずしも未使用ピンというわけではありません。

openocdに関しては

```shell-session:build
% sudo apt-get install libftdi-dev
% git clone git://git.code.sf.net/p/openocd/code openocd
% cd openocd
% ./bootstrap
% ./configure --prefix=$HOME/opt --enable-usb-blaster
% make
% make install
```

```shell-session:server
% openocd -f interface/altera-usb-blaster.cfg -f target/stm32f1x.cfg
Open On-Chip Debugger 0.10.0+dev-00094-g2804480 (2017-04-05-00:41)
Licensed under GNU GPL v2
For bug reports, read
	http://openocd.org/doc/doxygen/bugs.html
Warn : Adapter driver 'usb_blaster' did not declare which transports it allows; assuming legacy JTAG-only
Info : only one transport option; autoselect 'jtag'
adapter speed: 1000 kHz
adapter_nsrst_delay: 100
jtag_ntrst_delay: 100
none separate
cortex_m reset_config sysresetreq
Info : No lowlevel driver configured, will try them all
Info : usb blaster interface using libftdi
Info : This adapter doesn't support configurable speed
Info : JTAG tap: stm32f1x.cpu tap/device found: 0x3ba00477 (mfg: 0x23b (ARM Ltd.), part: 0xba00, ver: 0x3)
Info : JTAG tap: stm32f1x.bs tap/device found: 0x16410041 (mfg: 0x020 (STMicroelectronics), part: 0x6410, ver: 0x1)
Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints
```

1つめに読ませてる設定がUSB Blasterを使うための設定、2つめがSTM32F1xxxをターゲットにするための設定。catで繋げて1つのファイルにしておいて読ませてもOK。設定ファイルは&lt;install prefix&gt;/share/openocd/scriptsにて確認できます。

```shell-session:client
% telnet localhost 4444
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> reg
===== arm v7m registers
(0) r0 (/32)
(1) r1 (/32)
(2) r2 (/32)
(3) r3 (/32)
(4) r4 (/32)
(5) r5 (/32)
(6) r6 (/32)
(7) r7 (/32)
(8) r8 (/32)
(9) r9 (/32)
(10) r10 (/32)
(11) r11 (/32)
(12) r12 (/32)
(13) sp (/32)
(14) lr (/32)
(15) pc (/32)
(16) xPSR (/32)
(17) msp (/32)
(18) psp (/32)
(19) primask (/1)
(20) basepri (/8)
(21) faultmask (/1)
(22) control (/2)
===== Cortex-M DWT registers
(23) dwt_ctrl (/32)
(24) dwt_cyccnt (/32)
(25) dwt_0_comp (/32)
(26) dwt_0_mask (/4)
(27) dwt_0_function (/32)
(28) dwt_1_comp (/32)
(29) dwt_1_mask (/4)
(30) dwt_1_function (/32)
(31) dwt_2_comp (/32)
(32) dwt_2_mask (/4)
(33) dwt_2_function (/32)
(34) dwt_3_comp (/32)
(35) dwt_3_mask (/4)
(36) dwt_3_function (/32)
> exit
```

システムメモリ起動の状態で接続しました。stm32duinoが起動していると接続できません。おそらく起動直後にJTAGデバッグを無効化してる、または必要な有効化手続きを踏んでいないか。STM32はまだ突っ込んでコード書いてないので詳しくは知りません。

# Arduinoで使ってみる
## 基本方針
Arduino_STM32を使うことにします。インストール方法はGitHubのリポジトリにある[マニュアル](https://github.com/rogerclarkmelbourne/Arduino_STM32/wiki/Installation)を参照。

## Arduinoの準備
マニュアルによればVersion 1.6.9以上が必要なようです。ボードマネージャからArduino SAM Boards (32-bits ARM Cortex-M3)ってやつをインストールしておけば良いみたいです。この辺はオフィシャルドキュメントが古くなっているみたいなので注意。

またドキュメントからArduino_STM32を持ってきて手動でインストールします。インストール後にIDEを再起動しないとメニューに出てこないかも。

## dfu-util（macOSの場合）
書き込みにdfu-utilというCUIが必要となり、一応配布データにバイナリが含まれてはいるのですが……依存するlibusb-1.0.0.dylibが含まれておらず、その辺りは自力で対処する必要があります。

ドキュメントによれば以前はHomebrewでインストールする必要があった、との事なので、素直にHomebrewを取ってきてbrew install libusbしました。

## 設定
| 項目 | 設定 |
|------|------|
| ボード | Generic STM32F103C series |
| Variant | STN32F103CB (20k RAM, 128k Flash) |
| CPU Speed(MHz) | 72Mhz (Normal) |
| Upload method | STM32duino bootloader |
| シリアルポート | /dev/cu.usbmodem146211 (Maple Mini) |

シリアルポートとして現る名前はOSや環境によって変わるかと思いますが、Mapleをキーワードに選べば良いかと思います。

## スケッチ
とりあえずサンプルのBlinkを転送・実行します。LEDについては自由につかえる物がボード上にないので、PA0を指定して外部にLEDを繋げて試しました。ピン番号はシンボルが使えましたが、もし問題あった場合には[回路図](http://www.sunspot.co.uk/Projects/Arduino/STM32/MINI-STM32-Schematic-Diagram.pdf)を参考にピン番号を指定すると良いかと思います。

転送後は実行のためにリセットボタンを押す必要がありました。これはちょっと面倒。