#![no_std]
#![no_main]
use core::fmt::Write;
use rpi_hal::halt;
use rpi_hal::i2c::I2c;
use rpi_hal::mailbox::{Mailbox, EXPANDER_CAM_GPIO0, POWER_DOMAIN_UNICAM1};
use rpi_hal::ov5647;
use rpi_hal::pac::{self, BSC0};
use rpi_hal::timer::Timer;
use rpi_hal::uart::Uart;
use rpi_hal::unicam::Unicam;
const WIDTH: u32 = 640;
const HEIGHT: u32 = 480;
const STRIDE: usize = WIDTH as usize * 10 / 8;
const FRAME_SIZE: usize = STRIDE * HEIGHT as usize;
#[repr(C, align(64))]
struct Frame([u8; FRAME_SIZE]);
static mut FRAME: Frame = Frame([0; FRAME_SIZE]);
#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
let peripherals = unsafe { pac::Peripherals::steal() };
let mut uart = Uart::init(&peripherals.GPIO, peripherals.UART0);
let _ = writeln!(uart, "PANIC: {info}");
halt();
}
#[no_mangle]
pub extern "C" fn kmain() -> ! {
let peripherals = unsafe { pac::Peripherals::steal() };
let mut uart = Uart::init(&peripherals.GPIO, peripherals.UART0);
let timer = Timer::new(peripherals.SYSTMR);
let mut mailbox = Mailbox::new(peripherals.VCMAILBOX);
let _ = mailbox.set_expander_gpio(EXPANDER_CAM_GPIO0, true);
let _ = mailbox.set_power_domain(POWER_DOMAIN_UNICAM1, true);
timer.delay_ms(50);
let mut i2c = I2c::<BSC0>::init(&peripherals.GPIO, peripherals.BSC0, 0x05dc, &timer);
if !ov5647::detect(&mut i2c) {
let _ = writeln!(uart, "OV5647 not found; aborting");
halt();
}
let _ = writeln!(uart, "OV5647 present; capturing one frame...");
let frame = unsafe { &mut *core::ptr::addr_of_mut!(FRAME) };
let mut unicam = Unicam::new();
unicam.arm(&mut frame.0, WIDTH, HEIGHT, &timer);
if !ov5647::start_streaming(&mut i2c, &timer, true) {
let _ = writeln!(uart, "OV5647 streaming setup failed; aborting");
halt();
}
let result = unicam.wait_frame(&timer, 500);
let _ = writeln!(
uart,
"capture: lines={}/{} status={:#010x} ista={:#010x} timed_out={} error={}",
result.lines_captured,
HEIGHT,
result.status,
result.image_status,
result.timed_out,
result.had_error(),
);
let nonzero = frame.0[..STRIDE].iter().filter(|&&b| b != 0).count();
let _ = writeln!(uart, "first bytes: {:02x?}", &frame.0[..16]);
let _ = writeln!(uart, "non-zero bytes in line 0: {nonzero}/{STRIDE}");
if result.lines_captured >= HEIGHT && !result.had_error() && nonzero > 0 {
let _ = writeln!(uart, "CAPTURE OK: full frame received into RAM");
} else {
let _ = writeln!(uart, "capture incomplete or empty; see status above");
}
halt();
}