diff --git a/docs/esp32/img/esp32_cam.jpg b/docs/esp32/img/esp32_cam.jpg new file mode 100644 index 0000000000000..de1430abbf015 Binary files /dev/null and b/docs/esp32/img/esp32_cam.jpg differ diff --git a/ports/esp32/boards/ESP32_CAM/board.json b/ports/esp32/boards/ESP32_CAM/board.json new file mode 100644 index 0000000000000..771bddc2fdfe5 --- /dev/null +++ b/ports/esp32/boards/ESP32_CAM/board.json @@ -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" +} diff --git a/ports/esp32/boards/ESP32_CAM/board.md b/ports/esp32/boards/ESP32_CAM/board.md new file mode 100644 index 0000000000000..b2d2ec9782507 --- /dev/null +++ b/ports/esp32/boards/ESP32_CAM/board.md @@ -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 diff --git a/ports/esp32/boards/ESP32_CAM/mpconfigboard.cmake b/ports/esp32/boards/ESP32_CAM/mpconfigboard.cmake new file mode 100644 index 0000000000000..5ff5fabe996db --- /dev/null +++ b/ports/esp32/boards/ESP32_CAM/mpconfigboard.cmake @@ -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() diff --git a/ports/esp32/boards/ESP32_CAM/mpconfigboard.h b/ports/esp32/boards/ESP32_CAM/mpconfigboard.h new file mode 100644 index 0000000000000..22cf1fcdc2b11 --- /dev/null +++ b/ports/esp32/boards/ESP32_CAM/mpconfigboard.h @@ -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 diff --git a/ports/esp32/boards/ESP32_CAM/photo.py b/ports/esp32/boards/ESP32_CAM/photo.py new file mode 100644 index 0000000000000..dc0babe214cdb --- /dev/null +++ b/ports/esp32/boards/ESP32_CAM/photo.py @@ -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([]) diff --git a/ports/esp32/boards/ESP32_CAM/sdkconfig.d2wd b/ports/esp32/boards/ESP32_CAM/sdkconfig.d2wd new file mode 100644 index 0000000000000..2ac983693d3ff --- /dev/null +++ b/ports/esp32/boards/ESP32_CAM/sdkconfig.d2wd @@ -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" diff --git a/ports/esp32/boards/ESP32_CAM/sdkconfig.ota b/ports/esp32/boards/ESP32_CAM/sdkconfig.ota new file mode 100644 index 0000000000000..352dd96f2323f --- /dev/null +++ b/ports/esp32/boards/ESP32_CAM/sdkconfig.ota @@ -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 diff --git a/ports/esp32/boards/ESP32_CAM/sdkconfig.unicore b/ports/esp32/boards/ESP32_CAM/sdkconfig.unicore new file mode 100644 index 0000000000000..f0b0b5e03dd48 --- /dev/null +++ b/ports/esp32/boards/ESP32_CAM/sdkconfig.unicore @@ -0,0 +1 @@ +CONFIG_FREERTOS_UNICORE=y
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: