Streaming “live”


Managed to get data out from OV7670 camera using an Atmega8. I found it easier to code on AVR than ARM, but mostly for the connectivity part, ARM is much faster on the processing part and the amount of available memory is perfect for my application :)

Anyway, I am able to get out images from OV7670 over the serial connection and display them on PC. Of course is slow, cause teh serial connection is very slow, take few seconds to get one image out @160×120 pixels, but if I take out the serial loop is quite fast, around 12 fsp. With some assembler I guess I can go half the nominal frame rate (30 fps). Anyway, for my application 10-12 fps is more than enough considering the fact that I’m using an Atmega8 for this running at only 16 Mhz.

Advertisements

15 thoughts on “Streaming “live”

  1. Hi! Thanks for the posts. They helped me a lot~!~

    However, interfacing this ov7670 with LPC1769 is literally driving me nuts..

    My project is more or less like the tracking u’ve done. But first of all I need to get this camera working… I seemed can’t get the settings right..How should I set the registers if I want a 320(columns)* 240(rows) image?

    And, would you mind sharing some of your code? I feel like walking in complete darkness…

    Pls help…

    • Hi Kelsie, for registry setup you can check the manual or many of the examples already available online. Basically, the following registries have to be set to get the camera generate 320 x 240 @ 30 fps, YUV:

      CLKRC (0x11) = 0x01
      COM7 (0x12) = 0x00
      COM3 (0x0C) = 0x04
      COM14 (0x3E) = 0x19
      SCALING_XSC (0x70) = 0x3A
      SCALING_YSC (0x71) = 0x35
      SCALING_DCWCTR (0x72) = 0x11
      SCALING_PCLK_DIV (0x73) = 0xF1
      SCALING_PCLK_DELAY (0xA2) = 0x02

      You can change COM7 according to the format you need (YUV, RGB, etc). Will suggest to go through the OV7670 manual to understand how everything works.

      If you go through the posts on this site you find pretty much everything you need to understand the logic on how to control and communicate with the OV7670, however, my project make use of the FIFO memory, not very sure what hardware are you using.

      Good luck with your project.

      • Hi! God, thx for ur super fast reply!!!

        Well, I think I start to get it…

        Uhm…I am using this ov7670 + fifo version with LPC1769, and right now I am capturing an 160*120 (QQVGA) RGB444 image and will send it via UART to PC. How do I re-assemble the image and display it on the PC side…? Sorry I am really a newbie…..

      • I guess you already got the image out from your FIFO and you only need to send it out and receive it on the other side… All you need is to design a simple (or not that simple) protocol that allows you to get the data received with minimal errors on the PC side.

        In one of the posts is a long discussion about this, not sure which one. Anyway, to put it simple: there are 2 options:
        – stream continuously data from your MCU to PC and get the PC side handle the errors;
        – MCU stream a frame only when this is initiated by PC.

        First one may allow you to achieve higher speed, however, will introduce errors unless you add additional control data (start frame, start line, end frame, etc) which means additional data to be streamed…

        Second one will introduce additional delay as you will need to switch to receive mode then once request received switch back to sending mode, there are also additional conditions to check, etc. Some can be solved (use UART interrupt and check UART FIFO instead of waiting for a request, reduce the complexity of the protocol, etc).

        Based on your application you will need to decide what solution is better for you and design a communication protocol accordingly.

        Once data is safe and sound on the PC side the rest is easy, if you sent RGB format you can just push it to your application (well, as long is same format). If you stream YUV format, there is a post on this site that explains how to get it converted in RGB format. If you only send B&W (luminance data) then you can make R = G = B and treat it as RGB, and so on.

        I will suggest to use PROCESSING s/w for start, samples on how to get YUV displayed are already posted here, also is pretty easy to work with.

      • Thank you very much!!!

        I will give it a try….!!

        Uhm, what is your secret of fast tracking speed? I read online that a lot of people can only get 1 frame ever few seconds….How did u do that with LPC1769?..

      • Secret? What secret? Hahaha!

        I guess you are confusing streaming with tracking. When doing tracking you do not need to worry about transfering data to a PC, you just focus on implementing your tracking solution (e.g.: color segmentation). Of course high speed means your code have to be optimised (reduce number of loops, checks, etc.).

        Start capturing a frame, learn how to process an image, have an idea what you want to achieve and once you get it working think on how to optimise it later.

  2. Hi! Thanks for all ur advices!~ Now the uart transmission works perfect! I am saving images on the pc to verify its correctedness. I’ve sent some test images and the reconstruction is correct. I assume the program is working.

    But when I send the pixels got from the camera, something is wrong. I got different color strips instead of an image of the object my camera is facing..

    Can you take a look at my code…? Instead of RGB444, I am using QQVGA RGB555 this time

    This is from my main.c
    while(1) {
    ov7670_writeInit();
    ov7670_captureFrame();
    FIFO_readReset();

    //Send Start of frame
    UART_Send(LPC_UART2, &sof[0], 4, BLOCKING);

    for (y = 0;y < SIZEY;y++) {
    for (x = 0;x < SIZEX;x++) {

    //RGB555
    d1 = FIFO_readByte(); // GGGBBBBB
    d2 = FIFO_readByte() & 0x7F; // 0RRRRRGG
    pixel[0] = d1;
    pixel[1] = d2;

    //Send 2 bytes for 1 pixel
    UART_Send(LPC_UART2, &pixel[0], 2, BLOCKING);
    }
    }
    //Send end of frame
    UART_Send(LPC_UART2, &eof[0], 4, BLOCKING);
    }

    The following is from ov7670.c

    #define VSYNC (1 << 17) //p0.17
    #define D0 (1 << 30) //p1.30
    #define D1 (1 << 31) //p1.31
    #define D2 (1 << 2) //p0.2
    #define D3 (1 << 3) //p0.3
    #define D4 (1 << 21) //p0.21
    #define D5 (1 << 22) //p0.22
    #define D6 (1 << 4) //p0.4
    #define D7 (1 << 5) //p0.5

    #define FIO0PIN 0x2009C014
    #define FIO1PIN 0x2009C034
    volatile unsigned int *p0 = (unsigned int *)FIO0PIN;
    volatile unsigned int *p1 = (unsigned int *)FIO1PIN;

    uint8_t ov7670_init(void) {

    init_i2c();
    init_GPIO();

    // QQVGA RGB555
    ov7670_set(REG_CLKRC,0x80);
    ov7670_set(REG_COM11,0x0A) ;
    ov7670_set(REG_TSLB,0x04);
    ov7670_set(REG_COM7,0x04) ;

    //rgb555
    ov7670_set(REG_COM15, 0xf0);

    ov7670_set(REG_HSTART,0x16) ;
    ov7670_set(REG_HSTOP,0x04) ;
    ov7670_set(REG_HREF,0x24) ;
    ov7670_set(REG_VSTART,0x02) ;
    ov7670_set(REG_VSTOP,0x7a) ;
    ov7670_set(REG_VREF,0x0a) ;

    ov7670_set(REG_COM10,0x02) ;
    ov7670_set(REG_COM3, 0x04);

    ov7670_set(REG_COM14, 0x1a);
    ov7670_set(0x72, 0x22);
    ov7670_set(0x73, 0xf2);

    // COLOR SETTING
    ov7670_set(0x4f, 0x80);
    ov7670_set(0x50, 0x80);
    ov7670_set(0x51, 0x00);
    ov7670_set(0x52, 0x22);
    ov7670_set(0x53, 0x5e);
    ov7670_set(0x54, 0x80);
    ov7670_set(0x56, 0x40);
    ov7670_set(0x58, 0x9e);
    ov7670_set(0x59, 0x88);
    ov7670_set(0x5a, 0x88);
    ov7670_set(0x5b, 0x44);
    ov7670_set(0x5c, 0x67);
    ov7670_set(0x5d, 0x49);
    ov7670_set(0x5e, 0x0e);
    ov7670_set(0x69, 0x00);
    ov7670_set(0x6a, 0x40);
    ov7670_set(0x6b, 0x0a);
    ov7670_set(0x6c, 0x0a);
    ov7670_set(0x6d, 0x55);
    ov7670_set(0x6e, 0x11);
    ov7670_set(0x6f, 0x9f);

    ov7670_set(0xb0, 0x84);
    return 1;
    }

    /*
    * Pins:
    * rrst: P0.23
    * oe: P0.24
    * rclk: P0.25
    */
    void FIFO_readReset(void) {
    //pseudo code
    /*
    * oe = 0
    * rrst = 0
    * RCLK = 0
    * RCLK = 1
    * RCLK = 0
    * RRST = 1
    */
    GPIO_ClearValue(0, (1<<24)|(1<<23));
    GPIO_ClearValue(0, (1<<25));
    GPIO_SetValue(0, (1<<25));
    GPIO_ClearValue(0, (1<<25));
    GPIO_SetValue(0, (1<<23));

    }
    uint8_t FIFO_readByte(void) {
    //Pseudo code
    /*
    * rclk = 1
    * data
    * rclk = 0
    */
    uint8_t val;

    GPIO_SetValue(0, (1<<25));

    val = ((*p0 & D7) << 2)| ((*p0 & D6) <> 17)|
    ((*p0 & D4) >> 17)|(*p0 & D3)|(*p0 & D2)|((*p1 & D1) >> 30)|
    ((*p1 & D0) >> 30);

    GPIO_ClearValue(0, (1<<25));

    return val;
    }

    /*
    * Pins:
    * VSYNC: P0.17
    * WEN: P0.16
    */
    void ov7670_captureFrame(void) {

    while(*p0 & VSYNC);
    while(!(*p0 & VSYNC));
    GPIO_ClearValue(0, (1<<16));// write enable
    while(*p0 & VSYNC);
    //while(*p0 & VSYNC);
    GPIO_SetValue(0, (1<<16)); // write disable

    }

    void ov7670_writeInit(void) {
    GPIO_SetValue(0, (1<<16)); //write disable
    }

    Function captureFrame() causes me some concern, when doing "write enable", I think WEN pin is active low so I use GPIO_ClearValue; is that right? Well, I tried to change this part to SetValue but the image is no better…

    I couldn't find what is wrong….Anything catch your attention?

    • Hi Kelsie, by any chance can you show me a sample of what your camera sees?
      Also, the capture frame should be changed, why not just define an external interrupt on VSYNC instead? Also, check again the RRST sequence ithe datasheet. Is there a reason you keep clearing OE? I do not see where you set it anyway.

      I am a bit confused the way you read the data, by any chance, can you just find 8 consecutive pins on the same port? This will make it easier and also faster.

      Also, can you advise which FIFO module you are using?

      • Thanks very much for your advice~~ it’s very very kind of you…!!

        I am using this module http://www.ebay.com.sg/itm/200631213463?ssPageName=STRK:MEWAX:IT&_trksid=p3984.m1423.l2649

        I guess it’s the second version, coz it has “CF7670C-V2” printed on the back of the module…

        For read reset part, I rewrite the code; the pseudo code looks like:
        void FIFO_readReset(void) {
        /*
        * pseudo code
        * rclk = 0;
        * rrst = 1;
        * rclk = 1;
        * rrst = 0;
        * rclk = 0;
        * rclk = 1;
        * rclk = 0;
        * rclk = 1;
        * rclk = 0;
        * rrst = 1;
        * rclk = 1;
        */
        }

        For output enable OE, I don’t know what to do with it actually…Thought just need to keep it low whenever I am reading… Better way of handling..?

        Following your advice, I am now using p2.0-p2.7 for data reading…So now the code becomes:
        uint8_t FIFO_readByte(void) {
        //Pseudo code
        /*
        * rclk = 1
        * data
        * rclk = 0
        */
        uint8_t val;

        GPIO_SetValue(0, (1<<25));
        val = FIO_ByteReadValue(2, 0); //read from register FIO2PIN0, function from lib_mcu…
        GPIO_ClearValue(0, (1<IO0IntEnF = 1<IO0IntEnR = 1<IO0IntStatF >> 17) & 0x1) {
        VSYNC = 0;
        printf(“0.17 falling edge interrupt \n”);
        LPC_GPIOINT->IO0IntClr = 1<IO0IntStatR >> 17) & 0x1) {
        VSYNC = 1;
        printf(“0.17 rising edge interrupt \n”);
        LPC_GPIOINT->IO0IntClr = 1<<17;
        }

        }

        Then my captureframe function becomes:

        void ov7670_captureFrame(void) {

        while(VSYNC == 1); //wait for an old frame to finish
        while(VSYNC == 0); //wait for a new frame to begin
        GPIO_ClearValue(0, (1<<16));// write enable
        while(VSYNC == 1); //new frame
        GPIO_SetValue(0, (1<<16)); // write disable

        }

        Does the code look any better?
        Thank you for reading all these…

      • Hi Kelsie, seems you are using the version 2. In this case:
        – OE should just be set to GND unless you are using the data bus to connect other device.
        – If you look at page 9 in AL422B manual you will see how RCLK and RRST should look like.
        – There is already a post on my site that explain some differences between V1 and V2, you may want to take a look, will explain why may not work: https://thinksmallthings.wordpress.com/2012/03/10/cf7670c-vs-cf7670c-v2/
        – I am confused: you are trying to define an external interrupt for VSYNC, however, you are still using “while” loops to detect VSYNC… I’m lost…
        – not sure on the pixel reading part :)

  3. ???The middle part of my comment disappeared….many apologies for messing up your post……

    Repost:

    Following your advice, I am now using p2.0-p2.7 for data reading…So now the code becomes:
    uint8_t FIFO_readByte(void) {
    //Pseudo code
    /*
    * rclk = 1
    * data
    * rclk = 0
    */
    uint8_t val;

    GPIO_SetValue(0, (1<<25));
    val = FIO_ByteReadValue(2, 0); //read from register FIO2PIN0, function from lib_mcu…
    GPIO_ClearValue(0, (1<IO0IntEnF = 1<IO0IntEnR = 1<IO0IntStatF >> 17) & 0x1) {
    VSYNC = 0;
    printf(“0.17 falling edge interrupt \n”);
    LPC_GPIOINT->IO0IntClr = 1<IO0IntStatR >> 17) & 0x1) {
    VSYNC = 1;
    printf(“0.17 rising edge interrupt \n”);
    LPC_GPIOINT->IO0IntClr = 1<<17;
    }

    }

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s