From 9045476a23728809b32a59a6f16c62835ef8fe65 Mon Sep 17 00:00:00 2001 From: CuriosMind Date: Fri, 28 Mar 2025 19:31:45 +0100 Subject: [PATCH] WHAT --- src/PicoIris.cpp | 126 +++++++++++++++++++++++++++++++++------ src/ov2640/camera.cpp | 133 ++++++++++++++++++++---------------------- src/ov2640/camera.hpp | 5 ++ 3 files changed, 176 insertions(+), 88 deletions(-) diff --git a/src/PicoIris.cpp b/src/PicoIris.cpp index df98c8e..86dfdee 100644 --- a/src/PicoIris.cpp +++ b/src/PicoIris.cpp @@ -13,38 +13,128 @@ #include #include #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 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_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_sccb_sda = 4, /*!< GPIO pin for camera SDA line */ - .pin_sccb_scl = 5, /*!< GPIO pin for camera SCL line */ - .pin_data_base = 7, /*!< this pin + 7 consecutive will be used D0-D7 PCLK HREF */ - .pin_vsync = 18, /*!< 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 = 0, /* Select i2c controller ctrl: 0 - i2c0, 1 - i2c1, 2 - pio0, 3 - pio1, 4 - pio2 */ + .pin_xclk = 25, /*!< GPIO pin for camera XCLK line */ //? in theory could be shared or perhaps ommited? + .pin_sccb_sda = 26, /*!< GPIO pin for camera SDA line */ + .pin_sccb_scl = 27, /*!< GPIO pin for camera SCL line */ + .pin_data_base = 28, /*!< this pin + 7 consecutive will be used D0-D7 PCLK HREF */ + .pin_vsync = 39, /*!< GPIO pin for camera VSYNC line */ + .sccb_ctrl = 1, /* 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() { stdio_init_all(); - sleep_ms(4000); - //printf("Hello World!"); + printf("\n\n=== PicoIris Starting ===\n"); + sleep_ms(1000); + + // Test binary transfer + test_binary_transfer(); + sleep_ms(1000); + + printf("Configuring Camera...\n"); OV2640 left_cam = OV2640(left_eye_config); - left_cam.begin(DMA_IRQ_0, 1); - //left_cam.capture_frame(); - //fwrite(left_cam.fb, 1, sizeof(left_cam.fb), stdout); + left_cam.begin(DMA_IRQ_0, 2); // 0 for RGB565 mode + printf("Camera Configured!...\n"); + + // Image size (160 x 120 x 2 bytes per pixel for RGB565) + const size_t frame_size = 160 * 120 * 2; + while (true) { - //printf("Hello, world!\n"); - //sleep_ms(1000); + // Capture a frame + printf("Attempting to capture frame...\n"); left_cam.capture_frame(); - fwrite(&left_cam.fb, 1, sizeof(left_cam.fb), stdout); - //memset(&left_cam.fb, 0x00, sizeof(left_cam.fb)); - sleep_ms(1000); + + // Once the frame is ready, send it over UART + 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 } } diff --git a/src/ov2640/camera.cpp b/src/ov2640/camera.cpp index b44c43e..d4bea2d 100644 --- a/src/ov2640/camera.cpp +++ b/src/ov2640/camera.cpp @@ -16,6 +16,7 @@ static volatile bool frameReady = false; // true at end-of-frame static volatile bool suspended = true; +static volatile bool dma_busy = false; // true when DMA transfer is done static void* pointer; 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. 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_REG1_COM7, OV2640_COM7_SRST); // System reset - sleep_ms(300); // Datasheet: tS:RESET = 1 ms + this->sccb.writeRegister(OV2640_REG1_COM7, OV2640_COM7_SRST); // System reset< + printf("Camera reset complete\n"); switch(mode) { case 0: @@ -657,47 +659,8 @@ int OV2640::begin(int dma_irq, int mode) // mode is just here to make debbuging break; } - //this->sccb.writeList(OV2640_test_ptrn, sizeof(OV2640_test_ptrn)/sizeof(OV2640_test_ptrn[0])); - //this->sccb.writeList(OV2640_jpeg, sizeof(OV2640_jpeg)/sizeof(OV2640_jpeg[0])); - //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 pin setup + printf("Setting up GPIO pins for camera data...\n"); gpio_init(this->config.pin_vsync); gpio_set_dir(this->config.pin_vsync, GPIO_IN); 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); irq_set_exclusive_handler(DMA_IRQ_0, iCap_dma_finish_irq); irq_set_enabled(DMA_IRQ_0, true); - - // SET UP VSYNC INTERRUPT ------------------------------------------------ - + printf("DMA interrupt setup complete\n"); + + // 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, - &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; } @@ -871,34 +859,39 @@ void OV2640::set_lenc(bool enable) { this->sccb.writeMaskRegister(0xC3, 1, 1, enable?1:0); } +bool OV2640::isFrameReady() const { + return frameReady; +} + +void OV2640::resetFrameReady() { + frameReady = false; +} void OV2640::capture_frame() { 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( - // 0, &c, - // &this->fb, - // &pio2->rxf[0], - // sizeof(this->fb), - // false - // ); + // Wait for frame with timeout to prevent infinite loops + uint32_t start_time = time_us_32(); + uint32_t timeout_us = 2000000; // 2 second timeout - // // Wait for vsync rising edge to start frame - // ////prtintf("pin_vsync) == true\n"); - // while (gpio_get(this->config.pin_vsync) == true); - // ////prtintf("pin_vsync) == false\n"); - // while (gpio_get(this->config.pin_vsync) == false); - // ////prtintf("after while loops\n"); + while(!frameReady) { + // Check for timeout + if ((time_us_32() - start_time) > timeout_us) { + printf("Frame capture timeout! Sending incomplete frame...\n"); + // Reset DMA in case it's stuck + 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); - // dma_channel_wait_for_finish_blocking(0); + // Frame is ready, no need to do anything else + // The DMA handler has already set frameReady = true + printf("Frame captured successfully\n"); } diff --git a/src/ov2640/camera.hpp b/src/ov2640/camera.hpp index c90ea83..fb9a06a 100644 --- a/src/ov2640/camera.hpp +++ b/src/ov2640/camera.hpp @@ -34,6 +34,11 @@ class OV2640 { public: OV2640(camera_config_t config); ~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); void set_quality(int quality);