diff --git a/Cargo.toml b/Cargo.toml index 35959a1..4c7c915 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ esp-idf-hal = "0.43.1" esp-idf-sys = "0.34.1" [patch.crates-io] -esp-idf-sys = {git = "https://github.com/esp-rs/esp-idf-sys", branch = "master"} +esp-idf-sys = { git = "https://github.com/esp-rs/esp-idf-sys", branch = "master" } [[package.metadata.esp-idf-sys.extra_components]] component_dirs = "esp32-camera" diff --git a/examples/camera-example/.cargo/config.toml b/examples/camera-example/.cargo/config.toml new file mode 100644 index 0000000..058f7f5 --- /dev/null +++ b/examples/camera-example/.cargo/config.toml @@ -0,0 +1,17 @@ +[build] +target = "xtensa-esp32-espidf" + +[target.xtensa-esp32-espidf] +linker = "ldproxy" +# runner = "espflash --monitor" # Select this runner for espflash v1.x.x +runner = "espflash flash --monitor" # Select this runner for espflash v2.x.x +rustflags = [ "--cfg", "espidf_time64"] # Extending time_t for ESP IDF 5: https://github.com/esp-rs/rust/issues/110 + +[unstable] +build-std = ["std", "panic_abort"] + +[env] +MCU="esp32" +# Note: this variable is not used by the pio builder (`cargo build --features pio`) +ESP_IDF_VERSION = "v5.1.3" + diff --git a/examples/camera-example/.gitignore b/examples/camera-example/.gitignore new file mode 100644 index 0000000..7c18138 --- /dev/null +++ b/examples/camera-example/.gitignore @@ -0,0 +1,4 @@ +.embuild/ +target/ +components_esp32.lock +Cargo.lock \ No newline at end of file diff --git a/examples/camera-example/Cargo.toml b/examples/camera-example/Cargo.toml new file mode 100644 index 0000000..5d0d52b --- /dev/null +++ b/examples/camera-example/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "camera-example" +version = "0.1.0" +authors = ["Mathias Pius "] +edition = "2021" +rust-version = "1.71" + +[profile.release] +opt-level = "s" + +[profile.dev] +debug = true # Symbols are nice and they don't increase the size on Flash +opt-level = "z" + +[dependencies] +log = { version = "0.4", default-features = false } +anyhow = "1.0.82" +esp-idf-svc = { version = "0.48", default-features = false, features = [ + "binstart", + "std", +] } +esp-idf-sys = { version = "0.34.1" } +esp-camera-rs = { git = "https://github.com/MathiasPius/esp-camera-rs.git" } + +[build-dependencies] +embuild = "0.31.3" diff --git a/examples/camera-example/README.md b/examples/camera-example/README.md new file mode 100644 index 0000000..40882c7 --- /dev/null +++ b/examples/camera-example/README.md @@ -0,0 +1,12 @@ +This example assumes you have already set up all the tools necessary to compile Rust for ESP32. + +When run using `cargo run`, it will compile and flash the program to an ESP32-CAM mounted on an +ESP32-CAM-MB board connected via USB to the host machine. + +The program will: + + 1. Initialize the onboard OV2640 camera as well as the bright white LED (flash). + 2. Turn on the flash. + 3. Take a jpeg-encoded picture using the camera. + 4. Print information about the image: width, height and size in bytes. + 5. Enter deep sleep for 60 seconds, after which the device starts the process. \ No newline at end of file diff --git a/examples/camera-example/build.rs b/examples/camera-example/build.rs new file mode 100644 index 0000000..112ec3f --- /dev/null +++ b/examples/camera-example/build.rs @@ -0,0 +1,3 @@ +fn main() { + embuild::espidf::sysenv::output(); +} diff --git a/examples/camera-example/rust-toolchain.toml b/examples/camera-example/rust-toolchain.toml new file mode 100644 index 0000000..a2f5ab5 --- /dev/null +++ b/examples/camera-example/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "esp" diff --git a/examples/camera-example/sdkconfig.defaults b/examples/camera-example/sdkconfig.defaults new file mode 100644 index 0000000..c073e82 --- /dev/null +++ b/examples/camera-example/sdkconfig.defaults @@ -0,0 +1,5 @@ +# I think larger stack size is required for rust? Not sure where I got this info +CONFIG_ESP_MAIN_TASK_STACK_SIZE=8000 + +# Enable PSRAM, which allows us to store larger images +CONFIG_ESP32_SPIRAM_SUPPORT=y \ No newline at end of file diff --git a/examples/camera-example/src/main.rs b/examples/camera-example/src/main.rs new file mode 100644 index 0000000..a5b9267 --- /dev/null +++ b/examples/camera-example/src/main.rs @@ -0,0 +1,76 @@ +use esp_idf_svc::hal::{gpio::PinDriver, peripherals::Peripherals}; +use esp_idf_sys::esp_deep_sleep; +use log::info; +use std::time::Duration; + +fn main() -> anyhow::Result<()> { + // It is necessary to call this function once. Otherwise some patches to the runtime + // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71 + esp_idf_svc::sys::link_patches(); + + // Bind the log crate to the ESP Logging facilities + esp_idf_svc::log::EspLogger::initialize_default(); + + info!("initializing camera and flash"); + let peripherals = Peripherals::take().unwrap(); + + // ESP32-CAM has an onboard Flash LED addressed at GPIO-4 + let mut flash = PinDriver::output(peripherals.pins.gpio4)?; + flash.set_low()?; + + // Initialize the camera + let camera = esp_camera_rs::Camera::new( + peripherals.pins.gpio32, + peripherals.pins.gpio0, + peripherals.pins.gpio5, + peripherals.pins.gpio18, + peripherals.pins.gpio19, + peripherals.pins.gpio21, + peripherals.pins.gpio36, + peripherals.pins.gpio39, + peripherals.pins.gpio34, + peripherals.pins.gpio35, + peripherals.pins.gpio25, + peripherals.pins.gpio23, + peripherals.pins.gpio22, + peripherals.pins.gpio26, + peripherals.pins.gpio27, + esp_idf_sys::camera::pixformat_t_PIXFORMAT_JPEG, + esp_idf_sys::camera::framesize_t_FRAMESIZE_UXGA, + esp_idf_sys::camera::camera_fb_location_t_CAMERA_FB_IN_PSRAM, + )?; + + info!("initialization complete!"); + + // Turn on the flash and take a picture. + // You probably want to keep it on for a while and adjust + // the camera exposure to get a good image, but this is + // mainly here to show that the program is working. + info!("taking a picture"); + flash.set_high()?; + let framebuffer = camera.get_framebuffer(); + flash.set_low()?; + + if let Some(framebuffer) = framebuffer { + info!( + "took picture: {width}x{height} {size} bytes", + width = framebuffer.width(), + height = framebuffer.height(), + size = framebuffer.data().len(), + ); + + // TODO: Do something with the framebuffer. + // the JPEG-encoded byte data is in framebuffer.data() + // so you can just dump this to a file or send it over + // the network as "image.jpeg" and it should work. + } else { + panic!("failed to take image"); + }; + + // Send the board into deep sleep. This will basically turn off everything + // and consume very little power, and then "reboot" the device, restarting + // the pin initialization and taking another picture. + let delay = Duration::from_secs(60); + info!("finished, entering deep sleep for {delay:#?}"); + unsafe { esp_deep_sleep(delay.as_micros() as u64) } +}