0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【FreeRTOS × ESP32】Task Notification(タスク通知)とは?最軽量の1対1同期

Last updated at Posted at 2026-01-17

この記事でわかること

  • 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 記事シリーズ

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?