igrr / esp32-cam-demo

Demo for working with a camera on ESP32
Apache License 2.0
623 stars 242 forks source link

OV7670 support #29

Open nkolban opened 7 years ago

nkolban commented 7 years ago

I have a WROVER and an OV7670 camera. I am using the ESP-IDF as of this post date. All compiles cleanly and when I flash/run, the application runs. However, I do not see any output (please see log at end). I have tried enabling the test pattern and there is no change. Here is the log of a run with zero changes having been made to the source:

D (633) camera: Enabling XCLK output
D (633) ledc: LEDC_PWM CHANNEL 0|GPIO 21|Duty 0004|Time 0
D (633) camera: Initializing SSCB
I (633) gpio: GPIO[26]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 
I (633) gpio: GPIO[27]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 
I (643) gpio: GPIO[26]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 
I (653) gpio: GPIO[27]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 
D (663) camera: Resetting camera
D (673) camera: Searching for camera address
D (673) camera: Detected camera at address=0x21
D (673) camera: Camera PID=0x76 VER=0x73 MIDL=0x7f MIDH=0xa2
D (683) camera: Doing SW reset of sensor
D (733) camera: Test pattern enabled
D (733) camera: Setting frame size at 320x240
D (763) camera: Allocating frame buffer (320x240, 76800 bytes)
D (763) camera: Initializing I2S and DMA
I (763) gpio: GPIO[35]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 
I (763) gpio: GPIO[34]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 
I (773) gpio: GPIO[39]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 
I (783) gpio: GPIO[36]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 
I (793) gpio: GPIO[19]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 
I (793) gpio: GPIO[18]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 
I (803) gpio: GPIO[5]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 
I (813) gpio: GPIO[4]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 
I (823) gpio: GPIO[25]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 
I (833) gpio: GPIO[23]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 
I (843) gpio: GPIO[22]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 
D (843) camera: Allocating DMA buffer #0, size=1280
D (853) camera: Allocating DMA buffer #1, size=1280
cspwcspw commented 5 years ago

malloc() is not "built-in" to C++, but is defined in stdlib.h, so you need to have this line somewhere, probably at the top of the file giving trouble.

include

BeatArnet commented 5 years ago

Yeah, problem solved. Thanks for help.

espiot328266 commented 5 years ago

am having a problem with video streaming, it is showing a purple color instead of natural one 51467507_381909335930451_9202293316618551296_n 51645962_616072702197477_1934994079515410432_n how to fix that

rykovv commented 5 years ago

Greetings to all.

I am struggling for a couple of days trying to retrieve an image from the ov7670, but no result. I connect with the sensor, configure it, and the rest of initialization is pretty the same as the original project or similar ones.

My code has no compilation errors, however, when it comes to get an image using a web browser the code stops waiting for a frame. I have studied the code thoroughly and i2s interface functionality and it seems like i2s interruption never occurs. This is the reason why the dma is never filled with the image data and, thus, the semaphore is never released.

I can not figure out why this happens. If you have any ideas or suggestions I will appreciate any.

Screenshot from 2019-06-27 11-27-09

log.txt

cspwcspw commented 5 years ago

One possible thing to try: The camera module needs an external clock which the ESP32 must supply: without that, you will not get frames delivered. So this is one avenue to investigate that could explain your problem.

If you have an oscilloscope you need to check then the clock output signal is being generated and is connected to the correct pin on the camera module. (Beware, the ESP32 pins 34 and above are input only, so you cannot use those to output the clock.) Once the camera gets the clock, you should be able to see the camera returning pixel clock and VSYNC signals to the ESP32. Without those, you'll never get the interrupts you need.

rykovv commented 5 years ago

Thank you @cspwcspw, I really appreciate your help.

The camera module needs an external clock which the ESP32 must supply: without that, you will not get frames delivered. So this is one avenue to investigate that could explain your problem.

I use the 20MHz external clock, generating it through ledc (channel 0) on XCLK camera's pin (currently D21). I configure CLKRC camera's register as you and did in your project, and also I tried Use external clock directly (no clock pre-scale available) option activating bit[6] of the same register, but that gave no result.

Once the camera gets the clock, you should be able to see the camera returning pixel clock and VSYNC signals to the ESP32.

The interesting point is that enabling VSYNC interruption, it constantly occurs and I can see that. Therefore, the camera is sending image frames, as @igrr described. However the MCU does not capture the data.

I would be happy to have an oscilloscope on hands to check the pins, but I don't. The only clue I have now is that something wrong with the I2S0. Because, as I understand, when one data sample is transmitted, the I2S interruption occurs (_i2sisr), the sample is stored, and the process continues until the whole image received. But the _i2sisr never occurs.

cspwcspw commented 5 years ago

Mmm. Don't know what to suggest next. And I've torn down my hardware and given the oscilloscope I used back to its owner.

But my understanding of the i2s interrupt is a bit different: you should only get one interrupt per scanline, not one per sample (the ESP32 would never be able to handle interrupts that fast, one per pixel).

It has been a while now so my recall might be fuzzy, but essentially the I2S hardware with DMA manages the transfer of pixel data from the camera into DMA memory. Latching each 8-bit half-pixel and writing it to the next 16-bits of DMA (yes, half the bytes are zero because it is an 8-bit camera bus feeding into a 16-bit I2S hardware latch). That all happens without any interrupts. That latching is triggered by PCLK coming from the camera (so check that wiring, that the GPIO pin is correctly configured for INPUT, etc.)

The I2S hardware runs in the background, and waits until it has received the correct (pre-programmed) number of samples before it interrupts the ESP32. (i.e. this interrupt is count-based, from the i2S hardware, and means "one scan line is ready in memory"). The ESP32 interrupt service routine (ISR) counts the scan lines, and copies data out of the DMA buffer into successive locations in its frame buffer (skipping every second zero byte in the DMA buffer, of course). From counting scan-line interrupts it knows when the whole frame has been received.

The VSYNC and its ISR play a fairly minor role in the logic: the XCLK you generate runs continuously, so from the camera's point of view it is always running, busy delivering pixel data and control signals like VSYNC, PCLK, HREF. When ESP32 frame capture is initiated, the camera could be half-way through its current frame, so the ESP32 waits for VSYNC before enabling the i2S hardware capture. This ensures the next pixel captured by i2S hardware is indeed the very first pixel of the first scan line of the new frame.

Another thing I would also check is the PWDN line on the camera. It can be used to tri-state or suppress some camera control lines and pixel data - I'm not sure if VSYNC still runs when the camera is "tri-stated", but if your i2S hardware is never getting PCLK it will never latch any data, and you will never get the interrupt firing.

rykovv commented 5 years ago

@cspwcspw thank you again for your explanation. It really cleared up the things.

The next thing I am going to do is to find the oscilloscope and analyze the issue, particularly the PCLK pin activity.

The VSYNC and its ISR play a fairly minor role in the logic:

That's also true. After digging a little bit more into the datasheet I found that the digram bellow confirms your words.

Screenshot from 2019-06-28 17-36-50

Another thing I would also check is the PWDN line on the camera.

I had no information about it. I tried to pull down this pin with 10K resistor and the camera did not responded.

I will research more about these points and keep you posted on further steps.

Thank you @cspwcspw

cspwcspw commented 5 years ago

I found it easier to change the line of code that sets up the clock speed while debugging. It slows everything down. 20Mhz was a bit fast for the oscilloscope I used. But importantly, fast signals don't work well over long wires. The data sheet says 10Mhz is lowest XCLK speed, but I got down to about 8Mhz successfully.

You can try this too: If you #include"Arduino.h" at the top of the I2SCamera.cpp you will be able to use the standard Serial.print("xxx") inside the i2sInterrupt routine. See if any interrupts are occurring. (Serial printing is a slow process and you shouldn't be printing in the middle of a time-critical interrupt service routine, but you can use this anyway to try learn something useful.)

You could also sprinkle some print statements elsewhere to attempt to debug things, i.e. in the VSYNC ISR, or in the bit of logic that tries to determine whether enough scan lines have been received to stop the frame capture and return to the main program.

rykovv commented 5 years ago

@cspwcspw,

Thank you for your suggestions. Finally, I solved the issue. It was wrong VSYNC synchronization. I was expecting VSYNC to be negative and it was configured positive. So properly changing COM10 register or _gpio_matrixin function allowed image retrieval.

Now, I am struggling with colors adjustment issue. The image I get seems to have sepia effect. I suppose MTXN and GAMN must be properly adjusted.

cap

cspwcspw commented 5 years ago

Good news.

There are some other camera registers that allow one to determine the format of the colour stream pixels, and the order that the RGB components arrive at the ESP32. See e.g. the COM30 register. I always used RGB565 and there was also some OV7670 register option, I think, to send the channels in BGR order rather than RGB order. The OV7670 seems quite flexible because it was, I think, a camera for integrating into early cell-phones. I found it useful to get a red, green and blue card to put in front of the camera, then look at which bits get set in the 16-bit frame stream to make sure that what you think are the red channel are the ones that get higher values when you're looking at a red object, etc. If a blue card makes your image increase its redness and vice-versa, ....

Wrong displays might also be because the rendering / display side of things gets it wrong. Packing those bytes into a bitmap in that code uses a fixed bitmap header that defines the bitmap format, including sizes and order of the RGB channels. So perhaps you can completely ignore the camera and just manually pack a stream of bytes for rendering a test pattern (all red, all green, or all blue), etc. That can help debug whether your bitmap header and rendering in the browser is all as you expect it to be.

rykovv commented 5 years ago

@cspwcspw

That's really useful tips for debugging the color correctness. Thank you for your valuable suggestions! Will keep you posted.

jjsch-dev commented 5 years ago

Hi, I do a porting of the driver for the ov7670. The base code was the idf camera support, if you wish I send the source code please contact me.

app-z commented 4 years ago

I finale got it at most in logs. Camera running with QQVGA size only .frame_size = FRAMESIZE_QQVGA, I suppose to used your fork with support OV7670 - https://github.com/jjsch-dev/esp32-cam-demo

D (960) camera: Setting frame size to 160x120
D (970) ov7760: reset reg 0C, W(04) R(04)
D (970) ov7760: reset reg 3E, W(1A) R(1A)
D (970) ov7760: reset reg 70, W(3A) R(3A)
D (980) ov7760: reset reg 71, W(35) R(35)
D (980) ov7760: reset reg 72, W(22) R(22)
D (990) ov7760: reset reg 73, W(F2) R(F2)
D (990) ov7760: reset reg A2, W(02) R(02)
D (1000) ov7760: reset reg 17, W(13) R(13)
D (1000) ov7760: reset reg 18, W(01) R(01)
D (1000) ov7760: reset reg 32, W(36) R(36)
D (1010) ov7760: reset reg 19, W(02) R(02)
D (1010) ov7760: reset reg 1A, W(7A) R(7A)
D (1050) ov7760: reset reg 12, W(04) R(04)
D (1050) ov7760: reset reg 8C, W(00) R(00)
D (1050) ov7760: reset reg 04, W(00) R(00)
D (1050) ov7760: reset reg 40, W(D0) R(D0)
D (1050) ov7760: reset reg 1E, W(22) R(22)
D (1060) ov7760: reset reg 14, W(6A) R(6A)
D (1060) ov7760: reset reg 4F, W(B3) R(B3)
D (1060) ov7760: reset reg 50, W(B3) R(B3)
D (1070) ov7760: reset reg 51, W(00) R(00)
D (1070) ov7760: reset reg 52, W(3D) R(3D)
D (1080) ov7760: reset reg 53, W(A7) R(A7)
D (1080) ov7760: reset reg 54, W(E4) R(E4)
D (1080) ov7760: reset reg 3D, W(40) R(40)
V (1130) camera: DMA desc  0: 640 640 0 1 1 1 0x3ffb3cf8 0x3ffb3cd0
V (1130) camera: DMA desc  1: 640 640 0 1 1 1 0x3ffb6df0 0x3ffb3cdc
V (1130) camera: DMA desc  2: 640 640 0 1 1 1 0x3ffb7074 0x3ffb3ce8
V (1140) camera: DMA desc  3: 640 640 0 1 1 1 0x3ffb72f8 0x3ffb3cc4
V (1140) camera: Waiting for negative edge on VSYNC
V (1180) camera: Got VSYNC
I (1230) Camera-sample: fb->width = 160 , fb->height = 120 , fb->format = 0, fb->len = 57600 
jjsch-dev commented 4 years ago

@app-z good job, if you have problems please let me know. I also ported the QR recognition demo of @donny681 to esp_idf/esp32_camera that support the ov7670 sensor. https://github.com/jjsch-dev/ESP32_CAMERA_QR