◆以前HU-086ボードでマルチアプリセレクターを作成したものを、ES3C28Pボードで
タッチ操作でするものを作ってみました。
タッチ操作でするものを作ってみました。
また、アプリも四つほど入れ込んでみました。
マルチアプリセレクターの基本は、下記ブログ内記事を参照して下さい。
(1)現在、下記の四つのアプリを選択して実行できます。
⓪main:メインのアプリセレクター
①app1:15puzzle(game)
②app2:パタパタ時計表示&RSSニュース音声出力
➂app3:rdiko&インターネットラジオ
④app4:xiaozhi-rsp32 ベトナムバージョン
フラシュメモリを調整することでもう少し増やせると思います。
(2)現在各アプリに下記のサイズを指定しています。
また下記パーティションアドレスに応じてflash_download_tool_3.9.7で書き込みます。
partitions.csvの内容
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
factory, app, factory, 0x10000, 1M, <-⓪main
app1, app, ota_0, 0x110000, 2M, <-①app1
app2, app, ota_1, 0x310000, 3M, <-②app2
app3, app, ota_2, 0x610000, 3M, <-➂app3
app4, app, ota_3, 0x910000, 4M, <-④app4
storage, data, spiffs, 0xD10000, 2M,
0.main:メインのアプリセレクターについて
①アプリ選択画面
②IDE設定
・esp32s3 Dev
・USBCDCOnBoot="Enabled"
・Flash Size=16MB
・Partition Scheme: "Custom"
・PSRAM="Disabled"
➂es3c28p_mainフォルダに下記の2つのファイルを作成します。
(1)es3c28p_main.ino スケッチ(保障無しの自己責任で)
//es3c28p_main.ino
//2026/03/01 By JK1VCK マルチアプリセレクター
//blog URL:https://gijin77.blog.jp/archives/46787383.html
#include <esp_ota_ops.h>
#include <esp_partition.h> // パーティション操作に必要
#include "FT6336U.h"
#include <Arduino_GFX_Library.h>
//IDE設定
//・esp32s3 Dev
//・USBCDCOnBoot="Enabled"
//・Flash Size=16MB
//・Partition Scheme: "Custom"
//・PSRAM="Disabled"
String board ="Hello ES3C28P ESP32S3";
#define TFT_DC 46
#define TFT_RST -1
#define TFT_CS 10
#define TFT_MOSI 11 //SDA
#define TFT_SCK 12 //SCL
#define TFT_MISO 13
#define GFX_BL 45
Arduino_DataBus *bus = new Arduino_ESP32SPI(TFT_DC, TFT_CS, TFT_SCK, TFT_MOSI, TFT_MISO);
Arduino_GFX *gfx = new Arduino_ILI9341(bus, TFT_RST, 0,true); // 240x320 2.8 LCD
#define I2S_MCLK 4
#define I2S_BCLK 5
#define I2S_DIN 6 //mic in
#define I2S_LRC 7
#define I2S_DOUT 8 //sp out
#define I2C_SCL 15
#define I2C_SDA 16
#define PA_ENABLE 1
#define TOUCH_INT 17
#define TOUCH_RST 18
FT6336U ft6336u(I2C_SDA, I2C_SCL, TOUCH_RST, TOUCH_INT);
FT6336U_TouchPointType tp;
// グローバル変数
uint16_t tX, tY;
int sel=0, old_sel=-1;
bool selok=false;
#define BW 240
#define BH 32
#define SY 48
#define SH 40
int c[5][4]={ // Button(220x36) display and touch area
// タッチ位置(x,y)からTb(n)でボタンのon/offやLCD上の操作ができます。
// Button area
// 0, 1, 2, 3, Tb(0-4)
// x, y, w, h, 1234567890123
{ 36, SY, BW , BH}, // 0 App1:15puzzle
{ 36, SY+SH, BW , BH}, // 1 App2:RSS News
{ 36, SY+SH*2, BW , BH}, // 2 App3:radiko
{ 36, SY+SH*3, BW , BH}, // 3 App4:xiaozhi
{ 96, SY+SH*4, 115 , BH}, // 4 SELECT
};
const char *btn[] ={"App1:15puzzle","App2:RSS News","App3:radiko","App4:xiaozhi","SELECT"};
//アプリセレクト
void bootApp(int index) {
esp_partition_subtype_t subtype = (esp_partition_subtype_t)(ESP_PARTITION_SUBTYPE_APP_OTA_0 + index);
// 指定したサブタイプのパーティションを探す
const esp_partition_t* target = esp_partition_find_first(ESP_PARTITION_TYPE_APP, subtype, NULL);
if (target != NULL) {
gfx->fillScreen(BLACK);
gfx->setTextColor(ORANGE);
gfx->setTextSize(2);
gfx->setCursor(50,100);
gfx->printf("Switching to: %s\n", target->label);
Serial.printf("Switching to: %s\n", target->label);
esp_ota_set_boot_partition(target);
delay(1000);
esp_restart();
} else {
Serial.println("Error: Partition not found!");
}
}
void setup() {
Serial.begin(115200);
delay(2000);
const esp_partition_t* running = esp_ota_get_running_partition();
Serial.printf("現在起動中のパーティション: %s\n", running->label);
// ===== ディスプレイ初期化 =====
pinMode(GFX_BL, OUTPUT);
digitalWrite(GFX_BL, HIGH); //バックライトON
if (!gfx->begin()) {
Serial.println("gfx->begin() failed!");
} else {
Serial.println("gfx->begin() OK!!");
}
gfx->setRotation(3);
gfx->fillScreen(RED);delay(300);
gfx->fillScreen(GREEN);delay(300);
gfx->fillScreen(BLUE);delay(300);
gfx->fillScreen(BLACK);
//タッチパネル初期化
ft6336u.begin();
Serial.print("FT6336U Firmware Version: ");
Serial.println(ft6336u.read_firmware_id());
Serial.print("FT6336U Device Mode: ");
Serial.println(ft6336u.read_device_mode());
dispmain();
}
void loop() {
int sel=select_app();
Serial.printf("sel No=%d \n",sel);
bootApp(sel);
}
void dispmain(){
gfx->setTextColor(ORANGE);
gfx->setTextSize(3);
gfx->setCursor(50,5);
gfx->print("App selector");
drawbutton();
}
int c_touch(){
selok=false;
if (getTouch(&tX,&tY)) {
if(Tb(4)) {selok=true;return 99;}
for (int t=0;t<4;t++) {
if(Tb(t)) {sel=t;return sel;}
}
}
return -1;
}
int select_app() {
Serial.println("select_file start");
for(;;){
if (c_touch()==-1) continue;
Serial.printf("sel No=%d selok=%d \n",sel,selok);
if (selok) break;
drawbutton();
delay(50);
}
return(sel);
}
bool Tb( int p ){ // Touch button : Find button and touch locations
Serial.printf("p=%d tX=%d tX0=%d tX2=%d tY=%d tY0=%d tY1=%d\n",p,tX,c[p][0],(c[p][0]+c[p][2]),tY,c[p][1],(c[p][1]+c[p][3]));
if (tX>c[p][0] && tX<(c[p][0]+c[p][2]) // x1,y1 check
&& tY>c[p][1] && tY<(c[p][1]+c[p][3])) // x2,y2 check
{return true;} // with position
return false; // without pos
}
void drawbutton() {
int x_of[]={4,4,4,4,4};
int y_of=4;
for (int p=0;p<5;p++) {
gfx->fillRect(c[p][0],c[p][1],c[p][2],c[p][3], BLACK);
gfx->drawRoundRect(c[p][0],c[p][1],c[p][2],c[p][3],10, GREEN);
gfx->setCursor(c[p][0]+x_of[p],c[p][1]+y_of);gfx->setTextSize(3);
if (p==sel) gfx->setTextColor(YELLOW);
else gfx->setTextColor(CYAN);
if (p==4) gfx->setTextColor(RED);
gfx->print(btn[p]);
}
}
//ft6336u_Touch
bool getTouch(uint16_t* tX,uint16_t* tY) {
static bool prevTouched = false; // 前回のタッチ状態を保持
bool touched = false;
int w = gfx->width();
int h = gfx->height();
int r = gfx->getRotation();
int tix, tiy;
tp = ft6336u.scan();
if (tp.tp[0].status) {
touched = true;
// 前回タッチしていなかった → 今回タッチした = 押した瞬間
if (!prevTouched) {
switch (r) {
case 1: tiy = h - tp.tp[0].x; tix = tp.tp[0].y; break;
case 2: tix = w - tp.tp[0].x; tiy = h - tp.tp[0].y; break;
case 3: tiy = tp.tp[0].x; tix = w - tp.tp[0].y; break;
default: tix = tp.tp[0].x; tiy = tp.tp[0].y; break;
}
Serial.printf("Touch Down: x=%d y=%d r=%d\n", tix, tiy, r);
//gfx->fillCircle(tix, tiy, 3, BLUE);lcd_flush();
*tX = tix;
*tY = tiy;
prevTouched = true; // 状態更新
return true; // ★押した瞬間だけ true
}
} else {
touched = false;
}
// 離したら状態リセット
if (!touched) {
prevTouched = false;
}
return false; // 押しっぱなしや離した後は false
}
(2)パーティションテーブル partitions.csv
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
factory, app, factory, 0x10000, 1M,
app1, app, ota_0, 0x110000, 2M,
app2, app, ota_1, 0x310000, 3M,
app3, app, ota_2, 0x610000, 3M,
app4, app, ota_3, 0x910000, 4M,
storage, data, spiffs, 0xD10000, 2M,
1.app1:15puzzle(game)について
◆下記ブログ内記事を参照して下さい。
◆下記ブログ内記事を参照して下さい。

3.app3:rdiko&インターネットラジオについて
◆下記ブログ内記事を参照して下さい。


4.app4:xiaozhi-rsp32 ベトナムバージョンについて
◆下記ブログ内記事を参照して下さい。
5.実際の切り替えデモ
以上





























