Need help with ov5640 exposure timing

Hello, I am trying to debug an issue with how exposure works for my application.

in order to gather information and better understand how the camera timings work. I’m trying to calculate the actual time of exposure and math just doesn’t seem to line up with real world measurements.

my registers are set as follows

AEC is in auto mode - reg 0x3503 = 0x00
actual exposure value - reg 0x3500 - 0x3502 = 0x3750 (highest exposure under poor lighting)
total horizontal width - reg 0x380c - 0x380d = 0x080c (2060)
binning is on - reg 0x3821 = 0x07
pixel clock is 8,000,000 - reg 0x3034 = 0x1a
the final output resolution of the camera is low = 96x96. mainly being used for ML.

here is information about our clock settings

XVCLK: 16,000,000 Hz, - provided by esp32
REFIN: 16,000,000 Hz, - input to pll
VCO: 320,000,000 Hz, - voltage controlled oscillator, part of the pll
PLL_CLK: 128,000,000 Hz, - pll output frequency
SYSCLK: 32,000,000 Hz, - camera system clock
PCLK: 8,000,000 Hz - pixel clock

raw timing registers
0x3000: 0x20, 0x3001: 0x08, 0x3002: 0x1C, 0x3003: 0x00, 0x3004: 0xFF, 0x3005: 0xF7, 0x3006: 0xC3, 0x3007: 0xFF, 0x3008: 0x02, 0x3009: 0x01, 0x300a: 0x56, 0x300b: 0x40, 0x300c: 0x22, 0x300d: 0x00, 0x300e: 0x58, 0x300f: 0x00, 0x3010: 0x00, 0x3011: 0x00, 0x3012: 0x00, 0x3013: 0x00, 0x3014: 0x00, 0x3015: 0x07, 0x3016: 0x00, 0x3017: 0xFF, 0x3018: 0xFF, 0x3019: 0xF0, 0x301a: 0x00, 0x301b: 0x00, 0x301c: 0x00, 0x301d: 0x00, 0x301e: 0x00, 0x301f: 0x00, 0x3020: 0x00, 0x3021: 0x00, 0x3022: 0x00, 0x3023: 0x00, 0x3024: 0x00, 0x3025: 0x00, 0x3026: 0x00, 0x3027: 0x00, 0x3028: 0x00, 0x3029: 0x00, 0x302a: 0xB0, 0x302b: 0x00, 0x302c: 0xC3, 0x302d: 0x10, 0x302e: 0x00, 0x302f: 0x02, 0x3030: 0x0B, 0x3031: 0x00, 0x3032: 0x00, 0x3033: 0x03, 0x3034: 0x1A, 0x3035: 0x11, 0x3036: 0x14, 0x3037: 0x01, 0x3038: 0x00, 0x3039: 0x00, 0x303a: 0x00, 0x303b: 0x19, 0x303c: 0x11, 0x303d: 0x30

the equation for calculating actual time during exposure should be as follows
Exposure time = exposure value (regs 0x3500-02) * total horizontal size (0x380c-0d) / pixel clock (in our case it’s 8,000,000 hz).

exposure = 0x3750 (14160) = 885 scanlines
total width = 2060
pixel clock = 8,000,000
scanline time = 0.0002575 seconds = 0.2575 ms
exposure time = 227.8 ms = 4 frames per second

when I calculate the actual camera fps using an external timing strobe I get 16hz. Which is much higher than the 4 frames per second I calculated using the equation above.

Do you know if there is something missing here? Could it be possible that exposure could possibly be longer than the time it takes to capture an actual frame?
how does binning affect timing (with binning on, is the timing for each scanline actually 2060 / 2)?

Second question was I was considering using FREX global reset to capture the entire frame. If I trigger FREX from an i2c register (0x3b08) do you know if it needs an external shutter to work? Or if the shutter built into the ov5640 itself is used?

Hi, is this on the OpenMV Cam or the ESP32? A user submitted our most recent exposure control code and it works very well:

I’d use our driver unmodified. Countless hours were spent getting it work.

Regarding FREX.

I don’t remember much about that off the top of my head. I would say it’s not that useful though since it’s triggered by I2C. Then the camera just strobes the FREX pin for you to control an LED to capture something. It’s not a hardware trigger though from an external I/O. Since we run the camera in streaming mode it doesn’t really have a lot of value. I guess you could turn the streaming off and capture a frame via an I2C command to the camera. But, you won’t be able to align the camera and some external event nicely.

This is using esp32. and I’m not modifying how it works, I’m trying to get a better understanding of how it works. ie I’m getting an exposure values that should be driving the frame rate lower but are not. does this mean my exposure has some limit that I’m unaware of?

although this is interesting

static int get_exposure_us(sensor_t *sensor, int *exposure_us)
    uint8_t spc0, spc1, spc2, spc3, sysrootdiv, aec_0, aec_1, aec_2, hts_h, hts_l;
    int ret = 0;

    ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, SC_PLL_CONTRL0, &spc0);
    ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, SC_PLL_CONTRL1, &spc1);
    ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, SC_PLL_CONTRL2, &spc2);
    ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, SC_PLL_CONTRL3, &spc3);
    ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, SYSTEM_ROOT_DIVIDER, &sysrootdiv);

    ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, AEC_PK_EXPOSURE_0, &aec_0);
    ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, AEC_PK_EXPOSURE_1, &aec_1);
    ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, AEC_PK_EXPOSURE_2, &aec_2);

    ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, TIMING_HTS_H, &hts_h);
    ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, TIMING_HTS_L, &hts_l);

    uint32_t aec = ((aec_0 << 16) | (aec_1 << 8) | aec_2) >> 4;
    uint16_t hts = (hts_h << 8) | hts_l;

    int pclk_freq = calc_pclk_freq(spc0, spc1, spc2, spc3, sysrootdiv);
    int clocks_per_us = pclk_freq / 1000000;
    *exposure_us = (aec * hts) / clocks_per_us;

    return ret;

As far as frex mode goes. I would like to enable global reset mode which exposes the entire frame at once rather than using the default rolling shutter. With rapid movement the image shears which ends up affecting my ML performance.

The driver should just work. You have to turn auto exposure off or it just overwrites what you asked.

Regarding FREX.

I remember now, that pin isn’t exposed on the FPC module. So, we didn’t bother implementing support for it.

Yeah… so, you’ll have to work off of the little amount of info that datasheet provides about FREX. However, it looks like they provide enough info to get it working.

btw, I love learning new things. especially learning more about how cameras work on a low level. I’m curious why you are encouraging me to just use the current drivers rather than learning more about how they work? Sure just trusting the current driver would be the most efficient way to work on my project. but man, I would really love to fill in this knowledge gap considering it looks like there are inconsistencies in the data.

You are asking for help on the forum… so, I’m trying to provide that. If you are looking for answers on why it doesn’t match up I can’t really help on that.

There are numerous reasons why things could be off. That’s kinda on you to enjoy the debugging journey. :slight_smile: Which may entail days of wondering why it doesn’t work and trying various things.

:slight_smile: I like that. I need to enjoy my debugging journey of hitting my head against the wall until it bleeds.

See my path to performance series:

And understand that I spent more than 100 hours learning to write it!