Arduino Mega and Image Sensor, please help

Hello guys,
I am trying to interface a Arduino mega with a video sensor OV6620

The arduino mega talks to the sensor via a modified version of I2C and download images via the Y channel. I got to a point where I2C is good. Sensor is now configured to send to the Arduino about 1 image (176X144) per second with a clock of about 69 KHz. I implemented the frame synch, line synch and image clock synch with 3 interrupts. Maybe wasnt a wise choice but that’s what I could do.
code is:

/*
image_read

this program works for the Arduino Mega board connected to the C3088 camera module.
the program pulls images from the CCD sensor using port Y(0-7)
Arduino Mega and C3088 connections:

Arduino Mega Board:
pin 22 ->
pin 23 -> (C3088 pin31)
pin 24 -> 
pin 25 -> 
pin 26 -> 
pin 27 -> 
pin 28 -> 
pin 29 -> 
pin 30 -> 
pin 31 -> 
pin 32 -> (C3088 pin22)
pin 33 -> (C3088 pin21)
pin 34 -> (C3088 pin20)
pin 35 -> 
pin 36 -> (C3088 pin18) PCLK
pin 37 -> 
pin 38 -> (C3088 pin16) VSYNC
pin 39 -> (C3088 pin15)
pin 40 -> (C3088 pin14) HREF
pin 41 -> (C3088 pin13) SLC(I2C)
pin 42 -> 
pin 43 -> (C3088 pin11) SDA(I2C)
pin 44 -> (C3088 pin10) RST
pin 45 -> (C3088) pin9 PWDN
pin 46 -> Y7 (C3088 pin8)
pin 47 -> Y6 (C3088 pin7)
pin 48 -> Y5 (C3088 pin6)
pin 49 -> Y4 (C3088 pin5)
pin 50 -> Y3 (C3088 pin4)
pin 51 -> Y2 (C3088 pin3)
pin 52 -> Y1 (C3088 pin2)
pin 53 -> Y0 (C3088 pin1)


C3088 Board:
pin 20,22 -> Vcc(+5V)
pin 31,21,15 -> GND
pin 11 SDA(I2C)
pin 13 SLC(I2C)
pin 1,2,3,4,5,6,7,8 Ychannel(output)
pin 14 HREF (output)
pin 16 VSYNC    (output)
pin 18 PCLK (output)
pin 10 RST (input)
pin 9 PWDN (input)
*/

// #### DEFINITIONS ####

// system clock
#define SYSCLK 16

// CCD sensor control pins
#define HREF 40
#define VSYNC 38
#define PCLK 36
#define RST 44
#define PWDN 45

// CCD sensor power pins
#define VCC_A 32
#define VCC_B 34
#define GND_A 23
#define GND_B 33
#define GND_C 39

#define LED 13

// i2c registers used to talk to the ccd sensor

#define CCD_COM_A 0x12 // address register A
#define CCD_RESET  0x80 // reset command
#define CCD_CLKRC 0x11 // address for clock register
#define CCD_FRQ 0x10 // frequency command
#define CCD_COM_C 0x14 // address register A
#define CCD_QCIF  0x20 // reset command

// maybe not necessary
#define camAddRead 193
#define camAddWrite 192

#define camRegClock 0x11
#define camRegControlA 0x12
#define camRegControlC 0x14

#define camDatReset 0x80
#define camDatbarras 0x26
#define camDatEspejo 0x40
#define camDatEspejoNo 0xBF

#define camDatFrecVeryLo 0x3F  // very low frame rate, PCLK=69KHz, about 1 frame every 1.2 s
#define camDatFrecLo 0x10    // low frame rate
#define camDatFrecMed 0x01   // medium frame rate
#define camDatFrecUp 0x00    // high frame rate

#define camDatQCIF 0x20    // define size image
                           // QCIF 176x144
                           // CIF  352x292

#ifndef UCSRB
# ifdef UCSR1A          /* ATmega128 */
#  define UCSRA UCSR1A
#  define UCSRB UCSR1B
#  define UBRR UBRR1L
#  define UDR UDR1
# else /* ATmega8 */
#  define UCSRA USR
#  define UCSRB UCR
# endif
#endif
#ifndef UBRR
#  define UBRR UBRRL
#endif
#define TWI_SLA_CAM   0xc0  //Cam C0    sensor 90
#define MAX_ITER        200
#define PAGE_SIZE       8 // before 8


// #### local variables ####
int ind=0;
volatile byte ccd_pixel=B00000000;
//volatile byte ccd_frame[3000]={0};
volatile byte ccd_line[145]={0};


// #### external libraries ####
// avr lib reference: http://www.nongnu.org/avr-libc/user-manual/modules.html
#include <avr/io.h>
#include <util/twi.h>
#include <inttypes.h>
#include <Wire.h>  // not used

// ISR interrupt service routine
#include <avr/interrupt.h>


// #### variables for interrup routines ####
volatile boolean begin_frame = false;
volatile boolean begin_line = false;
volatile boolean full_line_flag = false;
volatile int pixel_position = 0;


// #### SETUP ####
void setup(){

  Serial.begin(115200);    // start serial port
  reset();                 // reset the CCD sensor  
  i2c_init(SYSCLK);        // initialize the i2c
 
  
  Serial.print("Reset the CCD sensor - (1=good, -1=bad): ");
  Serial.print(write_register(0x12, 0x80));    //reset the ccd sensor
  Serial.print(", ");
  delay(1000);
  Serial.print(write_register(0x11, camDatFrecVeryLo));    //set the ccd sensor frame rate to very low PCLK=69KHz
  Serial.print(", ");
  delay(1000);
  Serial.print(write_register(0x14, camDatQCIF));  //set the ccd sensor image size to QCIF (equivalent to 176x144)
  //Serial.print(", ");
  //delay(300);
  //Serial.print(write_register(0x12, 0x26));  //set the ccd sensor color bar test pattern
  delay(2000);
  Serial.println(". done !");
  
  // initialize the interrupts for port PWM3, COM18, COM19
  //
  // PWM3  => INT5  => VSYN
  // COM18 => INT3  => HREF
  // COM19 => INT2  => PCLK
  
  EICRA = 0xF0; //11110000 //RISING edge of COM18(INT3) and RISING edge of COM19(INT2) 
  EICRB = 0x08; //00001000 //FALLING edge of PWM3(INT5)
  SREG = 1; //s-reg I flag
  EIMSK = 0x2C; //00101100 set pin PWM3(INT5) , COM18(INT3), COM19(INT2) (Arduino Mega Board) for interrupt
  sei();
  
  Serial.println("begin processing...");
}

the rest comes in hte next post…

rest of the code:

// #### LOOP ####
void loop(){
  while (full_line_flag){  // full 144-pixel line available
    EIMSK = 0x00; // 00000000 disable all interrupts
    pixel_position=0;
    begin_line=false;
    for (int i = 0; i <= 143; i++){
      Serial.print(ccd_line[i], DEC);
      Serial.print(",");
     }
     Serial.println();
  }
  delay(300);
  EIMSK = 0x2C; // enable all 3 interrupts
}


// #### Interrupt pin PWM3 ####
// this is the VSYN interrupt
ISR(INT5_vect){
  EIMSK = 0x00; // 00000000 disable all interrupts
  //Serial.println("begin frame");
  begin_frame = true;
  pixel_position=0;
  EIMSK = 0x2C; // enable all 3 interrupts
}


// #### Interrupt pin COM18 ####
// this is the HREF interrupt
ISR(INT3_vect){
    EIMSK = 0x00; // 00000000 disable all interrupts
    //Serial.println("begin line");
    begin_line=true;
    pixel_position = 0;  // begin of a line
    EIMSK = 0x2C; // enable all 3 interrupts
}


// #### Interrupt pin COM19 ####
// this is the PCLK interrupt
ISR(INT2_vect){
  EIMSK = 0x00; // 00000000 disable all interrupts
  //Serial.println("begin of a pixel");
  if (begin_frame && begin_line && pixel_position<=143){
    ccd_line[pixel_position] = read_ccd_pixel();  //get one pixel
    pixel_position++;
  }
  else
    pixel_position=0;
  EIMSK = 0x2C; // enable all 3 interrupts
  if (pixel_position ==144){  // full 144-pixel line available
    EIMSK = 0x00; // 00000000 disable all interrupts
    full_line_flag = true;
  }
}



// #### READ CCD PIXEL  ####
byte read_ccd_pixel(void){
  byte ccd_pixel = 0;
  byte bit = 0; 
  // READ ONE PIXEL Y[0-7], pin53-pin46
   for (int i = 7; i >= 0; i--) {
     bit = digitalRead(46+i);
     ccd_pixel |= (bit << i);
   }
  return ccd_pixel;
}


// #### INIZIALIZE CCD SENSOR ####
void ccd_ini() {
// initializaiton implemnted with library WIRE.H... but finally not used
//    Wire.begin(); // initialize the i2c port
//    Wire.beginTransmission(CCD_COM_A); // start i2c cycle
//    Wire.send(CCD_RESET);  // reset the ccd sensor
//    Wire.endTransmission(); // ends i2c cycle
//    delay(1000);
    
//    Wire.beginTransmission(CCD_CLKRC); // start i2c cycle
//    Wire.send(CCD_FRQ); // set the frequency to 69.25KHz
//    Wire.endTransmission(); // ends i2c cycle

//    Wire.beginTransmission(CCD_COM_C); // start i2c cycle
//    Wire.send(CCD_QCIF); // set the CCD frame resolution to 176X144
//    Wire.endTransmission(); // ends i2c cycle    

//    Wire.beginTransmission(CCD_COM_A); // start i2c cycle
//    Wire.send(0x26); // enable the CCD color frame
//    Wire.endTransmission(); // ends i2c cycle      
    delay(200);
}


// #### RESET ####
void reset() {
  int i=0;
  
  //set pin22~53 to high impedence
  for(int i = 22;i<=53;i++) pinMode(i, INPUT);
  for(int i = 22;i<=45;i++) digitalWrite(i, HIGH); // set all pins (except Y0~7) to high impedence
  for(int i = 46;i<=53;i++) digitalWrite(i, HIGH); // set pins Y0~7 to high impedence
  
  pinMode(HREF, INPUT);
  pinMode(VSYNC, INPUT);
  pinMode(PCLK, INPUT);
  pinMode(RST, OUTPUT);
  pinMode(PWDN, OUTPUT);
  
  // some interrupt pins, set them as imput and put a pullup resistor
  for(int i = 14;i<=19;i++) pinMode(i, INPUT);
  for(int i = 14;i<=19;i++) digitalWrite(i, HIGH);
  for(int i = 2;i<=13;i++) pinMode(i, INPUT);
  for(int i = 2;i<=13;i++) digitalWrite(i, HIGH);  
  
  //let's power up the CCD sensor
  pinMode(VCC_A, OUTPUT);
  pinMode(VCC_B, OUTPUT);  
  pinMode(GND_A, OUTPUT);
  pinMode(GND_B, OUTPUT);
  pinMode(GND_C, OUTPUT);
  
  digitalWrite(VCC_A, HIGH);
  digitalWrite(VCC_B, HIGH);
  digitalWrite(GND_A, LOW);
  digitalWrite(GND_B, LOW);
  digitalWrite(GND_C, LOW);

  digitalWrite(PWDN, LOW);
  delay(100);  
  
  //let's reset the CCD sensor
  digitalWrite(RST, HIGH);
  delay(300);
  digitalWrite(RST, LOW);
  
}


// #### i2c write page ####
// this function was originaly written by Joerg Wunsch 2002/12/18 joerg@FreeBSD.ORG
// modified by Jaakko Ala-Paavola 2003/08/20 jap@iki.fi
// modified by Ioaki Navarro Oiza March 2004

int i2c_write_page(uint16_t eeaddr, int len, uint8_t *buf){
  uint8_t sla, n = 0;
  int rv = 0;
  uint16_t endaddr;
  if (eeaddr + len < (eeaddr | (PAGE_SIZE - 1)))
    endaddr = eeaddr + len;
  else
    endaddr = (eeaddr | (PAGE_SIZE - 1)) + 1;
  len = endaddr - eeaddr;
  /* patch high bits of EEPROM address into SLA */
  sla = TWI_SLA_CAM | (((eeaddr >> 8) & 0x07) << 1);
  restart:
  if (n++ >= MAX_ITER)
    return -1;
  begin:
  /* Note 13 */
  TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); /* send start condition */
  while ((TWCR & _BV(TWINT)) == 0) ; /* wait for transmission */
  switch ((TW_STATUS))
    {
    case TW_REP_START:          /* OK, but should not happen */
    case TW_START:
      break;
    case TW_MT_ARB_LOST:
      goto begin;
    default:
      return -1;                /* error: not in start condition */
                                /* NB: do /not/ send stop condition */
    }
  /* send SLA+W */
  TWDR = sla | TW_WRITE;
  TWCR = _BV(TWINT) | _BV(TWEN); /* clear interrupt to start transmission */
  while ((TWCR & _BV(TWINT)) == 0) ; /* wait for transmission */
  switch ((TW_STATUS))
    {
    case TW_MT_SLA_ACK:
      break;
    case TW_MT_SLA_NACK:        /* nack during select: device busy writing */
      goto restart;
    case TW_MT_ARB_LOST:        /* re-arbitrate */
      goto begin;
    default:
      goto error;               /* must send stop condition */
    }
  TWDR = eeaddr;                /* low 8 bits of addr */
  TWCR = _BV(TWINT) | _BV(TWEN); /* clear interrupt to start transmission */
  while ((TWCR & _BV(TWINT)) == 0) ; /* wait for transmission */
  switch ((TW_STATUS))
    {
    case TW_MT_DATA_ACK:
      break;
    case TW_MT_DATA_NACK:
      goto quit;
    case TW_MT_ARB_LOST:
      goto begin;
    default:
      goto error;               /* must send stop condition */
    }
  for (; len > 0; len--)
    {
      TWDR = *buf++;
      TWCR = _BV(TWINT) | _BV(TWEN); /* start transmission */
      while ((TWCR & _BV(TWINT)) == 0) ; /* wait for transmission */
      switch ((TW_STATUS))
        {
        case TW_MT_DATA_NACK:
          goto error;           /* device write protected -- Note [14] */
        case TW_MT_DATA_ACK:
          rv++;
          break;
        default:
          goto error;
        }
    }
  quit:
  TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); /* send stop condition */

  return rv;
  error:
  rv = -1;
  goto quit;
}


// #### i2c write bytes ####
// this function was originaly written by Joerg Wunsch 2002/12/18 <joerg@FreeBSD.ORG
// modified by Jaakko Ala-Paavola 2003/08/20 jap@iki.fi
// modified by Ioaki Navarro Oiza March 2004

int i2c_write_bytes(uint16_t eeaddr, int len, uint8_t *buf){
  int rv, total;
  total = 0;
  do{
      rv = i2c_write_page(eeaddr, len, buf);
      if (rv == -1)
        return -1;
      eeaddr += rv;
      len -= rv;
      buf += rv;
      total += rv;
    }
  while (len > 0);
  return total;
}


// #### write register ####
// this function was originaly written by Joerg Wunsch 2002/12/18 <joerg@FreeBSD.ORG
// modified by Jaakko Ala-Paavola 2003/08/20 jap@iki.fi
// modified by Ioaki Navarro Oiza March 2004

int write_register(uint16_t numregister, uint8_t value){
  uint8_t *pvalue;
  int num;
  pvalue = &value;
  num = i2c_write_bytes(numregister, 1, pvalue);
  if(num!=1) return -1;
  else return 1;
}


// #### write register ####
// this function was originaly written by Joerg Wunsch 2002/12/18 <joerg@FreeBSD.ORG
// modified by Jaakko Ala-Paavola 2003/08/20 jap@iki.fi
// modified by Ioaki Navarro Oiza March 2004
void i2c_init(int clk){
  /* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */
#if defined(TWPS0)
  /* has prescaler (mega128 & newer) */
  TWSR = 0;
#endif
  TWBR = (clk*1000000 / 100000UL - 16) / 2;
}

this is the output I get from the serial

Reset the CCD sensor - (1=good, -1=bad): 1, 1, 1. done !
begin processing…
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,10,158,134,90,58,246,
84,116,52,244,180,196,252,244,148,20,140,84,116,12,76,196,68,76,188,212,172,172,44,44,84,124,76,204,68,116,140,12,20,172,204,116,12,140,76,76,12,196,108,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,10,158,134,90,58,246,
84,…

it looks not very right…could somebody please advise on how to properly write the function:
byte read_ccd_pixel(void)

which pools data from Y[0-8]. I am not sure what I wrote is good…

Plus, is there something else wrong with the code? the I2C part seems ok but I am a little unsure about how I use interrupts and flags, is it good to turn them on and off with EIMSK = 0x00; ?

Any advise on how to improuve the code is highly appreciate? I am spending lots of time on this and learning a lot out of it but now I am kind of stacked…

thanks a lot
fabrizio

I am not sure what you are trying to do is possible. Many people have asked about this sort of thing and no one has ever done it (for good reason).

From what I can gather you want to read 176 X 144 = 25200 bytes per second, that means you have 40uS per byte to read in. Also it means you have 25K of data to store for a frame and there is only 8K of SRAM in the mega.

The code posted will print out a line, which will take an age and so the next line you print out will not be even close to the first line.

How are you synchronising your reads? What schematic / wiring are you using?

As to the specific question about writing the function byte read_ccd_pixel(void), you need to use direct port access and reduce the entire routine to just a single instruction.

Mike you answered Vincent_ch's question in this thread:http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1247060702/8#8

Vincent_ch, you have lots of threads with questions on your project, I suggest that you stick to just one thread so people don't waste their time on things that have already been addressed.

sorry, I will be more careful in the future.

Mike, I am aware that I am doing something that might not be possible.
Could you please give me an example of direct port access. Is this what you mean?

ccd_line[pixel_position] = ( (PINL & 0x0f) << 4) | ( (PINB & 0x0f) );
pixel_position++;

thank you
fab.

Yes, that's direct port access (two, actually), but I don't understand why you don't put this all on a single port. It is the most time-critical operation, so you should try as hard as possible to get all the data on a single port.

I will be more careful in the future.

Fab, no reason why you can't start now ;)

Pick one of the threads to continue the discussion and add a post in the other threads pointing to that thread as the place to respond. The discussion here is related to the thread I linked above and its also related to the other thread where it was suggested that you probably don't have enough time to process the data.

It really is much more polite if you now continue this topic in just one place