CCD interfacing problem

I’ve got a CCD (UPD3799CY, http://www.alldatasheet.com/datasheet-pdf/pdf/6939/NEC/UPD3799CY.html) wired up to my Duemilanove-based robot rover thing and need a bit of help with my driver.

It seems to almost work, except that I seem to be repeatedly getting the value from pixel 1 rather than moving across to pixel 5300*. I know this because shining a flashlight near pixel 1 gives me light even when reading from the other end, but shining on pixel 5300 never returns light. All the digital pins are set to output mode. This is the relevant code:

#define CCD_RED_INPUT 0
#define CCD_GREEN_INPUT 1
#define CCD_BLUE_INPUT 2
#define CCD_SHIFT_CLOCK_1 12
#define CCD_SHIFT_CLOCK_2 6
#define CCD_TG_CLOCK_RED 9
#define CCD_TG_CLOCK_GREEN 10
#define CCD_TG_CLOCK_BLUE 11
#define CCD_RESET_CLOCK 7
#define CCD_REAL_RESOLUTION 5300

typedef struct { int red, green, blue; } pixel;
pixel optical_black;

void ccd_skip(int n)
{
  for (int i = 0; i < n; i++)
  {
    digitalWrite(CCD_RESET_CLOCK, LOW);
    digitalWrite(CCD_SHIFT_CLOCK_1, HIGH);
    digitalWrite(CCD_SHIFT_CLOCK_2, LOW);
    delayMicroseconds(1);
    digitalWrite(CCD_RESET_CLOCK, HIGH);
    delayMicroseconds(1);
    digitalWrite(CCD_SHIFT_CLOCK_1, LOW);
    digitalWrite(CCD_SHIFT_CLOCK_2, HIGH);
    delayMicroseconds(1);
  }
}

void ccd_read(pixel& rv)
{
  
  digitalWrite(CCD_SHIFT_CLOCK_1, HIGH);
  digitalWrite(CCD_SHIFT_CLOCK_2, LOW);
  digitalWrite(CCD_RESET_CLOCK, LOW);
  delayMicroseconds(1);
  digitalWrite(CCD_RESET_CLOCK, HIGH);
  delayMicroseconds(1);
  digitalWrite(CCD_SHIFT_CLOCK_1, LOW);
  digitalWrite(CCD_SHIFT_CLOCK_2, HIGH);
  delayMicroseconds(2);

  rv.red = max(0, analogRead(CCD_RED_INPUT) - optical_black.red);
  rv.green = max(0, analogRead(CCD_GREEN_INPUT) - optical_black.green);
  rv.blue = max(0, analogRead(CCD_BLUE_INPUT) - optical_black.blue);
  
  digitalWrite(CCD_RESET_CLOCK, HIGH);
  delayMicroseconds(1);

  digitalWrite(CCD_SHIFT_CLOCK_1, LOW);
  digitalWrite(CCD_SHIFT_CLOCK_2, HIGH);
  delayMicroseconds(1);
}

void ccd_read_row()
{
  // reset the CCD
  digitalWrite(CCD_SHIFT_CLOCK_1, HIGH);
  digitalWrite(CCD_SHIFT_CLOCK_2, LOW);
  delayMicroseconds(1);
  digitalWrite(CCD_TG_CLOCK_RED, HIGH);
  digitalWrite(CCD_TG_CLOCK_GREEN, HIGH);
  digitalWrite(CCD_TG_CLOCK_BLUE, HIGH);
  for (int i = 0; i < 5; i++)
  {
    digitalWrite(CCD_RESET_CLOCK, HIGH);
    delayMicroseconds(1);
    digitalWrite(CCD_RESET_CLOCK, LOW);
    delayMicroseconds(1);
  }
  digitalWrite(CCD_TG_CLOCK_RED, LOW);
  digitalWrite(CCD_TG_CLOCK_GREEN, LOW);
  digitalWrite(CCD_TG_CLOCK_BLUE, LOW);
  delayMicroseconds(1);
  digitalWrite(CCD_SHIFT_CLOCK_1, LOW);
  digitalWrite(CCD_SHIFT_CLOCK_2, HIGH);
  Serial.println("CCD reset, starting read");

  ccd_skip(31);

  // get optical black
  // FIXME are all the OB pixels identical? if not average them or something.
  optical_black = {0, 0, 0};
  ccd_read(optical_black);

  Serial.print("Optical black is ");
  Serial.print(optical_black.red);
  Serial.print(" ");
  Serial.print(optical_black.green);
  Serial.print(" ");
  Serial.print(optical_black.blue);
  Serial.print("\n");

  // skip over more invalid pixels
  ccd_skip(32);
  
  // read in the pixels
  pixel p;
  for (int i = 0; i < CCD_REAL_RESOLUTION; i++)
  {
    ccd_read(p);
    
    Serial.print(i);
    Serial.print(" ");
    Serial.print(p.red);
    Serial.print(" ");
    Serial.print(p.green);
    Serial.print(" ");
    Serial.print(p.blue);
    Serial.print("\n");
  }
}
  • Yes, I know 5300 pixels won’t fit in the Arduino’s memory - the plan, once I get this bug out of the way, is to average pixels together while reading to create a lower-resolution image that will fit.