This commit is contained in:
CuriosMind 2025-03-28 19:31:45 +01:00
parent 73e499f215
commit 9045476a23
3 changed files with 176 additions and 88 deletions

View File

@ -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
} }
} }

View File

@ -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");
} }

View File

@ -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);