この記事でわかること
- Task Notification(タスク通知)で何ができるか
- Semaphore / EventGroup との違い(1対1・最軽量)
- 最小サンプル(ESP32 ESP-IDFで動く)
- 主要API(Notify / Wait / Give / Take / FromISR)の役割
こんな方におすすめ
- 「条件が揃うまで待つ」「イベントが来たら起こす」を最軽量で書きたい
- セマフォやキューを使うほどでもない“通知”が増えてきた
- ISR(割り込み)→ タスク起床 をシンプルにしたい
1. Task Notificationとは
FreeRTOSの Task Notification(タスク通知) は、特定のタスクに対して
「通知を送る → 待っているタスクを起こす」ための 最軽量の仕組みです。
- 通知する側:指定タスクに Notify(通知)
- 待つ側:Notify を待ってブロック(CPUを使わない)
さらに特徴として、通知は タスクごとに持っている32bitの値(通知値) を使います。
この通知値を「カウント」「ビットフラグ」「値の受け渡し」に使えます。
2. Semaphore / EventGroup との違い
結論だけ先にまとめるとこうです。
- Task Notification:1対1の通知に最適(最軽量)
- Semaphore:共有リソース保護(排他)や複数タスクにも使える
- EventGroup:複数条件(AND/OR)の待ち合わせに強い
Task Notification は「特定の1タスクを起こしたい」用途で特に強いです。
一方で Queueのような複数要素FIFOは無い ため、複数データを溜めたい場合は Queue / (Message|Stream)Buffer が向きます。
3. 典型ユースケース
Task Notificationがハマるのは、たとえばこういう場面です。
- ISR(割り込み)が来たら「処理タスクを起こす」
- 受信タスクがデータを貯めたら「パースタスクを起こす」
- 初期化が終わったら「メイン処理タスクを起こす」
- 定周期タイマで「特定タスクに合図する」
「合図・通知」だけなら、セマフォよりもTask Notificationがシンプルになりやすいです。
4. 【最小サンプル】通知でタスクを起こす(ESP32 + ESP-IDF)
やりたいこと
- SenderTask:500msごとに ReceiverTask に通知を送る
- ReceiverTask:通知を待って起床し、回数を表示する
この例では「通知回数(カウント)」として使うために
xTaskNotifyGive() / ulTaskNotifyTake() を使います。
#include <cstdio>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
static TaskHandle_t receiverHandle = NULL;
static void SenderTask(void *pv)
{
for (;;) {
// 受信側に「通知(カウント+1)」を送る
xTaskNotifyGive(receiverHandle);
vTaskDelay(pdMS_TO_TICKS(500));
}
}
static void ReceiverTask(void *pv)
{
for (;;) {
// 通知が来るまで待つ(CPUを使わない)
// pdTRUE にすると「通知カウントを0にクリア」してから返す
uint32_t count = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
printf("[Receiver] notified! count=%u\n", (unsigned)count);
}
}
extern "C" void app_main(void)
{
xTaskCreate(ReceiverTask, "ReceiverTask", 2048, NULL, 5, &receiverHandle);
xTaskCreate(SenderTask, "SenderTask", 2048, NULL, 5, NULL);
}
動きのポイント
ReceiverTask は ulTaskNotifyTake() で 通知が来るまでブロック
SenderTask が xTaskNotifyGive() すると ReceiverTask が起床
「合図」用途ならこれが最短で書けます
5. 主要API
Task Notificationで最初に覚えるのは 通知する / 待つ の2つです。
ISRから使う場合だけ FromISR 系を追加で押さえます。
xTaskNotifyGive(通知:カウント用途)
指定タスクの通知値を +1 して、待っていれば起こします
xTaskNotifyGive(receiverHandle);
ulTaskNotifyTake(待つ:カウント用途)
通知が来るまで待つ(ブロック)
戻り値は「溜まっていた通知回数」
uint32_t count = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
xTaskNotify / xTaskNotifyWait(ビット/値として使う)
通知値を「ビットフラグ」や「数値」で使いたいときに使います。
// 例:ビットを立てる(eSetBits)
xTaskNotify(task, BIT0, eSetBits);
// 例:通知を待って、通知値(ビット)を受け取る
uint32_t val = 0;
xTaskNotifyWait(0, 0xFFFFFFFF, &val, portMAX_DELAY);
FromISR系(割り込みから通知する)
ISRから起こしたいときは通常版ではなく FromISR を使います。
BaseType_t hpw = pdFALSE;
vTaskNotifyGiveFromISR(receiverHandle, &hpw);
if (hpw) portYIELD_FROM_ISR();
6. 注意点
- 基本は 1対1向き
- 通知値は32bit。使い方(カウント/ビット/値)を設計で決める
- ISR内は重い処理をしない → 通知だけ投げて処理はタスク側へ
7. まとめ
- Task Notificationは FreeRTOS最軽量の通知機構
- 「合図」「起床」「1対1の同期」が最短で書ける
- タスクごとに「32bitの通知値」を1つ持つ
- 設計次第で機能が変わる
FreeRTOS × ESP32 記事シリーズ