5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

2024 TRONプログラミングコンテスト 開発環境・開発ツール部門 応募プログラム【NT-Shell・CppUTestを使用した簡易テスト環境】の紹介

Last updated at Posted at 2024-09-18

この記事は何?

2024 TRONプログラミングコンテスト開発環境・開発ツール部門NT-Shell・CppUTestを使用した簡易テスト環境をテーマに応募しました。

この記事はNT-Shell・CppUTestを使用した簡易テスト環境について説明します。

コンテスト概要

TRONプログラミングコンテストについての説明はこちらの公式ホームページの説明を引用させていただきます。

2024 TRONプログラミングコンテスト 公式ホームページ

世界標準であるTRONのリアルタイムOS「μT-Kernel 3.0」と各社の最新のマイコンを用いたアプリケーション、 ミドルウェア、開発環境、そしてツールなど各分野のプログラムを募集します。リアルタイム性、省電力、小フットプリント などリアルタイムOSの特性を引き出すテクノロジー、新しい技術を活用した開発環境やツールなどを競います。
応募者には選考の上、協力各社より提供頂いたμT-Kernel 3.0を搭載した最新のマイコンボードが提供されます。

マイコンボード

コンテストに使用するマイコンボードは下図より選択可能です(TRONプログラミングコンテスト 公式ホームページより引用)。

board.jpg

私はSTマイクロエレクトロニクス株式会社の評価ボードNucleo-H723ZGを選択しました。
この評価ボードを選択した理由はSTマイクロエレクトロニクスの評価ボードは過去に使ったことがあるからです。

コンテストの応募部門

コンテストは以下の3つの応募部門があります。

  1. RTOSアプリケーション部門
  2. RTOSミドルウェア部門
  3. 開発環境・開発ツール部門

私は開発環境・開発ツール部門することに決めました。

コンテスト応募背景・理由

社会人になり仕事ではじめて使ったRTOSがμITRON準拠のTOPPERS/JSPでした。いままで不思議と(?)μT-Kernelはいままでつかったことがありませんでした。
Webを見ていて偶然コンテストの存在を知り、応募してみることにしました。

あとは20年くらい前にプロジェクトXを見て、トロンのことを知ってから坂村先生、トロンのファンになったから、というのも根底にあると思います。RTOSといえばμITRON準拠のものというのが自分の中に染み付いています。

新価格版 プロジェクトX 挑戦者たち 家電革命 トロンの衝撃

所有DVDのパッケージを撮影(表)
project_x_1.jpg

所有DVDのパッケージを撮影(裏)
project_x_2.jpg

テーマ選定の背景・理由

今回はNT-Shell・CppUTestを使用した簡易テスト環境をテーマに開発環境・開発ツール部門に応募しました。
このテーマにした背景・理由についてです。

開発者の不安を軽減したい

組込みソフトウェア開発のテストでは、

  • ハードウェア非依存部、依存部を明確にした分離した設計を行う
  • ハードウェア非依存部はホストPCでTDD開発環境を構築し、アプリケーションロジックを確認する。

を目指すのが理想だと思います。そうすることで何か問題は起こった時にハードウェア起因か否かの判断もつきやすいと思います。

とは言っても綺麗にハードウェア依存部、非依存部を分離した構造にできないこともあるかと思います。

綺麗にハードウェア依存部、非依存部を分離できたとしても「実機で動かしていない」は開発者にとって不安な点だと思います。

今回のNT-Shell・CppUTestを使用した簡易テスト環境は気軽に実機環境でテストができることで開発者の不安軽減につなげたいという思いで作りました。

多様な観点のテストで不安を少なくし、自分のコードに自信を持つ

テストは通常、組込みソフトウェアのアプリケーションロジックの確認を目的に作成、実行することがメインだと思います。
ただ、ソフトウェア開発のプロセスにおいて開発者の不安はアプリケーションロジックの動作以外にも存在すると思います。

例えば以下があると思います。

  • プログラミング言語がわからず不安
  • 使用するマイコンアーキテクチャの挙動がわからず不安
  • 使用するマイコンの仕様がわからず不安
  • ライブラリの実装状態がわからず不安
  • そもそもテストフレームワークの使い方がわからず不安
  • 実行基盤であるRTOS(今回の場合、μT-Kernel)の使い方がわからず不安

こういった数々の不安をテストを使い、確認し学んでいくことで軽くできないかと思いました。
NT-Shell・CppUTestを使用した簡易テスト環境は上記を確認するテストを書き確認をおこないました。

開発環境

NT-Shell・CppUTestを使用した簡易テスト環境の開発環境です。

ホストPC

  • MacBook Retina 12-inch, 2017
  • プロセッサ: 1.2 GHz デュアルコア Intel Core m3
  • SSD 250G
  • メモリ: 8GB, LPDDR3

ハードウェア

  • STマイクロエレクトロニクス株式会社 Nucleo-H723ZG
  • マイコン: STM32H723
  • CPUコア: Arm®️ Cortex®️-M7
  • 550MHz
  • Flash memory:1 Mbyte
  • SRAM:564 Kbyte

ソフトウェア

STM32Cube IDE

STM32CubeIDE Version: 1.13.2
Build: 18220_20230914_1601 (UTC)

NTShell

Version 0.3.1

CppUTest

v3.8

開発環境構築手順

STM32CubeIDEのインストール

STM32CubeIDEをインストールします。

簡易テスト環境のクローン

簡易テスト環境をGitHubから任意のディレクトリにクローンします。
実行コマンドは下記です。

$ git clone git@github.com:grace2riku/mtk3_bsp2_easy_test_env.git

実行結果は下記です。

Cloning into 'mtk3_bsp2_easy_test_env'...
remote: Enumerating objects: 1318, done.
remote: Counting objects: 100% (1318/1318), done.
remote: Compressing objects: 100% (673/673), done.
remote: Total 1318 (delta 561), reused 1271 (delta 516), pack-reused 0 (from 0)
Receiving objects: 100% (1318/1318), 1.69 MiB | 1010.00 KiB/s, done.
Resolving deltas: 100% (561/561), done.

CppUTestのクローン

CppUTest v3.8をSTM32CubeIDEのプロジェクトでライブラリにしました。
こちらもGitHubから任意のディレクトリにクローンします。
実行コマンドは下記です。

$ git clone -b v3.8 git@github.com:grace2riku/cpputest.git

実行結果は下記です。

Cloning into 'cpputest'...
remote: Enumerating objects: 314, done.
remote: Counting objects: 100% (314/314), done.
remote: Compressing objects: 100% (232/232), done.
remote: Total 314 (delta 76), reused 311 (delta 76), pack-reused 0 (from 0)
Receiving objects: 100% (314/314), 2.59 MiB | 1.00 MiB/s, done.
Resolving deltas: 100% (76/76), done.

STM32CubeIDEの操作

ここからはSTM32CubeIDEの操作です。

STM32CubeIDEの起動

STM32CubeIDEを起動します。
ワークスペースのパスを確認し、Launchボタンを押します。

stm32cubeide_start.jpg

簡易テスト環境のインポート

先ほどGitHubからクローンした簡易テスト環境をインポートします。
FileメニューからImportを選択します。

stm32cubeide_file-import.jpg

Existing Projects into Workspaceを選択します。
ide_existing_project_into_workspace.jpg

Browseボタンを押下し、簡易テスト環境のディレクトリ(mtk3_bsp2_easy_test_env)を選択します。
ide_import_select_mtk3-bsp2_prj_dir.jpeg

Projects:にmtk3_bsp2_easy_test_envがチェックされていることを確認し、Finishボタンを押します。
ide_import_mtk3-bsp2_prj.jpg

STM32CubeIDEの左側にmtk3_bsp2_easy_test_envのプロジェクトがインポートされます。
ide_import_complete_mtk3-bsp2_prj.jpg

CppUTestのインポート

簡易テスト環境のインポート手順と同じようにCppUTestのプロジェクトのディレクトリ(cpputest)を選択します。
ide_import_select_cpputest_prj_dir.jpg

Projects:にcpputestがチェックされていることを確認し、Finishボタンを押します。
ide_import_cpputest_prj.jpg

STM32CubeIDEの左側にcpputestのプロジェクトがインポートされます。
ide_import_complete_cpputest_prj.jpg

CppUTestのビルド

CppUTestのプロジェクトをビルドし、ライブラリを作成します。
ライブラリは簡易テスト環境のプロジェクトでリンクしているのでCppUTestのプロジェクトを先にビルドします。
ビルドアイコンを押します。

ide_build-cpputest-lib.jpg

ビルドが完了するとConsoleのタブにcreating libcpputest.aと表示されます。
ide_create-cpputest-lib.jpg

簡易テスト環境のビルド

簡易テスト環境のプロジェクトをビルドします。
簡易テスト環境は先にビルドしできたCppUTestのライブラリをリンクしています。
ビルドアイコンを押します。

ide_build-mtk3-bsp2.jpg

ビルドが完了するとConsoleのタブにFinished building target: mtk3_bsp3_easy_test_env.elfと表示されます。
ide_create-elf.jpg

デバッグ

ビルドが完了したらPCと評価ボードのUSBコネクタ(CN1)をUSBケーブル(A-マイクロB)で接続します。
デバッグボタンを押し、先ほど作成したmtk3_bsp3_easy_test_env.elfを評価ボードにダウンロードします。

ide_debug_start.jpg

デバッグの準備が完了するとmain関数の先頭で停止します。

ide_debug_connect.jpg

Resumeボタンを押すとプログラムをスタートします。

ide_debug_resume.jpg

シリアル通信の接続

任意のシリアルコンソールでシリアル通信に接続します。
この記事ではminicomを使います。

シリアルのパス名を確認します。

$ ls /dev/cu.usb*
/dev/cu.usbmodem14103

minicomでボーレート115200bpsでシリアル通信に接続します。
ボーレート以外の通信条件はつぎのとおりです。

  • データ長:8bit
  • パリティ:なし
  • ストップビット:1bit
  • フロー制御:なし
$ minicom -D /dev/cu.usbmodem14103 -b 115200

接続できるとつぎの表示になります。

Welcome to minicom 2.8

OPTIONS:
Compiled on Jan  4 2021, 00:04:46.
Port /dev/cu.usbmodem14103, 08:15:22

Press Meta-Z for help on special keys

シリアル通信の接続確認

シリアル通信で接続できたらソフトウェアが応答するかコマンド実行し確認してみます。
シリアルコンソールでエンターキーを押下するとキャレット(>)が表示されます。

>

helpを押下しエンターキーを押下します。

>help
help    :This is a description text string for help command.
info    :This is a description text string for info command.
read_userbutton :User button B1 reads.
write_led1      :Write to LED LD1.
write_led2      :Write to LED LD2.
write_led3      :Write to LED LD3.
cpputest        :Exec CppUTest.

NT-Shell・CppUTestを使用した簡易テスト環境が実行できるコマンドとコマンドの説明が表示されます。
これが確認できればシリアルコンソールと評価ボードの間の接続は問題ありません。

シリアルコンソールのキャリッジリターン設定

helpコマンドで表示されたcpputestコマンドを綺麗に表示するためにキャリッジリターンを設定します。
minicomの場合、EscキーとZキーを押下すると表示される下図の画面でUキーを押します。

add_cr.jpg

機能説明

NT-Shell・CppUTestを使用した簡易テスト環境の機能について説明します。

NT-Shell

記事の冒頭でつぎの文言を書きました。

今回のNT-Shell・CppUTestを使用した簡易テスト環境は気軽に実機環境でテストができることで開発者の不安軽減につなげたいという思いで作りました。

この気軽に実機環境でテストができることを実現する要素技術としてNT-Shellを選択しました。
NT-Shellは組込みシステム用のシェルです。NT-Shellを組込むことでシリアルコンソールから以下の操作が可能になります。

  • カーソルキーによる移動
  • Backspace, Deleteキー押下による文字の削除
  • 上下キー押下による実行コマンドの履歴参照
  • Ctrl+aで行の先頭、Ctrl+eで末尾への移動

これらの操作がシリアルコンソールからできることでデバッグしやすい、気軽に実機環境でテストできることにつながります。

コマンド 

NT-Shell・CppUTestを使用した簡易テスト環境ではいくつかコマンドを定義しています。
シリアルコンソールからhelpを押下し、表示される文字列がコマンドです。

>help
help    :This is a description text string for help command.
info    :This is a description text string for info command.
read_userbutton :User button B1 reads.
write_led1      :Write to LED LD1.
write_led2      :Write to LED LD2.
write_led3      :Write to LED LD3.
cpputest        :Exec CppUTest.

コマンドをいくつか紹介します。

CppUTest

シリアルコンソールからcpptestと押下するとテストフレームワークCppUTestで書かれたテストを実行します。

以下の例はcpputestを実行した場合の表示です。
この表示は以下を表しています。

  • 39個のテストがある
  • 36個がテストOK
  • 68個のチェック項目がある
  • 3つのテストを無視(テストを実行せずにスキップ)した
>cpputest
.....!!.......!........................
OK (39 tests, 36 ran, 68 checks, 3 ignored, 0 filtered out, 0 ms)

CppUTestには実行オプションがあります。

詳しくはこちらのCommand line Switchesを参照ください。

以下は-vを指定した場合の表示です。
オプションなしの実行に比べて、実行しているテストが詳細に表示されるようになりました。

>cpputest -v
TEST(TimeManagementTestGroup, BasicUsage_tk_get_otm) - 0 ms
TEST(TimeManagementTestGroup, BasicUsage_tk_get_tim) - 0 ms
TEST(SyncAndComTestGroup, BasicUsageMailbox) - 0 ms
TEST(SyncAndComTestGroup, MailboxUnknownCommandReceived) - 0 ms
TEST(MtKernelTaskManegementLerningTestGroup, BasicUsage_tk_ref_tsk) - 0 ms
IGNORE_TEST(MtKernelApiLerningTestGroup, CreateAndStartTsk) - 0 ms
IGNORE_TEST(IOPortAccessSupportTestGroup, in_w_B1USER_Button_Pressed) - 0 ms
TEST(IOPortAccessSupportTestGroup, in_w_B1USER_Button_NotPressed) - 0 ms
TEST(IOPortAccessSupportTestGroup, out_w_and_in_w) - 0 ms
TEST(FutureProblemTestGroup, 2038problem) - 0 ms
TEST(FutureProblemTestGroup, pre2038problem) - 0 ms
TEST(CPUSpecificationsGroup, endian) - 0 ms
TEST(CpputestUsageGroup, setup) - 0 ms
TEST(CpputestUsageGroup_2, setup) - 0 ms
IGNORE_TEST(CpputestUsageGroup, setupOtherTestGroupVariableReference) - 0 ms
TEST(CpputestUsageGroup, setupGlobalVariableReference) - 0 ms
TEST(CpputestUsageGroup_2, setupGlobalVariableReference) - 0 ms
TEST(CpputestUsageGroup, BasicUsage_BITS_EQUAL_Assertions) - 0 ms
TEST(CppLerningTestGroup, defaultArgument_arg1_2) - 0 ms
TEST(CppLerningTestGroup, defaultArgument_arg2) - 0 ms
TEST(CppLerningTestGroup, defaultArgumentNone) - 0 ms
TEST(CppLerningTestGroup, BasicUsageBinaryLiterals) - 0 ms
TEST(CppLerningTestGroup, BasicUsageDigitSeparators) - 0 ms
TEST(CortexM7ArchitectureGroup, intSize) - 0 ms
TEST(MinusTestGroup, Minus_MinValueInput) - 0 ms
TEST(MinusTestGroup, Minus_MaxValueInput) - 0 ms
TEST(MinusTestGroup, Minus_LargeNegativeDifference) - 0 ms
TEST(MinusTestGroup, Minus_LargePositiveDifference) - 0 ms
TEST(MinusTestGroup, Minus_SameValues) - 0 ms
TEST(MinusTestGroup, Minus_BoundaryCondition_AboveMin) - 0 ms
TEST(MinusTestGroup, Minus_BoundaryCondition_BelowMin) - 0 ms
TEST(MinusTestGroup, Minus_BoundaryCondition_ExactMin) - 0 ms
TEST(MinusTestGroup, Minus_ValidInput_WithinBounds) - 0 ms
TEST(MinusC2CoverageTestGroup, Minus_MinLessThanAns) - 0 ms
TEST(MinusC2CoverageTestGroup, Minus_MinGreaterThanAns) - 0 ms
TEST(MinusC2CoverageTestGroup, Minus_MinLessThanData2) - 0 ms
TEST(MinusC2CoverageTestGroup, Minus_MinGreaterThanData2) - 0 ms
TEST(MinusC2CoverageTestGroup, Minus_MinLessThanData1) - 0 ms
TEST(MinusC2CoverageTestGroup, Minus_MinGreaterThanData1) - 0 ms

OK (39 tests, 36 ran, 68 checks, 3 ignored, 0 filtered out, 0 ms)

もうひとつオプションを指定したテストの実行例を示します。
-sgはテストグループのテストを実行するオプションです。
以下の例はTimeManagementTestGroupのテストのみを実行してます。

>cpputest -v -sg TimeManagementTestGroup
TEST(TimeManagementTestGroup, BasicUsage_tk_get_otm) - 0 ms
TEST(TimeManagementTestGroup, BasicUsage_tk_get_tim) - 0 ms

OK (39 tests, 2 ran, 2 checks, 0 ignored, 37 filtered out, 0 ms)

さきほどはテストグループのテストを実行した例でした。
テスト名で実行するテストを指定し、テストを実行することもできます。
その場合は-snオプション、実行したいテスト名を指定します。
以下の例ではBasicUsageMailboxテストを指定しています。

>cpputest -v -sn BasicUsageMailbox
TEST(SyncAndComTestGroup, BasicUsageMailbox) - 0 ms

OK (39 tests, 1 ran, 2 checks, 0 ignored, 38 filtered out, 0 ms)

このようにシリアルコンソールから全てまたは任意のテストを実行できます。

LED点灯・消灯

write_led*(* = 1, 2, 3)コマンドはLEDを点灯・消灯するコマンドです。
つぎのコマンドでLED LD1を点灯します。

>write_led1 1

つぎのコマンドでLED LD1を消灯します。

>write_led1 0

LED2(LD2), LED3(LD3)もLED1(LD1)と同様に点灯、消灯できます。

スイッチ読込み

read_userbuttonコマンドはUSER B1ボタンのレベルを読込みます。
USER B1ボタンを押していないときは0が読み出せます。

>read_userbutton
USER BUTTON B1 = 0

USER B1ボタンを押しているときは1が読み出せます。

>read_userbutton
USER BUTTON B1 = 1

プログラム説明

プログラム構成

NT-Shell・CppUTestを使用した簡易テスト環境のプログラム構成です。

簡易テスト環境のプロジェクト

下図が簡易テスト環境のプロジェクトの構成です。
画像で選択されている項目がSTM32CubeIDEのデフォルト状態から変更した項目です。

mtk3_bsp2_prj_tree.jpg

下表は変更した項目の一覧表です。

パス ファイル名 内容 備考
Application app_main.c μT-Kernel3.0が呼び出すユーザプログラムのusermain関数を定義している。システムで使うタスク、資源を生成している。自身はtk_slp_tskでスリープし、他のタスクの処理に移行する。
Application led_blink.c LED3(LD3)の点滅を行うタスク
Application ntshell_task.c NT-Shellタスク。シリアルコンソールからの文字列入力・出力する。シリアルコンソールの入力文字列がコマンド文字列に一致する場合はusercmd.cのコマンドを実行する。
Application usercmd.c ユーザーコマンドの実装。
Core/Src main.c STM32CubeIDEが自動生成するmain関数。μT-Kernel 3.0の起動処理knl_start_mtkernel関数を実行するようにコードを追加している。 参考URL: 4.2.3. OS起動処理の呼び出し
lib/nt-shell/core NT-Shell Core モジュール 参考URL: NT-Shell Architecture
lib/nt-shell/util NT-Shell Util モジュール 参考URL: NT-Shell Architecture
mtk3_bsp2 μT-Kernel 3.0 BSP2 mtkernelディレクトリはμT-Kernel 3.0
test/calclogic_ChatGPT_support calclogic_ChatGPT_support.cpp アプリケーションロジックのテスト(テストをChatGPTで生成) 参考リンク:アプリケーションロジックのテストをChatGPTで生成した事例
test/cortexM7_architecture cortexM7_architecture_test.cpp Cortex-M7のアーキテクチャを確認するテスト 参考リンク:マイコンアーキテクチャ(Cortex-M7)のテスト
test/cpp_lerning_test cpp_lerning_test.cpp C++を学習するテスト 参考リンク:C++の学習テスト
test/cpputest_usage cpputest_usage.cpp テストフレームワークCppUTestの使い方を学べるテスト 参考リンク:テストフレームワークCppUTestの学習テスト
test/cpu_specifications cpu_specifications_test.cpp ターゲットマイコンのエンディアンのテスト 参考リンク:ターゲットマイコンの仕様を確認するテスト
test/future_problem_test future_problem_test.cpp 2038年問題のテスト 参考リンク:将来の問題のテスト
test/mtkernel_api_lerning_test μT-Kernel 3.0のAPIを学習するテスト 参考リンク:μT-Kernel 3.0の学習テスト

変更の方針はつぎにしました。

  • ApplicationディレクトリにNT-Shell・CppUTestを使用した簡易テスト環境のユーザープログラムを格納(STM32CubeIDEが生成したファイルは格納していない)
  • libディレクトリにNT-Shellのディレクトリをつくり、その中にNT-Shellのライブラリを格納
  • mtk3_bsp2ディレクトリにBSP2(μT-Kernel 3.0 BSP2)、μT-Kernel(μT-Kernel 3.0)を格納(環境構築はGitHubのドキュメントを参照した)
  • testディレクトリ以下にさらにテスト観点ごとにディレクトリをつくりテストコードを格納

CppUTestのプロジェクト

テストフレームワークCppUTestはライブラリ化します。
STM32CubeIDEのメニューからライブラリのプロジェクトとして作成します。

こちらの記事とおりの手順で進めました。

LowLevelCode
Unit Testing in STM32CubeIDE

CppUTestのソースコードはこちらのページからダウンロードしたv3.8を使いました。

./ Cpputest
Download Release 3.8 as .zip

解凍したファイルの中から以下のディレクトリ・ファイルをSTM32CubeIDEのプロジェクトにコピーしました。

  • cpputest-3.8 2/include/CppUTest ディレクトリ
  • cpputest-3.8 2/include/CppUTestExt ディレクトリ
  • cpputest-3.8 2/src/CppUTest ディレクトリ
  • cpputest-3.8 2/src/CppUTestExt ディレクトリ
  • cpputest-3.8 2/src/Platforms/Gcc/UtestPlatform.cpp

STM32CubeIDEプロジェクトのファイル構成は下図になります。

cpputest_prj_tree.jpg

リソース

NT-Shell・CppUTestを使用した簡易テスト環境のシステムのリソースについて説明します。

タスク構成

タスク、タスクが使うリソースは下表のとおりです。

ファイルパス タスク名 タスクの概要 使っているOSリソース
Application/led_blink.c led_blink_task LED3(LD3)の点滅を行う なし
Application/ntshell_task.c ntshell_task ・シリアルコンソールからの文字列入力・出力をおこなう。シリアルコンソールの入力文字列がコマンド文字列に一致する場合はusercmd.cのコマンドを実行する。
・同期・通信機能のテスト(テストグループ名SyncAndComTestGroup)でコマンドをメールで送信し、レスポンスをsync_and_com_provider_taskからメールで受信する。受信したメールの内容でテストOK・NGを判定する。
・メールのコマンドリクエスト用の固定長メモリプール(mpfid_request)
・コマンドリクエスト用ののメールボックス(mbxid_request)
test/mtkernel_api_lerning_test/mtkernel_task_manegemnrt.c mtkernel_task_manegemnrt_test_task ・テストグループ名 MtKernelApiLerningTestGroupのテスト名 CreateAndStartTskで保存したタスクIDを確認するテストで使用する。
・LED2(LD2)を点滅する
なし
test/mtkernel_api_lerning_test/sync_and_com_provider.c sync_and_com_provider_task 同期・通信機能のテスト(テストグループ名SyncAndComTestGroup)でntshell_taskがメールで送信したコマンドを受信し、レスポンスをメールでntshell_taskに返信する。 ・メールのレスポンス用の固定長メモリプール(mpfid_response)
・レスポンス用のメールボックス(mbxid_response)

OS以外で必要なリソース

シリアル通信

シリアルコンソールの入力文字列をNT-Shellが解釈します。入力文字列がコマンドであれば該当コマンドを実行します。
NT-Shellでシリアル通信を使うためシリアル通信のインタフェースがリソースとして必要です。

必須でないが使っているリソース

つぎのリソースは必須ではないですが、コマンドで使っています。

  • GPIO LED 3個(write_lednコマンドで使用。n = 1〜3)
  • GPIO タクトスイッチ(read_userbuttonコマンドで使用)

カーネルの変更点について

NT-Shell・CppUTestを使用した簡易テスト環境はNT-Shellの入出力インターフェースとしてシリアル通信を利用します。
μT-Kernel 3.0 BSP2で実装されていたデバイスドライバは以下でした。

  • A/Dコンバータ
  • I2C

シリアル通信のデバイスドライバがなかったため、μT-Kernel 3.0 BSPのシリアル通信デバイスドライバを移植しました。
そのような理由から今回のNT-Shell・CppUTestを使用した簡易テスト環境はBSP2だけではなく、BSPのコードが混じっています。

BSP2のデバイスドライバはSoCメーカー提供のコード(== 統合開発環境が生成するコード)を使う構造のようで、BSPのデバイスドライバの構造とは若干違うように見えました。

もし今後BSP2でシリアル通信のデバイスドライバが実装されたらNT-Shell・CppUTestを使用した簡易テスト環境もBSP2のシリアル通信デバイスドライバを使うようにしたいと思います。

テスト

NT-Shell・CppUTestを使用した簡易テスト環境では記事冒頭に書いたように、

テストは通常、組込みソフトウェアのアプリケーションロジックの確認を目的に作成、実行することがメインだと思います。
ただ、ソフトウェア開発のプロセスにおいて開発者の不安はアプリケーションロジックの動作以外にも存在すると思います。

ソフトウェア開発で開発者が不安を感じるであろう項目のテストを書き、確認しました。
この章では今回書いたテストについて説明します。

μT-Kernel 3.0の学習テスト

μT-Kernel 3.0の使い方を学ぶ目的のテストです。
μT-Kernel 3.0仕様書1に書いてある機能を確認します。

μT-Kernel 3.0の位置づけと構成

μT-Kernel 3.0は下図の位置付け・構成となっています。
つぎの文、図はμT-Kernel 3.0仕様書1の引用です。

μT-Kernel 3.0は、タスクのスケジューリングや同期・通信などリアルタイムOS本来の機能を提供する「μT-Kernel/OS(Operating System)」、
システム管理向けの拡張機能を提供する「μT-Kernel/SM(System Manager)」、
およびソフトウェアによるデバッガのための機能を提供する「μT-Kernel/DS(Debugger Support)」により構成される。

μT-Kernel 3.0の位置づけと構成.jpg

テスト一覧

μT-Kernel 3.0の学習テストの一覧表です。
表に書いてある章番号はμT-Kernel 3.0仕様書1の章番号です。

μT-Kernel機能 機能分類 API名称 テストの目的 テストグループ名 テスト名
μT-Kernel/OS 4.1 タスク管理機能 4.1.12 tk_ref_tsk - タスク状態参照 タスクの状態を参照するtk_ref_tskの使い方を学習する MtKernelTaskManagementGroup BasicUsage_tk_ref_tsk
μT-Kernel/OS 4.4 同期・通信機能 4.4.3.3 tk_snd_mbx - メールボックスへ送信
4.4.3.4 tk_rcv_mbx - メールボックスから受信
メールボックスの送信・受信のの使い方を学習する SyncAndComTestGroup BasicUsageMailbox
μT-Kernel/OS 4.7 時間管理機能 4.7.1.7 tk_get_tim - システム時刻参照(TRON表現) システム時刻を参照するtk_get_timの使い方を学習する TimeManagementTestGroup BasicUsage_tk_get_tim
μT-Kernel/OS 4.7 時間管理機能 4.7.1.9 tk_get_otm - システム稼働時間参照 システム稼働時間を参照するtk_get_otmの使い方を学習する TimeManagementTestGroup BasicUsage_tk_get_otm
μT-Kernel/SM 5.4 I/Oポートアクセス 5.4.1.7 in_w - I/Oポート読込み(ワード) 評価ボードのUSER B1ボタンの状態をin_wで読み込めるか確認する IOPortAccessSupportTestGroup in_w_B1USER_Button_NotPressed
μT-Kernel/SM 5.4 I/Oポートアクセス 5.4.1.3 out_w - I/Oポート書込み(ワード) 評価ボードのLED LD1に書込み、データレジスタを確認する IOPortAccessSupportTestGroup out_w_and_in_w

テストフレームワークCppUTestの学習テスト

NT-Shell・CppUTestを使用した簡易テスト環境はテストフレームワークCppUTestを使い、テストを書いています。
CppUTestを使ったことがない人はテストを書くことができないと思うので、CppUTestの使い方を学べるテストを書きました。

テストグループ名 テスト名 テスト目的
CpputestUsageGroup setup テストグループとsetupの動きを確認する。
setupCpputestUsageGroupのsetupでテストグループ内で共有する変数が初期化されることを確認する。
CpputestUsageGroup_2 setup テストグループ名が異なればテスト名は重複可能なことを確認する。
テストグループCpputestUsageGroup_2のsetupが呼び出されていることを確認する。
CpputestUsageGroup setupGlobalVariableReference CpputestUsageGroupのsetupでグローバル変数の初期化を確認する
CpputestUsageGroup_2 setupGlobalVariableReference CpputestUsageGroup_2のsetupでグローバル変数の初期化を確認する
CpputestUsageGroup BasicUsage_BITS_EQUAL_Assertions ビットパターンをチェックするアサーションBITS_EQUALを学習するテスト

ビットパターンをチェックするアサーションBITS_EQUALはマイコンのレジスタをチェックするなど組込みソフトウェアのテストで重宝しそうと思いました。

C++の学習テスト

プログラミング言語に不安があるという場合もあるかと思います。テストを使ってプログラミング言語を学習するというアプローチもよいと思います。今回はC++の学習にテストを使いました。

テストグループ名 テスト名 テスト目的
CppLerningTestGroup defaultArgumentNone デフォルト引数を使わないの場合の確認
CppLerningTestGroup defaultArgument_arg2 第2引数がデフォルト引数の場合の確認
CppLerningTestGroup defaultArgument_arg1_2 第1、2引数がデフォルト引数の場合
CppLerningTestGroup BasicUsageBinaryLiterals 2進数リテラル(C++14)の学習テスト
CppLerningTestGroup BasicUsageDigitSeparators 数値リテラルの桁区切り文字(C++14)の学習テスト

2進数リテラル(C++14)、数値リテラルの桁区切り文字(C++14)はこちらを参考にさせていただきました。
今回はじめて使いましたがマイコンのレジスタ書込み、読込みなど低レイヤのコードで使うと有用と思いました。

C++17 が組み込み開発にもたらす恩恵(その2)

cpprefjp - C++日本語リファレンス

アプリケーションロジックのテストをChatGPTで生成した事例

こちらの記事のアプリケーションの計算ロジックのテストをChatGPTで生成することを試してみました。
ChatGPTのモデルはChatGPT 4oにしました。

ChatGPTを使い簡単に単体テストコードを作る方法(CppUTest環境)
https://www.monokuma12.com/entry/cpputest_chatgpt#google_vignette

計算ロジックは条件付きの引き算です。引数、計算結果が-100以下にならなければtrueを返します。
ファイルはこちらのパスで関数名はMinusです。

  • mtk3_bsp2_easy_test_env/test/calclogic_ChatGPT_support/calclogic.c

ブラックボックステストの生成

前述の記事のとおり最初は以下のプロンプトでブラックボックステストの生成を依頼しました。

つぎのソースコードに対して、境界値テスト、同値テストを含んだブラックボックステストをくってください。テストフレームワークはCppUTestとします。
テストのファイル名はcalclogic_ChatGPT_support.cppとしてください。

bool Minus(
    int data1,
    int data2,
    int *ans)
{
    int min = -100;
    *ans = data1 - data2;
    if ((min >= data1) || (min >= data2) || (min >= *ans))
    {
        return false;
    }
    return true;
}

ChatGPTはつぎの9つのテストコードを生成しました。

テストグループ名 テスト名 テスト観点
MinusTestGroup Minus_ValidInput_WithinBounds 引数1と引数2が範囲内で、期待通りの結果が得られるかどうかをテスト
MinusTestGroup Minus_BoundaryCondition_ExactMin 引数1、引数2または計算結果がちょうど-100の場合の挙動を確認
MinusTestGroup Minus_BoundaryCondition_BelowMin 引数1、引数2または計算結果が-100未満の場合の挙動を確認
MinusTestGroup Minus_BoundaryCondition_AboveMin 引数1または引数2が-100より大きい範囲内のケースをテスト
MinusTestGroup Minus_SameValues 同じ値を引いたときの結果が0になることを確認
MinusTestGroup Minus_LargePositiveDifference 正の数同士の引き算が期待通りに動作するか確認
MinusTestGroup Minus_LargeNegativeDifference 引数2が引数1より大きい場合の計算が正しく行われるか確認
MinusTestGroup Minus_MaxValueInput 引数1がINT_MAXの場合の挙動をテスト
MinusTestGroup Minus_MinValueInput 引数1がINT_MINの場合にfalseを返すことを確認

生成されたテストコードを目視確認した限り、要求した境界値テスト、同値テストのテスト観点をおさえた有効なテストコードだと思いました。
私はINT_MAX、INT_MINのテストケースは想像していなかったので感心しました。また、わかりやすいテスト名を命名してくれることに驚きました。

生成されたテストコードに以下の追加を行いました。

  • ChatGPTに日本語コメントを追加してもらう
  • limits.hのインクルード(INT_MAX、INT_MINを参照するため)
  • テスト対象のロジックMinus関数のヘッダファイルをインクルード

テストのファイル以下です。

  • mtk3_bsp2_easy_test_env/test/calclogic_ChatGPT_support/calclogic_ChatGPT_support.cpp

テストコードはビルド、テストOKであることを確認しました。

ホワイトボックステストの生成

ChatGPTにカバレッジを満たすホワイトボックステストの生成を依頼しました。
プロンプトはこちらです。

先ほどのソースコード(Minus関数)に対して、C2カバレッジを満たすホワイトボックステストをくってください。
テストフレームワークはCppUTestとします。

ChatGPTはつぎの9つのテストコードを生成しました。

テストグループ名 テスト名 テスト観点
MinusC2CoverageTestGroup Minus_MinLessThanAns min >= *ans の条件が偽の場合
MinusC2CoverageTestGroup Minus_MinGreaterThanAns min >= *ans の条件が真の場合
MinusC2CoverageTestGroup Minus_MinLessThanData2 min >= data2 の条件が偽の場合
MinusC2CoverageTestGroup Minus_MinGreaterThanData2 min >= data2 の条件が真の場合
MinusC2CoverageTestGroup Minus_MinLessThanData1 min >= data1 の条件が偽の場合
MinusC2CoverageTestGroup Minus_MinGreaterThanData1 min >= data1 の条件が真の場合

生成してくれたテストコードを目視確認した限り、カバレッジを満たすテストコードを生成してくれました。

マイコンアーキテクチャ(Cortex-M7)のテスト

以前開発していたマイコンからアーキテクチャが異なるマイコンを使い開発する、などの場合、アーキテクチャの違いが気になったりしませんか?
テストでアーキテクチャを学習し、不安を少なくできないかと考えました。

マイコンアーキテクチャにより挙動が異なることとして最初に頭に浮かんだのはint型のサイズでした。
Cortex-M7マイコンは32bitマイコンなのでint型のサイズも4バイトになるかと思ったのでその確認を行うテストを書き、確認しました。

テストグループ名 テスト名 テスト観点
CortexM7ArchitectureGroup intSize int型のデータサイズの確認

ターゲットマイコンの仕様を確認するテスト

SoCメーカーの異なるマイコンシリーズなどではマイコンの仕様が異なっている、ということはないでしょうか?
そういった違いが開発を推進するうえでの不安要素になったりしていないでしょうか?

マイコン毎に異なる仕様で思いついたこととして、エンディアンがありました。
エンディアンを確認するテストを書き、確認しました。
今回のターゲットマイコンはリトルエンディアンのため、リトルエンディアンであることを確認しています。

テストグループ名 テスト名 テスト観点
CPUSpecificationsGroup endian リトルエンディアンであることの確認

将来の問題のテスト

いまは問題が起きていなくても将来起きる問題に不安を持つ方もいるのではないでしょうか。
将来起きる問題としてありがちなのは時間の経過で明らかになる不具合があると思います。
今回は2038年問題の対策状況のテストを書き、確認しました。

テストグループ名 テスト名 テスト観点
FutureProblemTestGroup pre2038problem 2038年問題未発生であることを確認する
FutureProblemTestGroup 2038problem 2038年問題が対策できているか

テストの結果、2038年問題が発生しないことが確認できました。
今回の例ではtime_t型の定義をコードで確認すれば、実機確認しなくてもわかりましたね💦

確認したい問題がマイコンが使っているライブラリに依存している時は実機での確認も有効だと思います(今回の例ではtime_t型の定義になります)。

まとめ

NT-Shell・CppUTestを使用した簡易テスト環境のまとめです。

必要なリソース

必要なリソースです。
別のマイコンに移植する際のヒントになればと思います。

シリアル通信

シリアルコンソールとNT-Shellを経由してコマンドを解釈、実行するシステムのためシリアル通信のインターフェースが必要です。

ROM・RAM使用量

下図は現在のROM・RAM使用量です。

rom_ram_used.jpg

ROM使用量は1024 KBのうちの178.35 KBを使用し、使用量は17.42%です。
RAM使用量はRAM_D1エリアの320 KBのうち18.11 KBを使用し、使用量は5.66%です。

性能

性能についてです。

ダウンロード速度

フラッシュROMへのダウンロード時間は10秒くらいでした。

不具合

一部のテストの不具合

テストグループ名 MtKernelApiLerningTestGroupのテスト名 CreateAndStartTskのテストですが、テストを2回おこなうとハードフォールトが発生します。
テスト内容的には

  • tk_cre_tsk
  • tk_sta_tsk
  • tk_ref_tsk

のAPIを呼び出しており、タスク生成→タスク開始→タスク状態参照の動作を確認する目的のテストです。
現在のところ原因がわからず解決できていないため無視テスト(IGNORE_TEST)として、テストしないようにしています。

RAMにコード配置、実行

素早くテストするための方法としてRAMにコード配置、実行することが考えれれます。
フラッシュROMにコード配置、実行するのに比べ、ダウンロード時間の短縮が期待できます。
フラッシュROMの書き換え回数を心配する必要もなくなります。

上記の理由からRAMにコード配置、実行を試してみましたが実行時エラーとなりました。
いまのところ解決方法がわからないためRAMにコード配置・実行は未対応です。

拡張

NT-Shell・CppUTestを使用した簡易テスト環境の拡張についてです。

ネットワーク対応

今回の評価ボードNucleo-H723ZGは有線イーサネットワークがあります。
ネットワークの対応を行うことで更にテストのしやすさの面でも使い勝手の向上が期待できそうです。
例えばGitHubへのプッシュでGitHub Actionsのワークフローが走り、実機テストを行う、などが思いつきます。
ネットワーク対応が実現できれば応用範囲も広がりそうです。

ライセンス

NT-Shell・CppUTestを使用した簡易テスト環境で使っているライブラリのライセンスです。

NT-Shell

MIT

CppUTest

BSD-3-Clause license

μT-Kernel 3.0およびBSP2

T-License 2.2

CMSIS

Apache License Version 2.0, January 2004

STM32H7xx_HAL_Driver

BSD-3-Clause

上記以外

上記以外のコードはMITライセンスとします。

MIT

  1. 参考資料1: μT-Kernel 3.0 仕様書 2019 年 12 月 初版 2 3

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?