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

Support for power down modes #33

Closed
doragasu opened this issue Apr 28, 2019 · 32 comments
Closed

Support for power down modes #33

doragasu opened this issue Apr 28, 2019 · 32 comments

Comments

@doragasu
Copy link

I am using an ESP32-CAM module, and currently the camera power consumption is relatively high when the camera is idle. I have done several not very accurate current measurement using my test project under several scenarios (all with the WiFi up):

  1. Camera initialized, module idle: 90 mA
  2. Camera taking photo: 165 mA
  3. Camera initialized, photo taken, camera deinitialized: 55 mA
  4. Camera initialized, photo taken, power down pin set to 1: 35 mA
  5. Camera initialized, photo taken, written 0x10 to register 0x0A (Standby mode) 35 mA

As the intended use for the module is to be battery powered and the camera will be idle most of the time, I would like to be able to put it to sleep and wake it up as needed. From the measurements above, it seems I should be able to cut current consumption almost by a 1/3 factor, but unfortunately, when I try options 4 an 5, I am not able to make the camera work again until I issue a power cycle. I have tried disabling Standby mode for option 5, and reinitializing the camera for both options, without success.

Are power down modes supported? If not, could power down support be added?

Regards,

doragasu

@c2mw4
Copy link

c2mw4 commented May 1, 2019

This issue is also critical to my project. @doragasu since your measurements are with WiFi up, that means the ESP32 processor and radio are continuing to consume power (eg, 55 / 35mA in cases 3, 4 & 5) just to maintain a connection, and perhaps other stuff. ESP-CAM specs suggest 5mA "sleep", presumably when WiFi is OFF. Do you get something like that? And ESP32 chip specs suggest a much lower sleep current is possible -- you and I both want to know if those sleep modes are supported?

@doragasu
Copy link
Author

doragasu commented May 6, 2019

Hi, I did not do any tests in sleep mode, because I cannot use it (I need to have the radio always on, I keep a TCP connection always open and ready to receive data). My problem is the power drained by the camera while "idle" is way too much because standby mode is not supported.

Also as I wrote, my measuremente are note very accurate, because I have to use my polimeter in the 10A scale. If I use a smaller scale (e.g. 200 mA), the module does not boot properly. And in the 10 A scale, the resolution is 10 mA. So when I say that a measurement is e.g. 55 mA, it is because the reading is continuously changing between 50 mA and 60 mA.

@me-no-dev
Copy link
Member

Maybe you can try stopping the XCLK while you do not want to use the camera. That in effect will stop the camera's CPU and should lower consumption.

@doragasu
Copy link
Author

What is the preferred way to stop XCLK?

@brettbeeson
Copy link

Hi! I'm another looking to reduce power during idle. I also couldn't restart camera. Any news on this or the xclk method? Thanks.

@me-no-dev
Copy link
Member

Forward declare both methods in your code (it's in private header currently) and then stop and start the clock as needed :) https://github.com/espressif/esp32-camera/blob/master/driver/private_include/xclk.h

@c2mw4
Copy link

c2mw4 commented Jul 4, 2019

Thanks @me-no-dev! I've been looking at the overall issue of Ultra Low Power BLE Advertising and Infrequent Connection (ULP BLE-AIC) for ESP32. The challenge is twofold: (1) long time to initialize the heavy system of ESP-IDF / Bluetooth and (2) only Modem Sleep but not Deep Sleep is used. I see an implementation strategy for Ultra Low Power BLE Advertising (ULP BLE-AIC) that does not require a shorter BLE / system initialization time.

The ULP BLE-AIC strategy would

  1. achieve few 100's microAmp average current consumption while waiting for a BLE connection
  2. not require changing the existing BLE stack
  3. not expose BLE radio or packet-level operating details to possible bad-guys
  4. avoid the issue of keeping the 100kB+ size BLE code in memory while trying to do other things
  5. be simple to implement

This would open a lot of IoT applications to use ESP32, that can't now! :) It requires Espressif cooperation. Any interest?

Cheers, /george

@me-no-dev
Copy link
Member

I will advise you to post this request for discussion in the ESP-IDF github page :) Its a bit off-topic here and the people that can help will not see it.

@doragasu
Copy link
Author

doragasu commented Jul 4, 2019

Thanks, I will test stopping XCLK as soon as I get some time.

@eried
Copy link

eried commented Aug 8, 2019

Anyone had success with this? How to do it in Arduino? Do I replace the driver directly in the esp32 tool directory?

I think you all are getting 35mA not just because the camera module but also the LM regulator. If you remove that from the esp32cam you will get into 4-3mA (not perfect yet)

@doragasu
Copy link
Author

Sorry, I still did not have the time to test it. I plan to do it, but it will take two weeks or more for me to get the time slot.

@brettbeeson
Copy link

I tested various options with (some) success. I'll post the (rather long, but hopefully useful) code below and summarise here. In short, although power down and light sleep cannot be used, you can get the power down to 26mA with the camera used infrequently.

Power consumption when idling is:

  • 24mA after boot
  • 64mA after camera init
  • 44mA using the XCLK method
  • 26mA using the XCLK method, plus DFS
  • 39mA using the XCLK method, plus DFS, turning on WiFi with WIFI_PS_MIN_MODEM and no light sleep

Other notes:

  • Used master branch current today.
  • With DFS, need to you ESP_PM_CPU_FREQ_MAX (a PM lock) while actually using camera
  • Light sleep with FreeRTOS tickless idle stops the camera working, even if I turn light sleep off
  • Using FreeRTOS tickless idle and WiFi stops the camera working, even without specifically turning on light-sleep. Maybe WiFi driver turns it on?
  • Note the signature:
    camera_enable_out_clock(camera_config_t *config);
  • In menuconfig, enable Power Management, SPI Ram, but not Tickless Idle.

Test app:

#include "esp_camera.h"
#include "esp_log.h"
#include "esp_pm.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#define WIFI 1
#define DELAY 5
#define POWER_DOWN_WILL_FAIL_TO_RESTART 0
#define LIGHT_SLEEP_WILL_FAIL 0
#define PM_LOCKS 1

#if WIFI
#include "nvs_flash.h"
#include "wifi_prov.h"
#endif

esp_pm_config_esp32_t pm_config = {0};
esp_pm_lock_handle_t nosleep_handle = 0;
esp_pm_lock_handle_t freq_handle = 0;
esp_pm_lock_handle_t apb_handle = 0;

// Forward declare cam clock stop/start. Note (new?)  signature.
esp_err_t camera_enable_out_clock(camera_config_t *config);
void camera_disable_out_clock();

#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
#define CAM_PIN_PCLK 22

static const char *TAG = "esp32cam";

static camera_config_t camera_config = {
    .ledc_channel = LEDC_CHANNEL_0,
    .ledc_timer = LEDC_TIMER_0,
    .pin_d0 = Y2_GPIO_NUM,
    .pin_d1 = Y3_GPIO_NUM,
    .pin_d2 = Y4_GPIO_NUM,
    .pin_d3 = Y5_GPIO_NUM,
    .pin_d4 = Y6_GPIO_NUM,
    .pin_d5 = Y7_GPIO_NUM,
    .pin_d6 = Y8_GPIO_NUM,
    .pin_d7 = Y9_GPIO_NUM,
    .pin_xclk = XCLK_GPIO_NUM,
    .pin_pclk = PCLK_GPIO_NUM,
    .pin_vsync = VSYNC_GPIO_NUM,
    .pin_href = HREF_GPIO_NUM,
    .pin_sscb_sda = SIOD_GPIO_NUM,
    .pin_sscb_scl = SIOC_GPIO_NUM,
    .pin_pwdn = PWDN_GPIO_NUM,
    .pin_reset = RESET_GPIO_NUM,
    .xclk_freq_hz = 20000000,
    .pixel_format = PIXFORMAT_JPEG,
    .frame_size = FRAMESIZE_UXGA, //QQVGA-QXGA Do not use sizes above QVGA when not JPEG
    .jpeg_quality = 12,           //0-63 lower number means higher quality
    .fb_count = 1                 //if more than one, i2s runs in continuous mode. Use only with JPEG
};

esp_err_t my_camera_init() {
  //power up the camera if PWDN pin is defined
  if (PWDN_GPIO_NUM != -1) {
    gpio_pad_select_gpio(PWDN_GPIO_NUM);
    gpio_set_direction(PWDN_GPIO_NUM, GPIO_MODE_OUTPUT);
    gpio_set_level(PWDN_GPIO_NUM, 0);
 }
  esp_err_t err = esp_camera_init(&camera_config);
  if (err != ESP_OK) {
    ESP_LOGE(TAG, "Camera Init Failed");
    return err;
  }
  ESP_LOGE(TAG, "Camera Init OK");
  return ESP_OK;
}

esp_err_t camera_capture() {
  camera_fb_t *fb = esp_camera_fb_get();
  if (!fb) {
    ESP_LOGE(TAG, "Camera Capture Failed");
    return ESP_FAIL;
  }
  esp_camera_fb_return(fb);
  ESP_LOGV(TAG, "Took a photo %d x %d\n", fb->width, fb->height);
  return ESP_OK;
}

void camera_captures() {
  for (int i = 0; i < 10; i++) {
    ESP_ERROR_CHECK(camera_capture());
    vTaskDelay(pdMS_TO_TICKS(1000));
  }
}

/**
 * mA readings with CPU set to 160MHz
 * */
void app_main() {
  ESP_ERROR_CHECK(esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, "1", &freq_handle));
  ESP_ERROR_CHECK(esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "2", &apb_handle));
  ESP_ERROR_CHECK(esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "3", &nosleep_handle));

  // 24mA
  ESP_LOGI(TAG, "1 Started. ");
  vTaskDelay(pdMS_TO_TICKS(DELAY * 1000));

  // 64 mA
  ESP_ERROR_CHECK(my_camera_init());
  ESP_LOGI(TAG, "2 Inited.");
  vTaskDelay(pdMS_TO_TICKS(DELAY * 1000));

  // 68 mA
  ESP_LOGI(TAG, "3 One photo each second.");
  camera_captures();

  // 64 mA
  ESP_LOGI(TAG, "4 Idle after photos");
  vTaskDelay(pdMS_TO_TICKS(DELAY * 1000));

#if POWER_DOWN_WILL_FAIL_TO_RESTART
  // 40 mA
  ESP_LOGI(TAG, "5 Powered down!");
  gpio_pad_select_gpio(PWDN_GPIO_NUM);
  gpio_set_direction(PWDN_GPIO_NUM, GPIO_MODE_OUTPUT);
  gpio_set_level(PWDN_GPIO_NUM, 1);
  vTaskDelay(pdMS_TO_TICKS(DELAY * 1000));

  // 80 mA, but fails to take photos again ("Timeout on VSYNC")
  ESP_LOGI(TAG, "6 Powered up again");
  gpio_pad_select_gpio(PWDN_GPIO_NUM);
  gpio_set_direction(PWDN_GPIO_NUM, GPIO_MODE_OUTPUT);
  gpio_set_level(PWDN_GPIO_NUM, 0);
  ESP_LOGI(TAG, "6.1 One photo each second.");
  camera_captures();
  vTaskDelay(pdMS_TO_TICKS(DELAY * 1000));
#endif

  // 44 mA
  ESP_LOGI(TAG, "7 Disable clock");
  camera_disable_out_clock();
  vTaskDelay(pdMS_TO_TICKS(DELAY * 1000));

  // 64 mA
  ESP_LOGI(TAG, "8 Enable clock");
  ESP_ERROR_CHECK(camera_enable_out_clock(&camera_config));
  vTaskDelay(pdMS_TO_TICKS(DELAY * 1000));

  // 66 mA
  ESP_LOGI(TAG, "10 One photo each second");
  camera_captures();

  // 41mA
  // Needs PM support in menuconfig
  // Initally failed with "camera: Failed to get the frame on time!"
  // Fixed by adding PM locks (just ESP_PM_CPU_FREQ_MAX, not ESP_PM_APB_FREQ_MAX nor ESP_PM_NO_LIGHT_SLEEP)
  ESP_LOGI(TAG, "11 Turn on DFS (no light sleep");
  pm_config.max_freq_mhz = 160;
  pm_config.min_freq_mhz = 10;
  pm_config.light_sleep_enable = false;
  ESP_ERROR_CHECK(esp_pm_configure(&pm_config));
  vTaskDelay(pdMS_TO_TICKS(DELAY * 1000));

  // 68mA
  ESP_LOGI(TAG, "12 One photo each second");
#if PM_LOCKS
  ESP_LOGI(TAG, "Locking PM");
  ESP_ERROR_CHECK(esp_pm_lock_acquire(freq_handle));
#endif

  camera_captures();

#if PM_LOCKS
  ESP_ERROR_CHECK(esp_pm_lock_release(freq_handle));
#endif

  // 26 mA
  // Combine: clock_disable and DFS and locks
  ESP_LOGI(TAG, "13 Turn on DFS (no light sleep + disable clock");
  pm_config.max_freq_mhz = 160;
  pm_config.min_freq_mhz = 10;
  pm_config.light_sleep_enable = false;
  ESP_ERROR_CHECK(esp_pm_configure(&pm_config));
  camera_disable_out_clock();
  vTaskDelay(pdMS_TO_TICKS(DELAY * 1000));

  // 64mA
  ESP_ERROR_CHECK(camera_enable_out_clock(&camera_config));
  ESP_LOGI(TAG, "14 One photo each second");
#if PM_LOCKS
  ESP_LOGI(TAG, "Locking PM");
  ESP_ERROR_CHECK(esp_pm_lock_acquire(freq_handle));
#endif

  camera_captures();

#if PM_LOCKS
  ESP_ERROR_CHECK(esp_pm_lock_release(freq_handle));
#endif

#if LIGHT_SLEEP_WILL_FAIL
  ESP_LOGI(TAG, "15 Turn on DFS (add light sleep");
  pm_config.max_freq_mhz = 240;
  pm_config.min_freq_mhz = 40;
  pm_config.light_sleep_enable = true;
  ESP_ERROR_CHECK(esp_pm_configure(&pm_config));
  vTaskDelay(pdMS_TO_TICKS(DELAY * 1000));

  // E (76036) camera: Timeout waiting for VSYNC
  // E (76036) esp32cam: Camera Capture Failed
  // Fix 1: Add Locks (still fails)
  // Fix 2: turn off light sleep via pm_configure (still fails)
  ESP_LOGI(TAG, "16 One photo each second");

  // Fix 2
  pm_config.max_freq_mhz = 240;
  pm_config.min_freq_mhz = 40;
  pm_config.light_sleep_enable = false;
  ESP_ERROR_CHECK(esp_pm_configure(&pm_config));

#if PM_LOCKS
  ESP_LOGI(TAG, "Locking PM");
  ESP_ERROR_CHECK(esp_pm_lock_acquire(nosleep_handle));
  ESP_ERROR_CHECK(esp_pm_lock_acquire(apb_handle));
  ESP_ERROR_CHECK(esp_pm_lock_acquire(freq_handle));
#endif
  camera_captures();
#if PM_LOCKS
  ESP_ERROR_CHECK(esp_pm_lock_release(nosleep_handle));
  ESP_ERROR_CHECK(esp_pm_lock_release(apb_handle));
  ESP_ERROR_CHECK(esp_pm_lock_release(freq_handle));
#endif
  camera_captures();
#endif

#if WIFI
  esp_err_t ret = nvs_flash_init();
  ESP_ERROR_CHECK(ret);
  simple_wifi_start();

  ESP_LOGW(TAG, "16 WIFI");
  vTaskDelay(pdMS_TO_TICKS(DELAY * 1000 * 5));

  // 39mA
  ESP_LOGW(TAG, "17 WIFI_PS_MIN_MODEM");
  esp_wifi_set_ps(WIFI_PS_MIN_MODEM);
  vTaskDelay(pdMS_TO_TICKS(DELAY * 1000 * 5));
  // Fails if FREERTOS_TICKLESS_IDLE is enabled
  // Perhaps esp_wifi_set_ps sets light sleep (with is shown, above, to break camera functionality)
  ESP_ERROR_CHECK(camera_enable_out_clock(&camera_config));
  ESP_LOGI(TAG, "One photo each second");
  ESP_ERROR_CHECK(esp_pm_lock_acquire(freq_handle));
  camera_captures();
  ESP_ERROR_CHECK(esp_pm_lock_release(freq_handle));
  camera_disable_out_clock();

  // 32 mA
  ESP_LOGW(TAG, "18 WIFI_PS_MAX_MODEM");
  esp_wifi_set_ps(WIFI_PS_MAX_MODEM);
  camera_disable_out_clock();
  vTaskDelay(pdMS_TO_TICKS(DELAY * 1000 * 5));

  ESP_ERROR_CHECK(camera_enable_out_clock(&camera_config));
  ESP_LOGI(TAG, "One photo each second");
  ESP_ERROR_CHECK(esp_pm_lock_acquire(freq_handle));
  camera_captures();
  ESP_ERROR_CHECK(esp_pm_lock_release(freq_handle));
  camera_disable_out_clock();

  // 88mA
  ESP_LOGW(TAG, "19 WIFI_PS_NONE");
  esp_wifi_set_ps(WIFI_PS_NONE);
  camera_disable_out_clock();
  vTaskDelay(pdMS_TO_TICKS(DELAY * 1000 * 5));

  ESP_ERROR_CHECK(camera_enable_out_clock(&camera_config));
  ESP_LOGI(TAG, "One photo each second");
  ESP_ERROR_CHECK(esp_pm_lock_acquire(freq_handle));
  camera_captures();
  ESP_ERROR_CHECK(esp_pm_lock_release(freq_handle));
  camera_disable_out_clock();
#endif
  ESP_LOGI(TAG, "Done");
}



@brettbeeson
Copy link

brettbeeson commented Sep 5, 2019

Anyone had success with this? How to do it in Arduino? Do I replace the driver directly in the esp32 tool directory?

I don't think power management is possible with Arduino. You'll need ESP-IDF to get the functionality. However, you should be able to get some improvement with the XCLK method in Arduino by calling the camera_enable_out_clock function.

I think you all are getting 35mA not just because the camera module but also the LM regulator. If you remove that from the esp32cam you will get into 4-3mA (not perfect yet)

That would be great - can you expand upon / explain how you did this?

@eried
Copy link

eried commented Sep 5, 2019

That would be great - can you expand upon / explain how you did this?

Yes, I just removed the regulator and power the board directly with batteries via the 3.3V pin:
image

Ignore the missing caps, you can remove them too, but they do not change anything. I was testing something else.

@brettbeeson
Copy link

brettbeeson commented Sep 17, 2019

Thanks @eried for the instructions. I removed the 5v regulator and successfully powered via the 3.3v pin via a Polou reg09b.
I did see some improvement on powering via the 5v pin : about 10% less (edit: see note below).
I also got brownout when trying to WiFi and take photos simultaneously. (This brownout might be because of the 3.3v regulator used and not an inherent problem.)

@eried
Copy link

eried commented Sep 17, 2019

Nice, and yes, you need to disable the brownout. I think in my case the improvement was more than 10%. How much was your board using with that regulator? Consider that you cant compare 3.3V vs 5V without converting the mA to mW

@brettbeeson
Copy link

The board was using 24mA after boot, before I did anything and now 21mA. I measured the mA on +ve connection to 5V or 3.3V pin. So I guess the actual reduction ( 24mA x 5V = 120mW to 21mA x 3.3V = 69mW) was more like 43%. I did a very unscientific test today and it lasted much longer.

I'll disable brownout - did you have instability issues with brownout disabled, or perhaps it's just dipping briefly during WiFi startup?

@eried
Copy link

eried commented Sep 18, 2019

Dipping during WiFi init. It has been running for weeks, without issues. But I wish I could achieve the sub mA values the ESP32 can reach :( to make the batteries last month not weeks.

@brettbeeson
Copy link

Okay, cheers. Is your timelapse code available? My is here (as a "timelapse" component and a "tlc32" project. I use a small PV panel to power it, but it's sunny here!

@eried
Copy link

eried commented Sep 19, 2019

It is not sunny here, and my code is not available yet, it is way simpler than the tlc32, using "vanilla" arduino and just uploading the photo to an ftp

@mtnbkr88
Copy link

Hello, I'm using the ESP32-CAM with the Arduino IDE. I have a similar need for low power when idle since my unit will be powered by solar with an 18650 battery. I tried brettbeeson's example code and I get lots of compiler errors and totally can't find the camera_enable_out_clock and camera_disable_out_clock subroutines. Is my Arduino IDE missing a bunch of stuff? I have been successful in running other example streaming and time lapse programs I've found. It's just this power management stuff I can't get to work.

@brettbeeson
Copy link

Hi mtnbkr88. You'll need to use ESP-IDF to compile that code. Even then, it's in development. I think you'll need ESP-IDF to access the power-saving modes easily. You can use arduino code as a 'component' in ESP-IDF.

@mtnbkr88
Copy link

Hi Brett. Thanks for the quick reply which was as I suspected. I'm not ready to give up my Arduino IDE just yet. I just learned how to use it. Yesterday I came up with the following work-around. I power up and connect to my local network and start the web server. With this much running I'm using around 40mA. Only when a request for streaming from the camera comes in do I initialize then use the camera. At this time the unit is then using around 200mA. Viewing what I want to see in the streamed image takes less than a minute. When the streaming connection to the camera is dropped, the unit goes to deep sleep for 5 seconds then boots up to just the wifi stuff at ~40mA again. I'll also deep sleep for ~10 hours when its dark at night. I'm hoping this will extend my 18650 battery long enough for the 6V 4.5W solar panel to keep up with charging it. Thanks.

@eried
Copy link

eried commented Sep 23, 2019

@brettbeeson does ESP-IDF allows you to get super low deep sleep consumption?

@brettbeeson
Copy link

brettbeeson commented Sep 25, 2019

@eried Yes and no. ESP-IDF allows more control of the esp32. This is good for things like XCLK and light sleep functions, which aren't exposed to Arduino IDE.
However, I reckon the deep sleep consumption will be the same, as Arduino-Esp32 calls the ESP-IDF functions to enter deepsleep. I got deepsleep of 4mA with the esp32 cam. That's when I booted and deepsleep'd without touching the cam. With a FireBeetle32 i got the advertised 10uA.
It might be possible to improve the deepsleep consumption doing such things as locking pins low/high, powering down the cam and other fiddles, but I have not succeeded.
Here are further rough notes on my experiments.

@fragger42
Copy link

fragger42 commented Dec 1, 2019

@mtnbkr88:
So did you try to trigger a complete reboot after a short deep sleep or are you just powering down?

I thought about starting the ESP32 cam only when necessary through a PIR/radar sensor in conjunction with a relay to save power. However, I thought there might be two issues:

  1. Bootup takes too long. Has anyone measured time for bootup with wifi disabled but camera on?
  2. There might be issues when power goes away without correctly stopping for example the microsd card (data corruption)...

Anyone tried that?

@mtnbkr88
Copy link

mtnbkr88 commented Dec 1, 2019

@fragger42:
I'm doing as I described in my Sep 22 post. My ESP32-CAM waits for a connection from 7:30a to 7:30p, it deep sleeps the rest of the time. When a request for the camera comes in, it then initializes the camera and provides a video stream which only takes a second or two. When the connection to the camera is dropped, the unit deep sleeps for 5 seconds then boots up to wait for connections with the camera uninitialized again. I have added more... My ESP32-CAM is powered from a 6V 4.5W solar panel connected to a TP4056 charge controller connected to one 18650 battery. The TP4056 is also connected to a boost converter to then give 5V to my ESP32-CAM (mine works much better on 5V than 3.3V). I have a voltage divider circuit connected to the battery and GPIO12. If a connection request comes in to check battery voltage, It temporarily stops the wifi, reads the battery ADC value from GPIO12, restarts the wifi, then sends the battery voltage value back. I also designed and 3D printed a two axis solar tracker for my panel that is driven by one servo (pretty tricky) and this servo is controlled using GPIO13. I can get away using these pins because I'm currently not using the micro SD card. It also checks battery voltage every 15 minutes and if it drops below 3.4 volts, it sends an email letting me know the battery is low then it deep sleeps until 7:30a the next day. It never completely powers down. Booting from deep sleep or even a hard reset to ready for use only takes a few seconds.

I've been having too much fun with this.

@JakeBeck
Copy link

JakeBeck commented Jan 4, 2020

mtnbkr88, I've been looking at doing this for about a month and just can't get to the low power setting needed. I haven't looked at using a solar panel as you have done. It sounds good and will meet what I'm looking to do which is integrating these cams into a mesh network to watch the perimeters of my property and sending notifications via a server that will handle all communication relayed by the cams. For years I've had problems with people trespassing and hunting on my property without permission to do so. I've also had my home broken into numerous times because there is no way to monitor who's walking in from the perimeters of my property. Could I get a copy of your code or could you help me figure this out to get a working setup and configuration to integrate into a mesh network? Any help you can provide would be greatly appreciated.
Thanks in advance.

@mtnbkr88
Copy link

mtnbkr88 commented Jan 5, 2020

JakeBeck, The first file attached is my code from mid October when I had my ESP32-CAM connected to a fixed position 6V 4.5W solar panel (with battery voltage check on GPIO12). This setup worked okay with sunny days but after a few days of cloudy the battery would run low and never recover.
StreamingSleepingWebServer_31.ino.txt
The second file attached is my code from mid December after I added the servo control for moving the solar panel to follow the sun. This setup didn't work as well as I hoped because the servo would sometimes jam and when it jams the current pull goes to over 500mA and the battery drains quickly.
StreamingSleepingWebServer_32.ino.txt
It was fun doing the solar tracking version but the 3D printed mount/setup is way too flimsy and unreliable to be left outside. So I think using a fixed position setup is better. I also think a better battery solution might be needed. These two versions only stream video when someone connects which is not what you need. At this time I've shelved doing a solar panel setup and I'm now working on a setup that will always be plugged in and will save one minute video to an SD card every time a PIR motion detector on GPIO3 (U0RXD pin) detects motion. The videos can be downloaded using FTP or possibly through a web page. This is closer to what you want but I have no idea yet how much power it will need and since its a work in progress the code is not ready to be shared. I can share it when its ready. I know you can also set the ESP32-CAM to deep sleep and wake when PIR motion is detected. This will save power but require sending the video to some device that is always awake so the video can be retrieved when you want. Maybe that will be my next project?? I may also work on a better solar powered solution in the future.
How much perimeter or how many cameras do you think you need? I'm happy to help if I can.

krasin pushed a commit to krasin/m5stack-cam-psram that referenced this issue Feb 3, 2020
Also wait 1 second for full initialization.

See also:
espressif/esp32-camera#33 (comment)
@KevWal
Copy link

KevWal commented Oct 23, 2020

Hi All, I am unable to call camera_enable_out_clock() or camera_disable_out_clock() in my code in Arduino, I get the error:

sketch\Test.ino.cpp.o:(.literal._Z5setupv+0x30): undefined reference to camera_enable_out_clock(camera_config_t*)'
sketch\Test.ino.cpp.o:(.literal._Z5setupv+0x34): undefined reference to camera_disable_out_clock()' sketch\Test.ino.cpp.o: In function setup()':
Code\Test/Test.ino:77: undefined reference to camera_enable_out_clock(camera_config_t*)' Code\Test/Test.ino:81: undefined reference to camera_disable_out_clock()'
collect2.exe: error: ld returned 1 exit status
exit status 1
Error compiling for board AI Thinker ESP32-CAM.`

The routines I am calling seem to exist in the binary file libesp32-camera.a which exists on my PC - but how do I use them?

My test code isolating this issue is below:

`
#include <esp_camera.h>

// Forward declare cam clock stop/start.
esp_err_t camera_enable_out_clock(camera_config_t *config);
void camera_disable_out_clock();

// CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM 32 //
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0 //
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22 //

#define SerialDebug Serial // Nice names for Serial ports

camera_config_t cam_config;
camera_fb_t *fb; // Declare the variable for the pointer to the framebuffer

void setup() {
SerialDebug.begin(115200);

setCpuFrequencyMhz(20); // Save power by going slowly

// Init out Camera
cam_config.ledc_channel = LEDC_CHANNEL_0;
cam_config.ledc_timer = LEDC_TIMER_0;
cam_config.pin_d0 = Y2_GPIO_NUM;
cam_config.pin_d1 = Y3_GPIO_NUM;
cam_config.pin_d2 = Y4_GPIO_NUM;
cam_config.pin_d3 = Y5_GPIO_NUM;
cam_config.pin_d4 = Y6_GPIO_NUM;
cam_config.pin_d5 = Y7_GPIO_NUM;
cam_config.pin_d6 = Y8_GPIO_NUM;
cam_config.pin_d7 = Y9_GPIO_NUM;
cam_config.pin_xclk = XCLK_GPIO_NUM;
cam_config.pin_pclk = PCLK_GPIO_NUM;
cam_config.pin_vsync = VSYNC_GPIO_NUM;
cam_config.pin_href = HREF_GPIO_NUM;
cam_config.pin_sscb_sda = SIOD_GPIO_NUM;
cam_config.pin_sscb_scl = SIOC_GPIO_NUM;
cam_config.pin_pwdn = PWDN_GPIO_NUM;
cam_config.pin_reset = RESET_GPIO_NUM;
cam_config.xclk_freq_hz = 20000000;
cam_config.pixel_format = PIXFORMAT_JPEG;
//init with high specs to pre-allocate larger buffers
if (psramFound()) {
  SerialDebug.println("  PS RAM Found.");
  cam_config.frame_size = FRAMESIZE_UXGA;
  cam_config.jpeg_quality = 10;
  cam_config.fb_count = 2;
} else {
  SerialDebug.println("  Error: PS RAM Not Found.");
  cam_config.frame_size = FRAMESIZE_SVGA;
  cam_config.jpeg_quality = 12;
  cam_config.fb_count = 1;
}

// Overide the above for testing
cam_config.frame_size = FRAMESIZE_VGA;
cam_config.jpeg_quality = 10;  // Quality of JPEG output. 0-63 lower means higher quality
cam_config.fb_count = 1;

delay(10000); // doing stuff here

esp_camera_init(&cam_config);

SerialDebug.printf("  Taking picture:\n");
setCpuFrequencyMhz(80); // Camera seems to need more than 40mhz to get a picture
camera_enable_out_clock(&cam_config);
delay(500);
fb = esp_camera_fb_get(); // Get the current frame buffer
delay(500);
camera_disable_out_clock();
setCpuFrequencyMhz(20);
SerialDebug.printf("  Picture length: %d\n", fb->len);

delay(10000); // doing stuff here

esp_camera_fb_return(fb);

}

void loop() {

}`

Thanks very much
Kevin

@KevWal
Copy link

KevWal commented Nov 11, 2020

I have solved the "calling XCLK routines from Arduino" issue, they need to be declared like so:

extern "C" { esp_err_t camera_enable_out_clock(camera_config_t *config); void camera_disable_out_clock(); }

It saves a bit of power and the clock can still be restarted and a picture taken again.

It doesn't save as much as powering down the camera and then powering it up again, but I can't get that to work, it always reboots on me:

22:36:51.943 -> [E][camera.c:1335] esp_camera_fb_get(): Failed to get the frame on time!
22:36:52.491 -> Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.

@github-actions
Copy link

This issue appears to be stale. Please close it if its no longer valid.

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

No branches or pull requests

9 participants