FreeRTOSベースのESP-IDFキュー処理の実装
キューの基本概念
ESP-IDFで提供されるキュー(queue)は、タスク間および割込みコンテキスト間の安全なデータ交換を実現するための仕組みです。FIFO方式に基づき、構造体や基本型データのやり取りが可能です。
- タスク間通信のためのデータパイプとして機能
- ブロッキング/ノンブロッキングモードをサポート
- 割込みコンテキストからの安全なデータ送信が可能
通信メカニズムの比較
| メカニズム | データ転送 | 同期方式 | メモリ使用量 | 主な用途 |
|---|---|---|---|---|
| キュー | 可 | ブロッキング/ノンブロッキング | 中 | 構造化データのやり取り |
| イベントグループ | 不可(フラグのみ) | ビットマスク待機 | 極小 | 複数イベントの通知 |
| セマフォ | 不可 | カウント型/バイナリ | 小 | リソース管理 |
主要APIの使用方法
キュー操作に必要なヘッダーファイル:
#include "freertos/queue.h"
キューの生成
QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength, UBaseType_t uxItemSize);
- uxQueueLength:要素数(バイト数ではない)
- uxItemSize:各要素のサイズ(バイト単位)
- 戻り値:成功時はキューハンドル、失敗時はNULL
データ送信(タスクコンテキスト)
BaseType_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);
例:
QueueHandle_t q = xQueueCreate(5, sizeof(float));
float value = 3.14f;
xQueueSend(q, &value, pdMS_TO_TICKS(100));
データ受信(タスクコンテキスト)
BaseType_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait);
受信バッファは事前に確保が必要:
float buffer;
if(xQueueReceive(q, &buffer, portMAX_DELAY) == pdTRUE) {
// 受信処理
}
割込みコンテキストでの送信
BaseType_t xQueueSendFromISR(QueueHandle_t xQueue, const void *pvItemToQueue, BaseType_t *pxHigherPriorityTaskWoken);
注意点:
- 割込みサービスルーチン(ISR)内での使用限定
- 高優先度タスクの起床確認が必要
例:
void IRAM_ATTR gpio_isr_handler(void* arg) {
BaseType_t woken = pdFALSE;
int event = 1;
xQueueSendFromISR(event_queue, &event, &woken);
if(woken) portYIELD_FROM_ISR(woken);
}
プロジェクト実装例
温度・湿度センサーからのデータ統合処理:
typedef struct {
uint8_t type;
float value;
uint64_t timestamp;
} sensor_data_t;
void sensor_task(void *pvParams) {
sensor_data_t data;
while(1) {
// センサーデータ取得
data.value = get_sensor_value();
xQueueSend(sensor_queue, &data, pdMS_TO_TICKS(100));
vTaskDelay(pdMS_TO_TICKS(2000));
}
}
重要実装ポイント
- データ構造体のサイズ最適化(128バイト未満推奨)
- キュー長の適正設定(生産/消費速度比×安全率)
- ポインタ渡しの制限(メモリライフタイム管理が必要)
- portMAX_DELAYの適切な使用場面
メモリ使用量の計算式
キュー総容量 = 要素数 × 要素サイズ + 約44バイト
例:10要素×12バイト構造体 → 約164バイト
高度な使用法
- オーバーライトキュー(最新データ保持用)
- ストリームバッファ(バイトストリーム処理)
- キュー集合(複数ソースのイベント集約)