STM32G4 GCCとIARのコンパイラによるビルド時間の比較(2)
前回の確認でSin関数の速度を確認してみたが、 今度は重い三角関数でかつよくセンサの処理などで利用するatan2の速度を確認してみたいと思う。
IARの三角関数のライブラリは最適化がよく聞いてそうだ。
では、ライブラリは高速だが、コードからコンパイルしたものはあんまり早くないとかあるかなって思って
にあったfast_atan2を拝借してfloat版にして実行してみた。
関数は各1000回実行した速度を測定している、※()内部の時間
なぜか、GCCのほうは 最初の500msecのチェックの時間がずれていてsin関数の時間が長くなってしまっている。 ここら辺は何が起こっているのかはわからないが、意図したとおりに動作してくれているIARはうれしい。
IAR : === check 500msec : 500851.00usec (500.85msec) sin : 0.60usec (0.60msec) cmsis sin : 0.40usec (0.40msec) error : 0.000325 atan2 : 0.70usec (0.70msec) fast atan2 : 0.39usec (0.39msec) error : 0.003900 GCC : === check 500msec : 250854.00usec (250.85msec) sin : 25.62usec (25.62msec) cmsis sin : 0.39usec (0.39msec) error : 0.000325 atan2 : 1.41usec (1.41msec) fast atan2 : 0.40usec (0.40msec) error : 0.003880
仕事で利用しているのだが、IARのatan2fが非常に高速なのには助かっている。 以前も仕事中にatan2f使うと重いかな~、、って思ってベンチマークしたんだが、 atan2f律速じゃないことを確認してそのまま利用することができたのでライブラリの速度は勝手に信頼していた。
どうやら、この実行結果だけを確認するとマイコンのコードを書くのにはIARの環境のほうが優秀な印象を受ける。(結構な値段するしだし当たり前か?)
とするとある条件でなぜGCCのほうが高速なプログラムを生成できたのか次に調べてみよう。
確認したプログラムは下記のとおり
STM32G4 GCCとIARのコンパイラによるビルド時間の比較(1)
あるプログラムをGCCで作成していたのだが、IARで同じコードをコンパイルして実行してみたら18usecで完了していた処理が23usecもかかってしまうようになった。
かってにIARのほうが有償だし、ARM用のコンパイラなのでGCCと比べて効率的にコンパイルしてくれるものだと思っていたので30%ぐらい遅くなっていたので少しびっくりしてしまった。
本当は使ったことがないMDK-ARMも比較しようと思ったのだが、なんか評価用ライセンスが、営業さん経由?じゃないともらえないみたいなのでやめてしまった。
一体GCCとIARのコンパイル後のバイナリの実行速度はどのぐらいになるのか比較していこうと思う。
比較環境
IAR
- version 9.10.2
- gcc-arm-none-eabi-9-2020-q2
start = get_usec(); for (size_t i = 0; i < buff_size; i++) { rslt_buff[i] = sinf(m_pi); } output_elapse("sin", start, buff_size);
1000回しての平均をとってみたら、実行してみたら。
IAR = 0.48usec
GCC = 0.04usec
さすがに何かがおかしい気がしたのでちょっと確認してみる。
引数に渡しているm_piという変数が毎回一緒なのでGCCのほうは最初っからコンパイルずみの数値をrslt_buffに突っ込んでいるのではないか?とおもって、 Sinに渡す引数をRNGをつかって数値を実行時に作って、計算前にバッファにためておいた引数を利用するように変更した。
start = get_usec(); for (size_t i = 0; i < buff_size; i++) { rslt_buff[i] = sinf(ix_buff[i]); } output_elapse("sin", start, buff_size);
IAR = 0.36usec
GCC = 0.46usec
なぜか、IARのほうがはやくなったしまったが、それっぽい結果になったNanoLibのSinよりもIAR同梱のSinのほうが最適化されているのでは?という当初の予想通りに結果になった。
ちなみにCMSISの高速なSin関数は どちらも 0.33usec だった。
とりあえず、実行環境ができたので、今日はここまで。
STM32G4 の開発環境構築 デバック環境
stm32g4 nucleoがdegikeyから届いたのでデバッグ環境を構築。
OPENOCDのビルド
配布されているOPENOCDはSTM32G4とSTLINK-V3がたいおうしていなかったので
github.com の対応版をダウンロードして自分でビルドすることにした。
適当なディレクトリ(自分は~/download内)に移動して
git clone https://github.com/mjbots/openocd.git cd openocd ./bootstrap export CFLAGS="-Wno-error" export CXXFLAGS="-Wno-error" ./configure make -j8 sudo make install
でinstall完了。
export CFLAGS="-Wno-error"と
export CXXFLAGS="-Wno-error"
はglibcのバージョンが新しいとsrc/helper/options.c内で#include <sys/sysctl.h>がdeprecatedのwarningをはいてビルドできなかったのでつけました。
udevの設定
下記のリンク先を参考に
tomoyuki-nakabayashi.github.io
stm32g4 nucleoを接続して
lsusb
してみると
Bus 001 Device 005: ID 0483:374e STMicroelectronics STLINK-V3
と出てきましたので、/etc/udev/rule.d/に60-openocd.cfgを作成して
# STMicroelectronics STLINK-V3 ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374d", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374e", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374f", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3753", MODE="660", GROUP="plugdev", TAG+="uaccess"
と記入。
sudo udevadm control --reload-rules
nucleoボードを一度抜き刺しして、パーミッションを確認。
ls -l /dev/bus/usb/001/005 # usb/から先は先程lsusbで確認した番号を入力 crwxrwxrwx+ 1 root root 189, 4 6月 13 15:15 /dev/bus/usb/001/005
パーミッションも設定できたので,これでst-linkを利用可能なはず。
VSCODEの設定
vscodeにプラグイン「Cortex-debug」をインストールする。
launch.jsonの編集
{ // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "Cortex Debug", "cwd": "${workspaceRoot}", "executable": "build/(プログラム名).elf", "request": "launch", "type": "cortex-debug", "servertype": "openocd", "configFiles": [ "interface/stlink.cfg", "target/stm32g4x.cfg" ], "preLaunchTask": "build" } ] }
# debug build? DEBUG = 1
にすれば設定は完了。
stm32g4 の開発環境構築 Linux編
先日Windows版の環境を作ったばっかりだが、デバッグに使うOPENOCDがG4対応していなくて自前でビルドしなくては行けないという情報を得てやっぱり自前でビルドするとなるとLinuxでやったほうがいいなと思ってLinux上に開発環境を構築することとした。
基本的な構築は前回の omonting.hatenablog.com とほとんどおなじなので同じ部分は割愛する。
必要なソフトウェア
GNU Arm Embedded Toolchain
GNU Arm Embedded toolchain は展開したフォルダを\opt内に配置
パスを通す
zshを使っているので、~/.zshrcの一番下に
export PATH="/opt/gc-arm-none-eabi-9-2020-q2-update/bin:$PATH"
を記載。
c_cpp_properties.json
下記に変更
"compilerPath": "/opt/gc-arm-none-eabi-9-2020-q2-update/bin/arm-none-eabi-g++",
Makefileの編集
今回のプロジェクトは基本C++で書こうと思っている。
CubeMXの吐き出したMakefileとソースコードはCソースコード吐き出しでMakefileもそのようになっていたので、C++もコンパルできるように修正。
ファイル名を
main.c => main.cpp
stm32g4xx_it.c => stm32g4xx_it.cpp
に変更。
# debug build? DEBUG = 0 # optimization OPT = -O3
に変更、MCUのファーム開発は僕は最適化効かせてdebug中に必要な箇所のみ一時的に最適化をきってdebugしている。
C_SOURCES 内からmain.cとstm32g4xx_it.cを削除 書きを追記
# CPP sources CXX_SOURCES = \ Src/main.cpp \ Src/stm32g4xx_it.cpp
cppのコンパイラを定義
CXX = $(GCC_PATH)/$(PREFIX)g++
CFLAGSの下に書きを追記
CXXFLAGS = $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections -isystem -std=c++17
ほかはCFLAGSと同様に処理しておく。
ビルド設定の部分を下記のように書き換え
####################################### # build the application ####################################### # list of objects OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o))) vpath %.c $(sort $(dir $(C_SOURCES))) OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(CXX_SOURCES:.cpp=.o))) #追記 vpath %.cpp $(sort $(dir $(CXX_SOURCES))) #追記 # list of ASM program objects OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.s=.o))) vpath %.s $(sort $(dir $(ASM_SOURCES))) $(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR) $(CXX) -c $(CXXFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@ # CC->CXXに変更 $(BUILD_DIR)/%.o: %.cpp Makefile | $(BUILD_DIR) #追記 $(CXX) -c $(CXXFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.cpp=.lst)) $< -o $@ #追記 $(BUILD_DIR)/%.o: %.s Makefile | $(BUILD_DIR) $(AS) -c $(CFLAGS) $< -o $@ $(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile $(CXX) $(OBJECTS) $(LDFLAGS) -o $@ #CC->CXXに変更 $(SZ) $@ $(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR) $(HEX) $< $@ $(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR) $(BIN) $< $@ $(BUILD_DIR): mkdir $@
以上で完了。
STM32G4のビルド環境構築
普段は仕事でIAR workbenchを利用しているんですが、ちょっと家でもなんか作ってみようかなと思ったので、ビルド環境を整えてみました。
昔STM32F1の環境を利用していた時とは周辺環境が変わってきたので最初から再設定。
環境
昔利用していた環境はmacだったのですが、今の環境はwindows10 64bitです。
必要なソフトウェア
Visual studio code
azure.microsoft.com
昔はeclipse使ったりしていたのですが、エディタは今はこれです。
IAR利用しているときもdebug以外はこれでやっています。
STから提供されているcube-ideという全部いりのIDEもあるんですが、IDEはなんか重くて好きくないのでvscodeを利用していきます。
プラグインには下記を利用しています。
C/C++ for Visual Studio Code
debugにも別のプラグイン入れようと思っていますが、今回はビルド環境のみ。
GNU Arm Embedded Toolchain
developer.arm.com
コンパイラはGNU-ARMeclipse IARと違ってC++17にちゃんと対応しているのがとてもいいです。(IARはC++17対応とおもって飛びついたら標準ライブラリは未対応だったので悲しかった。)
STM32 CubeMx
https://www.st.com/ja/development-tools/stm32cubemx.html
マイコンの基本設定などはCubeMXを使っています。めちゃくちゃ便利で大好きですがある場所が設定できなかったりバグってたりしてたまにトラブりますが、それを加味しても好きだ。アップデートがあったらバグがつぶれていることを期待して必ず更新しています。
ビルドシステムにはmakeじゃなくてmesonというビルドシステムがあるみたいでlinux環境で使ってみてなかなかわかりやすかったので使ってみたかったが windwosでcrossでちゃんと動かす方法がわからなかったのでとりあえずcube-mxで出てくるmakefileを利用しようと思う。 ただ、cube-mxで編集後に吐き出したmakefileを都度編集するのがなんだかなって思ったのでそのうち使えるようにしてみたい。
make
www.msys2.org
makeを使えるようにmsys2をインストール後msys2を起動して
pacman -S mingw-w64-x86_64-make
でインストール。
環境変数の設定
環境変数のPATHに さっき落としてきたGNU Arm Embedded Toolchainを展開した中のbinフォルダを指定。
私はCドライブ直下にtoolsというフォルダを作って展開したので、
C:\tools\gcc-arm-none-eabi-9-2020-q2-update-win32\bin
makeを呼べるために
msysのpathを追加
C:\msys64\mingw64\bin
VSCodeでビルドできる環境の作成
CubeMxでProject Manager->Projectタブ内のToolChain/IDEをmakefileに設定してコード生成。
ワークスペースファイルの作成。
ディレクトリ内にvscodeのワークスペースファイルを作成。 stm32g474.code-workspace
{ "folders": [ { "name": "プロジェクト名", "path": "./" } ], "settings": { "window.zoomLevel": 0, "C_Cpp.clang_format_fallbackStyle": "google", "editor.formatOnSave": true }, "extensions": {} }
task.jsonの設定
{ // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format "version": "2.0.0", "tasks": [ { "label": "build", "type": "shell", "command": "mingw32-make all", "args": [], "group": "build", // Use the standard MS compiler pattern to detect errors, warnings and infos "problemMatcher": { "base": "$g++", "fileLocation": [ "relative", "${workspaceRoot}/build" ] } }, { "label": "clean", "type": "shell", "command": "mingw32-make clean", "args": [], "group": "build", // Use the standard MS compiler pattern to detect errors, warnings and infos "problemMatcher": { "base": "$g++", "fileLocation": [ "relative", "${workspaceRoot}/build" ] } } ] }
補完がきいてエディタでエラーが出ないように設定。
下記のようにc_cpp_properties.jsonを作成。
{ "configurations": [ { "name": "Win32", "includePath": [ "${workspaceFolder}/**", "${workspaceFolder}/Inc/**", "${workspaceFolder}/Drivers/CMSIS/Core/include/**", "${workspaceFolder}/Drivers/CMSIS/Device/ST/STM32G4xx/include**", "${workspaceFolder}/Drivers/CMSIS/include**", "${workspaceFolder}/Drivers/STM32G4xx_HAL_Driver/inc**" ], "defines": [ "_DEBUG", "UNICODE", "_UNICODE", "USE_FULL_LL_DRIVER", # ここから下はcubemxで作成されたmakefileからコピーしてきた。 "HSE_VALUE=24000000", "HSE_STARTUP_TIMEOUT=100", "LSE_STARTUP_TIMEOUT=5000", "LSE_VALUE=32768", "EXTERNAL_CLOCK_VALUE=12288000", "HSI_VALUE=16000000", "LSI_VALUE=32000", "VDD_VALUE=3300", "PREFETCH_ENABLE=0", "INSTRUCTION_CACHE_ENABLE=1", "DATA_CACHE_ENABLE=1", "STM32G474xx" ], "windowsSdkVersion": "10.0.17763.0", "compilerPath": "C:\\tools/gcc-arm-none-eabi-9-2020-q2-update-win32/bin/arm-none-eabi-g++.exe", "cStandard": "c11", "cppStandard": "c++17", "intelliSenseMode": "gcc-x64" } ], "version": 4 }
以上の設定が完了したら。 ctrl+shift+bでビルド候補が出てくるのでbuildを選べばbuild完了。