weird behavior when setting gain


I’m trying to write a basic function to adjust the gain of the OV7725 sensor based on the l_mean seen in an image. To do some testing, I set up a loop which uses the sensor.set_auto_gain(False, gain_db = ) to write gain values from 128 through 0 (somewhat arbitrary limits used for testing). During this loop, I see the l_mean spike a few times even though the gain value is being decremented by 1. I see this same luminosity spike when I directly write register 0x00 and increment the value by 1 in a loop. The OV7725 data sheet doesn’t really provide much help in terms of what gain (in db) each register step corresponds to and I also can’t seem to find the sensor.set_auto_gain function in the omv source…

For ease of understanding the issue, attached is a photo of the data I’ve collected. You can see in the bottom plot the luminosity spikes that we’re seeing.

For the record, we have auto gain, auto wb, and auto exposure all disabled and have verified this by rgb gain and exposure registers to show that they are constant.

Any thoughts on this behavior? Let me know if any of what I mentioned doesn’t make sense or was worded confusingly.


Looks like the image didn’t get attached. Here you go.

Hi, I made this method set the gain in DB because the data sheet and application notes all referred to it this way. But, it’s very confusing.

The function is implemented here.

What you may be seeing is me misunderstanding what the gain DB is. I found two different data sheets when working on the method that referred to what the gain did differently.

When I implemented this method… I’m not clear on the data sheets what gain high is in the code. I think it’s a higher weighted gain value. But, I’ve seen some OmnVision data sheets refer to it as just something like:

(Bit 7 + 1) * (Bit 6 + 1) + ( Bit 5 + 1) + (Bit 4 + 1)


(Bit 7 to 4) * scale.

Um, to test just write the register directly after setting the gain and see what happens.

Hmmmm, I don’t seem to see those register structures in the data sheet that we have… Could you attach the data sheets that you’re referencing?..

All info about the camera is available online via the product page. Camera appnotes and whatnot. I made everything public. I might have pieced things together by looking at different camera models.

Use the sensor.__read_reg() and sensor.__write_reg() commands for direct camera access.


We have the data sheet and appnotes but all I’m seeing is what looks like a linear 0x00 to 0xFF range for overall gain at register address 0x00. See the attached snapshot.

Doing some more testing of the l_mean vs. the gain control register 0x00 it seems that there are glitches every 16 lsbs. The top graph here was created by incrementing the set_auto_gain gain_db argument by 1 and the bottom graph here was created by incrementing the register 0x00 value directly.

We found a second data sheet that does not match the one found at: The one on your website doesn’t reference any scaled gain values. We found one on TI’s website that does reference scaled gain bits in register 0x00. This data sheet can be found at I’ll see if this fixes these glitches.

Please see my comments about the equations above. Basically, this means the 4 msbs aren’t a scale value. They are likely then used as in the first equation. Meaning, the literal count of the number of 1s set matters. Not the binary pattern.

If you check the data sheet for the Ov9655 camera you’ll see what I mean.


After find the second data sheet I finally understand what you mean about the upper bits.

If you look below you can see that linearly incremementing the 0x00 register then gives you a gain response of something like this below. You can clearly see the 5 gain ranges here and there are multiple regions where you can access them. Nice.

Going back a few steps here I want address that the set_auto_gain(gain_db) function does not set the gain to be as expected from this curve. Earlier I printed out the 0x00 register value as I incremented the gain_db argument by 1. This gave me a map of gain_db argument vs. 0x00 register value. Looking at the above plot you can then map the 0x00 value to a calculated gain. Here is the table of these three values:

If I then plot the gain_db argument vs the calculated gain you see that there is a non linear relationship. This indicates that somewhere inside the set_auto_gain function there is something amiss.

As such, I implemented a different set_auto_gain function. Looking at the possible gain values from our earlier plot I decided that our gain should look something like the exponential function in the bottom plot below:

I matched an equation to that curve:
Screen Shot 2018-03-03 at 10.54.28.png
And then wrote the functions below in python to accurately set and get the gain value along that curve. Excuse the extraneous debug prints.

I hope to implement this in C, but am going to be away next week so it would at the earliest happen next next week. Let me know what you think about this.


Please send us a PR for the fix:

I think I got the AWB and exposure value calculations correct. Those were better documented. I think they are just linear multipliers.

That said, if you see any mistakes please send a PR for things. We can really use the help.

This will be fixed in the next release coming soon.

The equation for the gain is in the datasheet.

Gain = (b7+1) x (b6+1) x (b5+1) x (b4+1) x (b[3:0]/16+1)

The lower nibble is a multiplier of 1.0 - 1.9375. The upper nibble is 2 raised to the number of bits in the nibble with value 1.

Gain can be calculated from the register value with this formula:

gain = (((read_reg&0x80)>>7)+1) * (((read_reg&0x40)>>6)+1) *
(((read_reg&0x20)>>5)+1) * (((read_reg&0x10)>>4)+1) *

For example:
0b00110000 → gain=4
0b11000000 → gain=4
0b00110100 → gain=5
0b00111000 → gain=6
0b00111001 → gain=6.25
0b00111010 → gain=6.5
0b00111011 → gain=6.75
0b00111100 → gain=7
0b01110000 → gain=8