Aitendoで買ったこのボードにSTM32Duino Bootloaderを導入すべく苦心したまとめ。またlibmapleコア(Github mainブランチ版)で使う前提です。見よう見まねで結果オーライという部分があり、確実な動作確認も取れているわけではないのであしからず。あくまでも参考程度でお願いします。

また、僕のメインの環境はMacなので、以下はmacOSの場合の方法です。Windowsの場合は試してはいませんが参考になる情報など調べた範囲で入れておきます。Linuxの場合はMacとだいたい同じかと。またターミナル(コマンドライン)の操作に慣れている前提です。

1. はじめに

通常Bootloaderは、プリビルドのバイナリが公開されている。
https://github.com/rogerclarkmelbourne/STM32duino-bootloader/
ボードのユーザーLEDのピン番号に合わせたものをダウンロードしてくる。

今回のターゲットとなるボード回路を見ると、

ピン番号は、PC6、PC7、PD13、PD6の4つである。しかしプリビルドのもので該当するものが無い。つまり自分でBootloaderをビルドする必要がある。今回はPC6を設定することにする。

またBootloaderには強制的にDFUモードに入る機能があります。その機能をユーザースイッチに割り当てることができます。Blue PillではPC14をプルアップして電源投入すると強制DFUモードになるというアレです。Blue Pillだとリセットスイッチしか無いので割り当てできませんが、ユーザースイッチが有るなら割り当てたほうが便利です。(割り当てたこのボタンは実行モード時は通常のユーザースイッチとして利用可能です)
回路図を見てみると、


PE5、PE4、PE3、PE2がユーザースイッチ。今回はPE5にこの機能を割り当ててみます。

またUSB周りの回路(USBシリアル回路で無い方)を見てみると

こんな感じ。Blue PillとかならD+/DPが抵抗を介して直接3V3か5Vにプルアップされているんだけど、この回路はPC13で制御できるようになっている。これはこのUSBをクライアント、ホスト(OTG)の両方で使えるようにということであろう。僕としては今のところはUSBシリアルポートとして使うことしか考えていないのでクライアントで使えれば良いので、トランジスタ外して短絡するとかいう手もある。あえて今回はこの回路を活かしたまま使えるようにしてみたいと思う。結果からいうとこの設定はBootloaderだけではなく、libmapleコア側のvariant(ボードの定義)側の修正も必要です。というのもBootloaderが動作しているときはPC13がプルアップされるのだけど、実行モードではその設定は引き継がれないので、USBポートが認識されなくなります。プログラムでPC13をHIGHにセットしてやれば実行モードでプログラムが実行されればUSBポートが認識されるようになるんだけど、毎回スケッチにそれを書くのは面倒です。なのでボードの定義で対応しておくのが良さそうです。

2. bootloaderのビルド

2-1. ソースの修正

ソースの編集はテキストエディタで行いました。

GithubからBootloaderのソースを一式ダウンロードしてきます。
https://github.com/rogerclarkmelbourne/STM32duino-bootloader/
cloneしても良いし、zipでまとめて落としてきても良い。適当なフォルダ内に置きます。

編集するのは、「config.h」と「Makefile」の2つ。テキストエディタでOK。
まずは「config.h」から。以下のソースを160行目くらい(PC13の設定のブロックの後というか、#elif defined TARGET_GENERIC_F103_PG15という行の前)に追加します。

#elif defined TARGET_GENERIC_F103_PC6
    #define HAS_MAPLE_HARDWARE 1

    #define LED_BANK            GPIOC
    #define LED_PIN             6
    #define LED_ON_STATE        1

    // Button (if you have one)
    #define BUTTON_BANK GPIOE
    #define BUTTON_PIN 5
    #define BUTTON_PRESSED_STATE 0

    #define BOOTLOADER_WAIT 30

    /* USB Disc Pin Setup.   USB DISC is PC13 */
    #define USB_DISC_BANK         GPIOC
    #define USB_DISC_PIN             13

デバイスの定義なわけですが、HAS_MAPLE〜の行はひとまず飛ばしまして、LED_BANKからの3行がユーザーLEDの設定。PC6ピンは、BANKとしてはCの6番ということです。ON_STATEは、ピンの点灯がHIGH(1)なのかLOW(0)なのかの指定。今回の回路では”1″となる。

次のブロックがユーザースイッチの指定。 PE5というのはEバンクの6番ピンということです。PREESED_STATEは、スイッチが押されたときHIGH(1)なのかLOW(0)になるのかという指定。今回の回路の場合は、プルアップされててスイッチを押すとGNDに落ちるので”0″となる。

次のプロック(BOOTLOADER_WAIT)は、通常いらないようです。通常起動時DFUモードから抜けるのは数秒ですが、この指定で変えることができるようです。単位がいまいちわからないのですが、他のブロックで30としてたところがあったので30としました。通常は点滅6回でモードを抜けて、この指定だと30回かなと思うのですが…確証なし

最後のブロックがUSBのプルアップの指定。PC13ピンをセットするので、BANKはCでピンは13番ということですね。で、どうもこの指定だけではダメっぽくて、2行目の「HAS_MAPLE_HARDWARE」の指定がいるらしいのです。

次は「Makefile」の編集。拡張子がないけどテキストファイルなんでテキストエディタで編集できる。編集するのは2箇所。

【1箇所目】119行目の

generic-pc13: begin clean gccversion build_generic-pc13 sizeafter finished  copy_generic-pc13 end

という行のあとに、

generic-pc6: begin clean gccversion build_generic-pc6 sizeafter finished  copy_generic-pc6 end

を挿入します。ビルド処理の指定かしら。今回ビルドしたいgeneric-pc6のビルドでは、この順番でこの処理を行えという感じ?。どの設定も同じなんで書き換えてるだけです。

【2箇所目】元ファイルでは188行目、上の編集をした後では189行目くらいの

build_generic-pg15: TARGETFLAGS= -DTARGET_GENERIC_F103_PG15

の前に

build_generic-pc6: TARGETFLAGS= -DTARGET_GENERIC_F103_PC6
# Set the linker script
build_generic-pc6: LDFLAGS +=-T$(ST_LIB)/c_only_md_high_density.ld
build_generic-pc6: elf bin lss sym
copy_generic-pc6:
    @echo
    @echo "Copying to binaries folder"
    @echo
    cp $(TARGET).bin bootloader_only_binaries/generic_boot20_pc6.bin
    @echo

を入れます。
これは、実際のビルドの指定ですかね。これも他の同じにしています。ビルドされるファイル名は、generic_boot20_pc.binとしました。bootloader_only_binariesというフォルダに作成されます。よく考えたらボード専用なんでgenericじゃないんですよね。

2-2. ビルド

やっとビルドします。ここはターミナル(コマンドライン)での作業です。ターミナルを開いて上記のMakefileのある位置まで移動しておきます。
コンパイラはArduino IDEにインストールされているものを使います。ボードマネージャーでArduino Dueを追加すればインストールされるはず。ARM用のコンパイラインストールしてるけどという場合でGCC4.8の場合はそれが使えますが、4.9以降の場合は使えないのでArduino IDEのものを使います。Arduino IDEのコンパイラへはパスが通っていないので、一時的にパスを通します。ターミナルで

$ export PATH=$PATH:/Users/<username>/Library/Arduino15/packages/arduino/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin

と入れます。<usename>は環境に合わせて変えてください。それ以外はよほど変な設定を指定ない限りこのパスであってるハズ。ターミナルを閉じない限りこのパスは有効です。(ちなみにWinの場合はsetコマンドです。こことか参考になるも。) ただしくセットされても何も表示されないので不安ならば

$ export

としてやれば現在の設定状況が見れます。
でやっとMake(ビルド)します。ターミナルで

$ make generic-pc6

としてやれば、「bootloader_only_binaries」というフォルダの中に「generic_boot20_pc6.binbootloader」というファイルが作成される。もしエラーが出るようならソースの修正が間違っていると思うので見直すべし。

 

3. ボードの定義を追加する

既存の定義をコピーして必要なところを修正します。パスは標準的なインストール方法に従っている場合です。またターゲットはlibmapleコア(Arduino_STM32)です。Arduino IDEは終了させておきましょう。

/Users/<usename>/Documents/Arduino/hardware/Arduino_STM32/STM32F1/
以下にあるboard.txtを編集します。<username>はそれぞれのユーザー名が入ります。
これはボードの定義へのリンクやコンパイルオプション、転送方法などを定義しているファイルのようです。
board.txtの最後の行(####################)の前に以下を挿入します。テキストエディタでOK。

########################### aitendo STM32F103V ###########################

aitendoSTM32F103V.name=aitendo STM32F103V series
aitendoSTM32F103V.vid.0=0x1EAF
aitendoSTM32F103V.pid.0=0x0004
aitendoSTM32F103V.build.variant=aitendo_stm32f103v
aitendoSTM32F103V.build.vect=VECT_TAB_ADDR=0x8000000
aitendoSTM32F103V.build.core=maple
aitendoSTM32F103V.build.board=AITENDO_STM32F103V
aitendoSTM32F103V.upload.use_1200bps_touch=false
aitendoSTM32F103V.upload.file_type=bin
aitendoSTM32F103V.upload.auto_reset=true
aitendoSTM32F103V.upload.tool=maple_upload
aitendoSTM32F103V.upload.protocol=maple_dfu

aitendoSTM32F103V.build.error_led_port=GPIOE
aitendoSTM32F103V.build.error_led_pin=6

aitendoSTM32F103V.menu.device_variant.STM32F103VC=STM32F103VC
aitendoSTM32F103V.menu.device_variant.STM32F103VC.build.cpu_flags=-DMCU_STM32F103VC
aitendoSTM32F103V.menu.device_variant.STM32F103VC.upload.maximum_size=262144
aitendoSTM32F103V.menu.device_variant.STM32F103VC.upload.maximum_data_size=49152
aitendoSTM32F103V.menu.device_variant.STM32F103VC.build.ldscript=ld/stm32f103vc.ld

aitendoSTM32F103V.menu.device_variant.STM32F103VD=STM32F103VD
aitendoSTM32F103V.menu.device_variant.STM32F103VD.build.cpu_flags=-DMCU_STM32F103VD
aitendoSTM32F103V.menu.device_variant.STM32F103VD.upload.maximum_size=393216
aitendoSTM32F103V.menu.device_variant.STM32F103VD.upload.maximum_data_size=65536
aitendoSTM32F103V.menu.device_variant.STM32F103VD.build.ldscript=ld/stm32f103vd.ld

aitendoSTM32F103V.menu.device_variant.STM32F103VE=STM32F103VE
aitendoSTM32F103V.menu.device_variant.STM32F103VE.build.cpu_flags=-DMCU_STM32F103VE
aitendoSTM32F103V.menu.device_variant.STM32F103VE.upload.maximum_size=524288
aitendoSTM32F103V.menu.device_variant.STM32F103VE.upload.maximum_data_size=65536
aitendoSTM32F103V.menu.device_variant.STM32F103VE.build.ldscript=ld/stm32f103ve.ld

#---------------------------- UPLOAD METHODS ---------------------------

aitendoSTM32F103V.menu.upload_method.DFUUploadMethod=STM32duino bootloader
aitendoSTM32F103V.menu.upload_method.DFUUploadMethod.upload.protocol=maple_dfu
aitendoSTM32F103V.menu.upload_method.DFUUploadMethod.upload.tool=maple_upload
aitendoSTM32F103V.menu.upload_method.DFUUploadMethod.build.upload_flags=-DSERIAL_USB -DGENERIC_BOOTLOADER 
aitendoSTM32F103V.menu.upload_method.DFUUploadMethod.build.vect=VECT_TAB_ADDR=0x8002000
aitendoSTM32F103V.menu.upload_method.DFUUploadMethod.build.ldscript=ld/stm32f103veDFU.ld
aitendoSTM32F103V.menu.upload_method.DFUUploadMethod.upload.usbID=1EAF:0003
aitendoSTM32F103V.menu.upload_method.DFUUploadMethod.upload.altID=2

aitendoSTM32F103V.menu.upload_method.serialMethod=Serial
aitendoSTM32F103V.menu.upload_method.serialMethod.upload.protocol=maple_serial
aitendoSTM32F103V.menu.upload_method.serialMethod.upload.tool=serial_upload
aitendoSTM32F103V.menu.upload_method.serialMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG=1

aitendoSTM32F103V.menu.upload_method.STLinkMethod=STLink
aitendoSTM32F103V.menu.upload_method.STLinkMethod.upload.protocol=STLink
aitendoSTM32F103V.menu.upload_method.STLinkMethod.upload.tool=stlink_upload
aitendoSTM32F103V.menu.upload_method.STLinkMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG=1 -DSERIAL_USB -DGENERIC_BOOTLOADER

aitendoSTM32F103V.menu.upload_method.BMPMethod=BMP (Black Magic Probe)
aitendoSTM32F103V.menu.upload_method.BMPMethod.upload.protocol=gdb_bmp
aitendoSTM32F103V.menu.upload_method.BMPMethod.upload.tool=bmp_upload
aitendoSTM32F103V.menu.upload_method.BMPMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG

#-- CPU Clock frequency
aitendoSTM32F103V.menu.cpu_speed.speed_72mhz=72Mhz (Normal)
aitendoSTM32F103V.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L

aitendoSTM32F103V.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB)
aitendoSTM32F103V.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L

aitendoSTM32F103V.menu.cpu_speed.speed_128mhz=Overclocked 128Mhz NO USB SERIAL. MANUAL RESET NEEDED TO UPLOAD
aitendoSTM32F103V.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L

#-- Optimizations
aitendoSTM32F103V.menu.opt.osstd=Smallest (default)
aitendoSTM32F103V.menu.opt.osstd.build.flags.optimize=-Os
aitendoSTM32F103V.menu.opt.osstd.build.flags.ldspecs=
aitendoSTM32F103V.menu.opt.oslto=Smallest Code with LTO
aitendoSTM32F103V.menu.opt.oslto.build.flags.optimize=-Os -flto
aitendoSTM32F103V.menu.opt.oslto.build.flags.ldspecs=-flto
aitendoSTM32F103V.menu.opt.o1std=Fast (-O1)
aitendoSTM32F103V.menu.opt.o1std.build.flags.optimize=-O1
aitendoSTM32F103V.menu.opt.o1std.build.flags.ldspecs=
aitendoSTM32F103V.menu.opt.o1lto=Fast (-O1) with LTO
aitendoSTM32F103V.menu.opt.o1lto.build.flags.optimize=-O1 -flto
aitendoSTM32F103V.menu.opt.o1lto.build.flags.ldspecs=-flto
aitendoSTM32F103V.menu.opt.o2std=Faster (-O2)
aitendoSTM32F103V.menu.opt.o2std.build.flags.optimize=-O2
aitendoSTM32F103V.menu.opt.o2std.build.flags.ldspecs=
aitendoSTM32F103V.menu.opt.o2lto=Faster (-O2) with LTO
aitendoSTM32F103V.menu.opt.o2lto.build.flags.optimize=-O2 -flto
aitendoSTM32F103V.menu.opt.o2lto.build.flags.ldspecs=-flto
aitendoSTM32F103V.menu.opt.o3std=Fastest (-O3)
aitendoSTM32F103V.menu.opt.o3std.build.flags.optimize=-O3
aitendoSTM32F103V.menu.opt.o3std.build.flags.ldspecs=
aitendoSTM32F103V.menu.opt.o3lto=Fastest (-O3) with LTO
aitendoSTM32F103V.menu.opt.o3lto.build.flags.optimize=-O3 -flto
aitendoSTM32F103V.menu.opt.ogstd=Debug (-g)
aitendoSTM32F103V.menu.opt.o3lto.build.flags.ldspecs=-flto
aitendoSTM32F103V.menu.opt.ogstd.build.flags.optimize=-Og
aitendoSTM32F103V.menu.opt.ogstd.build.flags.ldspecs=

これは、generic STM32F103Vの内容のgenericをaitendoに変えただけです。これはSTM32F103VC、STM32F103VD、STM32F103VEの3種類のMCUに対応しており、今回必要なのはVEのみなのですが、面倒なのでそのままにしています。VCとVDのブロックを消せば表示されなくなると思いますが。

次に実際のボードの定義を編集します。
/Users//Documents/Arduino/hardware/Arduino_STM32/STM32F1/variants/
以下の「generic_stm32f103v」というフォルダをコピーして「aitendo_stm32f103v」とします。はそれぞれのユーザー名が入ります。
中の「board」というフォルダの中のboard.hというファイルを修正します。
35行目くらいの、

#ifndef _BOARDS_GENERIC_STM32F103V_H_
#define _BOARDS_GENERIC_STM32F103V_H_

#ifndef _BOARDS_AITENDO_STM32F103V_H_
#define _BOARDS_AITENDO_STM32F103V_H_

とします。
次に109-110行目の編集です。

#define BOARD_USB_DISC_DEV      GPIOC
#define BOARD_USB_DISC_BIT      12

#define BOARD_USB_DISC_DEV      GPIOC
#define BOARD_USB_DISC_BIT      13

とします。これがUSBのプルアップのピンの設定ですね。おそらく自動的にプログラム実行時にプルアップするという設定かと。

オプションとして、44行目からの

#define BOARD_BUTTON_PIN        PC0
#define BOARD_BUTTON_PIN2       PD12
#define BOARD_LED_PIN           PE5
#define BOARD_LED_PIN2          PE6

#define BOARD_BUTTON_PIN        PE5
#define BOARD_BUTTON_PIN2       PE4
#define BOARD_BUTTON_PIN3       PE3
#define BOARD_BUTTON_PIN4       PE2
#define BOARD_LED_PIN           PC6
#define BOARD_LED_PIN2          PC7
#define BOARD_LED_PIN3          PD13
#define BOARD_LED_PIN4          PD6

としておきましょうか。ユーザーLEDとユーザースイッチの定義です。Arduinoの標準の形式だと、LEDは、”LED_BUILTIN” です。1つ上の階層のファイル「variant.h」の14行目くらいに、

static const uint8_t LED_BUILTIN  = BOARD_LED_PIN;
static const uint8_t LED_BUILTIN2 = BOARD_LED_PIN2;
static const uint8_t LED_BUILTIN3 = BOARD_LED_PIN3;
static const uint8_t LED_BUILTIN4 = BOARD_LED_PIN4;

としておきましょう。これで標準的な書き方ができるようになります。
その他、このボード用にピンアサインを追加修正したほうが良いかもしれませんが、ひとまず今回はここまでとします。

これでBootloaderを本体に書き込んで、Arduino IDEからaitendo STM32F103Vを選べば使える用意になると思います。
bootloaderの書き込みとかはまた別記事にしたいと思います。

Share