Skip to content

Add ESP32_CAM support #13247

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

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added docs/esp32/img/esp32_cam.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions ports/esp32/boards/ESP32_CAM/board.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"deploy": [
"../deploy.md"
],
"docs": "",
"features": [
"External Flash",
"WiFi"
],
"images": [
"esp32_cam.jpg"
],
"mcu": "esp32",
"product": "ESP32 / CAM",
"thumbnail": "",
"url": "https://www.espressif.com/en/products/modules",
"variants": {
"IDF3": "Compiled with IDF 3.x",
"D2WD": "ESP32 D2WD",
"SPIRAM": "Support for SPIRAM / WROVER",
"UNICORE": "ESP32 Unicore",
"OTA": "Support for OTA"
},
"vendor": "Espressif"
}
20 changes: 20 additions & 0 deletions ports/esp32/boards/ESP32_CAM/board.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
The following files are firmware that work on the ESP32 CAM module using
an OV2640 camera.

ESP32 CAM has PSRAM (aka spiram) but the ESP32-S chip on it does not support bluetooth

To build this from source, load your env vars:-

. $HOME/esp/esp-idf/export.sh

Open a shell in the folder micropython/ports/esp32

and run this command:-

git clone https://github.com/lemariva/micropython-camera-driver.git
git clone https://github.com/espressif/esp32-camera
make USER_C_MODULES=../micropython-camera-driver/src/micropython.cmake BOARD=ESP32_CAM all

-or- (for ota support):-

make USER_C_MODULES=../micropython-camera-driver/src/micropython.cmake BOARD=ESP32_CAM MICROPY_BOARD_VARIANT=OTA
44 changes: 44 additions & 0 deletions ports/esp32/boards/ESP32_CAM/mpconfigboard.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
boards/sdkconfig.spiram
)

# boards/sdkconfig.ble
# boards/ESP32_CAM/sdkconfig.esp32cam

list(APPEND MICROPY_DEF_BOARD
MICROPY_HW_MCU_NAME="ESP32"
# Disable some options to reduce firmware size.
# MICROPY_OPT_COMPUTED_GOTO=0
# MICROPY_PY_NETWORK_LAN=0
# ESP32-CAMERA
CONFIG_OV2640_SUPPORT=y
MICROPY_HW_BOARD_NAME="ESP32S CAM module with SPIRAM and OV2640"
CONFIG_COMPILER_OPTIMIZATION_SIZE=n
CONFIG_COMPILER_OPTIMIZATION_PERF=y
)


if(MICROPY_BOARD_VARIANT STREQUAL "OTA")
set(SDKCONFIG_DEFAULTS
${SDKCONFIG_DEFAULTS}
boards/ESP32_GENERIC/sdkconfig.ota
)

list(APPEND MICROPY_DEF_BOARD
MICROPY_HW_BOARD_NAME="Generic ESP32 module with OTA"
)
endif()



if(MICROPY_BOARD_VARIANT STREQUAL "UNICORE")
set(SDKCONFIG_DEFAULTS
${SDKCONFIG_DEFAULTS}
boards/ESP32_GENERIC/sdkconfig.unicore
)

list(APPEND MICROPY_DEF_BOARD
MICROPY_HW_MCU_NAME="ESP32-UNICORE"
)
endif()
13 changes: 13 additions & 0 deletions ports/esp32/boards/ESP32_CAM/mpconfigboard.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Both of these can be set by mpconfigboard.cmake if a BOARD_VARIANT is
// specified.

#ifndef MICROPY_HW_BOARD_NAME
#define MICROPY_HW_BOARD_NAME "ESP32S CAM module with PSRAM and OV2640"
#endif

#define MICROPY_PY_BLUETOOTH (0)
#define MODULE_CAMERA_ENABLED (1)

#ifndef MICROPY_HW_MCU_NAME
#define MICROPY_HW_MCU_NAME "ESP32"
#endif
166 changes: 166 additions & 0 deletions ports/esp32/boards/ESP32_CAM/photo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
# photo.py

__version__ = '1.0.1' # Major.Minor.Patch

# Ways to run this program:-

# 1. With ampy
# ampy --port $PORT run bin/photo.py
# example output:-
# photo fn=out.jpg size=22((default)) quality=10
# Length of buf: 23579

# 2. From REPL shell
# >>> ARGV=["pic.jpg","5","10"];exec(open("bin/photo.py").read())
# example output:-
# photo fn=pic.jpg size=5(FRAME_QVGA) quality=10
# Length of buf: 9495

# 3. using mipyshell
# To run this program with arguments, install https://github.com/vsolina/mipyshell
# and save this file as bin/photo.py - then (for size 5 and quality 10):-
# photo outfile.jpg 5 10


import camera


def __main__(args):
capture(args[2:]) # mipyshell first 2 arguments are "python" and "photo.py"

def capture(args):
fn="out.jpg"
quality=10
size=22

camera_frames = { 0: {"name": "FRAME_96X96", "value": camera.FRAME_96X96},
1: {"name": "FRAME_QQVGA", "value": camera.FRAME_QQVGA},
2: {"name": "FRAME_QCIF", "value": camera.FRAME_QCIF},
3: {"name": "FRAME_HQVGA", "value": camera.FRAME_HQVGA},
4: {"name": "FRAME_240X240", "value": camera.FRAME_240X240},
5: {"name": "FRAME_QVGA", "value": camera.FRAME_QVGA},
6: {"name": "FRAME_CIF", "value": camera.FRAME_CIF},
7: {"name": "FRAME_HVGA", "value": camera.FRAME_HVGA},
8: {"name": "FRAME_VGA", "value": camera.FRAME_VGA},
9: {"name": "FRAME_SVGA", "value": camera.FRAME_SVGA},
10: {"name": "FRAME_XGA", "value": camera.FRAME_XGA},
11: {"name": "FRAME_HD", "value": camera.FRAME_HD},
12: {"name": "FRAME_SXGA", "value": camera.FRAME_SXGA},
13: {"name": "FRAME_UXGA", "value": camera.FRAME_UXGA},
14: {"name": "FRAME_FHD", "value": camera.FRAME_FHD},
15: {"name": "FRAME_P_HD", "value": camera.FRAME_P_HD},
16: {"name": "FRAME_P_3MP", "value": camera.FRAME_P_3MP},
17: {"name": "FRAME_QXGA", "value": camera.FRAME_QXGA},
18: {"name": "FRAME_QHD", "value": camera.FRAME_QHD},
19: {"name": "FRAME_WQXGA", "value": camera.FRAME_WQXGA},
20: {"name": "FRAME_P_FHD", "value": camera.FRAME_P_FHD},
21: {"name": "FRAME_QSXGA", "value": camera.FRAME_QSXGA},
22: {"name": "(default)", "value": None} }


if len(args) > 0:
fn = args[0]

## ESP32-CAM (default configuration) - https://bit.ly/2Ndn8tN
camera.init(0, format=camera.JPEG, fb_location=camera.PSRAM)

if len(args) > 1:
size = int(args[1])
camera.framesize(camera_frames[size]["value"])

if len(args) > 2:
quality = int(args[2])
camera.quality(quality)

print("photo fn={} size={}({}) quality={}".format(fn,size,camera_frames[size]["name"],quality))

# AI-Thinker esp32-cam board
#ai_thinker = {PIN_PWDN:32, PIN_RESET:-1, PIN_XCLK:0, PIN_SIOD:26, PIN_SIOC:27, PIN_D7:35, PIN_D6:34, PIN_D5:39, PIN_D4:36, PIN_D3:21, PIN_D2:19, PIN_D1:18, PIN_D0:5, PIN_VSYNC:25, PIN_HREF:23, PIN_PCLK:22, XCLK_MHZ:16, PIXFORMAT:5, FRAMESIZE:10, JPEG_QUALITY:10, FB_COUNT:1, }

## M5Camera (Version B) - https://bit.ly/317Xb74
# camera.init(0, d0=32, d1=35, d2=34, d3=5, d4=39, d5=18, d6=36, d7=19, format=camera.JPEG, framesize=camera.FRAME_VGA, xclk_freq=camera.XCLK_10MHz, href=26, vsync=25, reset=15, sioc=23, siod=22, xclk=27, pclk=21, fb_location=camera.PSRAM) #M5CAMERA

## T-Camera Mini (green PCB) - https://bit.ly/31H1aaF
# import axp202 # source https://github.com/lewisxhe/AXP202_PythonLibrary
# USB current limit must be disabled (otherwise init fails)
#axp=axp202.PMU( scl=22, sda=21, address=axp202.AXP192_SLAVE_ADDRESS )
#limiting=axp.read_byte( axp202.AXP202_IPS_SET )
#limiting &= 0xfc
#axp.write_byte( axp202.AXP202_IPS_SET, limiting )

#camera.init(0, d0=5, d1=14, d2=4, d3=15, d4=18, d5=23, d6=36, d7=39, format=camera.JPEG, framesize=camera.FRAME_VGA, xclk_freq=camera.XCLK_20MHz, href=25, vsync=27, reset=-1, pwdn=-1, sioc=12, siod=13, xclk=32, pclk=19)


# The parameters: format=camera.JPEG, xclk_freq=camera.XCLK_10MHz are standard for all cameras.
# You can try using a faster xclk (20MHz), this also worked with the esp32-cam and m5camera
# but the image was pixelated and somehow green.


# ## Other settings:
# # flip up side down
# camera.flip(1)
# # left / right
# camera.mirror(1)

# # framesize
# camera.framesize(camera.FRAME_240x240)
# # The options are the following:
# # FRAME_96X96 FRAME_QQVGA FRAME_QCIF FRAME_HQVGA FRAME_240X240
# # FRAME_QVGA FRAME_CIF FRAME_HVGA FRAME_VGA FRAME_SVGA
# # FRAME_XGA FRAME_HD FRAME_SXGA FRAME_UXGA FRAME_FHD
# # FRAME_P_HD FRAME_P_3MP FRAME_QXGA FRAME_QHD FRAME_WQXGA
# # FRAME_P_FHD FRAME_QSXGA
# # Check this link for more information: https://bit.ly/2YOzizz
#
# # special effects
# camera.speffect(camera.EFFECT_NONE)
# # The options are the following:
# # EFFECT_NONE (default) EFFECT_NEG EFFECT_BW EFFECT_RED EFFECT_GREEN EFFECT_BLUE EFFECT_RETRO
#
# # white balance
# camera.whitebalance(camera.WB_NONE)
# # The options are the following:
# # WB_NONE (default) WB_SUNNY WB_CLOUDY WB_OFFICE WB_HOME
#
# # saturation
# camera.saturation(0)
# # -2,2 (default 0). -2 grayscale
#
# # brightness
# camera.brightness(0)
# # -2,2 (default 0). 2 brightness
#
# # contrast
# camera.contrast(0)
# #-2,2 (default 0). 2 highcontrast
#
# # quality
# camera.quality(10)
# # 10-63 lower number means higher quality
#

buf = camera.capture()

if buf:
print("Length of buf:", len(buf))

if fn:
with open(fn, 'wb') as f:
f.write(buf)
else:
print("not written - no filename given")
#print("Contents of buf in hex:", buf.hex())

else:
print("Capture failed (too big for PSRAM?")

#print("open http://esp32-cam-05.local/foo.jpg")

camera.deinit()

try:
# if 'ARGV' in locals():
eval('capture(ARGV)') # ARGV is supplied by caller thusly: ARGV=["pic.jpg","5","10"];exec(open("bin/photo.py").read())
except: # Exception as e:
# print(e) # name 'ARGV' isn't defined
capture([])
17 changes: 17 additions & 0 deletions ports/esp32/boards/ESP32_CAM/sdkconfig.d2wd
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Optimise using -Os to reduce size
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_PERF=n
CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y

# Change maximum log level to error, to reduce firmware size.
CONFIG_LOG_MAXIMUM_LEVEL_ERROR=y
CONFIG_LOG_MAXIMUM_LEVEL_INFO=n

# Disable SPI Ethernet driver to reduce firmware size.
CONFIG_ETH_USE_SPI_ETHERNET=n

CONFIG_ESPTOOLPY_FLASHMODE_DIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_40M=y
CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-2MiB.csv"
7 changes: 7 additions & 0 deletions ports/esp32/boards/ESP32_CAM/sdkconfig.ota
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-4MiB-ota.csv"

# Reduce firmware size to fit in the OTA partition.
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_PERF=n
CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y
1 change: 1 addition & 0 deletions ports/esp32/boards/ESP32_CAM/sdkconfig.unicore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CONFIG_FREERTOS_UNICORE=y