pdf-icon

Arduino入門

2. デバイス&サンプル

5. 拡張モジュール&サンプル

アクセサリー

6. アプリケーション

Echo Pyramid Arduino 使用チュートリアル

1. 準備作業

Note
ファームウェア書き込み後は、USB Type-C ケーブルは AtomS3R ではなく Echo Pyramid 本体に接続してください。 AtomS3R の USB 接続はプログラムの書き込み時のみ必要で、通常動作中には不要です。 USB ケーブルが Echo Pyramid 本体に接続されていない場合、電源供給が不足して Echo Pyramid が正常に動作しない可能性があります。

本チュートリアルでは、AtomS3R と Echo Pyramid を組み合わせて使用する方法を説明します。各ホストデバイスでピン配置が異なるため、下記の互換性表を参照してください。

ピン互換性
各ホストデバイスごとにピン定義が異なるため、使用前に製品ドキュメント内の ピン互換性チャート を必ず確認し、実際の接続に合わせてサンプルプログラム内のピン定義を調整してください。

2. Echo Pyramid 通信概要

Echo Pyramid は、スマートボイスアプリケーション向けに設計された音声開発ベースで、M5Stack Atom シリーズ向けに設計された拡張ベースです。上部のピンヘッダに Atom コントローラを垂直に挿し込むことで、音声対話機能を備えたデバイスを素早く構築できます。ATOM モジュール(ESP32 / ESP32-S3 ベース)はメインコントローラとして動作し、音声処理、無線通信(Wi-Fi/Bluetooth)、IoT 接続などを担当し、音声アシスタントやスマートコントロールハブ、音声対応 IoT ターミナルなど、さまざまな音声インタラクションシナリオに適しています。

本デバイスは、高品質なオーディオシステムを備えており、ES8388 オーディオコーデックと ES7210 デュアルマイクフロントエンドおよび MEMS マイクにより、クリアな音声収音とノイズ抑制を実現します。AW87559 クラス D アンプで駆動される内蔵 2W スピーカーにより、十分な音量の音声出力が可能です。インタラクション面では、STM32G030F6P6 マイコンが静電容量式タッチキーと RGB LED を制御し、レスポンスの良いタッチ操作とダイナミックな視覚フィードバックを提供します。また Si5351 プログラマブルクロックジェネレータを内蔵しており、音声アプリケーションにおける安定したオーディオ性能を確保します。

  • Touch: 4 つの静電容量式タッチパッドにより、直感的なユーザー操作と素早い機能切り替えが可能です。

  • Microphone: デュアル MEMS マイクによりクリアな音声収音が可能で、音声認識や音声コマンドアプリケーションに適しています。

  • RGB LED: 内蔵のプログラマブル RGB LED は、ステータス表示や動的なライティングエフェクトなどの視覚フィードバックを提供します。

  • Speaker: 内蔵 2W スピーカーにより、音声応答、通知音、マルチメディア再生などのオーディオ出力を行えます。

3. ポート選択

AtomS3R 右側のボタンを押し続けた状態で、USB ケーブルを PC に接続します。

4. サンプルプログラム

以下のサンプルでは、Echo Pyramid の主要ハードウェア機能と基本的な使い方を紹介します。RGB LED 制御、音声の録音と再生、タッチ操作、マイク音声取得といった内容をカバーしており、簡単な Arduino プログラムを通してデバイスと対話し、主要なペリフェラルへアクセスする方法を学ぶことができます。サンプルプログラムを書き込むことで、RGB LED の制御、タッチパッドの検出、マイクとスピーカーを用いた音声録音・再生、およびシリアルモニタによる状態確認などを体験できます。

RGB LED

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
#include "M5Unified.h"
#include <M5EchoPyramid.h>

M5EchoPyramid ep;

int brightness = 0;
int step = 5;
bool rising = true;

int leds[4] = {0, 3, 7, 10};

void setup()
{
    M5.begin();
    Serial.begin(115200);

    Wire1.end();
    ep.begin(&Wire1, 38, 39, 6, 8, 5, 7, 44100);

    ep.ctrl().setBrightness(1, 100);
    ep.ctrl().setBrightness(2, 100);

    Serial.println("LED demo start");
}

void loop()
{
    if (rising)
    {
        brightness += step;
        if (brightness >= 255)
        {
            brightness = 255;
            rising = false;
        }
    }
    else
    {
        brightness -= step;
        if (brightness <= 10)
        {
            brightness = 10;
            rising = true;
        }
    }
    for (int i = 0; i < 4; i++)
    {
        ep.ctrl().setRGB(1, leds[i], brightness, 0, 255 - brightness);
        ep.ctrl().setRGB(2, leds[i], brightness, 0, 255 - brightness);
    }

    delay(40);
}

上記のプログラムを Arduino IDE にコピーし、アップロードボタンをクリックしてコンパイルと書き込みが完了するまで待ちます。プログラムが実行されると、Echo Pyramid の 2 つの LED リング上で、インデックス 0, 3, 7, 10 の 4 つの LED がスムーズなブレス(明滅)エフェクトで点灯します。LED の明るさは徐々に増減し、赤と青の間で色が変化して途中で紫のグラデーションになります。このアニメーションはループし続け、Echo Pyramid 上の RGB LED を制御する方法を示します。

Speaker

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
#include "M5Unified.h"
#include <M5EchoPyramid.h>

#define SAMPLE_RATE 44100
#define RECORD_SECONDS 5
#define FRAME_SIZE 256
#define TOTAL_SAMPLES (SAMPLE_RATE * RECORD_SECONDS)

M5EchoPyramid ep;

int16_t *recordBuffer = nullptr;
bool recordingBusy = false;

void recordAndPlay5s()
{
    if (recordingBusy) return;
    recordingBusy = true;

    Serial.println("Start 5s Recording...");

    int16_t mic[FRAME_SIZE];
    int16_t ref[FRAME_SIZE];
    int written = 0;

    while (written < TOTAL_SAMPLES) {
        ep.read(mic, ref, FRAME_SIZE);
        memcpy(recordBuffer + written, mic, FRAME_SIZE * sizeof(int16_t));
        written += FRAME_SIZE;
    }

    Serial.println("Recording Done.");
    delay(200);

    Serial.println("Start Playback...");

    int played = 0;
    while (played < TOTAL_SAMPLES) {
        ep.write(recordBuffer + played, FRAME_SIZE);
        played += FRAME_SIZE;
    }

    Serial.println("Playback Done.");

    recordingBusy = false;
}

void setup()
{
    M5.begin();
    Serial.begin(115200);
    delay(2000);

    Wire1.end();
    ep.begin(&Wire1, 38, 39, 6, 8, 5, 7, SAMPLE_RATE);

    ep.codec().setVolume(50);
    ep.codec().mute(false);

    recordBuffer = (int16_t *)malloc(TOTAL_SAMPLES * sizeof(int16_t));
    if (!recordBuffer) {
        Serial.println("Memory allocation failed!");
        while (1) {
            delay(1000);
        }
    }

    Serial.println("System Ready. Press touch1 to record & play 5s audio.");
}

void loop()
{
    if (ep.ctrl().isPressed(1)) {
        recordAndPlay5s();

        while (ep.ctrl().isPressed(1)) {
            delay(10);
        }
    }

    delay(10);
}

上記のプログラムを Arduino IDE にコピーし、アップロードボタンをクリックしてコンパイルと書き込みが完了するまで待ちます。デバイスが起動したら、Echo Pyramid 上のタッチボタン 1 を押すと録音が開始されます。デバイスは内蔵マイクから 5 秒間の音声を録音し、その生の PCM データをメモリに保存します。録音終了後、自動的にスピーカーから録音された音声を再生します。シリアルモニタには「Start 5s Recording...」「Recording Done.」「Start Playback...」「Playback Done.」などのメッセージが表示され、Echo Pyramid を使って音声を録音し直後に再生する一連の流れを確認できます。

Touch

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
#include "M5Unified.h"
#include <M5EchoPyramid.h>

#define INITIAL_BRIGHTNESS 50
#define INITIAL_VOLUME     50
#define STEP               5

M5EchoPyramid ep;

int brightnessLevel = INITIAL_BRIGHTNESS;
int volumeLevel     = INITIAL_VOLUME;

bool brightnessGestureActive = false;
bool volumeGestureActive     = false;

void applyBrightness()
{
    ep.ctrl().setBrightness(1, brightnessLevel);
    ep.ctrl().setBrightness(2, brightnessLevel);
}

void fillLedsColor(uint8_t r, uint8_t g, uint8_t b)
{
    for (int i = 0; i < 14; ++i) {
        ep.ctrl().setRGB(1, i, r, g, b);
        ep.ctrl().setRGB(2, i, r, g, b);
    }
}

void applyVolume()
{
    ep.codec().setVolume(volumeLevel);
}

void setup()
{
    M5.begin();
    Serial.begin(115200);
    delay(2000);

    Wire1.end();
    ep.begin(&Wire1, 38, 39, 6, 8, 5, 7, 44100);
    ep.codec().mute(false);

    fillLedsColor(255, 255, 255);
    applyBrightness();
    applyVolume();
}

void loop()
{
    bool t1 = ep.ctrl().isPressed(1);
    bool t2 = ep.ctrl().isPressed(2);
    bool t3 = ep.ctrl().isPressed(3);
    bool t4 = ep.ctrl().isPressed(4);

    if (!brightnessGestureActive) {
        if (t1 && !t2) {
            brightnessGestureActive = true;
            brightnessLevel += STEP;
            if (brightnessLevel > 100) brightnessLevel = 100;
            applyBrightness();
            Serial.printf("Brightness: %d%%\n", brightnessLevel);
        } else if (t2 && !t1) {
            brightnessGestureActive = true;
            brightnessLevel -= STEP;
            if (brightnessLevel < 0) brightnessLevel = 0;
            applyBrightness();
            Serial.printf("Brightness: %d%%\n", brightnessLevel);
        }
    } else {
        if (!t1 && !t2) {
            brightnessGestureActive = false;
        }
    }

    if (!volumeGestureActive) {
        if (t4 && !t3) {
            volumeGestureActive = true;
            volumeLevel += STEP;
            if (volumeLevel > 100) volumeLevel = 100;
            applyVolume();
            Serial.printf("Volume: %d%%\n", volumeLevel);
        } else if (t3 && !t4) {
            volumeGestureActive = true;
            volumeLevel -= STEP;
            if (volumeLevel < 0) volumeLevel = 0;
            applyVolume();
            Serial.printf("Volume: %d%%\n", volumeLevel);
        }
    } else {
        if (!t3 && !t4) {
            volumeGestureActive = false;
        }
    }

    delay(10);
}

上記のプログラムを Arduino IDE にコピーし、アップロードボタンをクリックしてコンパイルと書き込みが完了するまで待ちます。ファームウェアが Echo Pyramid 上で動作すると、4 つのタッチパッドを使って LED の明るさとスピーカー音量を制御できます。

Touch1 ~ Touch2: この 2 つのタッチパッドは、デバイスの LED 明るさを制御します。

  • Touch1: 押すたびに明るさを 5% ずつ増加させます。
  • Touch2: 押すたびに明るさを 5% ずつ減少させます。 明るさは 0% ~ 100% の範囲で変化し、更新後の値はシリアルモニタに表示されます。

Touch3 ~ Touch4: この 2 つのタッチパッドは、スピーカーの音量を制御します。

  • Touch4: 押すたびに音量を 5% ずつ増加させます。
  • Touch3: 押すたびに音量を 5% ずつ減少させます。 音量値も 0% ~ 100% の範囲で変化し、現在の値はシリアルモニタに表示されます。

Microphon

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
#include "M5Unified.h"
#include <M5EchoPyramid.h>

#define SAMPLE_RATE 44100
#define RECORD_SECONDS 5
#define FRAME_SIZE 256
#define TOTAL_SAMPLES (SAMPLE_RATE * RECORD_SECONDS)

M5EchoPyramid ep;

int16_t *recordBuffer = nullptr;
bool recordingBusy = false;

void record5s()
{
    if (recordingBusy) return;
    recordingBusy = true;

    Serial.println("Start 5s Recording...");

    int16_t mic[FRAME_SIZE];
    int16_t ref[FRAME_SIZE];

    int written = 0;

    while (written < TOTAL_SAMPLES) {
        ep.read(mic, ref, FRAME_SIZE);
        memcpy(recordBuffer + written, mic, FRAME_SIZE * sizeof(int16_t));
        written += FRAME_SIZE;
    }

    Serial.println("Recording Done.");

    const int channels = 1;
    const int bitsPerSample = 16;
    const int totalSamples = TOTAL_SAMPLES;
    const size_t totalBytes = totalSamples * sizeof(int16_t);
    const float durationSeconds = (float)totalSamples / SAMPLE_RATE;
    const int totalFrames = totalSamples / FRAME_SIZE;

    Serial.println("=== Record Info ===");
    Serial.printf("Sample rate    : %d Hz\n", SAMPLE_RATE);
    Serial.printf("Channels       : %d (mono)\n", channels);
    Serial.printf("Bits per sample: %d bit\n", bitsPerSample);
    Serial.printf("Total samples  : %d\n", totalSamples);
    Serial.printf("Total frames   : %d (frame size = %d)\n", totalFrames, FRAME_SIZE);
    Serial.printf("Total bytes    : %u (%.2f KB)\n", (unsigned int)totalBytes, totalBytes / 1024.0f);
    Serial.printf("Duration       : %.3f s\n", durationSeconds);
    Serial.println("====================");

    recordingBusy = false;
}

void setup()
{
    M5.begin();
    Serial.begin(115200);
    delay(2000);

    Wire1.end();

    ep.begin(&Wire1, 38, 39, 6, 8, 5, 7, SAMPLE_RATE);

    ep.codec().setVolume(50);
    ep.codec().mute(false);

    recordBuffer = (int16_t *)malloc(TOTAL_SAMPLES * sizeof(int16_t));
    if (!recordBuffer) {
        Serial.println("Memory allocation failed!");
        while (1) {
            delay(1000);
        }
    }

    Serial.println("System Ready. Press touch1 to record 5s audio.");
}

void loop()
{
    if (ep.ctrl().isPressed(1)) {
        record5s();

        while (ep.ctrl().isPressed(1)) {
            delay(10);
        }
    }

    delay(10);
}

上記のプログラムを Arduino IDE にコピーし、アップロードボタンをクリックしてコンパイルと書き込みが完了するまで待ちます。デバイスが起動したら、Echo Pyramid上のタッチボタン 1 を押すことで録音が開始されます。デバイスは内蔵マイクから 5 秒間の音声を録音し、その生 PCM データをメモリに保存します。同時に、サンプリング周波数(44.1 kHz)、チャンネル構成(モノラル)、ビット深度(16 ビット)、サンプル総数、フレーム数、データサイズ、録音時間などの情報をシリアルモニタに出力します。このサンプルにより、Echo Pyramid の音声インターフェースを用いてマイク音声データを取得し、録音パラメータを解析する方法を学ぶことができます。

5. コンパイルと書き込み

    1. ダウンロードモード:異なるデバイスにプログラムを書き込む前に、まずダウンロードモードへ切り替える必要があります。手順は使用するメインコントローラによって異なります。詳細は Arduino IDE 入門チュートリアル ページ下部の「デバイス別プログラム書き込みチュートリアル一覧」を参照し、各デバイスの具体的な操作方法を確認してください。
  • AtomS3R の場合、リセットボタンを約 2 秒間長押しし、内部の緑色 LED が点灯したら離します。この時点でデバイスはダウンロードモードに入り、書き込み待機状態となります。
    1. デバイスのポートを選択し、Arduino IDE 左上のコンパイル/書き込みボタンをクリックして、プログラムのコンパイルおよび書き込みが完了するまで待ちます。
On This Page