mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-27 12:20:56 +00:00
440 lines
9.7 KiB
Rust
440 lines
9.7 KiB
Rust
//! Drives the camera on a Freenove ESP32-S3 WROOM (also works as is on the
|
|
//! ESP32S3-EYE)
|
|
//!
|
|
//! This example reads a JPEG from an OV2640 and writes it to the console as
|
|
//! hex.
|
|
//!
|
|
//! The following wiring is assumed:
|
|
//! - SIOD => GPIO4
|
|
//! - SIOC => GPIO5
|
|
//! - XCLK => GPIO15
|
|
//! - VSYNC => GPIO6
|
|
//! - HREF => GPIO7
|
|
//! - PCLK => GPIO13
|
|
//! - D2 => GPIO11
|
|
//! - D3 => GPIO9
|
|
//! - D4 => GPIO8
|
|
//! - D5 => GPIO10
|
|
//! - D6 => GPIO12
|
|
//! - D7 => GPIO18
|
|
//! - D8 => GPIO17
|
|
//! - D9 => GPIO16
|
|
|
|
//% CHIPS: esp32s3
|
|
|
|
#![no_std]
|
|
#![no_main]
|
|
|
|
use esp_backtrace as _;
|
|
use esp_hal::{
|
|
delay::Delay,
|
|
dma_rx_stream_buffer,
|
|
i2c::{
|
|
self,
|
|
master::{Config, I2c},
|
|
},
|
|
lcd_cam::{
|
|
cam::{self, Camera},
|
|
LcdCam,
|
|
},
|
|
main,
|
|
time::Rate,
|
|
Blocking,
|
|
};
|
|
use esp_println::{print, println};
|
|
|
|
#[main]
|
|
fn main() -> ! {
|
|
let peripherals = esp_hal::init(esp_hal::Config::default());
|
|
|
|
let dma_rx_buf = dma_rx_stream_buffer!(20 * 1000, 1000);
|
|
|
|
let cam_siod = peripherals.GPIO4;
|
|
let cam_sioc = peripherals.GPIO5;
|
|
let cam_xclk = peripherals.GPIO15;
|
|
let cam_vsync = peripherals.GPIO6;
|
|
let cam_href = peripherals.GPIO7;
|
|
let cam_pclk = peripherals.GPIO13;
|
|
|
|
let cam_config = cam::Config::default().with_frequency(Rate::from_mhz(20));
|
|
|
|
let lcd_cam = LcdCam::new(peripherals.LCD_CAM);
|
|
let camera = Camera::new(lcd_cam.cam, peripherals.DMA_CH0, cam_config)
|
|
.unwrap()
|
|
.with_master_clock(cam_xclk)
|
|
.with_pixel_clock(cam_pclk)
|
|
.with_vsync(cam_vsync)
|
|
.with_h_enable(cam_href)
|
|
.with_data0(peripherals.GPIO11)
|
|
.with_data1(peripherals.GPIO9)
|
|
.with_data2(peripherals.GPIO8)
|
|
.with_data3(peripherals.GPIO10)
|
|
.with_data4(peripherals.GPIO12)
|
|
.with_data5(peripherals.GPIO18)
|
|
.with_data6(peripherals.GPIO17)
|
|
.with_data7(peripherals.GPIO16);
|
|
|
|
let delay = Delay::new();
|
|
|
|
delay.delay_millis(500u32);
|
|
|
|
let i2c = I2c::new(peripherals.I2C0, Config::default())
|
|
.unwrap()
|
|
.with_sda(cam_siod)
|
|
.with_scl(cam_sioc);
|
|
|
|
let mut sccb = Sccb::new(i2c);
|
|
|
|
// Checking camera address
|
|
sccb.probe(OV2640_ADDRESS).unwrap();
|
|
println!("Probe successful!");
|
|
|
|
sccb.write(OV2640_ADDRESS, 0xFF, 0x01).unwrap(); // bank sensor
|
|
let pid = sccb.read(OV2640_ADDRESS, 0x0A).unwrap();
|
|
println!("Found PID of {:#02X}, and was expecting 0x26", pid);
|
|
|
|
for (reg, value) in FIRST_BLOCK {
|
|
sccb.write(OV2640_ADDRESS, *reg, *value).unwrap();
|
|
}
|
|
delay.delay_millis(10u32);
|
|
for (reg, value) in SECOND_BLOCK {
|
|
sccb.write(OV2640_ADDRESS, *reg, *value).unwrap();
|
|
if *reg == 0xDD && *value == 0x7F {
|
|
delay.delay_millis(10u32);
|
|
}
|
|
}
|
|
|
|
// Start receiving data from the camera.
|
|
let mut transfer = camera.receive(dma_rx_buf).map_err(|e| e.0).unwrap();
|
|
|
|
// Skip the first 2 images. Each image ends with an EOF.
|
|
// We likely missed the first few bytes of the first image and the second image
|
|
// is likely garbage from the OV2640 focusing, calibrating, etc.
|
|
// Feel free to skip more images if the one captured below is still garbage.
|
|
for _ in 0..2 {
|
|
let mut total_bytes = 0;
|
|
loop {
|
|
let (data, ends_with_eof) = transfer.peek_until_eof();
|
|
if data.is_empty() {
|
|
if transfer.is_done() {
|
|
panic!("We were too slow to read from the DMA");
|
|
}
|
|
} else {
|
|
let bytes_peeked = data.len();
|
|
transfer.consume(bytes_peeked);
|
|
total_bytes += bytes_peeked;
|
|
if ends_with_eof {
|
|
// Found the end of the image/frame.
|
|
println!("Skipped a {} byte image", total_bytes);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
println!("Frame data (parse with `xxd -r -p <uart>.txt image.jpg`):");
|
|
|
|
// Note: JPEGs starts with "FF, D8, FF, E0" and end with "FF, D9".
|
|
// The OV2640 also sends some trailing zeros after the JPEG. This is expected.
|
|
|
|
loop {
|
|
let (data, ends_with_eof) = transfer.peek_until_eof();
|
|
if data.is_empty() {
|
|
if transfer.is_done() {
|
|
panic!("We were too slow to read from the DMA");
|
|
}
|
|
} else {
|
|
for b in data {
|
|
print!("{:02X}, ", b);
|
|
}
|
|
let bytes_peeked = data.len();
|
|
transfer.consume(bytes_peeked);
|
|
|
|
if ends_with_eof {
|
|
// Found the end of the image/frame.
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// The full frame has been captured, the transfer can be stopped now.
|
|
let _ = transfer.stop();
|
|
|
|
loop {}
|
|
}
|
|
|
|
pub const OV2640_ADDRESS: u8 = 0x30;
|
|
|
|
pub struct Sccb<'d> {
|
|
i2c: I2c<'d, Blocking>,
|
|
}
|
|
|
|
impl<'d> Sccb<'d> {
|
|
pub fn new(i2c: I2c<'d, Blocking>) -> Self {
|
|
Self { i2c }
|
|
}
|
|
|
|
pub fn probe(&mut self, address: u8) -> Result<(), i2c::master::Error> {
|
|
self.i2c.write(address, &[])
|
|
}
|
|
|
|
pub fn read(&mut self, address: u8, reg: u8) -> Result<u8, i2c::master::Error> {
|
|
self.i2c.write(address, &[reg])?;
|
|
|
|
let mut bytes = [0u8; 1];
|
|
self.i2c.read(address, &mut bytes)?;
|
|
Ok(bytes[0])
|
|
}
|
|
|
|
pub fn write(&mut self, address: u8, reg: u8, data: u8) -> Result<(), i2c::master::Error> {
|
|
self.i2c.write(address, &[reg, data])
|
|
}
|
|
}
|
|
|
|
const FIRST_BLOCK: &[(u8, u8)] = &[(0xFF, 0x01), (0x12, 0x80)];
|
|
|
|
const SECOND_BLOCK: &[(u8, u8)] = &[
|
|
(0xFF, 0x00),
|
|
(0x2C, 0xFF),
|
|
(0x2E, 0xDF),
|
|
(0xFF, 0x01),
|
|
(0x3C, 0x32),
|
|
(0x11, 0x01),
|
|
(0x09, 0x02),
|
|
(0x04, 0x28),
|
|
(0x13, 0xE5),
|
|
(0x14, 0x48),
|
|
(0x2C, 0x0C),
|
|
(0x33, 0x78),
|
|
(0x3A, 0x33),
|
|
(0x3B, 0xFB),
|
|
(0x3E, 0x00),
|
|
(0x43, 0x11),
|
|
(0x16, 0x10),
|
|
(0x39, 0x92),
|
|
(0x35, 0xDA),
|
|
(0x22, 0x1A),
|
|
(0x37, 0xC3),
|
|
(0x23, 0x00),
|
|
(0x34, 0xC0),
|
|
(0x06, 0x88),
|
|
(0x07, 0xC0),
|
|
(0x0D, 0x87),
|
|
(0x0E, 0x41),
|
|
(0x4C, 0x00),
|
|
(0x4A, 0x81),
|
|
(0x21, 0x99),
|
|
(0x24, 0x40),
|
|
(0x25, 0x38),
|
|
(0x26, 0x82),
|
|
(0x5C, 0x00),
|
|
(0x63, 0x00),
|
|
(0x61, 0x70),
|
|
(0x62, 0x80),
|
|
(0x7C, 0x05),
|
|
(0x20, 0x80),
|
|
(0x28, 0x30),
|
|
(0x6C, 0x00),
|
|
(0x6D, 0x80),
|
|
(0x6E, 0x00),
|
|
(0x70, 0x02),
|
|
(0x71, 0x94),
|
|
(0x73, 0xC1),
|
|
(0x3D, 0x34),
|
|
(0x5A, 0x57),
|
|
(0x4F, 0xBB),
|
|
(0x50, 0x9C),
|
|
(0x12, 0x20),
|
|
(0x17, 0x11),
|
|
(0x18, 0x43),
|
|
(0x19, 0x00),
|
|
(0x1A, 0x25),
|
|
(0x32, 0x89),
|
|
(0x37, 0xC0),
|
|
(0x4F, 0xCA),
|
|
(0x50, 0xA8),
|
|
(0x6D, 0x00),
|
|
(0x3D, 0x38),
|
|
(0xFF, 0x00),
|
|
(0xE5, 0x7F),
|
|
(0xF9, 0xC0),
|
|
(0x41, 0x24),
|
|
(0xE0, 0x14),
|
|
(0x76, 0xFF),
|
|
(0x33, 0xA0),
|
|
(0x42, 0x20),
|
|
(0x43, 0x18),
|
|
(0x4C, 0x00),
|
|
(0x87, 0x50),
|
|
(0x88, 0x3F),
|
|
(0xD7, 0x03),
|
|
(0xD9, 0x10),
|
|
(0xD3, 0x82),
|
|
(0xC8, 0x08),
|
|
(0xC9, 0x80),
|
|
(0x7C, 0x00),
|
|
(0x7D, 0x00),
|
|
(0x7C, 0x03),
|
|
(0x7D, 0x48),
|
|
(0x7D, 0x48),
|
|
(0x7C, 0x08),
|
|
(0x7D, 0x20),
|
|
(0x7D, 0x10),
|
|
(0x7D, 0x0E),
|
|
(0x90, 0x00),
|
|
(0x91, 0x0E),
|
|
(0x91, 0x1A),
|
|
(0x91, 0x31),
|
|
(0x91, 0x5A),
|
|
(0x91, 0x69),
|
|
(0x91, 0x75),
|
|
(0x91, 0x7E),
|
|
(0x91, 0x88),
|
|
(0x91, 0x8F),
|
|
(0x91, 0x96),
|
|
(0x91, 0xA3),
|
|
(0x91, 0xAF),
|
|
(0x91, 0xC4),
|
|
(0x91, 0xD7),
|
|
(0x91, 0xE8),
|
|
(0x91, 0x20),
|
|
(0x92, 0x00),
|
|
(0x93, 0x06),
|
|
(0x93, 0xE3),
|
|
(0x93, 0x05),
|
|
(0x93, 0x05),
|
|
(0x93, 0x00),
|
|
(0x93, 0x04),
|
|
(0x93, 0x00),
|
|
(0x93, 0x00),
|
|
(0x93, 0x00),
|
|
(0x93, 0x00),
|
|
(0x93, 0x00),
|
|
(0x93, 0x00),
|
|
(0x93, 0x00),
|
|
(0x96, 0x00),
|
|
(0x97, 0x08),
|
|
(0x97, 0x19),
|
|
(0x97, 0x02),
|
|
(0x97, 0x0C),
|
|
(0x97, 0x24),
|
|
(0x97, 0x30),
|
|
(0x97, 0x28),
|
|
(0x97, 0x26),
|
|
(0x97, 0x02),
|
|
(0x97, 0x98),
|
|
(0x97, 0x80),
|
|
(0x97, 0x00),
|
|
(0x97, 0x00),
|
|
(0xA4, 0x00),
|
|
(0xA8, 0x00),
|
|
(0xC5, 0x11),
|
|
(0xC6, 0x51),
|
|
(0xBF, 0x80),
|
|
(0xC7, 0x10),
|
|
(0xB6, 0x66),
|
|
(0xB8, 0xA5),
|
|
(0xB7, 0x64),
|
|
(0xB9, 0x7C),
|
|
(0xB3, 0xAF),
|
|
(0xB4, 0x97),
|
|
(0xB5, 0xFF),
|
|
(0xB0, 0xC5),
|
|
(0xB1, 0x94),
|
|
(0xB2, 0x0F),
|
|
(0xC4, 0x5C),
|
|
(0xC3, 0xFD),
|
|
(0x7F, 0x00),
|
|
(0xE5, 0x1F),
|
|
(0xE1, 0x67),
|
|
(0xDD, 0x7F),
|
|
(0xDA, 0x00),
|
|
(0xE0, 0x00),
|
|
(0x05, 0x00),
|
|
(0x05, 0x01),
|
|
(0xFF, 0x01),
|
|
(0x12, 0x40),
|
|
(0x03, 0x0A),
|
|
(0x32, 0x09),
|
|
(0x17, 0x11),
|
|
(0x18, 0x43),
|
|
(0x19, 0x00),
|
|
(0x1A, 0x4B),
|
|
(0x37, 0xC0),
|
|
(0x4F, 0xCA),
|
|
(0x50, 0xA8),
|
|
(0x5A, 0x23),
|
|
(0x6D, 0x00),
|
|
(0x3D, 0x38),
|
|
(0x39, 0x92),
|
|
(0x35, 0xDA),
|
|
(0x22, 0x1A),
|
|
(0x37, 0xC3),
|
|
(0x23, 0x00),
|
|
(0x34, 0xC0),
|
|
(0x06, 0x88),
|
|
(0x07, 0xC0),
|
|
(0x0D, 0x87),
|
|
(0x0E, 0x41),
|
|
(0x42, 0x03),
|
|
(0x4C, 0x00),
|
|
(0xFF, 0x00),
|
|
(0xE0, 0x04),
|
|
(0xC0, 0x64),
|
|
(0xC1, 0x4B),
|
|
(0x8C, 0x00),
|
|
(0x51, 0xC8),
|
|
(0x52, 0x96),
|
|
(0x53, 0x00),
|
|
(0x54, 0x00),
|
|
(0x55, 0x00),
|
|
(0x57, 0x00),
|
|
(0x86, 0x3D),
|
|
(0x50, 0x80),
|
|
(0x51, 0xC8),
|
|
(0x52, 0x96),
|
|
(0x53, 0x00),
|
|
(0x54, 0x00),
|
|
(0x55, 0x00),
|
|
(0x57, 0x00),
|
|
(0x5A, 0xA0),
|
|
(0x5B, 0x78),
|
|
(0x5C, 0x00),
|
|
(0xFF, 0x01),
|
|
(0x11, 0x00),
|
|
(0xFF, 0x00),
|
|
(0xD3, 0x10),
|
|
(0x05, 0x00),
|
|
(0xE0, 0x14),
|
|
(0xDA, 0x12),
|
|
(0xD7, 0x03),
|
|
(0xE1, 0x77),
|
|
(0xE5, 0x1F),
|
|
(0xD9, 0x10),
|
|
(0xDF, 0x80),
|
|
(0x33, 0x80),
|
|
(0x3C, 0x10),
|
|
(0xEB, 0x30),
|
|
(0xDD, 0x7F),
|
|
(0xE0, 0x00),
|
|
(0xE0, 0x14),
|
|
(0xDA, 0x12),
|
|
(0xD7, 0x03),
|
|
(0xE1, 0x77),
|
|
(0xE5, 0x1F),
|
|
(0xD9, 0x10),
|
|
(0xDF, 0x80),
|
|
(0x33, 0x80),
|
|
(0x3C, 0x10),
|
|
(0xEB, 0x30),
|
|
(0xDD, 0x7F),
|
|
(0xE0, 0x00),
|
|
(0xFF, 0x01),
|
|
(0x14, 0x08),
|
|
(0xFF, 0x00),
|
|
(0x87, 0x50),
|
|
(0x87, 0x10),
|
|
(0xC3, 0xFD),
|
|
(0x44, 0x0C),
|
|
];
|