今回は待機関数のお話です。
投稿時の開発環境を記しておきます。
PC:Windows10 OS
IDE: STM32CubeIDE Version1.6.0
Configurator: STM32CubeMX Version6.2.1
Board: STM32Nucleo-F401RE
プロジェクトを作成する
IDEを起動し、File- New – STM32 Project を選択し、Target Selection ウィンドウが出たら Board Selector タブを選択し Boards List から NUCLEO-F401RE を選択し Next ボタンを押します。
Project 名に F401RtosV2Wait と入力し、Finishボタンを押します。
Initialize all peripherals with their default Mode ? と聞いてくるので Yesを押します。
RTOSを使えるように設定する
Pinout & Configuration – Categories – Middleware – FREERTOS を選択し、
Mode の Interface で CMSIS_V2 を選択します。
その下の Configuration – Tasks and Queues タブを選択し、 Addボタンを押します。
New Task のウィンドウが出てくるので、上から2つ目の Priority を osPritrityNormal に変更し OK ボタンを押します。
これで優先順位が同じ2つのスレッドが作成されることになります。
タイムベース ソースを変更する
Categories – System Core – SYS を選択し、SYS Mode and Configuration – Mode で
Timebase Source を Systick から TIM10 に変更しておきます。
FreeRTOSでは Systick 以外を使うことが推奨されているからです。
ビルドしてエラーがないことを確認しておきます。
main.c で以下の記述を確認しておきます。
スレッドに渡す構造体のpriority属性がどちらも osPriorityNormal になっていることを確認しておきます。
/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
.name = "defaultTask",
.stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityNormal,
};
/* Definitions for myTask02 */
osThreadId_t myTask02Handle;
const osThreadAttr_t myTask02_attributes = {
.name = "myTask02",
.stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityNormal,
};
/* USER CODE BEGIN PV */
main.c の 更に下の方にいくと StartDefaultTask(), StartTask02() が見つかります。
for()ループの中に osDelay(1); の記述があるので、これら2つにブレークポイントを貼ってプログラムを実行します。
交互にブレークすることが確認できます。
待機関数
osDelay()関数 を見ると概要が理解できます。
この関数を呼んだスレッドを Blocked 状態にして、他のスレッドに処理を譲るというものです。
「私は手が空いたので、皆さんお使いください」といったところでしょうか。
osDelay()に渡す引数の tick について
Core – Inc – FreeRTOSConfig.h に以下の記述があります。
#define configTICK_RATE_HZ ((TickType_t)1000)
ということで単位は msec になります。
osDelay(10)とすれば約10msecの待機を行います。
もうひとつ osDelayUntil() という関数があります。
以下のような使い方をすることで、より正確な時間待ちができるようです。
より正確な時間待ちをさせたい場合には、こちらを使ってみてください。
void Thread_1(void *arg)
{
uint32_t tick;
tick = osKernelGetTickCount();
for(;;)
{
tick += 1000U; // 定期的に1000ティックを遅らせる
osDelayUntil(tick);
function();
}
}
osDelay() と HAL_Delay()
osDelay() と HAL_Delay()の違いについて簡単に触れておきます。
HAL_Delay()の方は単なる時間つぶしで OS が関与しません。
osDelay()の方がOSが関与しているので、他のスレッドにタスク切り替えが行われます。
そうすると優先順位が同じ、これらのスレッドはタスク切り替えが行われないのでは?と思われますね。
osDelay(1) をそれぞれ HAL_Delay(1) に書き換えて、 HAL_Delay(1)にブレークを貼り、プログラムを実行させてみましょう。
それでも、両方のブレークポイントにやってくることが確認できました。
なぜでしょうか?
実はこのタスク切り替えはタイマー割り込みによって行われます。
これも設定で決めることができるのですが、上で説明した FreeRTOSConfig.h には出てきません。
Middlewares – Third_party – FreeRTOS – Source – include にある
FreeRTOS.h の 793 行目に以下の記述があります。
#ifndef configUSE_TIME_SLICING
#define configUSE_TIME_SLICING 1
#endif
タイムスライスを使うかどうか、をここで設定することができます。
試しにこの #define をコメントにすると、タスク切り替えは行われなくなりますので確認してみてください。
(注)確認後、もとに戻しておくことをお忘れなく。。
タイムスライスはデフォルトでは有効になっています。
ある意味、ムダと考えることもできると思います。
システム設計によってはタイムスライスを無効にすることも充分考えられると思います。
いかがでしたか?
待機関数について動作確認できましたか?
お疲れさまでした。