espressif / esp32-camera

Apache License 2.0
1.79k stars 622 forks source link

ov2640 registry fuzzer #207

Closed raduprv closed 2 years ago

raduprv commented 3 years ago

I'm trying to document the undocumented register of this sensor. I've been doing it manually for a long time (modify register, compile, upload, run, save image, look at it, repeat) for a few weeks, but hen it got too tedious and slow. So I wrote a program that does it automatically, and saves the files on the sd card with the name of the register and value changed.

It only does a register at a time, so some settings that involve multiple registers can't be properly documented, but even so, I think it is nice and useful. Is there any interest for it? if so, I can release it on github, but after I clean the code a bit.

dadddda commented 3 years ago

Hey, I am working on a project which involves OV2640. The platform that I'm using is STM32 and for a few days now I am trying very hard to understand those registers... Some work, some don't... I don't understand why Omnivision keeps those things still secret, this camera is more than 10 years old...

Even the configuration in this esp32-camera repository gives me nonsense RGB565 images and very noisy JPEG ones... I'm lost. I found other configurations that give me very good JPEG images, but the FPS is 3-4 which is unacceptable...

And, if you'll have time, I would like to check your software. Maybe that will help, somehow. <3

raduprv commented 3 years ago

My code is mostly for a timelapse program I am writing, so I focused on still images, without caring about frame rate. Most of my changes drastically affect the frame rate, so you would get under 1fps if you apply them. Other changes have to do with setting the clock dividers and such, which is pretty platform specific.

One change that SHOULD work for you though is disabling the sharpening. You can do so like this: s->set_reg(s,0xff,0xff,0x00);//banksel s->set_reg(s,0x92,0xff,0x1); s->set_reg(s,0x93,0xff,0x0); So basically just put in the DSP register 0x92 the value 1 and in 0x93 value 0

dadddda commented 3 years ago

For me, that didn't change anything strangely. But I tracked down the issue. When I set the internal clock at 24 MHz the JPEG mode gets very unstable, I have to use 12 MHz to get a decent image. I don't know why it's unstable actually... Which configuration do you use for the internal clock and pixel clock?

dadddda commented 3 years ago

And also where did you find that 0x92 and 0x93 were doing sharpening? I was wondering what those 0x91, 0x92, and 0x93 were doing in the reference configurations...

write_SCCB(0x90, 0x00); write_SCCB(0x91, 0x0e); ... write_SCCB(0x91, 0xe8); write_SCCB(0x91, 0x20); // write_SCCB(0x92, 0x00); write_SCCB(0x93, 0x06); ... write_SCCB(0x93, 0x00); write_SCCB(0x93, 0x00); // write_SCCB(0x96, 0x00); write_SCCB(0x97, 0x08); ... write_SCCB(0x97, 0x00); write_SCCB(0x97, 0x00);

Also, why are some registers written twice or more than twice with the same or different values? And my last question will be that did you find anything about the indirect memory access thing? Brightness, saturation, and such things are configured in that way. Is there something out there documenting that registers? I didn't find anything.

raduprv commented 3 years ago

Read this, if you haven't already done so: https://github.com/espressif/esp32-camera/issues/203 As for why some registers are written twice, that's because they are written with different masks.

dadddda commented 3 years ago

Different masks? But normal write_SCCB functions take only two values, register address and value itself. I am talking about the registers I posted in the previous comment. And I have already read #203 I was also trying to use the configurations in the attached link, but they didn't work well for me.

raduprv commented 3 years ago

Oh, I thought you were asking about esp32 code. Yes, those writes don't use a mask. No idea why they do it like that, since there is no documentation for that. But I also seen that done with the code that changes the sharpness, which I linked to in the other thread.

Btw, on ESP32 cam the default (and highest possible) clock is 20Mhz, so my code works assuming that clock. Can you post some image of yours, to see if they can be improved compared to mine?

dadddda commented 3 years ago

Btw, on ESP32 cam the default (and highest possible) clock is 20Mhz, so my code works assuming that clock.

I have an input clock of 24MHz but I use a divider (0x11, 0x01) to get 12MHz internal because at 24MHz I get corrupted JPEG images despite the fact that the camera I think supports that. And I use pixel clock divided by 2 (0xD3, 0x02) despite the fact that my STM32 can handle up to 32MHz pixel clock... And I remembered that I had one question regarding register 0xD3 in DSP: sysclk (48) / [6:0] (YUV0) does this expression mean that the dividend is always 48, or does that equal to CLK calculated from register 0x11 in Bank 1? And what will happen if I write 0x00 to 0xD3? Will the divisor be equal to 0? And what will happen?

Can you post some image of yours, to see if they can be improved compared to mine?

Yes I definitely can as soon as I'll be back to my hardware.

Also, thanks for your replies!

raduprv commented 3 years ago

For the 0xd3 register, for me the best value that I found (experimentally) is 8. I have no idea why this is a good value, but you have to play with it to find the best value for you. What would happen if you put 0 in it? Well, I found that for values lower than 3 or so, I always get corrupted JPGs. It could be also a hardware dependent thing, for example at higher clock frequencies the sensor might not have enough power or something.

If you want, I can e-mail you my fuzzer code, but it is very ESP32 cam specific, so I doubt it would help you much. However, this is the pseudocode:

  1. Seed your random number generator
  2. Get 3 values, one in range of 0-1 (to select the sensor or dsp bank), and two 8 bit values (register, and the value of the register).
  3. Init the sensor normally.
  4. Write those values to the registries (don't forget to switch the bank)!
  5. s->set_reg(s,0x43,0xff,0x40);//magic value to give us the frame faster (bit 6 must be 1)
  6. Skip one frame (or two if you don't want to use the trick on step 5).
  7. Get the frame. Not sure how it is for you, but on ESP32 cam you might get some timeout errors if the exposure time is too long. I have a while loop to try up to 6 times, and then give up.
  8. Save the frame like so: bank_reg_value.jpg (where bank, reg and value are what you got from the random function)
  9. Reboot the MCU and start over.

So after you do this, you put the camera somewhere with enough light, and let it run for some hours, and then take the SD card out and look through the images. Once you find interesting images, you know the registers and values that produced them :)

dadddda commented 3 years ago

This is the latest image from my camera and it looks very bad... I don't know what I have changed because I was getting better images before. This image is 800x600 and the actual resolution is also 800x600.. test1

dadddda commented 3 years ago

This is before I changed some registers(Don't remember which...) IMAGE5

dadddda commented 3 years ago

Do you see all the bluish vertical lines in the first picture?

raduprv commented 3 years ago

I get lines like that when I play with the 0x3d register in the sensor bank. Try different values, such as 0x38 or so, see if it changes.

dadddda commented 3 years ago

I have that at 0x38 because I read somewhere that if you use SVGA or CIF as the main resolution you must use 0x38 and if you use UXGA then you must use 0x34.

Also, can you show me your best image so far shot in JPEG? I want to know the capabilities of this camera module. :D

raduprv commented 3 years ago

Well, like I said, play with it and see what happens. That particular register can give you vertical lines like that.

Not my best photos, but here are some from the last batch. Some are pretty long exposure (a few seconds). They are through a window, and there are some rain drops on it, so the real images would be a bit better. 00410_6437_3 00443_2603_27 00873_1857_253

dadddda commented 3 years ago

Wow, they look very good. The exposure is evenly distributed here than on my pictures. My daytime pictures are kind of overexposed in the center and dark in the corners, like vignetting. Are there some registers which configure how images get exposed, i.e. metering mode(Center-weighted Metering, Spot Metering...)?

raduprv commented 3 years ago

Those exposures are done manually by me. I read the light average from register 0x2f and I have a long if/else series where I give the exposure by selecting the frame rate, how many fake pixels to add, how many fake lines to add, etc.

Ironically though, I can't find any way to use the 15b AEC register (the one spread around 3 registers) to work. It makes no difference what values I put there, so I am a bit stumped on trying to get low enough exposure for bright daylight. Right now, I switch to auto mode if the light is brighter than I can handle. Did you by any chance manage to use the manual exposure using the AEC register?

As for your vignetting, it could be because of the lens that comes with the camera. Mine is not wide angle, so less vignetting.

dadddda commented 3 years ago

I read the light average from register 0x2f

Yes, I think this register is very handy.

Did you by any chance manage to use the manual exposure using the AEC register?

Yes, for example, I set the exposure with AEC to a very short time, and the images are dark, and also objects in motion are not blurred. Firstly I chose the sensor bank: SCCBWrite(0xFF, 0x01);

and then I turned off automatic exposure without touching any other values by this(I set the 0th bit to 0): SCCBRead(0x13, &read_data); SCCBWrite(0x13, read_data & 0b11111110U);

Then I set the AEC value to 100. AEC as you know is split into 3 registers. 100 in binary is 01100100 so 0x45 is AEC[15:10], 0x10 is AEC[9:2] and 0x04 is AEC[1:0] so the entire AEC[15:0] looks like that: 000000 00011001 00. So I did write those values without touching other bits that way: SCCBRead(0x45, &read_data); SCCBWrite(0x45, read_data & 0b11000000U); SCCBWrite(0x10, 0x19); SCCBRead(0x04, &read_data); SCCBWrite(0x04, read_data & 0b11111100U);

I hope that helps you!

raduprv commented 3 years ago

Yes, I know those things, and even used my fuzzer program to write random values to register 0x10 for example to see if anything changes. And it doesn't. The exposure IS set to manual, because it won't adjust it up or down depending on the ambient light. But no matter what value I put in registers 0x10 and 0x45, nothing is happening....

dadddda commented 3 years ago

Did you try my values? You know that it has an upper limit, yes?

raduprv commented 3 years ago

I didn't try your specific values for the AEC register, but I tried lots of random values, between 0 to 32768. I modified randomly both register 0x10 and 0x45, many times, and there is absolutely no difference at all. And yes, I know there is an upper limit, but again, there is no difference at all no matter what values I use.

I think there might be some undocumented bit somewhere that makes this register being used, or maybe some sort of hardware issue.

dadddda commented 3 years ago

I think there might be some undocumented bit somewhere that makes this register being used

Actually, I think you are right there. I remember when it was not doing anything for me too. Then I changed a lot of things and I think some register got changed in a way that made this work... Hmmm.

RibeiroSantos commented 3 years ago

I'm trying to document the undocumented register of this sensor. I've been doing it manually for a long time (modify register, compile, upload, run, save image, look at it, repeat) for a few weeks, but hen it got too tedious and slow. So I wrote a program that does it automatically, and saves the files on the sd card with the name of the register and value changed.

It only does a register at a time, so some settings that involve multiple registers can't be properly documented, but even so, I think it is nice and useful. Is there any interest for it? if so, I can release it on github, but after I clean the code a bit.

Hi, is it possible to share your program? Thanks a lot!

raduprv commented 3 years ago

Sure, give me your e-mail and I'll send it. Keep in mind that it's pretty rough in this state, I didn't polish it for publishing, but it shouldn't take much to clean it up.

RibeiroSantos commented 3 years ago

Sure, give me your e-mail and I'll send it. Keep in mind that it's pretty rough in this state, I didn't polish it for publishing, but it shouldn't take much to clean it up.

Any chance you publish it on github? Thanks

raduprv commented 3 years ago

I could, but then you'd have to wait a bit longer to do some code cleanup and stuff :)

github-actions[bot] commented 2 years ago

This issue appears to be stale. Please close it if its no longer valid.