環境構築:Arduino IDE 入門チュートリアルを参考に IDE をインストールし、使用する開発ボードに応じてボードパッケージと必要なドライバライブラリを導入してください。
使用ライブラリ:
使用ハードウェア製品:


本チュートリアルでは、AtomS3R と 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 スピーカーにより、音声応答、通知音、マルチメディア再生などのオーディオ出力を行えます。
AtomS3R 右側のボタンを押し続けた状態で、USB ケーブルを PC に接続します。
以下のサンプルでは、Echo Pyramid の主要ハードウェア機能と基本的な使い方を紹介します。RGB LED 制御、音声の録音と再生、タッチ操作、マイク音声取得といった内容をカバーしており、簡単な Arduino プログラムを通してデバイスと対話し、主要なペリフェラルへアクセスする方法を学ぶことができます。サンプルプログラムを書き込むことで、RGB LED の制御、タッチパッドの検出、マイクとスピーカーを用いた音声録音・再生、およびシリアルモニタによる状態確認などを体験できます。
#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 を制御する方法を示します。
#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 を使って音声を録音し直後に再生する一連の流れを確認できます。
#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 明るさを制御します。
Touch3 ~ Touch4:
この 2 つのタッチパッドは、スピーカーの音量を制御します。
#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 の音声インターフェースを用いてマイク音声データを取得し、録音パラメータを解析する方法を学ぶことができます。
