Cortex-M33へコードを追加

いざコードを追加しようと思うと、「どこにソースを追加するの」とか、「コンパイルはどうするの」とか、いくつかの小さい壁があります。また、ファームウェアはアットマークテクノ社よりアップデートがあるかもしれないので、うかつにソースを変更するとマージ作業が発生します。今回は、Cortex-M33へどうやってコードを追加していくか具体的な手順を見てみましょう。

ソースをどこに追加するのか

Armadillo-900のマニュアルをよく読むと、カスタマイズ用ディレクトリがあるからそこに追加してください、と書かれています。実際のカスタマイズディレクトリは「m33_firmware_at/custom」となります。このディレクトリに追加ソースをまとめておけば、ファームウェアの公式アップデート時にも差分が分かりやすくなります。

今回はとりあえずコードの追加が目的ですので、HelloWorldでも何でもいいのですがLチカ(LEDの点滅)をやります。Armadillo-900の開発ボードにSYSという電源用LEDがありますが、うまい具合にこのLEDはCortex-M33のGPIOで制御できるようになっています。このGPIOへ出力するコードを追加します。

ソースファイルの追加

ATDE9にインストールされているVS Codeを使って、customディレクトリにblinky.cというソースファイルを追加します。VS Codeを起動し、エクスプローラーにimx-boot-2023.04-at5フォルダを登録します。すると、フォルダツリーが表示されますので、m33_firmware_at/customを開きます。

VS Code画面

customフォルダで右クリックメニューの[新しいファイル]を選択し、ファイル名をblinky.cとします。

VS Code画面2

このソースにLチカのコードを書いていきます。SYS LEDはGPIOのPTC5に接続されている、とマニュアルに書かれていますので、PTC5をON/OFFすることでLチカを実現します。注意点として、Cortex-M33の一部の機能はLinuxから呼び出されていますので、Lチカを単純な無限ループで作ってCPUを占有するとLinuxの動作に影響が出ます。よって、LチカをFreeRTOSのタスクとして実装し、vTaskDelayで待ち状態を作れば、他のタスクへ制御を渡せるためCPUの占有を回避できます。また、GPIOの設定や出力にはAPIが用意されていますので、それらを活用します。実際のコードは次のようになります。

#include "FreeRTOS.h"
#include "task.h"
#include "app_gpio.h"

#define LED_GPIO_IDX   2
#define LED_PIN_IDX    5

void blinky_task(void *pvParameters)
{
    while (1) {
        APP_GPIO_Write(LED_GPIO_IDX, LED_PIN_IDX, 1);    // ON
        vTaskDelay(pdMS_TO_TICKS(500));

        APP_GPIO_Write(LED_GPIO_IDX, LED_PIN_IDX, 0);    // OFF
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

void blinky_init(void)
{
    // PTC5を出力に設定
    APP_GPIO_PinctrlSet(IOMUXC_PTC5_PTC5, IOMUXC_PCR_PE_MASK | IOMUXC_PCR_PS_MASK);
    APP_GPIO_SetupGPIO_Output(LED_GPIO_IDX, LED_PIN_IDX, 0);

    // Lチカタスクを作成
    xTaskCreate(blinky_task, "LED", 256, NULL, 1, NULL);
}

blinky_taskはLチカを行う無限ループタスクです。APP_GPIO_Write関数でPTC5へ出力しています。vTaskDelayを使って500msの間隔でLEDをON/OFFしています。

blinky_initはポートの初期化とタスクの生成を行います。このSYS LEDのポートはLinuxからも使用されますので、どこかで初期化される可能性は高いです。よって、blinky_initでの初期化は不要かもしれません。

最終的にblinky_initをcustom.cのcustom_init関数から呼び出せばOKです。

extern void blinky_init(void);
void custom_init(void)
{
    blinky_init();
}

custom_init関数はmain関数のタスクスケジューラが動く前に呼び出されますので、タスクの生成などを行うには都合が良い関数です(その目的で呼び出されているのでしょうけど)。これで追加分のコードはcustomディレクトリ内でクローズできます。

ファームウェアの再ビルド

ビルドの前に、ソースファイルを追加しましたので、ビルドシステムにそれを登録しないといけません。具体的には「m33_firmware_at/armgcc/CMakeList.txt」にblinky.cを追加します。CMakeList.txtはcmakeコマンドでMakefileに展開されますので、ソースファイルを追加した場合は、CMakeList.txtにファイル名を追加するだけでOKです。エディタでCMakeList.txtを開き、add_executableの定義に「"${ProjDirPath}/../custom/blinky.c"」を追加します。

CMakeList追加

CMakeList.txtはmake実行中のbuild.shで処理されます。おそらくこの段階でmakeを実行しても、正しいオブジェクトを作ってくれると思うのですが、ここは手堅くcleanしてからmakeします。make cleanを行うとbuild.sh debugも再度実行する必要があります。

atmark@atde9:~/imx-boot-2023.04-at5$ make clean
rm -rf uboot-imx/armadillo-900 imx-mkimage/armadillo-900
rm -rf uboot-imx/imx8ulp-evk imx-mkimage/imx8ulp-evk
rm -rf imx-mkimage/mkimage_imx8
rm -rf imx-optee-os/out_8ulp imx-atf/build
rm -rf imx-boot_imx8ulp-evk imx-boot_armadillo-900
if [ -e "/usr/bin/arm-none-eabi-gcc" ]; then \
	(cd m33_firmware_at/armgcc; sh clean.sh) \
fi
atmark@atde9:~/imx-boot-2023.04-at5$ ./m33_firmware_at/armgcc/build.sh debug
CMake Warning:
 :(省略)
atmark@atde9:~/imx-boot-2023.04-at5$ make imx-boot_armadillo-900
# cannot use -C because it outputs file in WD which can be yet
# another directory if called with make -C externally
cd imx-mkimage && make
 :(省略)
3098+0 レコード出力
3172352 bytes (3.2 MB, 3.0 MiB) copied, 0.00675934 s, 469 MB/s
make[1]: ディレクトリ '/home/atmark/imx-boot-2023.04-at5/imx-mkimage/armadillo-900' から出ます
cp imx-mkimage/armadillo-900/flash.bin imx-boot_armadillo-900

次はmkswuを実行しますが、boot.descを書き換えてファームウェアのバージョンをアップさせておかないと、ファームウェアのインストールで失敗します。エディタでファイルを開いて、「2023.4-at.5.1」を「2023.4-at.5.2」に変更します。

atmark@atde9:~/imx-boot-2023.04-at5$ vi boot.desc
swdesc_boot --version boot 2023.4-at.5.2 imx-boot_armadillo-900
atmark@atde9:~/imx-boot-2023.04-at5$ mkswu boot.desc
Enter pass phrase for /home/atmark/mkswu/swupdate.key:
boot.swu を作成しました。

ファームウェアのインストールの手順を再度行って、ファームウェアを書き換えます。書き換えに成功すると、Armadillo-900が再起動し、SYS LEDが点滅を開始します。

LEDが点滅しない場合

LEDが点滅しない場合はPALMiCE4でデバッグを行います。PALMiCE4の接続を行い電源を入れ、保存したプロジェクトファイル「cside.cpf」をダブルクリックで開きます。前回保存した状態でCSIDEが起動しますので、TeraTermを開いて、[再ロード]ボタンをクリックして初期化します。すると、以下の画面のようにCortex-M33がどこかで停止し、ソースが表示されます。

CSIDEコード表示

ここでblinky_taskのソースコードを表示させるため、ウィンドウ内でおもむろに[blinky_task]と入力します。

CSIDEコード表示2

Enterキーを押すとblinky_taskが表示されますので、画面の左側の点をクリックしてブレークポイントを設定します。逆三角の緑色のマークがブレークポイントです。

CSIDEコード表示3

実行ボタンをクリックするとブレークポイントで停止します。

CSIDEコード表示4

これでblinky_taskが正しく動作していることが分かります。ブレークポイントで止まらない場合は、blinky_taskが正しくタスク生成されていない、または初期化関数blinky_initが呼ばれていないなどの原因が考えられます。そもそもblinky_taskが表示されない場合は、コンパイルの環境の設定ミスや、ファームウェアのインストールに失敗しているなどの原因が考えられます。