20 FPS OV2640, OV5642 SPI module

1.Which seller did you purchase the product(s) from?
Amazon
2.The Model number of the product(s) you have purchased?
Arducam Mini 2MP Plus OV2640 SPI
Arducam Mini 5MP Plus OV5642 SPI
3.Which Platform are you using the product(s) on?
Beaglebone ( using driver I rewrote )
4.Which instruction are you following?
Streaming Example
5.Has your product ever worked properly?
OV2640 works fine with custom software, currently working on OV5642
6.What problems are you experiencing?

Hello,

Originally I wrote a hardware agnostic driver for the OV2640 a while back and am reusing the platform but due to some project requirements I need around 20 FPS at 640x480 jpeg format.

my original driver for OV2640: GitHub - Marquez607/ANY_ArduCam: Hardware Agnostic Driver for using the OV2640 based ArduCam. This library is currently friendly to low level embedded platforms.

I’m inquiring about whether or not this is possible on either the OV2640 or the OV5642 SPI modules.

I did some profiling and it seems the fps limitation is mostly on waiting for the image to be processed as opposed to the SPI bus; the SPI bus could have supported around 30 FPS. It seems that the sensor itself supports a higher FPS so it seems the bottleneck is the Arduchip? Are there additional settings I can use to increase FPS?

Can the OV5642 support a higher FPS than the OV2640?

Profiling:

image

I’ve gone ahead and attached my full program for reference

 #include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#include <stdbool.h>
#include <fcntl.h>

#include <sys/time.h>

#include "ArduCAM_Generic.h"
#include "board.h"

#define USE_FAST 1

#define BUFF_SIZE 30*1024
//static uint8_t cam_buff[BUFF_SIZE];
static uint8_t *cam_buff;
static const char *outfile = "./test.jpg";
static int PAGE_SIZE;

static void delay_ms(uint32_t ms){
  usleep(1000);
}

static int cam_capture(ArduCam_t *cam);
static int cam_capture_slow(ArduCam_t *cam);

struct timespec profile_start(){
  struct timespec start;
  clock_gettime(CLOCK_MONOTONIC_RAW, &start);
  return start;

}

void profile_end(struct timespec start, char *tracepoint){
  struct timespec end;
  clock_gettime(CLOCK_MONOTONIC_RAW, &end);
  uint64_t delta_us = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_nsec - start.tv_nsec) / 1000;
  printf("%s delta: %.1f\n",tracepoint,delta_us/(1E3));
}

//return new length
int jpeg_trim(uint8_t *buff,int len);

int main()
{
  PAGE_SIZE = getpagesize();
  board_init();
  ev_spi_cs_high0(); /* set pin high */

  ArduCam_t acam;
  acam.spi_write = ev_spi_write;
  acam.spi_read = ev_spi_read;
  acam.spi_cs_low = ev_spi_cs_low0;
  acam.spi_cs_high = ev_spi_cs_high0;
  acam.i2c_write = ev_i2c_write;
  acam.i2c_read = ev_i2c_read;
  acam.delay_ms = delay_ms;

  ACAM_Init(&acam);
  ACAM_OV2640_set_JPEG_size(&acam,OV2640_1024x768);
  ACAM_clear_fifo_flag(&acam);

  while(1){

    ACAM_clear_fifo_flag(&acam);
    ACAM_start_capture(&acam);

    /* wait for a capture to finish */
    printf("Caputure Start\n");
    struct timespec start, end;
    while(!ACAM_get_bit(&acam,ARDUCHIP_TRIG, CAP_DONE_MASK));
    start = profile_start();

    #ifdef USE_FAST
    int len = cam_capture(&acam);
    #else
    int len = cam_capture_slow(&acam);
    #endif
    profile_end(start,"cam capture");
    printf("Capture Size %d\n",len);

    printf("Caputure Finished\n");

    printf("Saving Image\n");
    //len = jpeg_trim(cam_buff,len);
    int outfd = open(outfile,O_RDWR | O_CREAT | O_TRUNC);
    write(outfd,cam_buff,len);
    close(outfd);
    free(cam_buff);
  }
  return 0;
}

/*
 * read and send full image from camera
 * roughly based on esp32 camCapture example
 *
 * uses single fifo read so is technically
 * half the possible bandwidth
 *
 */
static int cam_capture(ArduCam_t *cam){

  uint32_t len = ACAM_get_fifo_length(cam);
  // printf("len = %u\n",len);
  uint8_t dummy;
  int iters = 1;
  int buff_idx = 0;
  int rd_size = len;
  if (PAGE_SIZE < len){
    iters = (len + (PAGE_SIZE-1))/PAGE_SIZE;
    rd_size = PAGE_SIZE;
  }
  cam_buff = (uint8_t*)calloc(PAGE_SIZE*iters,sizeof(uint8_t));
  // printf("iters = %u\n",iters);
  // printf("rd_size = %u\n",rd_size);
  // printf("total size = %u\n",PAGE_SIZE*iters*sizeof(uint8_t));
  for(int i=0;i<iters;i++){
    cam->spi_cs_low();
    ACAM_set_fifo_burst(cam);
    cam->spi_read(&cam_buff[buff_idx],rd_size);
    buff_idx += rd_size;
    cam->spi_cs_high();
  }
  return len;
}

static int cam_capture_slow(ArduCam_t *cam){
    uint32_t len = ACAM_get_fifo_length(cam);
    uint32_t final_len = len;
    uint8_t temp=0,temp_last=0;
    bool is_header = false;
    int i = 0;
    cam_buff = calloc(len,sizeof(uint8_t));

    while(len--){
        temp_last = temp;
        temp = ACAM_read_fifo(cam);

        /* check for end of frame */
        if ( (temp==0xD9) && (temp_last==0xFF) ){
            cam_buff[i++] = temp;
            is_header = false;
            i=0;
            break;
        }
        /* check if header already passed (body of image) */
        if (is_header==true){
            if( true ){ /* wait for buffer to fill */
                cam_buff[i++] = temp; /* add to buff */
            }
        }
        /* look for header */
        else if ((temp==0xD8) && (temp_last==0xFF)){
            is_header = true;
            cam_buff[i++] = temp_last;
            cam_buff[i++] = temp;
        }
    }
    return final_len;
}

//return new length
int jpeg_trim(uint8_t *buff,int len)
{
  uint8_t last_temp = 0;
  uint8_t temp;
  int i=0;
  while(len--)
  {
    temp = buff[i];
    if ( (temp==0xD9) && (last_temp==0xFF) )
    {
      i++;
      return i; 
    }
    last_temp=temp;
    i++;
  }
}