前回の、ほぼ素のままのソースをビルドした結果を残しておこう。
text data bss dec hex filename
11336 16 17328 28680 7008 build/FreeRTOS1.elf
BSS、こんなに??
17KB近く使ってるじゃないか。。。
NUCLEOに載っているF411RETは、SRAMが128KBもあるので、まだ余裕があるといえばあるのだが、FreeRTOSとはいえ使いすぎじゃ無いか?
いや、待て。
新規プロジェクト生成直後で、FreeRTOS無しの場合を見ておこう。
text data bss dec hex filename
4812 12 1572 6396 18fc build/original.elf
ほぼ空なのに1.5KBも使っているのが気になるが、けっこうなサイズをFreeRTOSが確保することがわかった。
1.5KBも、ヒープサイズで0x200、スタックサイズとして0x400確保ししているためのようだ(STM32F411RETx_FLASH.ldの_Min_Heap_Sizeと_Min_Stack_Sizeだろう)。
FreeRTOSを使う場合も、ヒープとスタックは同じだけ確保している。
ただ、別途FreeRTOS用のヒープ領域を0x3c00確保しているので、もしFreeRTOS以外でヒープを使わないのであれば、Min_Heap_Sizeは0にしてよいのかもしれない(FreeRTOSが立ち上がるところで使うかもしれないので、断言はできんが。。)。
スタックもタスクごとに持たないとダメなんじゃなかろうか?
OSが無いなら、今実行しているメインスレッドのスタックと、割込みで実行するときのスタックがあれば済むだろうけど、メインスレッドのところが複数タスクになるので、それぞれのタスクでスタックを持っておかないとダメだろう、という考えだ。
FreeRTOSConfig.hにconfigMINIMAL_STACK_SIZEという定義があったから、これがスタックサイズなのだろう。
128だった。
その下にconfigTOTAL_HEAP_SIZEが15360で定義してあり、イコール0x3C00だ。
そういう感じで、configファイルに定義したものが反映されていくようだ。
ソースを取ってきて、Demoでも動かしてみよう、くらいしか書かれてない。。。
それ以外はリンク先をいろいろ見るようだが、PDFを売っているようなので本来はそっちを読んでほしいのだろう。
しかたないので、main.cを見ていく。
タスク生成しているのは、これだろう。
osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
defaultTaskHandleはosThreadId型なのでわかるし、StartDefaultTask()も関数があるのでわかる。
では、このヘッダにも定義がないdefaultTaskというのは何だ?
あー、osThreadDefはマクロだ。
const osThreadDef_t os_thread_def_##name = \
{ #name, (thread), (priority), (instances), (stacksz) }
ここだと、
const osThreadDef_t os_thread_def_defaultTask =
{ "defaultTask", StartDefaultTask, osPriorityNormal, 0, 128 };
defaultTaskHandle = osThreadCreate(&os_thread_def_defaultTask, NULL);
となる。
マクロで#を使うと、ダブルクォーテーションで展開されるんだな。
そしてosKernelStart()でカーネルが起動される、と。
main()はその後どうするかというと、無限ループになっている。
タイマ割込でラウンドロビンするのであれば、ここはWFIで寝かしてしまってもよいのだろうか?
__WFI()を入れてみたが、見て目には変わらないようだ。
ロジアナで点滅間隔を見てみるくらいしないとわからないかもね。
10msec間隔にしたが、まあこんなものか。
じゃあ、WFIした方がよいのかな?
あ、nRF5 SDKのサンプルを見ると、whileループしているのは同じだが、ループに入るとエラーハンドラが呼ばれるようになっている。
つまり、OSを終了しないと呼ばれないから、何があってもあまり関係ないということか。。。
開始するとIDLEタスクが作られているようだから、何もしていないときに無限ループで待つのではなく、IDLEタスクが実行されるだけか。
INCLUDE_xTaskGetIdleTaskHandleが1だと、IDLEタスクのハンドラを取得できるらしいが、IDLEタスクの関数を見ても何をやってるのかさっぱりわからん。。。
では、まねしてみよう。
まずはタスクを追加する。
今回は、UART2に送信を行うタスクにする(github)。
osThreadDef(uartTask, StartUartTask, osPriorityNormal, 0, 128);
osThreadCreate(osThread(uartTask), NULL);
名前が違うだけで、やっていることは同じですな。
起動されるタスクは、こう(github)。
void StartUartTask(void const * argument)
{
/* Infinite loop */
for(;;)
{
HAL_UART_Transmit(&huart2, "Hello!\r\n", 8, 200);
osDelay(500);
}
}
"Hello!"の出力を、500msec間隔で行うだけだ。
これで動いた。
uITRONだと、configurationファイルを書いてコンパイルするけど、FreeRTOSはヘッダファイルに書いてソースで作るだけのようだ。
これを静的にできるようになったのがV9なのかな?
0 件のコメント:
コメントを投稿
コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。
注: コメントを投稿できるのは、このブログのメンバーだけです。