2
\$\begingroup\$

I have to interface my STM32F401RE with an OV7670 camera module without external AL422. I followed some of the many tutorials for Arduino, and I was able to capture images using Arduino UNO. Unfortunately my requirements force me to use STM as board and to program it using the HAL library from ST. So my aim is to be able to capture an image on request, so I tried to adapt the code structure used for Arduino to my board and library but the results are quite frustrating because all I could get are messy noisy images, like these

enter image description here enter image description here

At the moment what my code does is taking an image and send it via UART where a Java application is listening the COM port and shows the image. Some more details:

  • I'm sure about the Java code correctness because if I send an image made of a single color it is perfectly shown;
  • I set the camera using QQVGA resolution and YUV color mode, the register values are the same that can be found surfing a bit on the net;
  • I tried both sending the image in stream, as in the first picture, and saving it in SRAM and then sending, second picture (there is a quite notable difference because the second case seems largely pure noise);
  • At the moment the camera is fed with a 8MHz clock form MCO pin that according many users seems to work even if the datasheets states 10MHz as minimum;
  • I played a bit with clock prescaling, but always striped messy images;
  • Sender and receiver baud rates are correct.

I am almost sure that there is some problem in reading signals correctly according the camera timing but I really cannot spot the problem. In my current settings PCLK does not toggle during horizontal blanking. The main function to capture the image is the following (almost the same that can be found surfing Arduino Forum):

    int camera_capture_image(uint8_t image_buffer[][2*COLS]) {
    uint16_t hg = 120, wg = 320, lg2;
    int num = 0;
    uint8_t buf[320];
    while(HAL_GPIO_ReadPin(VSYNC_PORT, VSYNC_PIN) == GPIO_PIN_RESET);
    while(HAL_GPIO_ReadPin(VSYNC_PORT, VSYNC_PIN) == GPIO_PIN_SET);
    while(hg--){
            uint8_t*b=buf,*b2=buf;
            lg2=wg/5;
            while(lg2--){
                while(HAL_GPIO_ReadPin(PCLK_PORT, PCLK_PIN) == GPIO_PIN_SET);
                *b++=(uint8_t)GPIOC->IDR;
                while(HAL_GPIO_ReadPin(PCLK_PORT, PCLK_PIN) == GPIO_PIN_RESET);//wait for high
                while(HAL_GPIO_ReadPin(PCLK_PORT, PCLK_PIN) == GPIO_PIN_SET);//wait for low
                *b++=(uint8_t)GPIOC->IDR;
                while(HAL_GPIO_ReadPin(PCLK_PORT, PCLK_PIN) == GPIO_PIN_RESET);//wait for high
                while(HAL_GPIO_ReadPin(PCLK_PORT, PCLK_PIN) == GPIO_PIN_SET);//wait for low
                *b++=(uint8_t)GPIOC->IDR;
                while(HAL_GPIO_ReadPin(PCLK_PORT, PCLK_PIN) == GPIO_PIN_RESET);//wait for high
                while(HAL_GPIO_ReadPin(PCLK_PORT, PCLK_PIN) == GPIO_PIN_SET);//wait for low
                *b++=(uint8_t)GPIOC->IDR;
                while(HAL_GPIO_ReadPin(PCLK_PORT, PCLK_PIN) == GPIO_PIN_RESET);//wait for high
                while(HAL_GPIO_ReadPin(PCLK_PORT, PCLK_PIN) == GPIO_PIN_SET);//wait for low
                *b++=(uint8_t)GPIOC->IDR;
                image_buffer[hg][lg2] = *b2++;
                num++;
                //HAL_UART_Transmit(&huart2, b2++, sizeof(b2), HAL_MAX_DELAY);
                while(HAL_GPIO_ReadPin(PCLK_PORT, PCLK_PIN) == GPIO_PIN_RESET);//wait for high
            }
            /* Finish sending the remainder during blanking */
            lg2=320-(wg/5);
            while(lg2--) {
                image_buffer[hg][lg2] = *b2++;
                num++;
                //HAL_UART_Transmit(&huart2, b2++, sizeof(b2), HAL_MAX_DELAY);
            }
        }
        return num;
}

If you need any other detail I am ready to provide it.

\$\endgroup\$
6
  • \$\begingroup\$ Do you really have a byte-wide parallel interface wired to PC0-7 in order? Did you configure the GPIO? Are you using the MCU clock PLL? Why are you using direct register access sometimes and the HAL routines othertimes? \$\endgroup\$ Jul 23, 2019 at 13:18
  • \$\begingroup\$ Yes, I configured the peropherals, including GPIO, using CubeMX. The MCU clock is set at 84MHz so PLLM = 8, PLLN = 84, PLLP = 2, PLLQ = 4 (set automatically by CubeMX). I access GPIO IDR register directly because in my ignorance I don't know any other way to read simultaneously more than 1 GPIO pin with HAL. Regarding the first question I'm not sure if I understood, but maybe my previous answer about GPIO IDR tells what you wher asking for. \$\endgroup\$
    – user362759
    Jul 23, 2019 at 13:38
  • \$\begingroup\$ I'd suggest you have the MCU blip an output at key points in the frame and compare that on a scope to the output of the camera, to see that you are actually achieving synchronization. \$\endgroup\$ Jul 23, 2019 at 13:43
  • \$\begingroup\$ I have no oscilloscope available, so this a quite difficult solution. Any other hint? \$\endgroup\$
    – user362759
    Jul 23, 2019 at 14:06
  • \$\begingroup\$ There are probably better ways to solve your unspecified actual problem - legitimate cases for feeding a camera into an MCU are fairly rare. The system that can actually make use of an image or video feed can probably handle an ordinary USB webcam. \$\endgroup\$ Jul 23, 2019 at 14:08

1 Answer 1

1
\$\begingroup\$

So this is probably too late to be helpful but I would like to answer this for others who google this.

There are a lot of missing details so I will try to answer it very generally:

  • Firstly, It IS possible to interface OV7670 with STM32F4 (specifically STM32F401RE)? I have written an article about it. (Admittedly, this hardware choice isn't ideal.)
  • I recommend that anyone who do this should iteratively implement and verify in small increment first. Otherwise, it would be hard to isolate faults as you described in the question:
    1. Verify that there is PCLK signal when powered on
    2. Check that camera control signal (SCCB) code works. (Try write and then read)
    3. Try counting horizontal line and vertical line for sanity check.
    4. Use test pattern mode to verify that the image capture code and display code is correct.
    5. Then finally switch to debugging the camera stuff (exposure, white balance, etc.).
  • Regarding the noisy image, Use test pattern mode as a sanity check. Though for your case I would probably try counting PCLK, HSYNC, and VSYNC first.
  • It is not possible to send image as a stream because UART is slower than camera output. Image must be buffered first.
  • Try >10MHz then pre-scale down inside the camera module. The MCU can handle it. (DMA might need to be used). My camera became noisy when using <10MHz. (Though not as noisy as the image provided.)
  • I see no alignment marker in the UART code. You might want alignment marker to mark the start of the frame transmission.
  • Using GPIO IDR Register is not a problem. Just be sure to match the pin, the configuration and the wire correctly.
  • I too, don't have an oscilloscope. I turned the MCU into a logic analyzer. This might work for you.
  • It is possible to use I2C for SCCB protocol, but you have to configure it treat ACK as Dont-Care because SCCB is not I2C.

To conclude, I think the most important thing is to verify that every step in the process does work.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.