How can I use esp32-cam module in my project

I am trying to use the AtomVM with esp32-CAM module. I have added the library as a dependency as it’s shown in the example:

{deps, [
    {atomvm_esp32cam, {git, "https://github.com/atomvm/atomvm_esp32cam.git", {branch, "master"}}}
]}.

And in my code I do:

start() ->
    ok = esp32cam:init(),
    io:format("Camera initialized.~n"),
    {ok, Image} = esp32cam:capture(),
    io:format("Captured image.  size=~p~n", [erlang:byte_size(Image)]).

When I upload the code on the code I am seeing this error:

I (824) AtomVM: Starting AtomVM revision 0.6.5
I (834) sys: Loaded BEAM partition boot.avm at address 0x1d0000 (size=262144 bytes)
I (854) network_driver: Initialized network interface
I (854) network_driver: Created default event loop
I (874) AtomVM: Found startup beam esp32init.beam
I (874) AtomVM: Starting esp32init.beam...
---
AtomVM init.
I (884) sys: Loaded BEAM partition main.avm at address 0x210000 (size=1048576 bytes)
Starting application...
CRASH
======
pid: <0.1.0>

Stacktrace:
[{esp32cam,init,1,[{file,"/Users/oleg/repos/atomvm_examples/erlang/tcp_server/_build/default/lib/atomvm_esp32cam/src/esp32cam.erl"},{line,52}]}]

cp: #CP<module: 4, label: 2, offset: 12>

x[0]: throw
x[1]: nif_error
x[2]: {1,1,103,1,[{5,35}],throw}

Stack
------

[]
#CP<module: 0, label: 34, offset: 0>


Mailbox
--------


Monitors
--------


**End Of Crash Report**
AtomVM finished with return value: throw
I (944) AtomVM: AtomVM application terminated.  Going to sleep forever ...

Part of your problem is we have an open pull request that needs to be merged. I poked Davide Bettio about this, so hopefully that will be taken care of soon.

The extra drivers (like atomvm_esp32cam) need to be built into a custom VM image. The reason being that microcontrollers like esp32 cannot dynamically load libraries, so all nifs and ports need to be statically compiled into the VM itself. To accomplish this you first need a local clone of the AtomVM repository. Then you will need to clone the atomvm_esp32cam repository into the atomvm/src/platforms/esp32/components directory of the previously cloned AtomVM repository. Then to make sure the new component is included in the build you can either run idf.py menuconfig and exit being sure to save the changes, or simply run idf.py reconfigure. This will also require having set up and installed the esp-idf and activaing it in your environment.

For more detailed instructions on building the image you can follow the Build Instructions for esp32.

If you do not want to wait for the open pull request to be merged you can clone the contributors branch with these changes by using:
git clone https://github.com/petermm/atomvm_esp32cam in the atomvm/src/platforms/esp32/components directory as mentioned above.

Hope this helps! If you run into more trouble please let us know and we will help you get this working.

Best of luck,
Winford

The PR has been merged, so that should simply things for you a bit.

One more resource I should have pointed out is the documentation for adding custom nifs, ports, and third-party components to an ESP32 binary image. This is at the end of the ESP32 build instructions after the section on flashing the image.

Let us know how it goes.

Thanks for your reply, I am trying to build atomVM with the cam module enabled this way:

git clone git@github.com:atomvm/AtomVM.git
cd atomVM/
cd src/platforms/esp32/components
git clone https://github.com/petermm/atomvm_esp32cam
cd ..

esp32|main ⇒ idf.py menuconfig
Executing action: menuconfig
Running cmake in directory /Users/oleg/repos/AtomVM/src/platforms/esp32/build
Executing "cmake -G Ninja -DPYTHON_DEPS_CHECKED=1 -DPYTHON=/Users/oleg/.espressif/python_env/idf5.2_py3.11_env/bin/python -DESP_PLATFORM=1 -DCCACHE_ENABLE=0 /Users/oleg/repos/AtomVM/src/platforms/esp32"...
-- IDF_TARGET not set, using default target: esp32
-- Found Git: /usr/local/bin/git (found version "2.38.1")
-- The C compiler identification is GNU 13.2.0
-- The CXX compiler identification is GNU 13.2.0
-- The ASM compiler identification is GNU
-- Found assembler: /Users/oleg/.espressif/tools/xtensa-esp-elf/esp-13.2.0_20230928/xtensa-esp-elf/bin/xtensa-esp32-elf-gcc
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Users/oleg/.espressif/tools/xtensa-esp-elf/esp-13.2.0_20230928/xtensa-esp-elf/bin/xtensa-esp32-elf-gcc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Users/oleg/.espressif/tools/xtensa-esp-elf/esp-13.2.0_20230928/xtensa-esp-elf/bin/xtensa-esp32-elf-g++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Building ESP-IDF components for target esp32
NOTICE: Skipping optional dependency: espressif/esp_wifi_remote
NOTICE: Skipping optional dependency: espressif/esp_wifi_remote
NOTICE: Skipping optional dependency: espressif/esp_wifi_remote
NOTICE: Skipping optional dependency: espressif/esp_wifi_remote
NOTICE: Processing 1 dependencies:
NOTICE: [1/1] idf (5.2.0)
NOTICE: Skipping optional dependency: espressif/esp_wifi_remote
CMake Error at /Users/oleg/esp/esp-idf/tools/cmake/build.cmake:268 (message):
  Failed to resolve component 'esp32-camera'.
Call Stack (most recent call first):
  /Users/oleg/esp/esp-idf/tools/cmake/build.cmake:310 (__build_resolve_and_add_req)
  /Users/oleg/esp/esp-idf/tools/cmake/build.cmake:599 (__build_expand_requirements)
  /Users/oleg/esp/esp-idf/tools/cmake/project.cmake:605 (idf_build_process)
  CMakeLists.txt:54 (project)


-- Configuring incomplete, errors occurred!
cmake failed with exit code 1

Sorry, I haven’t built this component for a while so forgot an important detail. You also need to clone the espressif/esp32-camera driver into the components directory next to the atomvm_eap32cam directory. I submitted a pull request (waiting for review) that will take care of the extra step of having to clone the espressif driver manually. I also opened an issue in the atomvm_esp32cam repository about improving the documentation on building and using this driver, but that may take a little while for me to get to — unless someone beats me to it

It’s not entirely easy to build this, you need to:
idf.py add-dependency "espressif/esp32-camera" in src/platforms/esp32

BUT, if you using 5.4 or greater there is an conflict with the i2c driver esp32-camera/CMakeLists.txt at 4467667b71f22a4c7db226f24105a9350abe7a05 · espressif/esp32-camera · GitHub - maybe one can edit/patch in the components folder, or version lock to older version.. but looks like you are on 5.2, so it should be fine..

Then you’ll want to bump cpu speed, and make the flash and psram faster(80mhz) (also enable psram) Build Instructions — AtomVM 0.7.0-dev+git.58fe3aec documentation

If you run out of “IRAM” - you can go into idf.py menuconfig Component config Wi-Fi and disable the WiFi RX IRAM speed optimization

I assume you are on the old AI thinker board?

Hi,

I have managed to build the AtomVM with the camera support, however I am having problems with my camera model (GC2145) that does not support JPEG output format according to GitHub - espressif/esp32-camera

According to docs it supports the following:
YUV/YCbCr422
RAW Bayer
RGB565

So I updated the atomvm_esp32cam.c parts of create_camera_config function with the

config->pixel_format = PIXFORMAT_RGB565;
config->frame_size = FRAMESIZE_QVGA;

Than re-built the atomVM, deployed it on the device, and re-deployed my application. Now I see this error:

---
AtomVM init.
I (976) sys: Loaded BEAM partition main.avm at address 0x210000 (size=1048576 bytes)
Starting application...
I (1016) gpio: GPIO[25]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:2
I (1016) cam_hal: cam init ok
I (1016) sccb: pin_sda 26 pin_scl 27
I (1026) sccb: sccb_i2c_port=1
I (1026) gpio: GPIO[32]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (1066) camera: Detected camera at address=0x3c
I (1066) ov3660: Mismatch PID=0x0
I (1066) ov5640: Mismatch PID=0x0
I (1066) camera: Detected GC2145 camera
I (1066) camera: Camera PID=0x2145 VER=0x00 MIDL=0x00 MIDH=0x00
I (1536) esp32 ll_cam: node_size: 2560, nodes_per_line: 1, lines_per_node: 1, dma_half_buffer_min:  2560, dma_half_buffer: 15360,lines_per_half_buffer:  6, dma_buffer_size: 30720, image_size: 153600
I (1546) cam_hal: buffer_size: 30720, half_buffer_size: 15360, node_buffer_size: 2560, node_cnt: 12, total_cnt: 10
I (1556) cam_hal: Allocating 153600 Byte frame buffer in PSRAM
E (1556) cam_hal: cam_dma_config(301): frame buffer malloc failed
E (1566) cam_hal: cam_config(390): cam_dma_config failed
E (1576) camera: Camera config failed with error 0xffffffff
E (1576) atomvm_esp32cam: Failed to initialize esp_camera: err=-1
Camera initialized.
E (1586) atomvm_esp32cam: Camera not initialized!  Bad state.
CRASH
======
pid: <0.1.0>

Stacktrace:
[{tcp_server,start,0,[{file,"/Users/oleg/repos/atomvm_examples/erlang/tcp_server/src/tcp_server.erl"},{line,33}]}]

cp: #CP<module: 4, label: 2, offset: 21>

x[0]: error
x[1]: bad_state
x[2]: {1,1,70,1,[{4,33}],error}

Stack
-----

[]
#CP<module: 0, label: 34, offset: 0>


Mailbox
-------


Monitors
--------


**End Of Crash Report**
AtomVM finished with return value: error

seems like you need to enable PSRAM:
idf.py menuconfig in src/platforms/esp32 Component config ---> ESP PSRAM

I tried it, but when building i see this:

collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.
HINT: The applications static IRAM usage is larger than the available IRAM size.
For more information on how to reduze IRAM usage run 'idf.py docs -sp api-guides/performance/ram-usage.html#optimizing-iram-usage'
ninja failed with exit code 1, output of the command is in the /Users/oleg/repos/AtomVM/src/platforms/esp32/build/log/idf_py_stderr_output_93199 and /Users/oleg/repos/AtomVM/src/platforms/esp32/build/log/idf_py_stdout_output_93199
1 Like

yeah, you can lower IRAM usage by something like:

1 Like

I have tried it, and the build now works. Hovewer the VM still crashes on camera init


 (1568) gpio: GPIO[32]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (1608) camera: Detected camera at address=0x3c
I (1608) ov3660: Mismatch PID=0x0
I (1608) ov5640: Mismatch PID=0x0
I (1608) camera: Detected GC2145 camera
I (1608) camera: Camera PID=0x2145 VER=0x00 MIDL=0x00 MIDH=0x00
I (2088) esp32 ll_cam: node_size: 3840, nodes_per_line: 1, lines_per_node: 2, dma_half_buffer_min:  3840, dma_half_buffer: 15360,lines_per_half_buffer:  8, dma_buffer_size: 30720, image_size: 115200
I (2098) cam_hal: buffer_size: 30720, half_buffer_size: 15360, node_buffer_size: 3840, node_cnt: 8, total_cnt: 7
I (2108) cam_hal: Allocating 115200 Byte frame buffer in OnBoard RAM
E (2108) cam_hal: cam_dma_config(301): frame buffer malloc failed
E (2118) cam_hal: cam_config(390): cam_dma_config failed
E (2128) camera: Camera config failed with error 0xffffffff
E (2128) atomvm_esp32cam: Failed to initialize esp_camera: err=-1
Camera initialized.
E (2138) atomvm_esp32cam: Camera not initialized!  Bad state.
CRASH

great, think we may need

.fb_location = CAMERA_FB_IN_PSRAM,

(I seem to have lost my customisations to atomvm_esp32cam due to git resets and what not inside atomvm folder)

I have first success after switching to GRAYSCALE format. e.g.

I (1148) camera: Detected camera at address=0x3c
I (1148) ov3660: Mismatch PID=0x0
I (1148) ov5640: Mismatch PID=0x0
I (1148) camera: Detected GC2145 camera
I (1148) camera: Camera PID=0x2145 VER=0x00 MIDL=0x00 MIDH=0x00
I (1628) esp32 ll_cam: node_size: 2560, nodes_per_line: 1, lines_per_node: 1, dma_half_buffer_min:  2560, dma_half_buffer: 15360,lines_per_half_buffer:  6, dma_buffer_size: 30720, image_size: 153600
I (1638) cam_hal: buffer_size: 30720, half_buffer_size: 15360, node_buffer_size: 2560, node_cnt: 12, total_cnt: 10
I (1648) cam_hal: Allocating 76800 Byte frame buffer in OnBoard RAM
I (1648) cam_hal: cam config ok
I (1658) gc2145: subsample win:640x480, ratio:0.500000
W (1668) gc2145: unsupport format
Camera initialized.
Captured image.  size=76800

ChatGPT suggest that I need to somehow initialize the PSRAM that has 4MB of memory. However the question is that I don’t understand how this can be done :(. If of course he says something real

1 Like

You can enable PSRSAM using the command idf.py menuconfig in the AtomVM/src/platforms/esp32 directory. Then you need to navigate to Component config > ESP PSRAM and just enable Support for external, SPI-connected RAM by selecting it and pressing the space bar. Then hit q and y to confirm saving the changes.

I believe I have it enabled in menuconfig:

    Type of SPI RAM chip in use (Auto-detect)  --->
    Set RAM clock speed (40MHz clock speed)  --->
[*] Initialize SPI RAM during startup
[ ]     Ignore PSRAM when not found
    SPI RAM access method (Make RAM allocatable using malloc() as well)  --->
[ ] Run memory test on SPI RAM initialization
(16384) Maximum malloc() size, in bytes, to always put in internal memory
[*] Try to allocate memories of WiFi and LWIP in SPIRAM firstly. If failed, allocate
(32768) Reserve this amount of bytes for data that specifically needs to be in DMA o
[ ] Allow .bss segment placed in external memory
[ ] Allow .noinit segment placed in external memory
[*] Enable workaround for bug in SPI RAM cache for Rev1 ESP32s
    SPIRAM cache workaround debugging  --->
    SPIRAM workaround libraries placement  --->
[*] Enable bank switching for >4MiB external RAM
(8)     Amount of 32K pages to reserve for bank switching
[*] Allow external memory as an argument to xTaskCreateStatic
    PSRAM clock and cs IO for ESP32-DOWD  --->
    PSRAM clock and cs IO for ESP32-D2WD  --->
    PSRAM clock and cs IO for ESP32-PICO-D4  --->
[*] Use custom SPI PSRAM WP(SD3) Pin when flash pins set in eFuse (read help)
(7) Custom SPI PSRAM WP(SD3) Pin
[*] Enable SPI PSRAM 2T mode

Yes. That looks good. Just make sure you confirm saving when you exit.

Hi, it looks like I was not saving it correctly. In any case now the PSRAM works and I have managed to save large pictures! Thank you for support!

2 Likes

Wonderful! Please let us know if you run into any other problems. Your feedback has brought several improvements to mind that we can make to simplify the build and configuration of this driver. Thanks for the feedback and working with us, it always helps us find wait improve user experience and spot places that the documentation needs to be improved.

Looking forward to hearing any updates about projects you are working on, or any other problems you may encounter while exploring AtomVM.

Happy hacking,
Winford