2016/08/18

[勉]FreeRTOS (3)

前回の、ほぼ素のままのソースをビルドした結果を残しておこう。

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ファイルに定義したものが反映されていくようだ。


FreeRTOS - Quick start guide

ソースを取ってきて、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()を入れてみたが、見て目には変わらないようだ。
ロジアナで点滅間隔を見てみるくらいしないとわからないかもね。

image

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 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。