Basic Interrupt Example - 割り込みサンプル¶
BMI270のDATA_RDY割り込みを使用して、効率的にセンサーデータを取得するサンプルです。
特徴¶
- 効率的: CPU使用率が低い(データがない時はスリープ)
- 即応性: 新しいデータが即座に利用可能
- 実用的: バッテリー駆動アプリケーションに最適
ポーリングとの比較¶
| 項目 | ポーリング | 割り込み(本サンプル) |
|---|---|---|
| CPU使用率 | 高い(常時チェック) | 低い(データがある時のみ動作) |
| 応答性 | ポーリング間隔に依存 | 即座(数μs) |
| 消費電力 | 高い | 低い |
| 実装の難易度 | 簡単 | やや複雑 |
動作概要¶
- SPI通信初期化
- BMI270センサー初期化
- センサー設定(100Hz, ±4g, ±1000°/s)
- GPIO11をINT1割り込みピンとして設定
- BMI270のDATA_RDY割り込みを有効化
- データ準備完了時に割り込み発生
- セマフォでタスクを起床
- データ読み取り&出力
- タスクがスリープ(次の割り込みまで)
ハードウェア接続¶
このサンプルはM5StampFly向けに設定されています:
| BMI270 | ESP32-S3 GPIO | 用途 |
|---|---|---|
| MOSI | GPIO14 | SPI データ出力 |
| MISO | GPIO43 | SPI データ入力 |
| SCK | GPIO44 | SPI クロック |
| CS | GPIO46 | SPI チップセレクト |
| INT1 | GPIO11 | DATA_RDY割り込み |
ビルド&実行¶
# 開発環境のセットアップ
source setup_env.sh
# ターゲット設定(初回のみ)
cd examples/basic_interrupt
idf.py set-target esp32s3
# ビルド&書き込み
idf.py build flash monitor
期待される出力¶
I (XXX) BMI270_BASIC_INT: ========================================
I (XXX) BMI270_BASIC_INT: BMI270 Basic Interrupt Example
I (XXX) BMI270_BASIC_INT: ========================================
I (XXX) BMI270_BASIC_INT: Step 1: Initializing SPI bus...
I (XXX) BMI270_BASIC_INT: SPI initialized
I (XXX) BMI270_BASIC_INT: Step 2: Initializing BMI270 sensor...
I (XXX) BMI270_BASIC_INT: BMI270 initialized (CHIP_ID: 0x24)
I (XXX) BMI270_BASIC_INT: Step 3: Configuring sensors (100Hz, ±4g, ±1000°/s)...
I (XXX) BMI270_BASIC_INT: Step 4: Configuring GPIO INT1 (GPIO11)...
I (XXX) BMI270_BASIC_INT: Step 5: Creating semaphore...
I (XXX) BMI270_BASIC_INT: Step 6: Configuring DATA_RDY interrupt...
I (XXX) BMI270_BASIC_INT: DATA_RDY interrupt configured on INT1 (GPIO11)
I (XXX) BMI270_BASIC_INT: Step 7: Creating data acquisition task...
I (XXX) BMI270_BASIC_INT: Data acquisition task started (waiting for interrupts)
I (XXX) BMI270_BASIC_INT: ========================================
I (XXX) BMI270_BASIC_INT: Interrupt-driven data acquisition active
I (XXX) BMI270_BASIC_INT: Waiting for DATA_RDY interrupts @ 100Hz
I (XXX) BMI270_BASIC_INT: ========================================
I (XXX) BMI270_BASIC_INT: Sample #10:
I (XXX) BMI270_BASIC_INT: Gyro [rad/s]: X= -0.002 Y= 0.003 Z= -0.001
I (XXX) BMI270_BASIC_INT: Accel [g]: X= 0.012 Y= -0.024 Z= 0.995
I (XXX) BMI270_BASIC_INT: Temp [°C]: 25.50
>gyr_x:-0.002
>gyr_y:0.003
>gyr_z:-0.001
>acc_x:0.012
>acc_y:-0.024
>acc_z:0.995
割り込み動作の仕組み¶
INT1ピン設定¶
// INT1ピン: アクティブハイ、プッシュプル、出力有効
uint8_t int1_io_ctrl = (1 << 1) | (1 << 3);
bmi270_write_register(&g_dev, BMI270_REG_INT1_IO_CTRL, int1_io_ctrl);
DATA_RDY割り込みマッピング¶
// DATA_RDY割り込みをINT1にマッピング
uint8_t int_map_data = (1 << 2); // bit2: drdy_int -> INT1
bmi270_write_register(&g_dev, BMI270_REG_INT_MAP_DATA, int_map_data);
GPIO割り込みハンドラ¶
static void IRAM_ATTR bmi270_int1_isr_handler(void* arg)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
// セマフォを渡してタスクを起床
xSemaphoreGiveFromISR(data_ready_sem, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken) {
portYIELD_FROM_ISR();
}
}
パラメータ調整¶
サンプリング周波数を変更¶
200Hzに変更する場合:
#define SENSOR_ODR_HZ 200 // 100 → 200Hz
// センサー設定も変更
bmi270_set_accel_config(&g_dev, BMI270_ACC_ODR_200HZ, BMI270_FILTER_PERFORMANCE);
bmi270_set_gyro_config(&g_dev, BMI270_GYR_ODR_200HZ, BMI270_FILTER_PERFORMANCE);
注意: 割り込み周波数もODRに合わせて自動的に200Hzになります。
INT1をラッチモードにする¶
デフォルトは非ラッチモード(パルス)ですが、ラッチモードに変更可能:
// bit0=1でラッチモード有効
uint8_t int1_io_ctrl = (1 << 0) | (1 << 1) | (1 << 3);
bmi270_write_register(&g_dev, BMI270_REG_INT1_IO_CTRL, int1_io_ctrl);
ラッチモードの場合、INT_STATUS_1レジスタを読むとクリアされます。
CPU使用率の最適化¶
割り込み駆動の利点を最大限活用するために:
-
メインタスクを低優先度に
-
データ処理を最小化
- ISRハンドラ内では最小限の処理のみ
-
セマフォでタスクに処理を委譲
-
スリープモードを活用
- データがない時はタスクが自動的にブロック
- FreeRTOSがCPUを低消費電力モードに移行
次のステップ¶
さらに高度なデータ取得方法:
basic_fifo- FIFOバッファで複数フレームを一括読み取り
トラブルシューティング¶
割り込みが発生しない¶
- GPIO配線を確認
-
INT1ピン(GPIO11)が正しく接続されているか
-
INT1設定を確認
-
割り込みマッピングを確認
"Failed to create semaphore"¶
- ヒープメモリが不足している可能性
menuconfigでFreeRTOSヒープサイズを増やす
データ読み取りエラー¶
- 割り込みハンドラ内でSPI通信を行っていないか確認
- タスク内でのみSPI通信を実行
API仕様¶
詳細なAPI仕様はdocs/API.mdを参照してください。