WHAT
This commit is contained in:
parent
73e499f215
commit
9045476a23
126
src/PicoIris.cpp
126
src/PicoIris.cpp
@ -13,38 +13,128 @@
|
|||||||
#include <ov2640/SCCB.hpp>
|
#include <ov2640/SCCB.hpp>
|
||||||
#include <ov2640/camera.hpp>
|
#include <ov2640/camera.hpp>
|
||||||
#include "cstring"
|
#include "cstring"
|
||||||
|
// Frame header and footer markers for synchronization - using distinctive values
|
||||||
|
const uint8_t FRAME_HEADER[] = {0xDE, 0xAD, 0xBE, 0xEF}; // Distinctive header
|
||||||
|
const uint8_t FRAME_FOOTER[] = {0xCA, 0xFE, 0xBA, 0xBE}; // Distinctive footer
|
||||||
|
const int FRAME_MARKER_SIZE = 4;
|
||||||
// PIO2 is reserved for the cam data retreive functions
|
// PIO2 is reserved for the cam data retreive functions
|
||||||
|
|
||||||
camera_config_t left_eye_config = {
|
camera_config_t left_eye_config = {
|
||||||
.pin_pwdn = -1, /*!< GPIO pin for camera power down line */ //? Also called PWDN, or set to -1 and tie to GND
|
.pin_pwdn = -1, /*!< GPIO pin for camera power down line */ //? Also called PWDN, or set to -1 and tie to GND
|
||||||
.pin_reset = -1, /*!< GPIO pin for camera reset line */ //? Cam reset, or set to -1 and tie to 3.3V
|
.pin_reset = -1, /*!< GPIO pin for camera reset line */ //? Cam reset, or set to -1 and tie to 3.3V
|
||||||
.pin_xclk = 3, /*!< GPIO pin for camera XCLK line */ //? in theory could be shared or perhaps ommited?
|
.pin_xclk = 25, /*!< GPIO pin for camera XCLK line */ //? in theory could be shared or perhaps ommited?
|
||||||
.pin_sccb_sda = 4, /*!< GPIO pin for camera SDA line */
|
.pin_sccb_sda = 26, /*!< GPIO pin for camera SDA line */
|
||||||
.pin_sccb_scl = 5, /*!< GPIO pin for camera SCL line */
|
.pin_sccb_scl = 27, /*!< GPIO pin for camera SCL line */
|
||||||
.pin_data_base = 7, /*!< this pin + 7 consecutive will be used D0-D7 PCLK HREF */
|
.pin_data_base = 28, /*!< this pin + 7 consecutive will be used D0-D7 PCLK HREF */
|
||||||
.pin_vsync = 18, /*!< GPIO pin for camera VSYNC line */
|
.pin_vsync = 39, /*!< GPIO pin for camera VSYNC line */
|
||||||
.xclk_div = 0, /*!< Frequency of XCLK signal, in Hz. */ //! Figure out the highest it can go to
|
.sccb_ctrl = 1, /* Select i2c controller ctrl: 0 - i2c0, 1 - i2c1, 2 - pio0, 3 - pio1, 4 - pio2 */
|
||||||
.sccb_ctrl = 0, /* Select i2c controller ctrl: 0 - i2c0, 1 - i2c1, 2 - pio0, 3 - pio1, 4 - pio2 */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Send a properly framed image using printf for binary data
|
||||||
|
void send_frame(const void* buffer, size_t size) {
|
||||||
|
// Ensure UART output buffer is flushed before sending binary data
|
||||||
|
printf("\n\nBINARY_START\n\n");
|
||||||
|
sleep_ms(100); // Small delay to ensure the text is transmitted separately
|
||||||
|
|
||||||
|
// Send binary data using fwrite directly to stdout
|
||||||
|
// This avoids any text processing that printf might do
|
||||||
|
|
||||||
|
// Send frame header
|
||||||
|
fwrite(FRAME_HEADER, 1, FRAME_MARKER_SIZE, stdout);
|
||||||
|
sleep_ms(100); // Small delay to ensure the text is transmitted separately
|
||||||
|
printf("test....");
|
||||||
|
|
||||||
|
// Send frame size (4 bytes, little-endian)
|
||||||
|
uint8_t size_bytes[4];
|
||||||
|
size_bytes[0] = size & 0xFF;
|
||||||
|
size_bytes[1] = (size >> 8) & 0xFF;
|
||||||
|
size_bytes[2] = (size >> 16) & 0xFF;
|
||||||
|
size_bytes[3] = (size >> 24) & 0xFF;
|
||||||
|
fwrite(size_bytes, 1, 4, stdout);
|
||||||
|
printf("test2....");
|
||||||
|
|
||||||
|
// Calculate checksum
|
||||||
|
uint32_t checksum = 0;
|
||||||
|
const uint8_t* buf = (const uint8_t*)buffer;
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
checksum += buf[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send frame data
|
||||||
|
fwrite(buf, 1, size, stdout);
|
||||||
|
sleep_ms(100); // Small delay to ensure the text is transmitted separately
|
||||||
|
|
||||||
|
// Send checksum (4 bytes)
|
||||||
|
uint8_t checksum_bytes[4];
|
||||||
|
checksum_bytes[0] = checksum & 0xFF;
|
||||||
|
checksum_bytes[1] = (checksum >> 8) & 0xFF;
|
||||||
|
checksum_bytes[2] = (checksum >> 16) & 0xFF;
|
||||||
|
checksum_bytes[3] = (checksum >> 24) & 0xFF;
|
||||||
|
fwrite(checksum_bytes, 1, 4, stdout);
|
||||||
|
sleep_ms(100); // Small delay to ensure the text is transmitted separately
|
||||||
|
// Send frame footer
|
||||||
|
fwrite(FRAME_FOOTER, 1, FRAME_MARKER_SIZE, stdout);
|
||||||
|
sleep_ms(100); // Small delay to ensure the text is transmitted separately
|
||||||
|
|
||||||
|
// Flush to ensure all binary data is sent
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
// Make the end marker very distinctive with multiple newlines and unique pattern
|
||||||
|
sleep_ms(100);
|
||||||
|
printf("\n\n###BINARY_END###\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test function to verify binary data transmission
|
||||||
|
void test_binary_transfer() {
|
||||||
|
printf("Testing binary transfer...\n");
|
||||||
|
|
||||||
|
// Create a small test buffer
|
||||||
|
uint8_t test_data[16];
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
test_data[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send it as a frame
|
||||||
|
send_frame(test_data, sizeof(test_data));
|
||||||
|
|
||||||
|
printf("Binary test complete\n");
|
||||||
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
stdio_init_all();
|
stdio_init_all();
|
||||||
|
|
||||||
sleep_ms(4000);
|
printf("\n\n=== PicoIris Starting ===\n");
|
||||||
//printf("Hello World!");
|
sleep_ms(1000);
|
||||||
|
|
||||||
|
// Test binary transfer
|
||||||
|
test_binary_transfer();
|
||||||
|
sleep_ms(1000);
|
||||||
|
|
||||||
|
printf("Configuring Camera...\n");
|
||||||
|
|
||||||
OV2640 left_cam = OV2640(left_eye_config);
|
OV2640 left_cam = OV2640(left_eye_config);
|
||||||
left_cam.begin(DMA_IRQ_0, 1);
|
left_cam.begin(DMA_IRQ_0, 2); // 0 for RGB565 mode
|
||||||
//left_cam.capture_frame();
|
printf("Camera Configured!...\n");
|
||||||
//fwrite(left_cam.fb, 1, sizeof(left_cam.fb), stdout);
|
|
||||||
|
// Image size (160 x 120 x 2 bytes per pixel for RGB565)
|
||||||
|
const size_t frame_size = 160 * 120 * 2;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
//printf("Hello, world!\n");
|
// Capture a frame
|
||||||
//sleep_ms(1000);
|
printf("Attempting to capture frame...\n");
|
||||||
left_cam.capture_frame();
|
left_cam.capture_frame();
|
||||||
fwrite(&left_cam.fb, 1, sizeof(left_cam.fb), stdout);
|
|
||||||
//memset(&left_cam.fb, 0x00, sizeof(left_cam.fb));
|
// Once the frame is ready, send it over UART
|
||||||
sleep_ms(1000);
|
printf("Checking if frame is ready...\n");
|
||||||
|
printf("Frame ready, sending...\n");
|
||||||
|
send_frame(left_cam.fb, frame_size);
|
||||||
|
left_cam.resetFrameReady();
|
||||||
|
printf("Frame sent...\n");
|
||||||
|
|
||||||
|
|
||||||
|
// Small delay to allow processing time
|
||||||
|
printf("Waiting before next attempt...\n");
|
||||||
|
sleep_ms(3000); // Increased delay for debugging
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
static volatile bool frameReady = false; // true at end-of-frame
|
static volatile bool frameReady = false; // true at end-of-frame
|
||||||
static volatile bool suspended = true;
|
static volatile bool suspended = true;
|
||||||
|
static volatile bool dma_busy = false; // true when DMA transfer is done
|
||||||
static void* pointer;
|
static void* pointer;
|
||||||
|
|
||||||
static void iCap_vsync_irq(uint gpio, uint32_t events) {
|
static void iCap_vsync_irq(uint gpio, uint32_t events) {
|
||||||
@ -636,10 +637,11 @@ int OV2640::begin(int dma_irq, int mode) // mode is just here to make debbuging
|
|||||||
// Let's guess it's similar to tS:REG (300 ms) from datasheet.
|
// Let's guess it's similar to tS:REG (300 ms) from datasheet.
|
||||||
sleep_ms(300);
|
sleep_ms(300);
|
||||||
|
|
||||||
// Perform a soft reset (we dont wanna waste GPIO on wiring in reset pins)
|
// Perform a soft reset
|
||||||
|
printf("Sending camera reset command...\n");
|
||||||
this->sccb.writeRegister(OV2640_REG_RA_DLMT, OV2640_RA_DLMT_SENSOR); // Bank select 1
|
this->sccb.writeRegister(OV2640_REG_RA_DLMT, OV2640_RA_DLMT_SENSOR); // Bank select 1
|
||||||
this->sccb.writeRegister(OV2640_REG1_COM7, OV2640_COM7_SRST); // System reset
|
this->sccb.writeRegister(OV2640_REG1_COM7, OV2640_COM7_SRST); // System reset<
|
||||||
sleep_ms(300); // Datasheet: tS:RESET = 1 ms
|
printf("Camera reset complete\n");
|
||||||
|
|
||||||
switch(mode) {
|
switch(mode) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -657,47 +659,8 @@ int OV2640::begin(int dma_irq, int mode) // mode is just here to make debbuging
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//this->sccb.writeList(OV2640_test_ptrn, sizeof(OV2640_test_ptrn)/sizeof(OV2640_test_ptrn[0]));
|
// GPIO pin setup
|
||||||
//this->sccb.writeList(OV2640_jpeg, sizeof(OV2640_jpeg)/sizeof(OV2640_jpeg[0]));
|
printf("Setting up GPIO pins for camera data...\n");
|
||||||
//this->sccb.writeRegister(0xd3, 0x0f);
|
|
||||||
|
|
||||||
|
|
||||||
// this->set_framesize();
|
|
||||||
// sleep_ms(10);
|
|
||||||
// this->sccb.writeList(OV2640_jpeg, sizeof(OV2640_jpeg)/sizeof(OV2640_jzpeg[0]));
|
|
||||||
|
|
||||||
//this->set_gainceiling(GAINCEILING_2X);
|
|
||||||
//sleep_ms(10);
|
|
||||||
//this->set_bpc(false);
|
|
||||||
//sleep_ms(10);
|
|
||||||
//this->set_wpc(true);
|
|
||||||
//sleep_ms(10);
|
|
||||||
//this->set_lenc(true);
|
|
||||||
//sleep_ms(10);
|
|
||||||
// this->set_quality(5);
|
|
||||||
// sleep_ms(10);
|
|
||||||
// this->sccb.writeList(OV2640_jpeg, sizeof(OV2640_jpeg)/sizeof(OV2640_jpeg[0]));
|
|
||||||
|
|
||||||
// this->set_quality(5);
|
|
||||||
|
|
||||||
// //prtintf("Write list of init\n");
|
|
||||||
// // sleep_ms(10);
|
|
||||||
// // this->sccb.writeRegister(OV2640_REG_RA_DLMT, OV2640_RA_DLMT_DSP);
|
|
||||||
// sleep_ms(10);
|
|
||||||
// //this->sccb.writeRegister(0xd3, 0x05);
|
|
||||||
// sleep_ms(10);
|
|
||||||
|
|
||||||
|
|
||||||
// // for (int i=0; i<5; i++) {
|
|
||||||
// // this->sccb.writeRegister(0xff, 0x00);
|
|
||||||
// // this->sccb.writeRegister(special_effects_regs[0][i], special_effects_regs[3][i]);
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// this->sccb.writeRegister(0xff, 0x00);
|
|
||||||
// this->sccb.writeRegister(0xd3, 0x05); // try 0x80 next
|
|
||||||
|
|
||||||
|
|
||||||
//prtintf("Gpio init\n");
|
|
||||||
gpio_init(this->config.pin_vsync);
|
gpio_init(this->config.pin_vsync);
|
||||||
gpio_set_dir(this->config.pin_vsync, GPIO_IN);
|
gpio_set_dir(this->config.pin_vsync, GPIO_IN);
|
||||||
gpio_pull_down(this->config.pin_vsync);
|
gpio_pull_down(this->config.pin_vsync);
|
||||||
@ -797,11 +760,36 @@ int OV2640::begin(int dma_irq, int mode) // mode is just here to make debbuging
|
|||||||
dma_channel_set_irq0_enabled(0, true);
|
dma_channel_set_irq0_enabled(0, true);
|
||||||
irq_set_exclusive_handler(DMA_IRQ_0, iCap_dma_finish_irq);
|
irq_set_exclusive_handler(DMA_IRQ_0, iCap_dma_finish_irq);
|
||||||
irq_set_enabled(DMA_IRQ_0, true);
|
irq_set_enabled(DMA_IRQ_0, true);
|
||||||
|
printf("DMA interrupt setup complete\n");
|
||||||
// SET UP VSYNC INTERRUPT ------------------------------------------------
|
|
||||||
|
// Set up VSYNC interrupt
|
||||||
|
printf("Setting up VSYNC interrupt on pin %d...\n", this->config.pin_vsync);
|
||||||
gpio_set_irq_enabled_with_callback(this->config.pin_vsync, GPIO_IRQ_EDGE_RISE, true,
|
gpio_set_irq_enabled_with_callback(this->config.pin_vsync, GPIO_IRQ_EDGE_RISE, true,
|
||||||
&iCap_vsync_irq);
|
&iCap_vsync_irq); // Register VSYNC handler
|
||||||
|
printf("VSYNC interrupt setup complete\n");
|
||||||
|
|
||||||
|
// Test if VSYNC is toggling
|
||||||
|
printf("Checking if VSYNC is toggling...\n");
|
||||||
|
bool initial_vsync = gpio_get(this->config.pin_vsync);
|
||||||
|
uint32_t start_time = time_us_32();
|
||||||
|
bool vsync_changed = false;
|
||||||
|
while ((time_us_32() - start_time) < 1000000) { // 1 second timeout
|
||||||
|
bool current_vsync = gpio_get(this->config.pin_vsync);
|
||||||
|
if (current_vsync != initial_vsync) {
|
||||||
|
vsync_changed = true;
|
||||||
|
printf("VSYNC toggled from %d to %d\n", initial_vsync, current_vsync);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sleep_ms(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vsync_changed) {
|
||||||
|
printf("WARNING: VSYNC signal not detected during initialization\n");
|
||||||
|
} else {
|
||||||
|
printf("VSYNC signal detected successfully\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Camera initialization complete\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -871,34 +859,39 @@ void OV2640::set_lenc(bool enable) {
|
|||||||
this->sccb.writeMaskRegister(0xC3, 1, 1, enable?1:0);
|
this->sccb.writeMaskRegister(0xC3, 1, 1, enable?1:0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OV2640::isFrameReady() const {
|
||||||
|
return frameReady;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OV2640::resetFrameReady() {
|
||||||
|
frameReady = false;
|
||||||
|
}
|
||||||
|
|
||||||
void OV2640::capture_frame() {
|
void OV2640::capture_frame() {
|
||||||
suspended = false;
|
suspended = false;
|
||||||
while(!frameReady);
|
|
||||||
return;
|
|
||||||
// dma_channel_config c = dma_channel_get_default_config(0);
|
|
||||||
// channel_config_set_read_increment(&c, false);
|
|
||||||
// channel_config_set_write_increment(&c, true);
|
|
||||||
// channel_config_set_dreq(&c, pio_get_dreq(pio2, 0, false));
|
|
||||||
// channel_config_set_transfer_data_size(&c, DMA_SIZE_16);
|
|
||||||
|
|
||||||
// dma_channel_configure(
|
// Wait for frame with timeout to prevent infinite loops
|
||||||
// 0, &c,
|
uint32_t start_time = time_us_32();
|
||||||
// &this->fb,
|
uint32_t timeout_us = 2000000; // 2 second timeout
|
||||||
// &pio2->rxf[0],
|
|
||||||
// sizeof(this->fb),
|
|
||||||
// false
|
|
||||||
// );
|
|
||||||
|
|
||||||
// // Wait for vsync rising edge to start frame
|
while(!frameReady) {
|
||||||
// ////prtintf("pin_vsync) == true\n");
|
// Check for timeout
|
||||||
// while (gpio_get(this->config.pin_vsync) == true);
|
if ((time_us_32() - start_time) > timeout_us) {
|
||||||
// ////prtintf("pin_vsync) == false\n");
|
printf("Frame capture timeout! Sending incomplete frame...\n");
|
||||||
// while (gpio_get(this->config.pin_vsync) == false);
|
// Reset DMA in case it's stuck
|
||||||
// ////prtintf("after while loops\n");
|
dma_channel_abort(0);
|
||||||
|
dma_channel_set_write_addr(0, pointer, false);
|
||||||
|
dma_busy = false;
|
||||||
|
suspended = true;
|
||||||
|
return; // Exit without waiting for frameReady
|
||||||
|
}
|
||||||
|
// Small yield to avoid tight loop
|
||||||
|
sleep_us(100);
|
||||||
|
}
|
||||||
|
|
||||||
// dma_channel_start(0);
|
// Frame is ready, no need to do anything else
|
||||||
// dma_channel_wait_for_finish_blocking(0);
|
// The DMA handler has already set frameReady = true
|
||||||
|
printf("Frame captured successfully\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -34,6 +34,11 @@ class OV2640 {
|
|||||||
public:
|
public:
|
||||||
OV2640(camera_config_t config);
|
OV2640(camera_config_t config);
|
||||||
~OV2640();
|
~OV2640();
|
||||||
|
// Check if a new frame is ready
|
||||||
|
bool isFrameReady() const;
|
||||||
|
|
||||||
|
// Reset the frame ready flag after processing
|
||||||
|
void resetFrameReady();
|
||||||
|
|
||||||
int begin(int dma_irq, int mode);
|
int begin(int dma_irq, int mode);
|
||||||
void set_quality(int quality);
|
void set_quality(int quality);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user