OV7670 - Arduino Mega

Hello guys, I’m developing an example using this camera based on Mr_Arduino code for arduino mega, I am transmitting the data to the PC via serial interface, but the data are not coming properly.
Could you help me ?
Thaks :slight_smile:

#include <stdint.h>
#define F_CPU 16000000UL
#include <stdint.h>
#include <avr/io.h>
#include <util/twi.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include<I2C.h>

void wrReg(uint8_t reg,uint8_t dat);
uint8_t rdReg(uint8_t reg);
enum RESOLUTION{VGA,QVGA,QQVGA};
enum COLORSPACE{YUV422,RGB565,BAYER_RGB};
struct regval_list{
  uint8_t reg_num;
  uint8_t value;
};
void setColorSpace(enum COLORSPACE color);
void setRes(enum RESOLUTION res);
void camInit(void);
#define OV7670_I2C_ADDRESS  0x21
#define camAddr_WR 0x42
#define camAddr_RD 0x43


//register definitions not show...


static void errorD(void){
}
void twiStart(void){
  TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);//send start
  while (!(TWCR & (1<<TWINT))) {}//wait for start to be transmitted
  if ((TWSR & 0xF8) != TW_START)
    errorD();
}
void twiWriteByte(uint8_t DATA,uint8_t type){
  static uint16_t err=5;
  TWDR = DATA;
  TWCR = _BV(TWINT) | _BV(TWEN);
  while (!(TWCR & (1<<TWINT))) {}
  if ((TWSR & 0xF8) != type)
    errorD();
  ++err;
}
void twiAddr(uint8_t addr,uint8_t typeTWI){
  TWDR = addr;//send address
  TWCR = _BV(TWINT) | _BV(TWEN);    /* clear interrupt to start transmission */
  while ((TWCR & _BV(TWINT)) == 0); /* wait for transmission */
  if ((TWSR & 0xF8) != typeTWI)
    errorD();
}
uint8_t twiRd(uint8_t nack){
  if (nack){
    TWCR=_BV(TWINT) | _BV(TWEN);
    while ((TWCR & _BV(TWINT)) == 0); /* wait for transmission */
  if ((TWSR & 0xF8) != TW_MR_DATA_NACK)
    errorD();
    return TWDR;
  }else{
    TWCR=_BV(TWINT) | _BV(TWEN) | _BV(TWEA);
    while ((TWCR & _BV(TWINT)) == 0) ; /* wait for transmission */
    if ((TWSR & 0xF8) != TW_MR_DATA_ACK)
      errorD();
    return TWDR;
  }
}
void wrReg(uint8_t reg,uint8_t dat){
  //send start condition
  //PORTG|=1<<5;
  twiStart();
  twiAddr(camAddr_WR,TW_MT_SLA_ACK);
  twiWriteByte(reg,TW_MT_DATA_ACK);
  twiWriteByte(dat,TW_MT_DATA_ACK);
  TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);//send stop
  _delay_ms(1);
  //PORTG&=~(1<<5);
}
uint8_t rdReg(uint8_t reg){
  //PORTG|=1<<5;
  uint16_t dat;
  twiStart();
  twiAddr(camAddr_WR,TW_MT_SLA_ACK);
  twiWriteByte(reg,TW_MT_DATA_ACK);
  TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);//send stop
  _delay_ms(1);
  twiStart();
  twiAddr(camAddr_RD,TW_MR_SLA_ACK);
  dat=twiRd(1);
  TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);//send stop
  _delay_ms(1);
  //PORTG&=~(1<<5);
  return dat;
}
void wrSensorRegs8_8(const struct regval_list reglist[]){
  uint8_t reg_addr,reg_val;
  const struct regval_list *next = reglist;
  while ((reg_addr != 0xff) | (reg_val != 0xff)){
    reg_addr = pgm_read_byte(&next->reg_num);
    reg_val = pgm_read_byte(&next->value);
    wrReg(reg_addr, reg_val);
      next++;
  }
}
void setColorSpace(enum COLORSPACE color){
  switch(color){
    case YUV422:
      wrSensorRegs8_8(yuv422_ov7670);
    break;
    case RGB565:
      wrSensorRegs8_8(rgb565_ov7670);
      {uint8_t temp=rdReg(0x11);
      _delay_ms(1);
      wrReg(0x11,temp);}//according to the Linux kernel driver rgb565 PCLK needs rewriting
    break;
    case BAYER_RGB:
      wrSensorRegs8_8(bayerRGB_ov7670);
    break;
  }
}
void setRes(enum RESOLUTION res){
  switch(res){
    case VGA:
      wrReg(REG_COM3,0);  // REG_COM3
      wrSensorRegs8_8(vga_ov7670);
    break;
    case QVGA:
      wrReg(REG_COM3,4);  // REG_COM3 enable scaling
      wrSensorRegs8_8(qvga_ov7670);
    break;
    case QQVGA:
      wrReg(REG_COM3,4);  // REG_COM3 enable scaling
      wrSensorRegs8_8(qqvga_ov7670);
    break;
  }
}
void camInit(void){
  wrReg(0x12, 0x80);//Reset the camera.
  _delay_ms(100);
  wrSensorRegs8_8(ov7670_default_regs);
  wrReg(REG_COM10,32);//PCLK does not toggle on HBLANK.
}

#define useVga
//#define useQvga
//#define useQqvga

static inline void serialWrB(uint8_t dat){
  //while(!( UCSR0A & (1<<UDRE0)));//wait for byte to transmit
  UDR0=dat;
  while(!( UCSR0A & (1<<UDRE0)));//wait for byte to transmit
}

static void StringPgm(const char * str){
  do{
    serialWrB(pgm_read_byte_near(str));
  }while(pgm_read_byte_near(++str));
}

static void captureImg(uint16_t wg,uint16_t hg){
  uint16_t lg2;
#ifdef useQvga
  uint8_t buf[640];
#elif defined(useQqvga)
  uint8_t buf[320];
#endif
  serialWrB('R');
  serialWrB('D');
  serialWrB('Y');
  //StringPgm(PSTR("RDY"));
  //Wait for vsync it is on pin 3 (counting from 0) portD
  while(!(PINE&32));//wait for high
  while((PINE&32));//wait for low
#ifdef useVga
  while(hg--){
    lg2=wg;
    while(lg2--){
      while((PINE&16));//wait for low
      UDR0=PINC;
      while(!(PINE&16));//wait for high
    }
  }
#elif defined(useQvga)
  /*We send half of the line while reading then half later */
  while(hg--){
    uint8_t*b=buf,*b2=buf;
    lg2=wg/2;
    while(lg2--){
      while((PINE&16));//wait for low
      *b++=PINC;
      while(!(PINE&16));//wait for high
      while((PINE&16));//wait for low
      *b++=PINC;
      UDR0=*b2++;
      while(!(PINE&16));//wait for high
    }
    /* Finish sending the remainder during blanking */
    lg2=wg/2;
    while(!( UCSR0A & (1<<UDRE0)));//wait for byte to transmit
    while(lg2--){
      UDR0=*b2++;
      while(!( UCSR0A & (1<<UDRE0)));//wait for byte to transmit
    }
  }
#else
  /* This code is very similar to qvga sending code except we have even more blanking time to take advantage of */
  while(hg--){
    uint8_t*b=buf,*b2=buf;
    lg2=wg/5;
    while(lg2--){
      while((PINE&16));//wait for low
      *b++=PINC;
      while(!(PINE&16));//wait for high
      while((PINE&16));//wait for low
      *b++=PINC;
      while(!(PINE&16));//wait for high
      while((PINE&16));//wait for low
      *b++=PINC;
      while(!(PINE&16));//wait for high
      while((PINE&16));//wait for low
      *b++=PINC;
      while(!(PINE&16));//wait for high
      while((PINE&16));//wait for low
      *b++=PINC;
      UDR0=*b2++;
      while(!(PINE&16));//wait for high
    }
    /* Finish sending the remainder during blanking */
    lg2=320-(wg/5);
    while(!( UCSR0A & (1<<UDRE0)));//wait for byte to transmit
    while(lg2--){
      UDR0=*b2++;
      while(!( UCSR0A & (1<<UDRE0)));//wait for byte to transmit
    }
  }
#endif
}

void setup() {

  //cli();
  DDRL|=8;
  ASSR &= (uint8_t)~(_BV(EXCLK) | _BV(AS2));
  //generate 8mhz clock
  TCCR5A=67;
  TCCR5B=17;
  DDRC=0;//set ov7670 pins to input
  
  OCR5A=0;
  DDRC=0;
  //DDRG|=1<<5;
  UBRR0H=0;
  UCSR0A|=2;//double speed aysnc
  UBRR0L=1;//0 = 2m 1= 1m 3 = 0.5M 2M baud rate = 0 7 = 250k 207 is 9600 baud rate
  UCSR0B = (1<<RXEN0)|(1<<TXEN0);//Enable receiver and transmitter
  UCSR0C=6;//async 1 stop bit 8bit char no parity bits
  ADCSRA=(1<<ADEN)|(1<<ADPS2);//enable ADC
  sei();
  TWSR&=(uint8_t)~3;//disable prescaler for TWI
  TWBR=72;//set to 100khz

  camInit();
#ifdef useVga
  setRes(VGA);
  setColorSpace(BAYER_RGB);
  wrReg(0x11,25);
#elif defined(useQvga)
  setRes(QVGA);
  setColorSpace(YUV422);
  wrReg(0x11,12);
#else
  setRes(QQVGA);
  setColorSpace(YUV422);
  wrReg(0x11,3);
#endif

  //serialWrB('T');
  captureImg(640,480);
  //uart_putchar('A');
  //initCam(0);    
  //setColor(BAYER_RGB);
  //setRes(VGA);
  //uart_putchar('B');
  //captureImg(320, 240);
}

void loop() {

  captureImg(640,480);
  //captureImg(320, 240);
}

Schematic model ov7670 - arduino mega,

PINS D0-D7 => D37 - D30
VYSNC - PIN 3
PCLK - PIN 2
SCIOC - PIN 21
SCIOD - PIN 20
HCLK - PIN D46 (Used two resistors 4.7 K)
RESET - VCC
PWDN - 3.3V
HREF - Not connected

change wrReg(0x11,3); to wrReg(0x11,12);