2016年7月6日水曜日

FreeRTOSのポーティング

STBeeにFreeRTOSをポーティングしてみる。
メモ帳代わりに変更点をブログエディタに書いてるので時系列にはなってるけど内容はまとまってない。暇な時の読み物にでも。


開発環境はGCCを使用している。
とりあえず普段使っている雛形を元に、OSを追加していく形で実装した。
この雛形について。USART1による通信やLチカを実装済み。協調的マルチタスクを自前で実装済みで、USARTからのコマンドの受け取りとかはマルチスレッドで行うことができる。センサロガーとかとして使う場合はタイマ割り込みの中でSPI通信とかを叩いていた。とりあえずマイコンの動作はできているのが確認できている。

FreeRTOSは各自で探してもらうとして、執筆時点ではv9.0.0が落ちてきた。RTOSなるものは初めて使うのにいきなりメジャーアップデート直後とかこの時点で不安が。

今回は初めてRTOSを使うことも有り、動作するかもわからないのでOSはプロジェクトのフォルダの中にコピーした。ちゃんと使うときは、OS自体はプロジェクトとは別においておくのがいいらしい。

プロジェクトのディレクトリの中にinc, lib, srcのディレクトリが有り、他にmakefileが入っている。StdPriph_Driverとかはlibに入っている。とりあえずlibの中にFreeRTOSディレクトリを作り、その中にFreeRTOS/Sourceの*.cとincludeディレクトリをコピーする。更にportableディレクトリを作り、Source/portableのMemMangをコピーする。
OSの機能はこれで足りるらしい。

とりあえずこの時点でmakefileに./lib/FreeRTOS/includeをインクルードパスに追加する。それと./lib/FreeRTOS/*.cをソースファイルとして追加する。

次にmakeする。すると予想通り「FreeRTOSConfig.hが見つからないぞ」とエラーが出る。あとはエラーを消していく作業をすれば、最低限ビルドが通るようにはなるはず。

まずはFreeRTOS/Demo/CORTEX_STM32F103_GCC_Rowley/FreeRTOSConfig.hを./inc/にコピーしてビルド。portmacro.hが無いというエラーが出た。
FreeRTOS/Source/portable/GCC/ARM_CM3のportmacro.hをincにコピー。
これでビルドが通った。警告も特に出ている様子はない。

ここでバイナリをSTBeeに書き込む。RTOSを追加しただけなので、望む動作は雛形と変わりない。とりあえずデバッグメッセージやLチカは正常に動作している。

次はRTOSを動作させる番。

まずFreeRTOS.hとtask.hをインクルードする。すでにインクルードパスにincludeディレクトリを追加しているので問題なくビルドが通るはず。


とりあえずxTaskCreateとvTaskStartSchedulerを試す。てきとーな関数を作ってTaskCreateに渡す。その後でTaskStartを叩く。ビルドするといろいろ未定義エラーが出る。とりあえず真っ先に目につくのがメモリ関係かな。
ソースファイルにFreeRTOS/portable/MemMang/heap_1.cを追加する。メモリ(Malloc,Free)関係の未定義エラーはおおよそ消えた。あとはpxPortInitialseStack, xPortStartScheduler, vPortEnterCritical, vPortExitCriticalが未定義となっている。
potable/GCC/ARM_CM3/port.cを./lib/FreeRTOS/にコピーしてmakefileに追加する。
これでビルドエラーが消えた。STBeeにバイナリを書いて実行。xTaskCreateは通ったが、vTaskStartSchedulerを叩いてもタスクのデバッグメッセージは出てこない。
例外ハンドラに文字列出力を入れたところ、HardFault_Handlerが呼ばれているらしい。

FreeRTOSをSTM32F4にポーティングする - あくまで個人的メモ用ブログに#defineを消すとHardFaultする、というのが書いてあったので、#defineを3行追加する。
このマクロの意図するところは、FreeRTOSの関数名を変更するらしい。例えばxPortSysTickHandlerはマクロによりSysTick_Handlerという名前になり、これはCMSISのSysTick割り込み名となる。
ただしこの3個の関数はstm32f10x_it.cですでに作成されているため、ビルドエラーとなる。とりあえずit.cの方をコメントアウトすることで対応した。
それをビルドしたところ、今度はvApplicationStackOverflowHook関数が無いとエラーが出た。ということでとりあえず引数なし、戻り値なしで中で無限ループする関数を作り、UARTでHookした旨を表示するようにした。
これでビルドが通ったのでSTBeeに書いてみる。すると2個登録したタスクの内1個を実行し、StakOverflowHookが呼ばれた旨の表示が出た。

これの原因は簡単にわかった。以前に読んだページで、「printfは大量にメモリ使うからstack足りなくなるよ」と書いてあったのを覚えていたため。タスクの動作テストにはprintfで文字列を出していたから、それが原因だろうと思い、printfをputsに変更したところStackOverflowHookは引っかからなくなった。


タスク2個の内容はほぼ同じで、違いはデバッグメッセージだけ。中身は文字列を出力した後、while(1);で無限ループとする。協調的マルチタスクでこのコードを実行すると、最初に呼ばれた関数の中で無限ループに入り、次のタスクへ処理がわたらなくなる。
今回のFreeRTOSもまだSysTickの初期化は行っていないから、実質的には協調的マルチタスクとなっている、はずだった。しかしなぜかTask1もTask2もデバッグメッセージを出力している。
port.cのなかでSysTick関係のレジスタを叩いているようなので、この中で初期化を行っているのかもしれない。

Task1のループで500ms待って文字出力、Task2のループで1000ms待って文字出力、という機能を追加したところ、おおよそそれくらいのタイミングで文字が出てきている。ということでマルチタスクの動作はできているらしい。


とりあえず最低限のFreeRTOSの動作は確認できた。USART周りは低レベルで書いてあったりするけど、動作していることに違いはない。あとは低レベルな部分をRTOSで書き直したりすれば良いのかな。
RTOSを使えば協調的マルチタスクと違って、勝手にOSがマルチタスクっぽくやってくれるので、気を使うところが少し減るかも。OSはOSで面倒な部分もあるんだろうけど。
でも最低限動作はしてるんだから、少しずつ改善していけば使えるようになるはず。



今回ハマったところまとめ
・FreeRTOSのデモを使わなくても、すでにあるコードに追加して動作させられる
→GCC使ってる人はデモ使うの面倒らしいし
・OSが使う割り込み3個はマクロで実装

以外に少ない。思ってたより簡単だったかも。

0 件のコメント:

コメントを投稿