M5Stackアプリの移植
2021.07.10

YouTube でも紹介しています。画像をクリックすると再生できます。
今回は、M5Stack用アプリをESP32S2 へ移植してみました。
M5StackはESP32を搭載しているので、M5Stack専用ライブラリーと、ESP32からESP32S2で変更になった部分に対応すればよいだけですので、
さほど難しくはありません。

m5stack/M5Stack
Github にある M5Stack Library から下記の3つを移植してみます。

M5Stack-SpaceShooter - スペースインベーダー for M5Stack
インベーダー風のゲームです。400行程度のソースコードでコーディングがとても綺麗でわかりやすいです。

nixietubeM5 - M5Stackでニキシー管ディスプレイを再現します
ニキシー管風の文字を表示させるアプリです。真っ暗な部屋で実行すると、まさにニキシー管です。

M5Stack-Pacman-JoyPSP - パックマン for M5Stack/PSP ジョイパッド、サウンド付き
ご存じバックマンです。今回は効果音WAVデータのDAC出力のみを行います。
■開発環境

ソースコードのビルドには、PlatformIOを使用しています。
Ref.Arduino開発環境構築 PlatformIO
■Unexpected Maker TinyS2

TinyS2 は ESP32-S2チップを搭載し、SPI Flash 4MB、PSRAM 2MB を実装しています。
■2.8 "240 × 320 SPI TFT LCD (ILI9341)

M5StackのLCDは、ILI9341ドライバ・ライブラリーを使用しています。
手元にあった解像度240x320のILI9341 SPIディスプレイを使用しました。
■5方向ナビゲーションボタンモジュール(ジョイスティック)

■配線
| TinyS2 | - | ILI9341 |
| GND | - | GND |
| 5V | - | LED |
| GPIO[14] | - | DC |
| 3V3 | - | RESET |
| 3V3 | - | VCC |
| GPIO[38] | - | CS |
| SPI MO[35] | - | SDI(MOSI) |
| SPI MI[36] | - | SDO(MISO) |
| SPI SCK[37] | - | SCK |
| | | JoyStick |
| GPIO[4] | - | LEFT |
| GPIO[5] | - | RIGHT |
| GPIO[6] | - | SET |
| GPIO[7] | - | RST |
| | | Speaker |
| DAC1 GPIO[17] | - | Speaker - 100Ω - GND |

■環境設定
$ mkdir ~/M5Stack
$ cd M5Stack
$ pio init -b tinypico
$ vi platformio.ini
[env:tinypico]
platform = https://github.com/platformio/platform-espressif32.git
platform_packages =
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32
board = tinypico
framework = arduino
board_build.mcu = esp32s2
build_flags =
-DBOARD_HAS_PSRAM
-mfix-esp32-psram-cache-issue
monitor_speed = 115200
lib_deps =
adafruit/Adafruit ILI9341@^1.5.7
adafruit/Adafruit BusIO@^1.7.5
adafruit/Adafruit GFX Library@^1.10.10
■M5Stack-SpaceShooter→ESP32への移植
M5Stack-SpaceShooter-master.zip を解凍して、M5Stack-SpaceShooter.ino を ~/M5Stack/src に配置します。
$ vi src/M5Stack-SpaceShooter.ino
1.ヘッダファイル関連
#include <M5Stack.h>
↓
#include <Arduino.h>
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
2.ILI9341ドライバ関連
void setup() {
....
M5.begin();
M5.Lcd.setRotation(0);//M5.Lcd.setRotation(3);
M5.Lcd.fillScreen(ILI9341_BLACK);
M5.Lcd.setTextColor(0x5E85);
M5.Lcd.setTextSize(4);
↓
#define SPI_miso 36
#define SPI_mosi 35
#define SPI_sck 37
#define SPI_tft_ss 38
#define SPI_tft_dc 14
#define SPI_tft_rst 9
Adafruit_ILI9341 tft = Adafruit_ILI9341(SPI_tft_ss, SPI_tft_dc, SPI_mosi, SPI_sck, SPI_tft_rst, SPI_miso);
void setup() {
....
tft.begin();
tft.setRotation(3);
tft.fillScreen(ILI9341_BLACK);
tft.setTextColor(0x5E85);
tft.setTextSize(4);
メソッド・変数名の変更
M5.Lcd.メソッド → tft.メソッド
BLACK → ILI9341_BLACK
WHITE → ILI9341_WHITE
MAGENTA → ILI9341_MAGENTA
YELLOW → ILI9341_YELLOW
BLUE → ILI9341_BLUE
RED → ILI9341_RED
3.ジョイスティック関連
void loop() {
if(M5.BtnA.isPressed()) { left () ;}
if(M5.BtnB.isPressed()) { right () ;}
if(M5.BtnC.isPressed()) { select() ;}
↓
#define BUTTON_A_PIN 4
#define BUTTON_B_PIN 5
#define BUTTON_C_PIN 6
boolean BtnA_isPressed() {
if(digitalRead(BUTTON_A_PIN)==0) return true;
return false;
}
boolean BtnB_isPressed() {
if(digitalRead(BUTTON_B_PIN)==0) return true;
return false;
}
boolean BtnC_isPressed() {
if(digitalRead(BUTTON_C_PIN)==0) return true;
return false;
}
void loop() {
if(BtnA_isPressed()) { left () ;}
if(BtnB_isPressed()) { right () ;}
if(BtnC_isPressed()) { select() ;}
4,その他
void loop() {
....
M5.update();
}
↓
void Btn_update() {
}
void loop() {
....
Btn_update();
}
TinyS2をRaspberry Pi にUSB接続後に、[BOOT]を押しながら[RESET]をクリックして、デバイスをダウンロードモードにします
$ pio run -t upload
[RESET]をクリックして、プログラムを起動します

→ M5Stack-SpaceShooter移植版ダウンロード
■nixietubeM5→ESP32への移植
nixietubeM5 は、ニキシー管を模した数字画像を表示するアプリです。
ニキシー管(Nixie Tube)は数字あるいは文字・記号の情報を表示する一種の冷陰極放電管(冷陰極管)です。
ガラス製で、数字あるいは文字などの形状をした多数の陰極と1つのメッシュ状陽極から構成され、内部は少量のアルゴンあるいはさらに少量の水銀を添加した0.15気圧以下のネオンガスで満たされています。
各陰極と陽極との間に約140 - 170Vの直流電圧が印加されると陰極から電子放出が起こり、陰極を覆うように赤橙色のグロー放電発光が生じるので数字などを認識することができます。
出典: フリー百科事典『ウィキペディア(Wikipedia)』
プログラムの移植では、ニキシー管を模した数字の画像配列データ alldigits.c を残して、ソースコードをすべて書換えました。
const unsigned long d0len = 4721;
......
const unsigned char d0[4721] = {
0xff,0xd8,0xff,0xe0,0x00,0x10,0x4a,0x46,0x49,0x46,
0x00,0x01,0x01,0x01,0x00,0x64,0x00,0x64,0x00,0x00,
0xff,0xdb,0x00,0x43,0x00,0x10,0x0b,0x0c,0x0e,0x0c,
0x0a,0x10,0x0e,0x0d,0x0e,0x12,0x11,0x10,0x13,0x18,
......
M5.Lcd.drawJpg(d0, d0len, xpos, 0);
M5Stack では、独自のdrawJpg() に画像配列データ、データ長、表示位置を引き渡すだけで表示できますが、
ESP32S2では、汎用的なpicojpegライブラリーを用います。
picojpeg と JPEG→Bitmap変換に関しては、下記の書籍を参考にしました。
Interface 2020年11月号
特集「ESP32で画像処理プログラム100」
第1章 画像処理プログラムを試す準備
第2章 明るさ&色
第3章 形&大きさ変換
第4章 フィルタ
第5章 拡大/回転/移動/膨張
第6章 画像分析
第7章 特殊加工
移植のポイント
picojpegの一般的な使い方としては、FILEクラスライブラリーを用いて、JPEG画像ファイルを読み込んでいます。
ファイルからではなく、画像配列からの読込みを行う場合は、Cの標準ライブラリーfmemopen()で、FILEディスクリプタを取得して、fread()で読み込んでいきます。
#include <stdio.h>
FILE *fileJpeg
boolean Jpg2Pixel(int digit, const unsigned char *data, const unsigned long len) {
....
if ((fileJpeg = fmemopen((void*)data, len, "rb"))==NULL) {
uint8_t pjpeg_callback(uint8_t* pBuf, uint8_t buf_size, uint8_t *pBytes_actually_read, void *pCallback_data) {
....
fread(pBuf,1,n,fileJpeg);
移植したプログラムでは、画像情報をPSRAM上に展開しています。
ESP32-S2では、ESP32とは、PSRAMを用いたメモリー操作が異なります。
~/src 配下に、alldigits.c, nixietubeM5.ino, picojpeg.c, picojpeg.h を配置します。
TinyS2をRaspberry Pi にUSB接続後に、[BOOT]を押しながら[RESET]をクリックして、デバイスをダウンロードモードにします
$ pio run -t upload
[RESET]をクリックして、プログラムを起動します

真っ暗な室内では、まさにニキシー管のような雰囲気を醸し出しています。
また、時刻表示に用いる場合には、画像を小さくするか、TFTライブラリーを使用せずに、直接アドレスを叩くように変更して高速化を図ってください。
→ nixietubeM5移植版ダウンロード
■パックマン for M5Stack/PSP ジョイパッド、サウンド付き
ここでは、効果音の配列データを読み込んで、DAC端子への出力のみを行ってみました。

ESP32 のDAC は、GPIO25,GPIO026に固定で割り振られていましたが、ESP32S2では、GPIO17,GPIO18に変更になっています。
$ cat /home/pi/.platformio/packages/framework-arduinoespressif32
@src-4942392190fa5de522c4d55bf2967706
/tools/sdk/esp32s2/include/hal/include/hal/dac_types.h
typedef enum {
DAC_CHANNEL_1 = 0, /*!< DAC channel 1 is GPIO25(ESP32) / GPIO17(ESP32S2) */
DAC_CHANNEL_2 = 1, /*!< DAC channel 2 is GPIO26(ESP32) / GPIO18(ESP32S2) */
DAC_CHANNEL_MAX,
} dac_channel_t;
ここでは、モノラル、8ビットのWAV配列データを読み込んで、DAC1に出力しています。
unsigned char PROGMEM pacman[33850] = {
0x52, 0x49, 0x46, 0x46, 0x32, 0x84,
0x00, 0x00, 0x57, 0x41, 0x56, 0x45,
0x66, 0x6D, 0x74, 0x20, 0x10, 0x00,
0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
0x40, 0x1F, 0x00, 0x00, 0x40, 0x1F,
0x00, 0x00, 0x01, 0x00, 0x08, 0x00,
・・・・
こういうときにポインタを使えるC言語は便利です。
読み込んだWAVデータに、ヘッダーファイルの構造体を重ね合わせて、サンプリング周波数や波形データ長を取得しています。
あとは、8ビットの波形データをdac_output_voltage()により、ピン出力しています。
#include <driver/dac.h>
#include "SoundData.h" // wav data with header
// The Canonical WAVE file format
typedef struct {
uint8_t ChunkID[4];
uint32_t ChunkSize;
uint8_t Format[4];
uint8_t Subchunk1ID[4];
uint32_t Subchunk1Size;
uint16_t AudioFormat;
uint16_t NumChannels;
uint32_t SampleRate;
uint32_t ByteRate;
uint16_t BlockAlign;
uint16_t BitPerSample;
uint8_t Subchunk2ID[4];
uint32_t Subchunk2Size;
} WAVE_FORMAT;
void play(unsigned char *audio) {
WAVE_FORMAT *pwf = (WAVE_FORMAT *)audio;
uint8_t *p;
uint16_t cnt;
uint16_t delayus;
delayus = 1000000/pwf->SampleRate;
dac_output_enable(DAC_CHANNEL_1);
cnt = pwf->Subchunk2Size;
p = audio + sizeof(WAVE_FORMAT);
while (cnt > 0) {
dac_output_voltage(DAC_CHANNEL_1, *p);
ets_delay_us(delayus);
p += pwf->NumChannels;
cnt -= pwf->NumChannels;
}
}
void setup() {
play(pacman);
delay(2000);
play(pacmanDeath);
delay(2000);
play(chomp);
delay(2000);
}
void loop() {}
音が鳴らない!、TinyS2ではDACピン出力が微弱なので、ピン出力を増幅してみると、ちゃんと効果音が聞こえてきました。
→ Packman効果音DAC出力限定版ダウンロード
■その他の情報
・Raspberry Pi Picoによる液晶ゲーム制作
・MachiKania(マチカニア)
・Arduino Space Invaders – Making on Stripboard
・ESP32でゲームを作ってみた
・Detailed explanation of WAV file format
|
Raspberry Pi(ラズベリー パイ)は、ARMプロセッサを搭載したシングルボードコンピュータ。イギリスのラズベリーパイ財団によって開発されている。
たいていのことは100日あれば、うまくいく。長田英知著
「時間がなくて、なかなか自分のやりたいことができない」
「一念発起して何かを始めても、いつも三日坊主で終わってしまう」
「色んなことを先延ばしにしたまま、時間だけが過ぎていく」
そこで本書では、そんな著者が独自に開発した、
まったく新しい目標達成メソッド「100日デザイン」について、
その知識と技術を、余すところなくご紹介します。
まんがで納得ナポレオン・ヒル 思考は現実化する
OLとして雑務をこなす日々に飽き足らず、科学者だった父が残した薬品を商品化すべく、起業を決意した内山麻由(27)。彼女はセミナーで知り合った謎の女性からサポートを得ながら、彼女と二人三脚でナポレオン・ヒルの成功哲学を実践し、さまざまな問題を乗り越えていく。
ヒル博士の<ゴールデンルール>に従い、仕事に、恋に全力疾走する彼女の、成功への物語。
今日は人生最悪で最高の日 1秒で世界を変えるたったひとつの方法 ひすいこたろう著
偉人の伝記を読むと、最悪な日は、不幸な日ではなく、新しい自分が始まる日であることがわかります。最悪な出来事は、自分の人生が、想像を超えて面白くなる兆しなのです。偉人伝を読むことで、このときの不幸があったおかげで、未来にこういう幸せがくるのかと、人生を俯瞰する視線が立ち上がるのです。
ご飯は私を裏切らない heisoku著
辛い現実から目を背けて食べるご飯は、いつも美味しく幸せを届けてくれる。
29歳、中卒、恋人いない歴イコール年齢。バイト以外の職歴もなく、短期バイトを転々とする日々。ぐるぐると思索に耽るけど、ご飯を食べると幸せになれる。奇才の新鋭・heisokuが贈るリアル労働グルメ物語!
【最新版Gemini 3に対応!】できるGemini (できるシリーズ)
Geminiを「最強の知的生産パートナー」として使いこなすための、実践的なノウハウを凝縮した一冊です。
基本的な操作方法から、具体的なビジネスシーンでの活用、日々の業務を自動化するGoogle Workspaceとの連携、さらには自分だけのオリジナルAIを作成する方法まで余すところなく解説します。
Rustプログラミング完全ガイド 他言語との比較で違いが分かる!
Rustの各手法や考え方を幅広く解説!
500以上のサンプルを掲載。実行結果も確認。
全24章の包括的なチュートリアル。
ポチらせる文章術
販売サイト・ネット広告・メルマガ・ブログ・ホームページ・SNS…
全WEB媒体で効果バツグン!
カリスマコピーライターが教える「見てもらう」「買ってもらう」「共感してもらう」すべてに効くネット文章術
小型で便利な Type-C アダプター USB C オス - USB3.1 オスアダプター
Type-C端子のマイコンボードをこのアダプタを介して直接Raspberry Piに挿すことができます。ケーブルなしで便利なツールです。
Divoom Ditoo Pro ワイヤレススピーカー
15W高音質重低音/青軸キーボード/Bluetooth5.3/ピクセルアート 専用アプリ/USB接続/microSDカード
電源供給USBケーブル スリム 【5本セット】
USB電源ケーブル 5V DC電源供給ケーブル スリム 【5本セット】 電源供給 バッテリー 修理 自作 DIY 電子工作 (100cm)
|