STM32をVSCode & PlatformIO (C++) で開発する

STM32CubeIDEでよくない?

この点はどのMCUメーカー謹製IDEにも言えることなんですが、何よりエディタが使いづらくないですか? まあオプションの設定など細かいところで便利に思うことも多いのですが、その機能の大半は触らないんですよね。 VSCodeとか知っている身からすればコード補完してくれなかったりとコーディング中の不満点のほうが多いわけです。

そこで今回はVSCode上でSTM32の開発をC++でできるように環境構築をしてみました。

結論から言うと、この環境めちゃくちゃ快適です。

(記事の誤り等ありましたら一報いただけると幸いです。)

下準備

環境

VSCode拡張でPlatformIOをインストールしておきましょう。

stm32pioのインストール

CubeMXで生成されたプロジェクトをPlatformIOで扱えるように変換してくれるスクリプトです。 ソースコード - github

ターミナルを開いてpipでstm32pioをインストールします。

$ pip install stm32pio

platformioのインストール

stm32pioでファイルをPlatformIOの形式に変換する際にPlatformIOを呼び出す関係でインストールされている必要があります。

VSCode拡張のPlatformIOとは別でコンピュータにインストールされている必要があるので注意。

インストールされていない場合は、

$ pip install platformio

でインストールすればOK。

使い方

ワークフロー

  1. CubeMXでピン割当やペリフェラルなどの設定 → コード生成
  2. stm32pioでプロジェクトをPlatformIO用に変換
  3. VSCode上で開発

のようになります。 IDEで開発する場合に比べて多少プロセスは増えますが、それ以上の恩恵が得られるので文句は言わない。

以下で詳解していきますが、こちらは stm32pio - Example(CLI) を参考に進めていきます。

今回はNUCLEO-F401RE - 秋月を例にとって説明します。 お手持ちのボード/MCUに合わせて適宜補完してください。

CubeMX

CubeMXを開いてボードを選択 → Start Project このとき、

と表示されますが、[Yes]で続けます。

各種ピン設定やペリフェラル設定を行い、[Project Manager]を開きます。

ここで次のように設定を変更します。

全ての設定を終えたら[GENERATE CODE]を押します。

こちらも[Yes]で。

以上でCubeMX側の操作は終わりです。

stm32pio

ターミナルを立ち上げ、上で生成したプロジェクトのディレクトリに移動し、次のコードを実行します。

$ stm32pio new -b nucleo_f401re

または、-dオプションでディレクトリを渡して、

$ stm32pio new -d [project dir] -b nucleo_f401re

としてもOKです。

ボードオプション-bはボードIDを設定するものです。

今回のケースだとPlatformIOの対応ボード一覧NUCLEO-F401REから、nucleo_f401reを設定すればいいことがわかります。

これを行うと、PlatformIOの設定ファイルであるplatformio.iniが生成され、ディレクトリ構成は以下のようになります。

PlatformIO_Test/
├ Core/
├ Drivers/
├ Inc/
├ lib/
├ Src/
├ test/
├ platformio.ini
├ stm32pio.ini
├ PlatformIO_Test.gpdsc
├ PlatformIO_Test.ioc
├ .mxproject
└ .gitignore

以上でstm32pioの操作は完了です。

VSCode(C++への変換)

最後に変換したプロジェクトをVSCodeで開くと次の画像のように自動でPlatformIOが立ち上がります。

サイドバーのPlatformIOアイコンのページに移動し、[Build]してみます。

無事ビルドが通りました!

これを[Upload]すればSTM32への書き込みは完了です。

とりあえずここまでで一通りの開発はできるかと思います。

これ以降はオプションですが、最後に、私はC++で開発するのでこのプロジェクトをC++に変換します。

とはいってもやり方は極めて簡単、main.cmain.cppにリネームするだけです。

適当に次のようなクラスを実装してみます。

counter.h:

class Counter
{
public:
    Counter();
    void CountUp();
private:
    int counter;
};

counter.cpp:

#include "counter.h"

Counter::Counter()
{
    counter = 0;
}

void Counter::CountUp()
{
    counter++;
}

これをmain.cppで、

#include "counter.h"

int main(void)
{
  /* (中略) */
  Counter counter;

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    counter.CountUp();
    /* USER CODE END WHILE */
  }
}

のようにクラスを呼び出して[Build]してみます。

成功しました!

これでPlatformIO上でSTM32をC++で開発することができるようになりました。

お疲れさまでした。

補足

C++ファイルを追加する場合は、ファイルの依存関係に注意してください。 具体的には、追加したC++ファイルは他のCファイルに読み出されることがないように注意が必要です。 例えば、main.h内でC++ヘッダをインクルードすると次のようなエラーが出ます。

gpio.cなどのCファイルからmain.hを読み出すときにエラーが出ているようです。

Cファイルから見たらclassってなんぞや?となっているということですね。

このように、main.hは他のCファイルからも参照されるので、これを修正してmain.cpp内でインクルードすればきちんとビルドできます。