2018年10月14日日曜日

BluePill に USB 経由でプログラムを転送する

1. 概要

STM32 マイコンボードの BluePill は STM32F103C8 を搭載していて、とても安く (海外からだと200円以下で) 購入できる。

STM32 Blue Pill perspective.jpg
BluePill


ここでは、STM32duino (STM32 用の Arduino 環境) ではなく、MDK-ARM(Keil) や GCC 等の開発環境を使って C言語で書いたプログラムを BluePill に USB 経由で書き込む方法を説明する。

最初に一回 SWD (Derial Wire Debug) かシリアル通信を使って BluePill に STM32duino 用のブートローダを書き込んでおけば、それ以降は USB 経由で、コマンドライン版の DFU (Device Firmware Upgrade) ツールを使ってプログラムを書き込める。ただし、ブートローダはプログラムを 0x2000 番地から書き始めるため、ブートローダ経由で書き込みたいプログラムは、開始アドレスと割り込みベクタのオフセットを 0x0000(0x8000000) から 0x2000(0x8002000)  にしておく必要がある。

※ 手順を細かく書いていますが、要点は文中の赤字の部分のみです。

2. 準備するもの (64bit Windows 10 の場合)

 

1. ブートローダのファイルと書き込み装置


■ STM32duino 用のブートローダのコンパイル済みバイナリファイル (generic_boot20_pc13.bin)
https://github.com/rogerclarkmelbourne/STM32duino-bootloader/

※ 書き込み装置は、今回は SEGGER JLINK-LITE + J-Flash Lite v6.34g を使った。これを使わずにシリアル通信で書き込む方法もあるようだ。

2. プログラムの開発環境


■ プログラムのひな形を作成するツール: STM32CubeMX 4.27.0 (下記のページの一番下のリンクからダウンロードできる。ダウンロード時にはメールアドレスの登録が必要)。インストール後に必要なライブラリが自動でダウンロードされる。

https://www.st.com/ja/development-tools/stm32cubemx.html

■ 開発環境: MDK-ARM(Keil) Version 5.26。インストール後に必要なライブラリが自動でダウンロードされる。

http://www2.keil.com/stmicroelectronics-stm32/mdk/

※ FreeBSD 上で GCC を使って開発する方法は後述

■ OBJCOPY ツール (arm-none-eabi-objcopy.exe)
MDK-ARM(Keil) が生成した HEX ファイルを BIN ファイルに変換する際に使う。GNU Arm Embedded Toolchain に含まれている。

https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads

3. DFU ツール


■ DFU-UTIL 0.9

https://sourceforge.net/projects/dfu-util/

■ Windows 用 DFU のデバイスドライバ

https://github.com/rogerclarkmelbourne/Arduino_STM32/archive/master.zip


3. ブートローダの書き込み

BluePill に STM32duino 用のブートローダのコンパイル済みバイナリファイル (generic_boot20_pc13.bin) を書き込む。確実に書き込むには下記の手順で。 書き込み時には BluePill に USB 端子から電源を供給する必要があることにも注意。

(1) BluePill と SEGGER JLINK-LITE を接続。SWD の4ピンを接続して J-Flash Lite v6.34g を起動する。マイコンの種類は STM32F103C を選択する。
(2) BOOT0 ピンを "1" にしてリセットボタンを押す。
(3) J-Flash Lite の "Erase Chip" をクリックする。
(4) BOOT0 ピンを "0" にして J-Flash Lite のファイル選択で "generic_boot20_pc13.bin" を選択し "Program Device" をクリックする。
(5) リセットボタンを押す。

ブートローダの書き込みに成功すると、リセット直後に短時間緑色の LED が高速で点滅し、その後低速で点滅するようになる。
  

4. テスト用プログラムの作成


ボード上の緑色の LED (GPIOの PC13 に接続されている) を1秒間隔で点滅させるソフト LEDTEST.bin を作る。

(6) STM32CubeMX を起動し "New Project" でプロジェクトを新規作成する。チップの種類は "STM32F103C8" を選ぶ。ピンの PC13 をGPIO_Output にする。

STM32CubeMXで PC13 を GPIO_Output に設定する


なお、STM32CubeMX を使う時は、SYS→Debug を "Serial Wire" にして、SWD ピンを有効にしておかないと、後にデバッガが使えなくなったり、プログラムの書き込みができなくなるので注意。

STM32CubeMX では SWD ピンを有効にする


(7) "Project" → "Settings" でToolChain/IDE を "MDK-ARM V5" に変更する。"Project" → "Generate Code" を実行すると、指定したフォルダ以下に、ソースファイルのテンプレートが生成する。 

STM32CubeMXで開発環境を MDK-ARM V5(Keil) にする



(8) MDK-ARM(Keil) Version 5.26 の Keil uVision5 を起動して、(7) で生成したフォルダの中にあるプロジェクトファイルを開く。main.c の main() 関数の中に書いてある while(){} の無限ループの中に下記の2行を追加する。

HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); // LED を点滅
HAL_Delay(1000);

ここで一度 "Project" → "Build target" でビルドしておく。

(9) "Project" → "Option for Target" のリンカのオプションで、*.sct ファイルを使うようにするため、次のように指定する。

プログラムの開始アドレスの変更: "EDIT" をクリックして LEDTEST.sct ファイルを編集し、ファイル中に書かれているアドレス 0x8000000 を 0x8002000 に変更する(2カ所)。

Keil uVision5 でリンカの設定を変更



プログラムの開始アドレスの変更

割り込みベクタのオフセットの変更:"system_stm32f1xx.c" の VECT_TAB_OFFSET の定義を変更して

#define VECT_TAB_OFFSET  0x00002000U 

に書き換える。

割り込みベクタのオフセットの変更

 "Project" → "Build target" でビルドすると、HEX ファイル LEDTEST.hex が生成する。ここで生成した LEDTEST.hex を開き、アドレス (赤で囲んだ箇所) が 2000 になっていることを確認する。

※ このアドレスが 0000 になっている場合は、上記 (9) の *.sct ファイルの設定が正しく反映していないのでやり直す。

生成した HEX(Intel HEX) ファイル。赤文字の部分が 2000 になっていないといけない

(10) 下記のコマンドで HEX ファイルを BIN ファイルに変換する。
> arm-none-eabi-objcopy.exe -I ihex -O binary LEDTEST.hex LEDTEST.bin

5. DFU ツールでの書き込み


(11) DFU デバイスドライバのインストール

https://github.com/rogerclarkmelbourne/Arduino_STM32/archive/master.zip

から master.zip をダウンロードして、Arduino_STM32-master → drivers → win にある install_drivers.bat を実行すると、ドライバがインストールされる。ドライバをインストールすると、BluePill を デバイスマネージャで見たときに "Maple DFU" として表示されるようになる。

ドライバのインストール

ドライバのインストール前


ドライバのインストール後

(12) 書き込みと実行: BOOT0 ピンが "0" に設定されていることを確認する。BluePill を Windows PC に USB 接続する。リセットボタンを押し、緑色の LED が点滅している間に次のコマンドを実行すると、ファームウェアが転送される。

> dfu-util-static.exe -D LEDTEST.bin -a 2



※ dfu-util-static.exe には 32bit 版と 64bit 版がある。OS に合った方を実行しないと書き込めない。
※ "Error sending completion packet" と表示されるが、これで正常に転送されている。

書き込み直後にリセットボタンを押すと、正常に書き込まれていれば、書き込んだプログラムが起動して LED が 1秒間隔で点滅する(明らかに1秒以下の間隔で点滅していたり、つきっぱなし、消えっぱなしになった場合は失敗)。次回以降は、リセット後に2秒間ファームウェアの転送を待ち、その後にプログラムが実行される。

6. FreeBSD + GCC で開発する場合


Windows 版の MDK-ARM(Keil uVision5) の代わりに、FreeBSD 上で GCC を使って開発することもできる。

(13) FreeBSD に次のパッケージをインストールする
■ gcc-arm-embedded-7.3.20180627
■ dfu-util-0.9

(14) 上記 (6) (7) の手順でプログラムのひな形を作成する。(7) で STM32CubeMX で "Project" → "Settings" で ToolChain/IDE を "Makefile" にすると、GCC 用のひな形を生成できる。

(15) プログラムの開始アドレスの変更: Makefile と同じディレクトリにある STM32F103C8Tx_FLASH.ld の、次の赤文字の箇所を書き換える。

/* Specify the memory areas */
MEMORY
{
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx)      : ORIGIN = 0x8002000, LENGTH = 128K
}

(16) 割り込みベクタのオフセットの変更: Src/system_stm32f1xx.c 中の VECT_TAB_OFFSET の定義を次のように変更する。

/* #define VECT_TAB_SRAM */
#define VECT_TAB_OFFSET  0x00002000U

(17)  Src/main.c の main() 内に (8) に書いた LED を点滅させるための 2行を加える。
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); // LED を点滅
HAL_Delay(1000);
(18) make コマンドを実行するとコンパイルされ、 build/LEDTEST.bin が生成する。
(19) リセットボタンを押し、緑色の LED が点滅している間に、次のコマンドで BluePill に書き込む。
# dfu-util -D build/LEDTEST.bin -a 2