CoIDEを使ってSTM32F4 DiscoveryでTDD(Unity)をやってみた


#開発環境のインストール

フリーでサイズ制限が無いCooCox CoIDEを使ってみる。
特徴としてはざっとこんな感じ。

* 最初からRAM上でデバッグできる機能を持っている。
* semihosting機能を使ってprintf()を簡単に使える。
* 最適化オプションを使うと動かないことがある？知らんけど。
* 残念な点としてC++のサポートが甘い。

##ツールチェーンのインストール

まずARMのツールチェーン（コンパイラやリンカ）をダウンロードしてきてインストールする。

###Sourcery CodeBench Lite Editionをダウンロード

ここからダウンロードした。
http://www.mentor.com/embedded-software/sourcery-tools/sourcery-codebench/editions/lite-edition/

ARM Processors　→　Download the EABI Release
フォームに入力するとE-MailでダウンロードのURLが送られてくる。
Sourcery CodeBench Lite 2013.05-23 をダウンロード。
IA32 Windows Installer をダウンロードした。

###Sourcery CodeBench Lite Editionのインストール

全てデフォルトでインストールした。

##ST-LINKユーティリティのインストール

ここからダウンロードした。
http://www.st-japan.co.jp/web/jp/catalog/tools/PF251168

STM32 ST-LINK utility
STSW-LINK004 STM32 ST-LINK utility

Win8用のドライバもあるのでWin8でも動きそうな気がする。

基本的に基板を繋ぐ前にインストールする。


##CoIDEのインストール

http://www.coocox.org/CooCox_CoIDE.htm
Download the latest CoIDE directly をダウンロード

updateツールはうるさいのでインストールしなくていいと思う。
![19.PNG](https://qiita-image-store.s3.amazonaws.com/0/21786/0156685b-710e-30e0-0428-4d56e55f9bd2.png)

##CoIDEの設定
IDE起動を起動し、Project => Select Toolchain Pathを選びツールチェーンのパスを指定する。
入力「C:¥Program Files¥CodeSourcery¥Sourcery_CodeBench_Lite_for_ARM_EABI¥bin」
![22.PNG](https://qiita-image-store.s3.amazonaws.com/0/21786/c9964f3a-7a5a-538a-45e5-31a39e7b1954.png)

#Unityを実機で動作させる
##プロジェクトの作成
メニューからProject => New Projectを選んで新規のプロジェクトを生成する。
プロジェクト名はUnityとした。
![1.PNG](https://qiita-image-store.s3.amazonaws.com/0/21786/41d236f3-064f-f6b5-a062-76dbb17ad5c6.png)
Chipを選択。
![2.PNG](https://qiita-image-store.s3.amazonaws.com/0/21786/24c9c361-71a3-e7f7-4431-9503563da33a.png)
ST=>STM32F4x=>STM32F407VGを選択。
![25.PNG](https://qiita-image-store.s3.amazonaws.com/0/21786/466a9051-7d74-5178-98a6-4dcf11faf43b.png)
Finishで生成完了。

##プロジェクトの設定
###Semihosting有効
Hello WorldをIDEに送って表示させるためにSemihostingにチェックする。
依存関係のあるものが自動的に選択され、関連するソースコードが読み込まれる。
![4.PNG](https://qiita-image-store.s3.amazonaws.com/0/21786/49132afc-ab22-a083-1163-56ed992bd17b.png)

###CMSIS BOOT有効
STM32F4のブートシステムにCMSISを使用する。
これも依存関係のあるものが自動的に選択され、関連するソースコード、
つまり、スタートアップルーチンなどが読み込まれる。
![5.PNG](https://qiita-image-store.s3.amazonaws.com/0/21786/1572ffaa-e844-5438-9d0d-6e389436bafb.png)

###Project Configuration
View=>Configurationを選んで設定画面を開く。

LinkタブでDebug in RAMとしておく。
Flashに書き込まないでDebug可能なメモリ配置となる。
Flashの書き込み回数には限りがあるためRAMだけで実行できた方がうれしい。
![6.PNG](https://qiita-image-store.s3.amazonaws.com/0/21786/ec385421-412b-2293-7e84-1a64906a059e.png)

DebuggerタブでSemihosting Enableにチェックを入れておく。
![7.PNG](https://qiita-image-store.s3.amazonaws.com/0/21786/fd3ec528-1df6-7f13-240a-0154e622e8a4.png)

###printfをsemihostingに接続

Projectのstdio/printf.cを開いて、PrintChar()関数の中身を記述する。
semihosting機能を使ってデバッガ上に表示させるので、SH_SendChar(c);を呼ぶ。
ヘッダファイルも読み込んでおく。

```c:printf.c
#include <semihosting.h>

/**
 * @brief  Transmit a char, if you want to use printf(), 
 *         you need implement this function
 *
 * @param  pStr	Storage string.
 * @param  c    Character to write.
 */
void PrintChar(char c)
{
	/* Send a char like: 
	   while(Transfer not completed);
	   Transmit a char;
	*/	
	SH_SendChar(c);
}
```

###メイン関数の修正
main.cを開き、printf("Hello World!!!¥r¥n");を加筆する。

```c:main.c
int main(void)
{
	printf("Hello World!!!\r\n");

	while(1)
    {
    }
}
```

###ビルド
Project=>Build（もしくはF7）でビルドできる。

###デバッグ
実機で確認してみる。
USBポートにDiscovery基板を接続、必要に応じてドライバインストールされる。
Debugを押下すると自動的にダウンロードされてメイン関数で一時停止する。
![8.PNG](https://qiita-image-store.s3.amazonaws.com/0/21786/16834524-5234-53b0-c1ad-e7c51d20f394.png)

Debug=>Runで実行、SemihostiongウィンドウにHello World!!!が表示されれば成功。
![9.PNG](https://qiita-image-store.s3.amazonaws.com/0/21786/6a0bf200-0be4-d90d-3175-8474002af2d3.png)

##テストフレームワークの組み込み
unity-masterから次のファイルを組み込む。
ディレクトリ構造をそのまま組み込むにはエクスプローラのドラッグアンドドロップを用いる。
C:¥CooCox¥CoIDE¥workspace¥Unityフォルダにエクスプローラでファイルをコピーする。
![12.PNG](https://qiita-image-store.s3.amazonaws.com/0/21786/300a9749-adb6-aaa4-6613-7a993d0ceebe.png)
ファイルを選んでドラッグし、ProjectのUnityプロジェクトにドロップする。
追加するかを聞いてくるのでOK押下で組み込まれる。
![11.PNG](https://qiita-image-store.s3.amazonaws.com/0/21786/93058d51-d25a-c981-e421-87fa8849874b.png)

##テストケースの記述
本当はファイルを分けた方がいいが、簡単のため今回はmain.c関数に直接テストケースを記述した。

```c:main.c
#include <stdio.h>
#include <unity.h>
#include <unity_fixture.h>

TEST_GROUP(hoge);

TEST_SETUP(hoge)
{
}

TEST_TEAR_DOWN(hoge)
{
}

TEST(hoge,first)
{
  TEST_ASSERT_EQUAL(1, 1);
}

TEST(hoge,second)
{
  TEST_ASSERT_EQUAL(2, 1);
}

TEST_GROUP_RUNNER(hoge)
{
  RUN_TEST_CASE(hoge, first);
  RUN_TEST_CASE(hoge, second);
}

static void RunAllTests(void)
{
	RUN_TEST_GROUP(hoge);
}

int main(void)
{
	printf("Hello World!!!\r\n");

	static char *argv[] = { "main" };
	UnityMain(sizeof(argv)/sizeof(*argv), argv, RunAllTests);

	while(1)
    {
    }
}
```

##Unityの一文字出力をsemihostingに接続
Configuration=>CompilerタブのDefined Symbols欄にAddで次のように記述する。
![444.PNG](https://qiita-image-store.s3.amazonaws.com/0/21786/fa91b4bd-81ca-6c96-d465-9f18d0886055.png)
UNITY_OUTPUT_CHAR=PrintChar
![14-2.png](https://qiita-image-store.s3.amazonaws.com/0/21786/04a6b3f6-5d03-ba8e-0936-84f7a60e7f80.png)

##ビルド
ビルドを実行するとエラーが出るので、その対策。

```
       [cc] Starting link
       [cc] arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -g -nostartfiles -Wl,-Map=Unity.map -O0 -Wl,--gc-sections -LC:¥CooCox¥CoIDE¥configuration¥ProgramData¥Unity -Wl,-TC:¥CooCox¥CoIDE¥configuration¥ProgramData¥Unity/link.ld -g -o Unity.elf ..¥obj¥semihosting.o ..¥obj¥unity.o ..¥obj¥startup_stm32f4xx.o ..¥obj¥main.o ..¥obj¥printf.o ..¥obj¥sh_cmd.o ..¥obj¥system_stm32f4xx.o ..¥obj¥syscalls.o ..¥obj¥unity_fixture.o
       [cc] collect2.exe: error: ld returned 1 exit status
       [cc] ..¥obj¥printf.o:(.data+0xf0): first defined here
       [cc] c:/program files/codesourcery/sourcery_codebench_lite_for_arm_eabi/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/thumb2¥libc.a(lib_a-impure.o):(.data+0x0): multiple definition of `_impure_ptr'
```

多重定義でエラーになっているだけのようなので、コメントアウトで対処する。

```c:printf.c
// struct _reent *_impure_ptr = &r;
```

##実行結果
一つ成功、一つ失敗するようにテストを書いたので結果はこの通り。
テスト結果がケーブル一本でIDE上に表示されるのがうれしい。
![13.PNG](https://qiita-image-store.s3.amazonaws.com/0/21786/7fbd40c2-3576-95f7-430e-2ffe17b58b77.png)

なお、今回はスタックサイズなど一切設定を変えていないが、ちゃんと実機動作させるためにはスタックサイズやヒープサイズなどきちんと見積もって設定しなければならないことは書き添えておく。