#![no_std] #![no_main] #![feature(type_alias_impl_trait)] use embassy_executor::Spawner; use embassy_stm32::dcmi::{self, *}; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::i2c::I2c; use embassy_stm32::rcc::{Mco, Mco1Source, McoClock}; use embassy_stm32::time::{khz, mhz}; use embassy_stm32::{bind_interrupts, i2c, peripherals, Config}; use embassy_time::{Duration, Timer}; use ov7725::*; use {defmt_rtt as _, panic_probe as _}; const WIDTH: usize = 100; const HEIGHT: usize = 100; static mut FRAME: [u32; WIDTH * HEIGHT / 2] = [0u32; WIDTH * HEIGHT / 2]; bind_interrupts!(struct Irqs { I2C1_EV => i2c::InterruptHandler; DCMI => dcmi::InterruptHandler; }); #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); config.rcc.sys_ck = Some(mhz(400)); config.rcc.hclk = Some(mhz(400)); config.rcc.pll1.q_ck = Some(mhz(100)); config.rcc.pclk1 = Some(mhz(100)); config.rcc.pclk2 = Some(mhz(100)); config.rcc.pclk3 = Some(mhz(100)); config.rcc.pclk4 = Some(mhz(100)); let p = embassy_stm32::init(config); defmt::info!("Hello World!"); let mco = Mco::new(p.MCO1, p.PA8, Mco1Source::Hsi, McoClock::Divided(3)); let mut led = Output::new(p.PE3, Level::High, Speed::Low); let cam_i2c = I2c::new( p.I2C1, p.PB8, p.PB9, Irqs, p.DMA1_CH1, p.DMA1_CH2, khz(100), Default::default(), ); let mut camera = Ov7725::new(cam_i2c, mco); defmt::unwrap!(camera.init().await); let manufacturer_id = defmt::unwrap!(camera.read_manufacturer_id().await); let camera_id = defmt::unwrap!(camera.read_product_id().await); defmt::info!("manufacturer: 0x{:x}, pid: 0x{:x}", manufacturer_id, camera_id); let config = dcmi::Config::default(); let mut dcmi = Dcmi::new_8bit( p.DCMI, p.DMA1_CH0, Irqs, p.PC6, p.PC7, p.PE0, p.PE1, p.PE4, p.PD3, p.PE5, p.PE6, p.PB7, p.PA4, p.PA6, config, ); defmt::info!("attempting capture"); defmt::unwrap!(dcmi.capture(unsafe { &mut FRAME }).await); defmt::info!("captured frame: {:x}", unsafe { &FRAME }); defmt::info!("main loop running"); loop { defmt::info!("high"); led.set_high(); Timer::after(Duration::from_millis(500)).await; defmt::info!("low"); led.set_low(); Timer::after(Duration::from_millis(500)).await; } } mod ov7725 { use core::marker::PhantomData; use defmt::Format; use embassy_stm32::rcc::{Mco, McoInstance}; use embassy_time::{Duration, Timer}; use embedded_hal_async::i2c::I2c; #[repr(u8)] pub enum RgbFormat { Gbr422 = 0, RGB565 = 1, RGB555 = 2, RGB444 = 3, } pub enum PixelFormat { Yuv, ProcessedRawBayer, Rgb(RgbFormat), RawBayer, } impl From for u8 { fn from(raw: PixelFormat) -> Self { match raw { PixelFormat::Yuv => 0, PixelFormat::ProcessedRawBayer => 1, PixelFormat::Rgb(mode) => 2 | ((mode as u8) << 2), PixelFormat::RawBayer => 3, } } } #[derive(Clone, Copy)] #[repr(u8)] #[allow(unused)] pub enum Register { Gain = 0x00, Blue = 0x01, Red = 0x02, Green = 0x03, BAvg = 0x05, GAvg = 0x06, RAvg = 0x07, Aech = 0x08, Com2 = 0x09, PId = 0x0a, Ver = 0x0b, Com3 = 0x0c, Com4 = 0x0d, Com5 = 0x0e, Com6 = 0x0f, Aec = 0x10, ClkRc = 0x11, Com7 = 0x12, Com8 = 0x13, Com9 = 0x14, Com10 = 0x15, Reg16 = 0x16, HStart = 0x17, HSize = 0x18, VStart = 0x19, VSize = 0x1a, PShift = 0x1b, MidH = 0x1c, MidL = 0x1d, Laec = 0x1f, Com11 = 0x20, BdBase = 0x22, BdMStep = 0x23, Aew = 0x24, Aeb = 0x25, Vpt = 0x26, Reg28 = 0x28, HOutSize = 0x29, EXHCH = 0x2a, EXHCL = 0x2b, VOutSize = 0x2c, Advfl = 0x2d, Advfh = 0x2e, Yave = 0x2f, LumHTh = 0x30, LumLTh = 0x31, HRef = 0x32, DspCtrl4 = 0x67, DspAuto = 0xac, } const CAM_ADDR: u8 = 0x21; #[derive(Format)] pub enum Error { I2c(I2cError), } pub struct Ov7725<'d, Bus: I2c> { phantom: PhantomData<&'d ()>, bus: Bus, } impl<'d, Bus> Ov7725<'d, Bus> where Bus: I2c, Bus::Error: Format, { pub fn new(bus: Bus, _mco: Mco) -> Self where T: McoInstance, { Self { phantom: PhantomData, bus, } } pub async fn init(&mut self) -> Result<(), Error> { Timer::after(Duration::from_millis(500)).await; self.reset_regs().await?; Timer::after(Duration::from_millis(500)).await; self.set_pixformat().await?; self.set_resolution().await?; Ok(()) } pub async fn read_manufacturer_id(&mut self) -> Result> { Ok(u16::from_le_bytes([ self.read(Register::MidL).await?, self.read(Register::MidH).await?, ])) } pub async fn read_product_id(&mut self) -> Result> { Ok(u16::from_le_bytes([ self.read(Register::Ver).await?, self.read(Register::PId).await?, ])) } async fn reset_regs(&mut self) -> Result<(), Error> { self.write(Register::Com7, 0x80).await } async fn set_pixformat(&mut self) -> Result<(), Error> { self.write(Register::DspCtrl4, 0).await?; let mut com7 = self.read(Register::Com7).await?; com7 |= u8::from(PixelFormat::Rgb(RgbFormat::RGB565)); self.write(Register::Com7, com7).await?; Ok(()) } async fn set_resolution(&mut self) -> Result<(), Error> { let horizontal: u16 = super::WIDTH as u16; let vertical: u16 = super::HEIGHT as u16; let h_high = (horizontal >> 2) as u8; let v_high = (vertical >> 1) as u8; let h_low = (horizontal & 0x03) as u8; let v_low = (vertical & 0x01) as u8; self.write(Register::HOutSize, h_high).await?; self.write(Register::VOutSize, v_high).await?; self.write(Register::EXHCH, h_low | (v_low << 2)).await?; self.write(Register::Com3, 0xd1).await?; let com3 = self.read(Register::Com3).await?; let vflip = com3 & 0x80 > 0; self.modify(Register::HRef, |reg| reg & 0xbf | if vflip { 0x40 } else { 0x40 }) .await?; if horizontal <= 320 || vertical <= 240 { self.write(Register::HStart, 0x3f).await?; self.write(Register::HSize, 0x50).await?; self.write(Register::VStart, 0x02).await?; // TODO vflip is subtracted in the original code self.write(Register::VSize, 0x78).await?; } else { defmt::panic!("VGA resolutions not yet supported."); } Ok(()) } async fn read(&mut self, register: Register) -> Result> { let mut buffer = [0u8; 1]; self.bus .write_read(CAM_ADDR, &[register as u8], &mut buffer[..1]) .await .map_err(Error::I2c)?; Ok(buffer[0]) } async fn write(&mut self, register: Register, value: u8) -> Result<(), Error> { self.bus .write(CAM_ADDR, &[register as u8, value]) .await .map_err(Error::I2c) } async fn modify u8>(&mut self, register: Register, f: F) -> Result<(), Error> { let value = self.read(register).await?; let value = f(value); self.write(register, value).await } } }