以下の内容はhttps://gijin77.blog.jp/archives/2026-01.htmlより取得しました。


◆ESP32S3は16Mものフラッシュを積んでいるので、ひとつのボード内で複数の
 アプリを切り替えで実行する仕組み(ランチャー)を作ってみました。
 下記画像は、AI作成の単なるイメージです。
 app_select

1.概要
 ①パーティションをカスタムで区切ってそれぞれにアプリを入れます。
 ②まずは、メインとして各アプリを切り替えるランチャ部分を作ります。
  ここでは、普通にIDEで作り書き込みします。
 ➂次に、アプリ1~3をコンパイルしてバイナリファイルとして保存します。
 ④最後にアプリ1~3のバイナリファイルをflash_download_toolを使って
  指定されたアドレスに書き込んで終了です。

2.各フォルダの内容
 ◆全体のフォルダツリー
 フォルダーツリー

 ①mainフォルダに下記の2つのファイルを作成します。
  *IDE設定
  ・esp32s3 Dev
  ・USBCDCOnBoot="Enabled"
  ・Flash Size=16MB
  ・Partition Scheme: "Custom"
  ・PSRAM="Disabled"

  (1)main.ino
//main.ino
//V2025/01/31 By JK1VCK
//blog URL:https://gijin77.blog.jp/archives/46648023.html

//esp32s3 Dev USBCDCOnBoot="Enabled" Flash Size=16MB Partition Scheme: "Custom" PSRAM="Disabled"

//partitions.csv
//# Name,   Type, SubType,  Offset,   Size,     Flags
//nvs,      data, nvs,      0x9000,   0x5000,
//otadata,  data, ota,      0xe000,   0x2000,
//factory,  app,  factory,  0x10000, 3M,
//app1,     app,  ota_0,    0x310000, 3M,
//app2,     app,  ota_1,    0x610000, 3M,
//app3,     app,  ota_2,    0x910000, 3M,
//storage,  data, spiffs,   0xC10000, 3M,

#include <esp_ota_ops.h>
#include <esp_partition.h> // パーティション操作に必要

void bootApp(int index) {
    // 定数名を ESP_PARTITION_SUBTYPE_APP_OTA_x に修正
    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) {
        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);
    Serial.println("\n--- MAIN MENU ---");
    Serial.println("Send '1', '2', or '3' to switch apps.");
}

void loop() {
    if (Serial.available()) {
        char c = Serial.read();
        if (c == '1') bootApp(0);
        if (c == '2') bootApp(1);
        if (c == '3') bootApp(2);
    }
}

  (2)partitions.csv
 *各アプリに3Mのサイズを確保しています。ここを調整することでアプリ数を
  増やすことが出来ます。
# Name,   Type, SubType,  Offset,   Size,     Flags
nvs,      data, nvs,      0x9000,   0x5000,
otadata,  data, ota,      0xe000,   0x2000,
factory,  app,  factory,  0x10000, 3M,
app1,     app,  ota_0,    0x310000, 3M,
app2,     app,  ota_1,    0x610000, 3M,
app3,     app,  ota_2,    0x910000, 3M,
storage,  data, spiffs,   0xC10000, 3M,


 ②app1のフォルダ
  *IDE設定
  ・esp32s3 Dev
  ・USBCDCOnBoot="Enabled"
  ・Flash Size=4MB
  ・Partition Scheme: "Huge APP(3MB)"
  ・PSRAM="Disabled"

  (1)app1.ino
//app1.ino
//V2025/01/31 By JK1VCK
//blog URL:https://gijin77.blog.jp/archives/46648023.html

//esp32s3 Dev USBCDCOnBoot="Enabled" Flash Size=4MB Partition Scheme: "Huge APP(3MB)" PSRAM="Disabled"

#include <esp_ota_ops.h>
#include <esp_partition.h>

void setup() {
    Serial.begin(115200);
    delay(1000);
    pinMode(0, INPUT_PULLUP);
    // 次回リセット時はメイン(Factory)に戻るように設定
    // 定数名を ESP_PARTITION_SUBTYPE_APP_FACTORY に修正
    const esp_partition_t* factory = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
    
    if (factory != NULL) {
        esp_ota_set_boot_partition(factory);
        Serial.println("Next boot: Main Menu");
    }
    Serial.println("Greetings from [App 1]! (Reset to go back)");
}

void loop() {
  Serial.println("Runnig [App 1] (Reset to go back)");
  delay(1000);
  int d=digitalRead(0);
  if (d==0) esp_restart();
  // ここでアプリのメイン処理を行う
}


  (2)\build\esp32.esp32.esp32s3\app1.ino.bin
  *IDE内でバイナリファイルで保存します。
 IDE2bin

 ➂app2のフォルダ
  (1)app2.ino
  *app1.inoをコピーしてスケッチ内の「1」->「2」にしてapp2.inoとして保存します。
  (2)\build\esp32.esp32.esp32s3\app2.ino.bin
  *app1と同様にして作成します。
  
 ④app3のフォルダ
  (1)app3.ino
  *app1.inoをコピーしてスケッチ内の「1」->「3」にしてapp3.inoとして保存します。
  (2)\build\esp32.esp32.esp32s3\app3.ino.bin
  *app1と同様にして作成します。

4.バイナリファイルの書込み
 ①flash_download_tool_3.9.7.exeの実行
 *書き込みツールを持っていなければ下記よりダウンロードします。
  flash_download_tool_3.9.7.zip

 ②esp32s3を選択
 esp32s3_sel

 ➂app1~3のバイナリファイルを選択&アドレスを指定&COMとBAUDを指定
 0x3100_app1

 ④STARTで書き込み開始
 0x3100_app2

 ⑤FINSHが出たら「X」で終了
 0x3100_app3

5.実行時のシリアル出力

①電源ONでmain.inoが実行され、シリアル端末にて「1,2,3」で実行します。
②各アプリ内では、「boot」釦でメインに戻ります。
➂繰り返します。

*************************************************************************
(1)mainが実行中
現在起動中のパーティション: factory

--- MAIN MENU ---
Send '1', '2', or '3' to switch apps.  <---「1」を圧下
Switching to: app1

◆リブートメッセージ省略
Next boot: Main Menu
Greetings from [App 1]! (Reset to go back)
Runnig [App 1] (Reset to go back)  <---- app1が実行中
Runnig [App 1] (Reset to go back)
Runnig [App 1] (Reset to go back)
Runnig [App 1] (Reset to go back) <----「boot」を圧下

◆リブートメッセージ省略
現在起動中のパーティション: factory  <---mainに戻る

--- MAIN MENU ---
Send '1', '2', or '3' to switch apps.  <---「2」を圧下
Switching to: app2

◆リブートメッセージ省略
Next boot: Main Menu
Greetings from [App 2]! (Reset to go back)
Runnig [App 2] (Reset to go back)  <---- app2が実行中
Runnig [App 2] (Reset to go back)
Runnig [App 2] (Reset to go back) <----「boot」を圧下

◆リブートメッセージ省略
現在起動中のパーティション: factory  <---mainに戻る

--- MAIN MENU ---
Send '1', '2', or '3' to switch apps.  <---「3」を圧下
Switching to: app3

Next boot: Main Menu
Greetings from [App 3]! (Reset to go back)
Runnig [App 3] (Reset to go back)  <---- app3が実行中
Runnig [App 3] (Reset to go back)
Runnig [App 3] (Reset to go back)
Runnig [App 3] (Reset to go back) <----「boot」を圧下

◆リブートメッセージ省略
現在起動中のパーティション: factory  <---mainに戻る

--- MAIN MENU ---
Send '1', '2', or '3' to switch apps.

*************************************************************************
これでランチャーの基本が分かりましたのでこれから応用して行けます。

6.応用としてHU-086にてGUIのランチャーを作ってみました。
 hu-086_selector
 hu-086_radiko


今日は、ここまで


ブログトップへ

◆HU-086 ESP32S3 のボードの解析が出来たので「xiaozhi esp32」を V1.5.6からV2.1.0に
 バージョンアップしてみた。
hu-086_xiaozhi_1

 解析については、下記ブログ内記事を参照して下さい。
  ・hxfb HU-086 AI多機能スマートハンドヘルドキットを使ってみた(解析中)

1.まず下記よりV2.1.0のソースをダウンロードします。
  xiaozhi esp32のソースコード

2.準備
 ①ダウンロードしたzipファイルを適当なフォルダに解凍します。
 ②その中のボード「xiaozhi-esp32-2.1.0\main\boards\bread-compact-wifi-lcd」フォルダ内
  下記の二つのファイル「config.h」「compact_wifi_board_lcd.cc」を上書き保存します。

 (1)config.h
#ifndef _BOARD_CONFIG_H_
#define _BOARD_CONFIG_H_

#include <driver/gpio.h>

#define AUDIO_INPUT_SAMPLE_RATE  16000
#define AUDIO_OUTPUT_SAMPLE_RATE 24000

//HU-086 PDMマイク
#define AUDIO_I2S_MIC_GPIO_SCK  GPIO_NUM_5
#define AUDIO_I2S_MIC_GPIO_DIN  GPIO_NUM_4

//NS4186
#define AUDIO_I2S_SPK_GPIO_DOUT GPIO_NUM_7
#define AUDIO_I2S_SPK_GPIO_BCLK GPIO_NUM_15
#define AUDIO_I2S_SPK_GPIO_LRCK GPIO_NUM_16
#define PA_CTRL_GPIO            GPIO_NUM_17

#define BUILTIN_LED_GPIO        GPIO_NUM_6
#define BOOT_BUTTON_GPIO        GPIO_NUM_14 //down SW
#define TOUCH_BUTTON_GPIO       GPIO_NUM_NC
#define VOLUME_UP_BUTTON_GPIO   GPIO_NUM_46 //right SW
#define VOLUME_DOWN_BUTTON_GPIO GPIO_NUM_8  //left  SW

//HU-086
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_42
#define DISPLAY_MOSI_PIN      GPIO_NUM_39
#define DISPLAY_CLK_PIN       GPIO_NUM_40
#define DISPLAY_DC_PIN        GPIO_NUM_38
#define DISPLAY_RST_PIN       GPIO_NUM_41
#define DISPLAY_CS_PIN        GPIO_NUM_NC

//HU-086
#ifdef CONFIG_LCD_ST7789_240X320
#define LCD_TYPE_ST7789_SERIAL
#define DISPLAY_WIDTH   320 //240
#define DISPLAY_HEIGHT  240 //320
#define DISPLAY_MIRROR_X true //false
#define DISPLAY_MIRROR_Y false
#define DISPLAY_SWAP_XY true //false
#define DISPLAY_INVERT_COLOR    false //true
#define DISPLAY_RGB_ORDER  LCD_RGB_ELEMENT_ORDER_RGB
#define DISPLAY_OFFSET_X  0
#define DISPLAY_OFFSET_Y  0
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT true //false
#define DISPLAY_SPI_MODE 3 //0
#endif

#ifdef CONFIG_LCD_ST7789_240X320_NO_IPS
#define LCD_TYPE_ST7789_SERIAL
#define DISPLAY_WIDTH   240
#define DISPLAY_HEIGHT  320
#define DISPLAY_MIRROR_X false
#define DISPLAY_MIRROR_Y false
#define DISPLAY_SWAP_XY false
#define DISPLAY_INVERT_COLOR    false
#define DISPLAY_RGB_ORDER  LCD_RGB_ELEMENT_ORDER_RGB
#define DISPLAY_OFFSET_X  0
#define DISPLAY_OFFSET_Y  0
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
#define DISPLAY_SPI_MODE 0
#endif

// A MCP Test: Control a lamp
#define LAMP_GPIO GPIO_NUM_NC

#endif // _BOARD_CONFIG_H_

 (2)compact_wifi_board_lcd.cc

#include "wifi_board.h"
#include "codecs/no_audio_codec.h"
#include "display/lcd_display.h"
#include "system_reset.h"
#include "application.h"
#include "button.h"
#include "config.h"
#include "mcp_server.h"
#include "lamp_controller.h"
#include "led/single_led.h"
#include "assets/lang_config.h"

#include <esp_log.h>
#include <driver/i2c_master.h>
#include <esp_lcd_panel_vendor.h>
#include <esp_lcd_panel_io.h>
#include <esp_lcd_panel_ops.h>
#include <driver/spi_common.h>

#define TAG "CompactWifiBoardLCD"

class CompactWifiBoardLCD : public WifiBoard {
private:
 
    Button boot_button_;
    Button touch_button_;
    Button volume_up_button_;
    Button volume_down_button_;
    LcdDisplay* display_;

    void InitializeSpi() {
        spi_bus_config_t buscfg = {};
        buscfg.mosi_io_num = DISPLAY_MOSI_PIN;
        buscfg.miso_io_num = GPIO_NUM_NC;
        buscfg.sclk_io_num = DISPLAY_CLK_PIN;
        buscfg.quadwp_io_num = GPIO_NUM_NC;
        buscfg.quadhd_io_num = GPIO_NUM_NC;
        buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
        ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO));
    }

    void InitializeLcdDisplay() {
        esp_lcd_panel_io_handle_t panel_io = nullptr;
        esp_lcd_panel_handle_t panel = nullptr;
        // 液晶屏控制IO初始化
        ESP_LOGD(TAG, "Install panel IO");
        esp_lcd_panel_io_spi_config_t io_config = {};
        io_config.cs_gpio_num = DISPLAY_CS_PIN;
        io_config.dc_gpio_num = DISPLAY_DC_PIN;
        io_config.spi_mode = DISPLAY_SPI_MODE;
        io_config.pclk_hz = 40 * 1000 * 1000;
        io_config.trans_queue_depth = 10;
        io_config.lcd_cmd_bits = 8;
        io_config.lcd_param_bits = 8;
        ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI3_HOST, &io_config, &panel_io));

        // 初始化液晶屏驱动芯片
        ESP_LOGD(TAG, "Install LCD driver");
        esp_lcd_panel_dev_config_t panel_config = {};
        panel_config.reset_gpio_num = DISPLAY_RST_PIN;
        panel_config.rgb_ele_order = DISPLAY_RGB_ORDER;
        panel_config.bits_per_pixel = 16;
#if defined(LCD_TYPE_ILI9341_SERIAL)
        ESP_ERROR_CHECK(esp_lcd_new_panel_ili9341(panel_io, &panel_config, &panel));
#elif defined(LCD_TYPE_GC9A01_SERIAL)
        ESP_ERROR_CHECK(esp_lcd_new_panel_gc9a01(panel_io, &panel_config, &panel));
        gc9a01_vendor_config_t gc9107_vendor_config = {
            .init_cmds = gc9107_lcd_init_cmds,
            .init_cmds_size = sizeof(gc9107_lcd_init_cmds) / sizeof(gc9a01_lcd_init_cmd_t),
        };        
#else
        ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel));
#endif
        
        esp_lcd_panel_reset(panel);

        esp_lcd_panel_init(panel);
        esp_lcd_panel_invert_color(panel, DISPLAY_INVERT_COLOR);
        esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY);
        esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
#ifdef  LCD_TYPE_GC9A01_SERIAL
        panel_config.vendor_config = &gc9107_vendor_config;
#endif
        display_ = new SpiLcdDisplay(panel_io, panel,
                                    DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
    }

//NS4186用アンプON設定追加
    void pa_ctrl_init(void) {
        gpio_config_t io_conf = {
            .pin_bit_mask = 1ULL << PA_CTRL_GPIO,
            .mode = GPIO_MODE_OUTPUT,
            .pull_up_en = GPIO_PULLUP_DISABLE,
            .pull_down_en = GPIO_PULLDOWN_DISABLE,
            .intr_type = GPIO_INTR_DISABLE,
        };
        gpio_config(&io_conf);
        gpio_set_level(PA_CTRL_GPIO, 1);  // ★ アンプ ON
        printf(">>>>>amp on control gpio=%d\n", PA_CTRL_GPIO);
    }

    void InitializeButtons() {
        boot_button_.OnClick([this]() {
            auto& app = Application::GetInstance();
            if (app.GetDeviceState() == kDeviceStateStarting) {
                EnterWifiConfigMode();
                return;
            }
            app.ToggleChatState();
        });
//HU-086にあるSW追加(ボリュームup/down)        
        touch_button_.OnPressDown([this]() {
            Application::GetInstance().StartListening();
        });

        touch_button_.OnPressUp([this]() {
            Application::GetInstance().StopListening();
        });

        volume_up_button_.OnClick([this]() {
            auto codec = GetAudioCodec();
            auto volume = codec->output_volume() + 10;
            if (volume > 100) {
                volume = 100;
            }
            codec->SetOutputVolume(volume);
            GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume));
        });

        volume_up_button_.OnLongPress([this]() {
            GetAudioCodec()->SetOutputVolume(100);
            GetDisplay()->ShowNotification(Lang::Strings::MAX_VOLUME);
        });

        volume_down_button_.OnClick([this]() {
            auto codec = GetAudioCodec();
            auto volume = codec->output_volume() - 10;
            if (volume < 0) {
                volume = 0;
            }
            codec->SetOutputVolume(volume);
            GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume));
        });

        volume_down_button_.OnLongPress([this]() {
            GetAudioCodec()->SetOutputVolume(0);
            GetDisplay()->ShowNotification(Lang::Strings::MUTED);
        });        
    }

    // 物联网初始化,添加对 AI 可见设备
    void InitializeTools() {
        static LampController lamp(LAMP_GPIO);
    }

public:
    CompactWifiBoardLCD() :
        boot_button_(BOOT_BUTTON_GPIO),
        touch_button_(TOUCH_BUTTON_GPIO),
        volume_up_button_(VOLUME_UP_BUTTON_GPIO),
        volume_down_button_(VOLUME_DOWN_BUTTON_GPIO) {
        InitializeSpi();
        InitializeLcdDisplay();
        InitializeButtons();
        pa_ctrl_init();
        InitializeTools();
        if (DISPLAY_BACKLIGHT_PIN != GPIO_NUM_NC) {
            GetBacklight()->RestoreBrightness();
        }
        
    }
//HU-086は、LEDが付いていないけどgpio6が空いているよ
    virtual Led* GetLed() override {
      static SingleLed led(BUILTIN_LED_GPIO);
      return &led;
    }

//HU-086はPDMマイクであるよ
    virtual AudioCodec* GetAudioCodec() override {
        static NoAudioCodecSimplexPdm audio_codec(AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
            AUDIO_I2S_SPK_GPIO_BCLK, AUDIO_I2S_SPK_GPIO_LRCK, AUDIO_I2S_SPK_GPIO_DOUT,I2S_STD_SLOT_BOTH,
            AUDIO_I2S_MIC_GPIO_SCK, AUDIO_I2S_MIC_GPIO_DIN);
        return &audio_codec;
    }

    virtual Display* GetDisplay() override {
        return display_;
    }

    virtual Backlight* GetBacklight() override {
        if (DISPLAY_BACKLIGHT_PIN != GPIO_NUM_NC) {
            static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT);
            return &backlight;
        }
        return nullptr;
    }
};

DECLARE_BOARD(CompactWifiBoardLCD);

3.Visual Studio Codeでビルド&書き込みします。
 ①vscを立ち上げ、上記フォルダを開きます。
 ②その後下記一連の作業をします。エラー無く書き込めれば完成です。
 
 
  //hu-086 ビルド手順
  idf.py fullclean

  idf.py set-target esp32s3

  idf.py menuconfig

  Xiaozhi Assistant  --->
    Default Language (Chinese)  --->       (X) Japanese
    Board Type (Bread Compact WiFi (面包板))  ---> (X) Bread Compact WiFi + LCD (面包板) 
    Select display style (Enable default message style)  ---> (X) Enable WeChat Message Style 
    Wake Word Implementation Type (Wakenet model with AFE)  --->    ???????
  ESC ESC (Y)

  idf.py build

  *シリアルポートを設定する

  idf.py -p COM10 flash monitor

 ◆2026/02/01追加
  実行して、リブートする用でしたら「compact_wifi_board_lcd.cc」の
  154行をコメントアウトしてみて下さい。
  153:  void InitializeTools() {
  154:     //static LampController lamp(LAMP_GPIO);
  155:  }


4.その後「xiaozhi me」へデバイス登録します。
  デバイス登録等については、下記ブログ内記事を参照して下さい。
  ・小智「XiaoZhi」を ATOMS3/ESP32S3 にて 日本語 で話してみた
  
以上
 
 


ブログトップへ


◆面白そうなESP32S3内蔵のコンソールをAliExpressで見つけたので入手してみました。
 esp32_ai

 hu-086内容
 入手先は下記で
 LCDディスプレイスクリーン ゲームコンソール 電子キット 多機能デバイス 天気時計
 AIロボット 溶接練習 ルーズパーツ タイプC

 又は
 LCDディスプレイスクリーンゲームコンソール電子キット多機能デバイス天気時計
 AIロボット溶接練習キット(バッテリー付き)

 
1.取扱説明書
 HU-086 AI多機能スマートハンドヘルドキット取扱説明書

2.構成部品
 ①ESP32S3
 ESP32S3PinLayout

 ②オーディオIC NS4168 & スピーカ
 オーディオIC_NS4168
 ➂電源IC ETA9640 & バッテリー
 電源IC_ETA9460
 HU_086_電源コントロール

 ④2.4インチLCDディスプレイ,解像度240x320,10ピン
 S3_LCD_10ピン
 ◆下記は参考LCD
 2.4インチTFT LCDディスプレイ,解像度240x320,st7789vチップ,10ピン

 ⑤MicroSDカード
 MicroSD_ピンアサイン

 ⑥スイッチ入力 8入力
 ⑦電源スイッチ
  
3.回路図(現在作成中)
 ①回路図等の提供がないので現在パターンを追っかけ中(現在作成中)
 
 ②GPIOのピンアサインを作成中(2026/01/28修正)
 *IO4,5,6を修正しました。I2SマイクではなくPDMマイクでした。
 GPIOピン

4.プログラムをダウンロードできるようにアダプタを作成しました。
 (1)アダプタ作成
  ①ブート釦とリセット釦
  ②電源LED
  ➂USB-シリアルアダプタへのRXD,TXDの接続
  ④電源釦とパラレルにスライドスイッチを追加
   (読み書きの時、ずっと電源を入れておく為)
 ブートアダプタ
  hu-086ブートアダプタ

 (2)プログラムをダウンロードする前にいつでも購入時に戻せるように
  フラッシュメモリを吸い上げます。(バックアップします)
  下記ブログ内記事を参照して下さい。
  ・ESP32-S3 etc でフラッシュメモリの読み書きツールを作ってみた

  ①ブート釦を押しながら電源を入れます。
  ②ツールを使いバックアップします。

 (3)テスト用のスケッチを書き込みます。
  ①ブート釦を押しながら電源を入れます。
  ②IDEで書き込みます。
  ➂リセット釦を押し実行します。

5.確認できていない項目
 2026/1/24追記
 ST7789にて表示出来るようになりました。
 ①LCDの制御ICが分からず表示出来ていません。
 *ST7789,ILI9341,GC9A01等で試しましたが表示しませんでした。
 *どうにかして表示させたいのですが、解析する方法は有りませんでしょうか。
 *どなたか教えて下さい。
 *多分SPI接続と思われます。
 *LCDの10ピンのピン名(上記参考LCDの配置)
 LCD_S3
 HU-086_LCD_OK

6.解析済みの動作確認スケッチ
 (1)LCD表示試験
//hu_086_LCD.ino

#include <Arduino_GFX_Library.h>
#define TFT_MOSI 39 
#define TFT_CS   -1 
#define TFT_DC   38 
#define TFT_SCK  40 
#define TFT_RST  41 
#define TFT_BL   42 

Arduino_DataBus *bus = new Arduino_ESP32SPI(TFT_DC, TFT_CS, TFT_SCK, TFT_MOSI, -1);
Arduino_GFX *gfx = new Arduino_ST7789(bus, TFT_RST, 0);//

void setup() {
  Serial.begin(115200);
  delay(2000);
  Serial.println("<Program Start>");
  pinMode(TFT_BL, OUTPUT);
  Serial.println("BL L");
  digitalWrite(TFT_BL, LOW);
  if (!gfx->begin()) {
    Serial.println("gfx->begin NG"); 
  }else{
    Serial.println("gfx->begin OK"); 
  }
  gfx->invertDisplay(true);   // ← これの追加が必要 
  gfx->fillScreen(RED);delay(1000);
  gfx->fillScreen(GREEN);delay(1000);
  gfx->fillScreen(BLUE);delay(1000);
}
void loop() {
}
 hu-086_LCD_test

 (2)LCD以外の動作試験
 *SDカードのルートにある"test.mp3"を再生
 *左側4つの釦でボリューム減、右側4つの釦でボリューム増
  ①電源sw入力&電源制御
  ②MicroSDカード
  ➂オーディオ出力
  ④釦入力

//hu-086_test.ino
//V2026/01/22 By JK1VCK
//blog URL:https://gijin77.blog.jp/archives/46577853.html
//MicroSDカード オーディオ出力 スイッチ入力 電源制御 テストプログラム
//esp32s3 Dev USBCDCOnBoot=ds Flash=16MB P-Scheme: "16M Flash (3MB APP/9.9MB FATFS) psram=OPIPSRAM 

#include "Arduino.h"
#include "Audio.h"
#include "SD_MMC.h"

// I2Sピン設定
#define I2S_MIC_WS    4
#define I2S_MIC_SCK   5
#define I2S_MIC_SD    6
#define I2S_DOUT      7
#define I2S_BCLK     15
#define I2S_LRC      16
#define PA_CTRL      17

// SDカードピン設定(1-bit mode)
#define SD_CLK       10
#define SD_CMD        9
#define SD_D0        11

//電源コントロールピン設定
#define POWER_SW      2
#define POWER_CTRL    1

Audio audio;

//操作ボタンピン設定
int sw_pins[] = {18,8,46,14,45,48,47,21};
char sw_name[][6] ={"UP","LEFT","RIGHT","DOWN","B","STA","A","SEL"};
int vol=15;
int sw;
uint32_t ps_Time; //電源OFF
bool power_off_flg=false;

void setup() {  
  pinMode(POWER_SW, INPUT_PULLUP);
  pinMode(POWER_CTRL, OUTPUT);
  digitalWrite(POWER_CTRL, HIGH); //電源ON

	Serial.begin(115200);
  delay(1000);
  Serial.println("\n\nProgram Start\n");
  for (int i = 0; i < 8; i++) {
    pinMode(sw_pins[i], INPUT_PULLUP); //釦入力設定
  }  
  
  // アンプ制御ピンの初期化
  pinMode(PA_CTRL, OUTPUT);
  digitalWrite(PA_CTRL, HIGH); // アンプON
  
  // SDカードの初期化(1-bit mode)
  SD_MMC.setPins(SD_CLK, SD_CMD, SD_D0);
  if(!SD_MMC.begin("/sdcard", true)) { // true = 1-bit mode
    Serial.println("SDカード初期化失敗");
    return;
  }
  Serial.println("SDカード初期化成功");
  
  // I2Sの設定
  audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
  audio.setVolume(vol); // 0-21で音量設定
  Serial.printf("vol=%2d \n",vol);
  // MP3ファイルの再生
  while(!digitalRead(POWER_SW)); //電源SWがOFFになるのを待つ
  delay(100);
  audio.connecttoFS(SD_MMC, "/test.mp3"); // SDカードのルートにある"test.mp3"を再生
}

void loop(){
  if (audio.isRunning()) audio.loop();
  else audio.connecttoFS(SD_MMC, "/test.mp3"); // SDカードのルートにある"test.mp3"を再生
  if (!digitalRead(POWER_SW)) { //電源SW圧下により電源OFF
    delay(100);
    Serial.println("Power OFF");
    digitalWrite(POWER_CTRL, LOW); //電源OFF
  }
  for (int i = 0; i < 8; i++) {
    sw=digitalRead(sw_pins[i]);
    if (sw==0) {
      if (i<4) {vol--;if (vol<0) vol=0;}
      else {vol++;if (vol>21) vol=21;}
      audio.setVolume(vol);
      Serial.printf("sw_name=%5s vol=%2d \n",sw_name[i],vol);
      delay(200);
    }
  }
}

◆「xiaozhi esp32」をv2.1.0」にバージョンアップしてみました。
 詳しくは、下記ブログ内記事を参照して下さい
 ・HU-086 ESP32S3 で「xiaozhi esp32 v2.1.0」をソースから入れてみた
 hu-086_xiaozhi_1

◆アプリセレクターを通して4つのアプリを選択実行できるようにしました。
 基本は、下記ブログで
 ・ESP32S3 ArduinoIDE で簡易的なランチャーを作ってみた

 *HU-086については下記ブログで
 ・HU-086 ESP32S3ボードでマルチアプリセレクターを作ってみた

 hu-086_app4



最後に
◆今回のLCD表示不能について色々とChatGPTに教えてもらっていて
 本日、汎用の代わりのLCDをAliExpressに注文した後に、再度パターン
 確認してGPIOピンを確定してコンパイルしましたらST7789で表示出来ました。
 なんか不思議です。マーフィの法則にはまったみたいです。

下記は、ChatGPTからの最後のメッセージです。
*************************************************************************************

😂 それはもう **完全にマーフィの法則案件**ですね……
「新しい部品を注文した瞬間に、旧部品が素直になる」やつです。

でも、**ちゃんと理屈は通っています**。
少しだけ整理して、今回の“不思議”を言語化して締めますね。

---

## なぜ急に ST7789 で表示できたのか(冷静分析)

### ① 工場FWの影響が一度リセットされた可能性

* 工場FW実行後

  * LCD側の **電源順序 / VCOM / 内部レジスタ** が安定状態に入る
* その後 Arduino に書き換えると

  * **初期条件が変わって、ST7789初期化が通る**

👉 中華LCDでは **わりとある現象**です
(「一度目を覚ましたら次から素直」)

---

### ② GPIO確定作業で「偶然、正解順序を踏んだ」

* GPIO割り当て
* RST扱い(有効 / 無効)
* 初期化タイミング

これが **一番合う組み合わせ**にハマった可能性が高いです。

---

### ③ ST7789 は “割と寛容”

* RESET無しでも動く個体が多い
* CS / DC のタイミングが多少ズレても生きる
* SPI速度にも比較的強い

👉 **ILI9341 だったら詰んでた可能性**あります😅

---

## でも一番大事なこと

### 🔵 あなたの切り分けは「完全に正攻法」でした

* 配線疑い → OK
* GPIO限定 → OK
* RST単体テスト → 正しい
* SPI反応確認 → 正しい
* 工場FW依存疑い → 論理的

**どこにも無駄はなかった**です。

---

## 今回の教訓(実務あるある)

* ✔ 中華ESP32 LCDは「動いたら勝ち」
* ✔ ST7789 はとりあえず試す価値あり
* ✔ 「何も変えてないのに動いた」は
  → 実は **条件が1つだけ変わっている**

そして最大の教訓:

> **AliExpressで部品を注文すると、
> 既存部品が急に協力的になる**

これはもう電子工作界の定数です😂

---

## こちらこそ、ありがとうございました

ここまで **深く・丁寧に切り分けたやり取り**、
正直かなり楽しかったです。

また

* LCDが言うこと聞かない時
* ESP32-S3が無言の時
* 「これはマーフィか?」と思った時

いつでも呼んでください👍
*************************************************************************************


ブログトップへ

◆aitendo 2026福BOXに入っていた2.2インチTFT液晶モジュール★240x320★
 [M022C9328SPI]をESP32で使ってみました。
 ILI9328_LCD_4

 ドライバICがILI9328でかなり癖のあるものでちょっと手こずりました。
 ①aitendoの商品リンク
  2.2インチTFT液晶モジュール★240x320★ [M022C9328SPI]

1.準備
 ①商品説明の中のライブラリili9328SPIを下記よりダウンロードします。
  ライブラリili9328SPI
 
 ②ArduinoIDEへzip形式でライブラリをインストールします。

 ➂ライブラリの中のサンプルスケッチ
 「\ILI9328_Driver_Library\examples\textFillTest\textFillTest.ino」を
 ESP32用に書き換えます。
 5~16行の部分をESP32標準のSPIのGPIOに設定します。

#include <ili9328.h>
#include <SPI.h>
#include <Adafruit_GFX.h>

/* LCD pin define ESP32*/
// ピンアサイン
#define LCD_MISO 19
#define LCD_MOSI 23
#define LCD_SCK  18
#define LCD_CS    5
#define LCD_DC   17
#define LCD_RST  16
#define GFX_BL   -1 //LEDは、直接GNDに接続
//DC,MISOも接続しなくてもOK
/* ili9328 object */ ili9328SPI tft(LCD_CS, LCD_RST); //Beautiful Colors For UI. #define BLACK 0x29ea #define BLUE 0x2c17 #define RED 0xc1c5 #define GREEN 0x256c #define YELLOW 0xF621 #define WHITE 0xef9e void setup() { Serial.begin(115200); tft.begin(); Serial.println(F("Hello LCD World!!")); Serial.println(F("ILI9328 library test")); tft.fillScreen(BLACK); tft.setCursor(0,60); tft.setTextColor(YELLOW); tft.setTextSize(4); tft.println("Hello World!!"); tft.setTextColor(GREEN); tft.setTextSize(2); tft.println("Welcome to LCD World!"); tft.setTextColor(WHITE); tft.setTextSize(1); tft.println("Lorem ipsum dolor sit amet,"); tft.println("consectetur adipisicing elit,"); tft.println("sed do eiusmod tempor incididunt ut"); tft.println("labore et dolore magna aliqua."); delay(5000); Serial.println(F("Fill")); tft.fillScreen(BLACK); tft.fillScreen(RED); tft.fillScreen(GREEN); tft.fillScreen(BLUE); tft.fillScreen(BLACK); } void loop() { tft.fillRect(random(0, TFT_WIDTH - 1), random(0, TFT_HEIGHT - 1), random(0, TFT_WIDTH - 1), random(0, TFT_HEIGHT - 1), random(0xffff)); }
 ④これでコンパイルすると、Port関連のエラーが発生しますので
  ライブラリの中の「\ILI9328_Driver_Library\ili9328.h」ファイルの下記行の
  「uint32_t」の部分を修正します。

 42:  uint8_t CSpin, RSTpin, rotation;
 43:  uint32_t CSPinSet;
 44:  volatile uint32_t *CSPort;
 45  };

 ⑤修正したら再度コンパイル&書き込みすると表示されました。

 ILI9328_LCD_1

 ILI9328_LCD_3

ブログトップへ

◆27日ゲットした2026お楽しみ福BOXが、28日届きました。
 中身は、下記のようなものでした。色々遊べそうです。
 2026福BOX_all

◆入っていた中身で分かる範囲のaitendoの部品のURLを調べました。
 *保障無しの参考程度に(価格は税込み)

1.カタログのモジュール
 Aitendo_2026福BOX_1

 ①★特売品★みにサイズキャラクタ液晶モジュール★16x2★ [VHF162-32] ¥218
 ②パワーアンプモジュール [M2030S] 385
 ➂パーツボックス入り可変抵抗
 ④2.2インチTFT液晶モジュール★240x320★ [M022C9328SPI]  1,925
  ◆実際ESP32で表示させてみました。下記ブログ内記事参照
  ・aitendo 2.2インチTFT液晶モジュール [M022C9328SPI]をESP32で使ってみた
 ⑤マルチ出力DC-DCモジュール [3CH1117M2155]  544
 ⑥ヘッドホンアンプモジュール [M4881A] 434
 ⑦ヘッドホンアンプモジュール [AMP1308]  495
 ⑧DC-DC降圧モジュール [M2596S] 328
 ⑨★SPDT★スライドスイッチ(50個入) [SS12F15G5-50BX] 328
 ➉リレーモジュール★12V★ 該当なし 参考
 ⑪グラフィックス液晶モジュール★96x64★ [JLX9664B] 328
 ⑫★特価★RGBフルカラーLED(100個入) [570R709GBC-A] 328
 ⑬パーツボックス入りピンソケット 類似品 328
 ⑭★3W★モノラルパワーアンプモジュール [M8002E] 214
 ⑮★4桁★7セグLED表示器モジュール [TM4D1637] 434
 ⑯大電流出力可変DC/DCブーストコンバータ [M6287W] 218
 ⑰★φ50★スピーカユニット [SPK50R0403WA] 275
 ⑱グラフィックス液晶モジュール★SPI★ [B12832K13] 528
 ⑲★0.36★2線式LED電圧表示器★30V★ [VM3D-30V-036] 275
 ⑳DSPラジオモジュール [DSP-444] 528
 (21)ESP-32でいいの★ESP-32★ [R32D1] ESP32無し
 (22)★3W+3W★超薄D級パワーアンプモジュール [M8403A]  214
 (23)白色ユニバーサル基板 [UP-DWS] 50x70  110
 (24)★特売品★単3電池懐中電灯 [FL140T2A] 218
 (25)FMラジオモジュール [M5807MS8DA] Xtal無し 495??
 (26)★特売品★マイクロカードソケットモジュール(2個入) [TFP09-2-12B] 99x2
 (27)充電昇圧一体化モジュール [CHR4056]Type-C 324
 (28)ユニバーサル基板 
 (29)信号機LED [F5RGB-A] 99
 (30)8桁7セグLED表示器 [M-7SEG8D1638] 429
 (31)FMラジオモジュール [M5807MS5SA] Xtal無し275??

2.おまけのモジュール6点
 Aitendo_2026福BOX_2

 ①★特売品★LEDランプユニット [LED5050X24] ¥42
 ②★特売品★LEDドットマトリクス★8x8★1.48★ [1588] x4
 ➂315MHz帯4ch受信モジュール★2272★ [RX315-R19A] ¥628
 ④★HC-49/S★水晶発振子(10個入) [HC49/S] 7.023MHz ¥165
 ⑤★激安特価★フラットトップ円柱型昼白色LED(100個入) [LED0307W-WC] ¥218
 ⑥LCDモジュール ZM95005A-01-FPC

以上 遊ぶ時の参考になれば幸いです。


ブログトップへ



以上の内容はhttps://gijin77.blog.jp/archives/2026-01.htmlより取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14