Edge Impulse検証(3)ーM5Stack製ESP32CAM PSRAMの故障調査

前回の続き

今回の内容は以前私が投稿したEdge Impulse検証(2)ーM5Stack製ESP32CAM PSRAMの使用の続きです。内容の把握のため以前の投稿を読んでいただくことをお勧めします。

前回Edge ImpulseとM5stack製ESP32CAM PSRAMを使用して物体検出プログラムを実行しました。

しかしその後すぐ機能停止してしまい、物体検出が再現できなくなってしまいました。マイコンが故障したと思われます。

新しくESP32CAM PSRAMを購入してもよかったのですが、本当に故障したのか検証しようと思います。

ChatGPTに相談だ

私にはこうしたケースの対処法を知りません。なのでChatGPT君に相談しました。

m5stackのesp32cam psramを使ったプログラムcamera web serverが動かない。コンパイルも書き込みも成功するが実行するとエラーが吐き出されて動かない。数ヶ月前は動いていたがある日突然動かなくなった。マイコンが故障したのかプログラムに問題があるのか検証するためにcameraweb server以外のプログラムで検証したい。

了解しました!camera web server が突然動かなくなったとのことで、マイコンの故障かプログラムの問題かを切り分けるため、camera 機能を使わない「LED点滅」などの簡単なテストスケッチをまず実行してみましょう。

という感じでトライプログラムを3つ教えてくれたのでそれを実行しました。

トライプログラムで検証

今回USB type Cケーブルを新しく購入しました。

今まではM5stack製品などを購入した際についてきた付属品ケーブルを使っていましたが、通信速度が遅いとエラーの原因となる可能性もあり、USB3.1の比較的新しいものを購入しました。

 

今回はこちらを使用してプログラミングしていきます。

Lチカ

void setup() {
  pinMode(14, OUTPUT);  // 通常、ESP32-CAMのLEDフラッシュは GPIO33
}


void loop() {
  digitalWrite(14, HIGH);  // 点灯
  delay(500);
  digitalWrite(14, LOW);   // 消灯
  delay(500);
}

簡単に本体LEDを点滅させるプログラムを実行しました。

ChatGPTに出力させたプログラムですが、本体LEDのGPIO番号が誤っていたのでそこだけ修正しています。

無事本体LEDが点滅しました。これでマイコンは故障していないことはわかります。

シリアル通信

次に提案してくれたプログラムはシリアル通信のプログラムです。

void setup() {
  Serial.begin(115200);
  Serial.println("ESP32 起動完了!");
}


void loop() {
  Serial.println("動作中...");
  delay(1000);
}

ESP32が起動したらシリアルモニタにて”ESP32起動完了”の文字列が表示されます。その後1秒ごとに”動作中…”の文字列が出力されます。

こちらも問題なく機能しました。

Wifi通信

#include <WiFi.h>


const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";


void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);


  Serial.print("WiFi接続中");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }


  Serial.println("");
  Serial.println("WiFi接続成功!");
  Serial.println(WiFi.localIP());
}


void loop() {
  // WiFiが生きてるか確認
  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("WiFi接続継続中");
  } else {
    Serial.println("WiFi切断!");
  }
  delay(2000);
}

WiFiのプログラムです。”YOUR_SSID”と”YOUR_PASSWORD”に自宅のWiFi機器のものに書き換えてください。

こちらも問題なくWiFi接続されました。
どうやらマイコン本体は故障していないようです。

Camera web serverプログラムの改善

ここまでで原因が突き止められませんでした。カメラ側の故障かもしれません。

そこでESP32CAMのプログラム例”Camera web server”に以下のプログラムを追加してどこまで故障しているかを調査しました。

//カメラの初期化エラー
esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }

//PSRAMの故障有無
  if (!psramFound()) {
    Serial.println("❌ PSRAM が見つかりません!");
  } else {
    Serial.println("✅ PSRAM OK");
  }

//カメラフレームの取得可否
camera_fb_t * fb = esp_camera_fb_get();
  if (!fb) {
    Serial.println("❌ カメラフレーム取得失敗(fb == NULL)");
  } else {
    Serial.println("✅ カメラフレーム取得成功!");
    esp_camera_fb_return(fb);
  }

ここでは3つの項目にわたって調査します。

“カメラの初期化エラー”はCamera web serverにも記載されているプログラムです。カメラの初期化に失敗したらシリアルモニタに”Camera init failed with error”が表示されます。

“PSRAMの故障有無”ではPSRAMと通信を行い、認識されなかったら”❌ PSRAM が見つかりません!”、認識されたら”✅ PSRAM OK”が表示されます。こちらはCamera web serverに無かったので追加しました。

“カメラフレームの取得可否”でカメラから画像情報が取得できるかを確認します。こちらも追加したものです。

これらの情報を2025/6/1時点で最新のCamera web serverプログラムに追記したものが以下となります。

#include "esp_camera.h"
#include <WiFi.h>


//
// WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality
//            Ensure ESP32 Wrover Module or other board with PSRAM is selected
//            Partial images will be transmitted if image exceeds buffer size
//
//            You must select partition scheme from the board menu that has at least 3MB APP space.
//            Face Recognition is DISABLED for ESP32 and ESP32-S2, because it takes up from 15
//            seconds to process single frame. Face Detection is ENABLED if PSRAM is enabled as well


// ===================
// Select camera model
// ===================
//#define CAMERA_MODEL_WROVER_KIT // Has PSRAM
//#define CAMERA_MODEL_ESP_EYE  // Has PSRAM
//#define CAMERA_MODEL_ESP32S3_EYE // Has PSRAM
//#define CAMERA_MODEL_M5STACK_PSRAM // Has PSRAM
#define CAMERA_MODEL_M5STACK_V2_PSRAM // M5Camera version B Has PSRAM
//#define CAMERA_MODEL_M5STACK_WIDE // Has PSRAM
//#define CAMERA_MODEL_M5STACK_ESP32CAM // No PSRAM
//#define CAMERA_MODEL_M5STACK_UNITCAM // No PSRAM
//#define CAMERA_MODEL_M5STACK_CAMS3_UNIT  // Has PSRAM
//#define CAMERA_MODEL_AI_THINKER // Has PSRAM
//#define CAMERA_MODEL_TTGO_T_JOURNAL // No PSRAM
//#define CAMERA_MODEL_XIAO_ESP32S3 // Has PSRAM
// ** Espressif Internal Boards **
//#define CAMERA_MODEL_ESP32_CAM_BOARD
//#define CAMERA_MODEL_ESP32S2_CAM_BOARD
//#define CAMERA_MODEL_ESP32S3_CAM_LCD
//#define CAMERA_MODEL_DFRobot_FireBeetle2_ESP32S3 // Has PSRAM
//#define CAMERA_MODEL_DFRobot_Romeo_ESP32S3 // Has PSRAM
#include "camera_pins.h"


// ===========================
// Enter your WiFi credentials
// ===========================
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";


void startCameraServer();
void setupLedFlash(int pin);


void setup() {
  Serial.begin(115200);
  Serial.setDebugOutput(true);
  Serial.println();


  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sccb_sda = SIOD_GPIO_NUM;
  config.pin_sccb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.frame_size = FRAMESIZE_UXGA;
  config.pixel_format = PIXFORMAT_JPEG;  // for streaming
  //config.pixel_format = PIXFORMAT_RGB565; // for face detection/recognition
  config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
  config.fb_location = CAMERA_FB_IN_PSRAM;
  config.jpeg_quality = 12;
  config.fb_count = 1;


  // if PSRAM IC present, init with UXGA resolution and higher JPEG quality
  //                      for larger pre-allocated frame buffer.
  if (config.pixel_format == PIXFORMAT_JPEG) {
    if (psramFound()) {
      config.jpeg_quality = 10;
      config.fb_count = 2;
      config.grab_mode = CAMERA_GRAB_LATEST;
    } else {
      // Limit the frame size when PSRAM is not available
      config.frame_size = FRAMESIZE_SVGA;
      config.fb_location = CAMERA_FB_IN_DRAM;
    }
  } else {
    // Best option for face detection/recognition
    config.frame_size = FRAMESIZE_240X240;
#if CONFIG_IDF_TARGET_ESP32S3
    config.fb_count = 2;
#endif
  }


#if defined(CAMERA_MODEL_ESP_EYE)
  pinMode(13, INPUT_PULLUP);
  pinMode(14, INPUT_PULLUP);
#endif


  // camera init
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }


  if (!psramFound()) {
    Serial.println("❌ PSRAM が見つかりません!");
  } else {
    Serial.println("✅ PSRAM OK");
  }


camera_fb_t * fb = esp_camera_fb_get();
  if (!fb) {
    Serial.println("❌ カメラフレーム取得失敗(fb == NULL)");
  } else {
    Serial.println("✅ カメラフレーム取得成功!");
    esp_camera_fb_return(fb);
  }


  sensor_t *s = esp_camera_sensor_get();
  // initial sensors are flipped vertically and colors are a bit saturated
  if (s->id.PID == OV3660_PID) {
    s->set_vflip(s, 1);        // flip it back
    s->set_brightness(s, 1);   // up the brightness just a bit
    s->set_saturation(s, -2);  // lower the saturation
  }
  // drop down frame size for higher initial frame rate
  if (config.pixel_format == PIXFORMAT_JPEG) {
    s->set_framesize(s, FRAMESIZE_QVGA);
  }


#if defined(CAMERA_MODEL_M5STACK_WIDE) || defined(CAMERA_MODEL_M5STACK_ESP32CAM)
  s->set_vflip(s, 1);
  s->set_hmirror(s, 1);
#endif


#if defined(CAMERA_MODEL_ESP32S3_EYE)
  s->set_vflip(s, 1);
#endif


// Setup LED FLash if LED pin is defined in camera_pins.h
#if defined(LED_GPIO_NUM)
  setupLedFlash(LED_GPIO_NUM);
#endif


  WiFi.begin(ssid, password);
  WiFi.setSleep(false);


  Serial.print("WiFi connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");


  startCameraServer();


  Serial.print("Camera Ready! Use 'http://");
  Serial.print(WiFi.localIP());
  Serial.println("' to connect");
}


void loop() {
  // Do nothing. Everything is done in another task by the web server
  delay(10000);
}

※こちらは追記位置がわかるように記載したものなので、実際のプログラムはESP32CAMのスケッチ例からダウンロードしてください。

またAruduino IDEでは初期設定でPSRAMが非適用となっています。「ツール」→「PSRAM」からチェックマークを”Enabled”に変更してからプログラムを書き込んでください。

実行すると以下のような文章がシリアルモニタに出力されました。

✅PSRAM OK

✖カメラフレーム取得失敗(fb == NULL)

カメラ初期化には成功。PSRAMも故障していない。しかしカメラフレームが取得できないことが判明しました。

この後ブラウザ上でカメラ映像が見れるURLがシリアルモニタに表示されますが、そのアドレスにアクセスしてもカメラ映像は見えません。

当初ESP32CAMを丸ごと再購入しようと考えていましたが、もしかするとOV2640だけ故障しているかもしれません。

次回は新しくOV2640だけ購入して挑戦します。

※以下備忘録のため記載します。

以前Sipeed Maix M1 Dockプログラミング(1) | 環境構築+顔認証で使用していたSipeed Maix M1 DockにもOV2640がセットされていたのでそれを仮で使用したところ、カメラ初期化エラーが発生しました。もしかするとピン配置が異なっているのかもしれません。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA



reCaptcha の認証期間が終了しました。ページを再読み込みしてください。