テストフレームワークの一つであるCppUTestを実機(STM32F4DISCOVERY)で動作させてみる。
#準備
##ターゲットとサンプル
ターゲットはCortex-M4コアのSTMicro社製マイクロコントローラSTM32F407VGを搭載した「STM32F4DISCOVERY」とする。ターゲット基板の詳細はこの辺りに記載されている。このページ下部にある「Related Tools and Software」という項目があり、そこにあるファームウェアパッケージSTSW-STM32068をベースにして進める事とする。クリックしてリンクを進むとドキュメントAN3983: STM32F4DISCOVERY peripheral firmware examplesとサンプル(Part Number : STSW-STM32068)をダウンロードするボタンがあるので、クリックして「stsw-stm32068.zip」をダウンロードする。
ダウンロードしたファイルを全て解凍しても良いが、ここでは次のディレクトリ(☆マークのあるディレクトリ以下全て)のみ解凍したものとして進める。なお、解凍場所は任意のディレクトリで良いが、ここでは便宜的にsample_rootに解凍したものとする。
sample_root
├─Libraries
│ ├─CMSIS
│ │ ├─Include ☆
│ │ ├─Lib ☆
│ │ └─ST ☆
│ ├─STM32F4xx_StdPeriph_Driver ☆
│ ├─STM32_USB_Device_Library ☆
│ └─STM32_USB_OTG_Driver ☆
├─Project
│ ├─Demonstration ☆
│ ├─Master_Workspace
│ │ └─EWARM ☆
│ └─Peripheral_Examples
│ └─IO_Toggle ☆
└─Utilities
└─STM32F4-Discovery ☆
##開発環境
今回、開発環境はIAR社のEmbedded Workbenchを使用し、まずはコード制限付きの評価版で可能かどうか検証してみる。Embedded Workbench ver.6.6 for ARM(以下、EWARM)をこの辺りからダウンロードしてきて、IAR社からライセンスを取得する。インストール及びライセンスの取得に関する部分はこの辺りやこの辺りが参考になる。
##ワークス-ペース
マスターワークスペースを開く。インストールが完了している場合、エクスプローラ等から次のファイルを開けばEWARMが起動する。
sample_root/Project/Master_Workspace/EWARM/STM32F4-Discovery.eww
解凍しなかったファイルある場合は警告表示が出るので全てOKで切り抜ける。成功すると次のようなプロジェクトが登録されているのをみる事ができる。
プロジェクト「STM32F4-Discovery_Demo」は工場出荷時に書き込まれているものと同じである(と思う)。最後に元に戻しておくために組み込んでいる。今回、ベースにするのはプロジェクト「IO_Toggle」で、LEDをON/OFFするだけの単純なものである。ここでそれぞれプロジェクトを右クリックからmakeを実行しビルドが成功することを確認しておくと良い。
#ライブラリの生成
##ライブラリプロジェクトの作成
Project ⇒ Create New Projectを選んで新規のプロジェクトを生成する。
ツールチェーンはARM、テンプレートは Empty project を選んでOKボタンを押下し、空のプロジェクトを作成する。
プロジェクトファイルの格納場所を聞いてくるが、ディレクトリ構造は自動的に決定されないので自力でディレクトリ構造を構築する必要がある。フォルダの作成等を駆使しつつ次のようにディレクトリ構造を構築し、プロジェクトファイルを決めて確定する。
続いて、ファイルをCppUTestからコピーする。
├─include
│ ├─CppUTest
│ │ CommandLineArguments.h
│ │ CommandLineTestRunner.h
│ │ JUnitTestOutput.h
│ │ MemoryLeakAllocator.h
│ │ MemoryLeakDetector.h
│ │ MemoryLeakDetectorMallocMacros.h
│ │ MemoryLeakDetectorNewMacros.h
│ │ MemoryLeakWarningPlugin.h
│ │ PlatformSpecificFunctions.h
│ │ SimpleString.h
│ │ TestFailure.h
│ │ TestHarness.h
│ │ TestHarness_c.h
│ │ TestOutput.h
│ │ TestPlugin.h
│ │ TestRegistry.h
│ │ TestResult.h
│ │ TestTestingFixture.h
│ │ Utest.h
│ │ UtestMacros.h
│ │ VirtualCall.h
│ └─Platforms
│ └─Gcc
│ Platform.h
└─src
├─CppUTest
│ CommandLineArguments.cpp
│ CommandLineTestRunner.cpp
│ JUnitTestOutput.cpp
│ MemoryLeakAllocator.cpp
│ MemoryLeakDetector.cpp
│ MemoryLeakWarningPlugin.cpp
│ SimpleString.cpp
│ TestFailure.cpp
│ TestHarness_c.cpp
│ TestOutput.cpp
│ TestPlugin.cpp
│ TestRegistry.cpp
│ TestResult.cpp
│ Utest.cpp
└─Platforms
└─Iar
UtestPlatform.cpp
##ファイルの追加
分かりやすいようにGroupを追加しておく。プロジェクトを右クリックからコンテキストメニューを開き、Add⇒Add Groupを選ぶ。
ここではグループ名を Src とした。OKボタンを押下して確定する。
続いて追加したグループを右クリックからコンテキストメニューを開き、Add⇒Add Filesでファイル選択ダイアログを開く。
先ほどコピーしたファイルからソースコードを選択して追加する。
プラットフォーム固有のソースコードも追加する。
バージョンなどの違いによりtolower()関数が定義されているヘッダファイルが異なっているので、プロジェクトのsrc/Platforms/Iar/UtestPlatform.cppを開き、インクルードファイルにctype.hを追加する。
#include <ctype.h>
##プロジェクトの設定
プロジェクトを右クリックからoptionを選ぶ。先ずはGeneral Optionsから設定していく。Processor variantはDeviceを選択し、右のボタン押下でコンテキストメニューを開き、ST ⇒ STM32F407 ⇒ ST STM32F407VGと選択する。
Output fileは Library を選択する。
Use CMSISにチェックを入れる。
CategoryでC/C++ Compilerを選び、Languageを C++ 、C++ dialectで C++ を選択する。
Enable multibyte supportはチェックマークが外れていることを確認。
Optimizationではサイズ制限評価版を使っているので可能な限りコードサイズを小さくするため、Levelを High にして Size 優先を選択しておく。
インクルードパスに $PROJ_DIR$\include
を通しておく。OKボタンを押下して設定内容を確定する。
プロジェクトを右クリックからmakeを起動するとライブラリが生成される。30個くらい警告が出るが今回は無視した。
#テストケースの作成
IO_Toggleプロジェクトをアクティブに切り替える。
C++でコンパイルするため、プロジェクトに含まれるmain.cをmain.cppに変更する。実際にはRemoveして名前を変更してからAddする。
##プロジェクトの設定
コンパイラの指定を C++ に変更する。
インクルードパスに $PROJ_DIR$\..\..\..\Test_Framework\CppUTest\include
を追加。
Linkerの設定でLinker configuration fileをプロジェクトのファイルでオーバーライドして個別設定する。Editボタンを押下してLinker configuration file editorを開く。
デフォルトのヒープサイズでは不足するのでここでは 0x2000 確保している。Saveボタンを押下し、configuration fileに書き込む。
追加のライブラリに $PROJ_DIR$\..\..\..\Test_Framework\CppUTest\Debug\Exe\CppUTest.a
を加える。
STM32F4xx_StdPeriph_Driverにある stm32f4xx_usart.c を追加。
##出力先をシリアルにする
シリアルへの接続この辺りを参考に組み込む。
この辺りにも情報がある。
#include <stdio.h>
#include <CppUTest/CommandLineTestRunner.h>
USART_InitTypeDef USART_InitStructure;
void USART_Configuration(void){
// sort out clocks
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
/* Configure USART2 Tx (PA.02) as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// Map USART2 to A.02
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);
// Initialize USART
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx;
/* Configure USART */
USART_Init(USART2, &USART_InitStructure);
/* Enable the USART */
USART_Cmd(USART2, ENABLE);
}
/**
* @brief Function that printf uses to push characters to serial port
* @param ch: ascii character
* @retval character
*/
int putcharx(int ch)
{
while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
USART_SendData(USART2, (uint8_t)ch);
return ch;
}
int main(void)
{
USART_Configuration();
static char *argv[] = { "main" };
CommandLineTestRunner::RunAllTests(sizeof(argv)/sizeof(*argv), argv);
}
##テストケースの記述
プロジェクトにtest.cppを追加し、テストケースを記述する。
#include <CppUTest/TestHarness.h>
int hoge(void)
{
return 3;
}
int hoge(int a)
{
return a+1;
}
TEST_GROUP(TestSuiteHoge)
{};
TEST(TestSuiteHoge, TestCaseHoge)
{
LONGS_EQUAL(3, hoge());
}
TEST(TestSuiteHoge, TestCaseHoge2)
{
LONGS_EQUAL(3, hoge(2));
}
#ビルドと実行
##ビルド
プロジェクトのコンテキストメニューからMakeを選んでビルドする。ビルドに成功すればIO_Toggle.outが生成される。
##デバッグ実行
USBポートにSTM32F4 DISCOVERYを接続する。初めて接続した場合や、接続するUSBポートを変更した場合はST-Linkドライバのセットアップが必要になる。ST-Linkドライバのセットアップに関してはこの辺りが参考になる。今回のセットアップ環境では C:\Program Files\IAR Systems\Embedded Workbench 6.5\arm\drivers\ST-Link\ST-Link_V2_USBdriver.exe を実行した。
正常にデバイスが使用できるようになったら、IO_Toggleプロジェクトを選択しProject⇒Download and Debug(Ctrl+D)を選択する。自動的にダウンロードされmain関数で一時停止する。
テスト結果を表示させるため、View⇒Terminal I/OでTerminal I/Oビューを表示しておく。
Debug⇒Go(F5)で実行すると、次のようにTerminal I/Oにテスト結果が表示される。
##コードサイズ
ちなみに今回の実装でコードサイズは28.5KB程度となった。コードサイズ限定版を使っている場合は、コードサイズが32KB以下にならないとビルドできないようになっているため、残り3.5KB程度となっている。
29,163 bytes of readonly code memory
6,073 bytes of readonly data memory
19,136 bytes of readwrite data memory