この記事の目的

Amazonにて123円(2017/03/16現在)で販売されているSTM32F103C8T6開発ボードを買ってみました。が、簡単には動かなかったので動かすまでの道のりを記録しました。一度理解すれば簡単です。

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

書き換え方法を探る

USB

STM32duino化が済めば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モードの関係は、他の同チップ開発ボード(例えば秋月で売ってるボード)と同じとすれば、参考資料から推測するに以下の通り。
(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ポートと同時に繋ぐとたぶんショートすると思います(これも試してません&調べてません)。

IMG_20170316_024755.jpg

で、この状態でFlash Loader Demonstratorを使おうとした結果が以下の通り。

Flash Loader Demonstrator  2017_03_16 2_18_25.png

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

COM3 - Tera Term VT 2017_03_16 2_58_20.png

AN2606
によれば0x7Fが送られてくるはずなのかな?どうもこのアプリは0x7F以外の値を受け取ると先ほどのスクリーンショットのようなエラーを出すらしい、という書き込みを海外でちらほら見かけました。ちょっとボードの不具合が不安になり始めます。

SWD

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

STM32 ST-LINK Utility 2017_03_16 3_11_11.png

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

ST-Link Upgrade 2017_03_16 3_11_45.png

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

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

Ugly boardはこの辺の回路図を見ると

Pin Desc.
7 JTMS
9 JTCK
4 GND

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

IMG_20170316_032428.jpg

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

STM32 ST-LINK Utility 2017_03_16 3_31_35.png

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

STM32 ST-LINK Utility 2017_03_16 3_25_22.png

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

STM32 ST-LINK Utility 2017_03_16 3_39_56.png

STM32 ST-LINK Utility 2017_03_16 3_40_13.png

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

JTAG

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

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

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

/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に関しては

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
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。設定ファイルは<install prefix>/share/openocd/scriptsにて確認できます。

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のリポジトリにあるマニュアルを参照。

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を繋げて試しました。ピン番号はシンボルが使えましたが、もし問題あった場合には回路図を参考にピン番号を指定すると良いかと思います。

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