Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OV2640 esp_camera_fb_get causing panic: (LoadStoreAlignment). Exception was unhandled. #489

Closed
chris-at-redfernsolutions opened this issue Dec 16, 2022 · 12 comments · Fixed by #491

Comments

@chris-at-redfernsolutions
Copy link

chris-at-redfernsolutions commented Dec 16, 2022

I am trying to use the esp_camera library to take large (i.e. FRAMESIZE_UXGA) images from an OV2640 camera on an ESP32S2. Images this large must be stored in PSRAM, i.e. config.fb_location = CAMERA_FB_IN_PSRAM.

Upon executing esp_camera_fb_get(), a LoadStoreAlignment exception apparently triggered within cam_verify_jpeg_eoi occurs. This occurs at any requested resolution.

Firmware / hardware used

Minimal code required to reproduce:

Using Arduino 2.0.3:

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

#define PIN_SDA 41
#define PIN_SCL 42

#define PIN_CAM_D0		13
#define PIN_CAM_D1		18
#define PIN_CAM_D2		17
#define PIN_CAM_D3		14
#define PIN_CAM_D4		12
#define PIN_CAM_D5		34
#define PIN_CAM_D6		35
#define PIN_CAM_D7		37
#define PIN_CAM_PCLK	33
#define PIN_CAM_MCLK	36
#define PIN_CAM_VSYNC	39
#define PIN_CAM_HSYNC	38
#define PIN_CAM_RST		40


bool takePicture(void)
{
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = PIN_CAM_D0;
  config.pin_d1 = PIN_CAM_D1;
  config.pin_d2 = PIN_CAM_D2;
  config.pin_d3 = PIN_CAM_D3;
  config.pin_d4 = PIN_CAM_D4;
  config.pin_d5 = PIN_CAM_D5;
  config.pin_d6 = PIN_CAM_D6;
  config.pin_d7 = PIN_CAM_D7;
  config.pin_xclk = PIN_CAM_MCLK;
  config.pin_pclk = PIN_CAM_PCLK;
  config.pin_vsync = PIN_CAM_VSYNC;
  config.pin_href = PIN_CAM_HSYNC;
  config.pin_sscb_sda = PIN_SDA;
  config.pin_sscb_scl = PIN_SCL;
  config.fb_location = CAMERA_FB_IN_DRAM;
  config.pin_pwdn = -1;
  config.pin_reset = PIN_CAM_RST;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
  config.grab_mode = CAMERA_GRAB_LATEST;
  

  if (psramFound())
  {
      Serial.println("PSRAM found");
      config.fb_location = CAMERA_FB_IN_PSRAM;
      config.frame_size = FRAMESIZE_VGA;   // Use a normal frame size. If config.fb_location is set to CAMERA_FB_IN_DRAM, this function succeeds.
      config.jpeg_quality = 10;
      config.fb_count = 2;
  }
  else 
  {
    Serial.println("PSRAM not found");
    return false;
  }

  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK)
  {
    Serial.printf("Camera init failed w/ err 0x %d\r\n", err);
    return false;
  }

  sensor_t* s;
  s->set_exposure_ctrl(s, true);                  // Want auto-exposure
  s->set_aec2(s, true);                           // Auto-exposure DSP mode on
  s->set_aec_value(s, 300);                       // Set expose time ceiling [uS]
  s->set_ae_level(s, 0);                          // Auto expose level = 0 (-2 to 2). Dictates the exposure algorithm.
  s->set_brightness(s, 0);                        // Brightness 0 (-2 to 2)
  s->set_gain_ctrl(s, true);                      // Want auto-gain
  s->set_agc_gain(s, 30);                         // Set to maximum gain ceiling (0 to 30)

  camera_fb_t* photo = esp_camera_fb_get();
  Serial.printf("Photo taken, has addr. %d\r\n", photo);
  if (photo == NULL) {
    Serial.println("Null ptr as camera framebuffer");
    return false;
  }
    
  err = esp_camera_deinit();
  if (err != ESP_OK)
  {
    Serial.printf("Camera deinit failed w/ err 0x%x\r\n", err);
    return false;
  }
  esp_camera_fb_return(photo);

  return true;
}

void setup(void)
{
  bool success;
  Serial.begin(115200);
  success = psramInit();
  if (!success) {
    Serial.println("Error initing PSRAM");
  }

  takePicture();
}

void loop(void)
{

}

Crash report

When run on our hardware this causes the ESP32 to crash:

...
PSRAM found
Guru Meditation Error: Core 0 panic'ed (LoadStoreAlignment) 
...

Decoding the exception gives this stacktrace:

/Users/ficeto/Desktop/ESP32/ESP32S2/esp32-arduino-lib-builder/components/esp32-camera/driver/cam_hal.c:70:::0x40095555:cam_verify_jpeg_eoi
    (inlined by) cam_take at /Users/ficeto/Desktop/ESP32/ESP32S2/esp32-arduino-lib-builder/components/esp32-camera/driver/cam_hal.c:480
/Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/freertos/port/xtensa/xtensa_vectors.S:633:::0x40028390:_xt_user_exc
/Users/ficeto/Desktop/ESP32/ESP32S2/esp32-arduino-lib-builder/components/esp32-camera/driver/cam_hal.c:68:::0x40095552:cam_verify_jpeg_eoi
    (inlined by) cam_take at /Users/ficeto/Desktop/ESP32/ESP32S2/esp32-arduino-lib-builder/components/esp32-camera/driver/cam_hal.c:480
/Users/ficeto/Desktop/ESP32/ESP32S2/esp32-arduino-lib-builder/components/esp32-camera/driver/esp_camera.c:360:::0x40094c77:esp_camera_fb_get
C:\Users\Chris\Project\PSRAMCameraTest.ino:98 (discriminator 2):::0x400820a4:takeDummyPicture(int)
C:\Users\Chris\Project\PSRAMCameraTest.ino(168): error 0x40082224:takePictureUnsafe(bool)
C:\Users\Chris\Project\PSRAMCameraTest.ino(284): error 0x40082580:setup()
C:\Users\Chris\AppData\Local\arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/main.cpp(42): error 0x40087f16:loopTask(void*)
/Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/esp_system/esp_system.c:44 (discriminator 1):::0x40026de9:esp_restart_noos_dig

The failure of cam_verify_jpeg_eoi, cam_take implies the EOI flag of the image fails to decode...?

Hardware schematic

A custom ESP32 PCB is used for this example. The software project uses the Arduino "ESP32S2 Dev Module" in lieu of creating a dedicated custom board file via idf.py menuconfig.

The ESP32 in question:

image

The PSRAM IC:

image

Camera schematic:

image

Software

Parameter Value
OS Windows 10
IDE Arduino IDE 2.0.3
arduino-esp32 version 2.0.5
ESP32 "board" selected in Arduino ESP32S2 Dev Module

Board specific parameters (settings in the Arduino IDE):

Board parameter Setting
CPU Frequency 240MHz (WiFi)
Flash Mode QIO
Flash Size 4MB (32Mb)
Partition Scheme Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)
Core Debug Level Info
File System Upload Tool SPIFFS
Erase All Flash Before Sketch Upload Disabled
Upload Speed 912600
Flash Frequency 80 MHz
PSRAM Frequency 80 MHz
PSRAM Enabled

As per the Installation Instructions section of the ESP32-camera README, this board is configured to use a flash and PSRAM freq. of 80 MHz.

What I've tried

Testing the PSRAM

I can ps_malloc a 100kB buffer, write to it and successfully read it back using this code:

    bool success = psramInit();
    Serial.println("PSRAM init? %d", success);
    Serial.println("Total PSRAM: %d, Free PSRAM: %d", ESP.getPsramSize(), ESP.getFreePsram());

    char* buffer = (char*) ps_malloc(100000);
    for (int i = 0; i < 100000; i++) {
        buffer[i] = (char) 5;
    }
    for (int i = 0; i < 100000; i++) {
        Serial.println("ADDR: %d, VAL=%d", i, buffer[i]);
    }

    Serial.println("Total PSRAM: %d, Free PSRAM: %d", ESP.getPsramSize(), ESP.getFreePsram());
    free(buffer);
    Serial.println("Total PSRAM: %d, Free PSRAM: %d", ESP.getPsramSize(), ESP.getFreePsram());

The entire buffer is correctly written / read to. The ESP.getPsramSize() & ESP.getFreePsram() correctly reflect PSRAM levels changing after ps_malloc and free. The camera error remains unchanged if this code runs at the start of setup().

Reducing clock frequency

Reducing config.xclk_freq_hz from 20,000,000 to 16,000,000 had no effect.

Allocating the camera_config within the PSRAM

Replacing

camera_config_t config;

with

camera_config_t* config_buffer = (camera_config_t*) ps_malloc(sizeof(camera_config_t));
camera_config_t config = *config_buffer;

This had no effect.

Preallocating a large PSRAM buffer before camera operation

If a large buffer is preallocated in PSRAM and never freed, esp_camera_fb_get succeeds (no more crashes occur) but returns null pointers. Values tried include 700,000 and 2,000,000 bytes.

byte* psram_buffer = (byte*)ps_malloc(2000000);   

For small images e.g. FRAMESIZE_96X96, esp_camera_fb_get returns a valid framebuffer address. Large images (FRAMESIZE_VGA, FRAMESIZE_UXGA) cause it to return a null pointer.

Changing the jpeg_quality and fb_count in the camera config

Values tried include:

  • fb_count: [1, 2, 3]
  • jpeg_quality: [1, 2, 10, 30, 63]

No effect was had.

Taking small images without PSRAM: config.fb_location = CAMERA_FB_IN_DRAM

We currently use this in our prototype and it works fine with sizes of FRAMESIZE_VGA, jpeg_quality = 12, and fb_count = 1. This always results in a valid .jpg in the framebuffer.

@WangYuxin-esp
Copy link
Contributor

Can I know the size of the current device's psram?

@chris-at-redfernsolutions
Copy link
Author

We use PSRAM64

@WangYuxin-esp
Copy link
Contributor

I guess this is a problem of PSRAM driver. You can consider using ESP-IDF release/v5.0 or replacing small capacity PSRAM to verify the problem.

@Lawrence-RedFern
Copy link

Thanks for your reply @WangYuxin-esp. Did you know where we can purchase the PSRAM32? As far as I'm aware this chip has been discontinued.

@WangYuxin-esp
Copy link
Contributor

Sorry, you can contact relevant businesses on our official website to obtain procurement information. I only know some technical topics here.

@igrr
Copy link
Member

igrr commented Dec 19, 2022

In the meantime we can also fix the unaligned access in the camera driver. I'll try to submit a PR this week.

@me-no-dev
Copy link
Member

@Lawrence-RedFern you have also submitted an issue in the Arduino repository. Please try what I suggested there first. You can also try the included in Arduino camera example (without modifications other than GPIOs used).

@Lawrence-RedFern
Copy link

In the meantime we can also fix the unaligned access in the camera driver. I'll try to submit a PR this week.

Thanks @igrr. I look forward to it!

@Lawrence-RedFern you have also submitted an issue in the Arduino repository. Please try what I suggested there first. You can also try the included in Arduino camera example (without modifications other than GPIOs used).

@me-no-dev Thanks for your response. Unfortunately we no longer have hardware to test, but we should have very soon. We will close that thread to prevent clutter. I just wanted to cast a wide net :)

@igrr igrr linked a pull request Dec 19, 2022 that will close this issue
@chris-at-redfernsolutions
Copy link
Author

chris-at-redfernsolutions commented Jan 11, 2023

@igrr Thank you for writing the patch. I loaded your code into the project and it now can take larger images without triggering a LoadStoreAlignment panic. If the config.jpeg_quality parameter gets set to 1 or 0, crashes still occur for detailed images, e.g:

config.frame_size = FRAMESIZE_VGA;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.jpeg_quality = 0;
config.fb_count = 1;

This config leads to Debug exception reason: Stack canary watchpoint triggered (loopTask) with stacktrace:

Exception:Error:
0x4004c000: ?? ??:0
0x40050000: ?? ??:0
0x4004c18c: ?? ??:0
/Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/freertos/port/xtensa/xtensa_vectors.S:1076:::0x40028665:_xt_lowint1
/Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/esp_system/port/arch/xtensa/panic_handler_asm.S:46:::0x40028c78:_xt_panic
/Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/freertos/port/xtensa/xtensa_vectors.S:1075:::0x40028662:_xt_lowint1
/Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/esp_system/esp_system.c:44 (discriminator 1):::0x40027015:esp_restart_noos_dig
/Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/freertos/port/xtensa/portasm.S:106:::0x4002a7d6:_frxt_int_enter
/Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/freertos/port/xtensa/xtensa_vectors.S:1104:::0x40028685:_xt_lowint1
/Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/freertos/port/xtensa/portasm.S:79:::0x4002a7d3:_frxt_setup_switch
/Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/freertos/port/xtensa/xtensa_vectors.S:1096:::0x40028682:_xt_lowint1
/Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/freertos/queue.c:1459:::0x4002b253:xQueueReceive
C:\Users\Chris\Documents\CritterPic_Software\ESP32-S2\CritterPicV0_6_1\libraries\esp-camera-patched\src/cam_hal.c(471): error 0x400873e9:cam_take
C:\Users\Chris\Documents\CritterPic_Software\ESP32-S2\CritterPicV0_6_1\libraries\esp-camera-patched\src/cam_hal.c:483 (discriminator 15):::0x4008742b:cam_take

I assume the jpeg_quality parameter controls the JPEG compression, and that this crash is due to the image being too large. I notice that if I set config.jpeg_quality=2 I can get images up to 255kB in size without issue.

@RostakaGmfun
Copy link

Hi, @chris-at-redfernsolutions, I think the latest issue you mentioned might happen because of stack overflow in the task calling cam_hal_take().
If you look closely at the implementation (https://github.com/espressif/esp32-camera/blob/master/driver/cam_hal.c#L483), you will see that the function can call itself multiple times if the timeout is long enough and the driver was not able to receive the image completely (no EOI was found in the JPEG payload).

@krjeschk
Copy link

krjeschk commented Mar 3, 2023

Hi, @chris-at-redfernsolutions, I think the latest issue you mentioned might happen because of stack overflow in the task calling cam_hal_take()

@RostakaGmfun Do you know any workround/solution for this issue?

@RostakaGmfun
Copy link

@krjeschk you should look into why cam_take() fails. My guess is it's because of either:

  1. Frame gets corrupted due to signal integrity issues, which will be manifested as "NO-SOI" or "NO-EOI" errors.
  2. Framebuffer is too small to hold a JPEG image with a low compression factor. You will see "FB-OVF" in the logs.

Generally, I would not recommend using a JPEG quantization factor that is that low. The current implementation allocates a framebuffer that is width*height/5 bytes in size, which does not guarantee that all JPEG frames can fit in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants