Arduino Forum

Using Arduino => Project Guidance => Topic started by: Bumpasticka77 on Dec 11, 2012, 11:21 am

Title: Controlling an ILX511 Linear CCD Sensor
Post by: Bumpasticka77 on Dec 11, 2012, 11:21 am
I'm attempting to control a linear CCD sensor using an Arduino Uno.  The sensor is a Sony ILX511.  The datasheet can be found here: (http://www.oceanoptics.com/technical/detectorsonyILX511.pdf).  The sensor requires a clock pulse and a gate pulse.  If I understand correctly from the datasheet, the gate pulse is HIGH (5V) while the clock pulse creates square waves to tell the sensor to shift along the pixels in the array. When the gate pulse goes from HIGH to LOW and back to HIGH it tells the sensor to restart.  I've finally come out with code that will create the proper pulses, with clock pulses having a 50% duty cycle.  I've tested the pulses by plotting in Labview and watching LEDs light up.  There is no maximum time in between clock pulses, so I've tried running the code at slow paces and at fast paces and still come out with the same problem.  The problem is that the sensor does not shift pixels in the array, and instead it remains on the first pixel.  I'm able to see this because output voltages only change when I shine light on the first pixel.

So, has anyone had any experience with running a CCD sensor with the arduino?  I don't see why it wouldn't be possible because the datasheet states that there are no maximum times in between clock pulses.  I've wired up the sensor exactly how the datasheet shows on page 10.  Any advice would be great.

I also suspected that voltage output by the arduino might be the case, so I tried with a 9V battery connected to the arduino and still the same problem.

Here is my code:

Code: [Select]
int CLKPin = 3;
int ROGPin = 5;
float pulsetimer = 0;
float counter = 0;


void setup() {
  DDRD = B00101000;  //Pins 3 and 5 as outputs
  Serial.begin(115200);
}

void loop() {
  pulsetimer = pulsetimer + 1;
  counter = counter + 1;
  Pulses();
  pulseRead();
  delay(15);
}

void pulseRead() {
  static float timer; //currently not used
  long PhotoRead;
  timer = (timer + 1); //currently not used
  PhotoRead = analogRead(0);
  //Serial.print("YELLOW = ");
  Serial.println(PhotoRead);
  //Serial.print(",");
  //Serial.print("RED = ");
  //Serial.print(redRead);
  //Serial.print(",");
  //Serial.print("Time = ");
  //Serial.print(timer);
  //Serial.print(",");
  //Serial.print("Pulsetimer = ");
  //Serial.println(pulsetimer);
  //Serial.print(",");
  //Serial.print("Counter = ");
  //Serial.print(counter);
  //Serial.print(",");
  //Serial.flush();
}

void Pulses() {
  int CLKState;
  CLKState = digitalRead(CLKPin);
  if(pulsetimer <= 30) {
    PORTD = B00001000;  //ROG - Low, CLK - High
    counter = 0;
  }
  else if(pulsetimer > 30 && pulsetimer < 35) {
    PORTD = B00101000; //ROG - High, CLK - High
    counter = 0;
  }
  else if(pulsetimer >= 35 && pulsetimer <= 12563) {
    if(counter == 3) { //Change CLK state every 3 iterations
      if(CLKState == HIGH) { //If CLK = HIGH set to low
                             //and vice versa
        PORTD = B00100000; //ROG - High, CLK - Low
        counter = 0;
      }
      else {
        PORTD = B00101000; //ROG - High, CLK - High
        counter = 0;
      }
    }
  }
  else if (pulsetimer > 12563 && pulsetimer < 12568) {
    PORTD = B00101000; //ROG - High, CLK - High
  }
  else if(pulsetimer == 12568) {
  pulsetimer = 0; //Restart
  PORTD = B00101000; //ROG - High, CLK - High
  counter = -1;
        }
    }
Title: Re: Controlling an ILX511 Linear CCD Sensor
Post by: ralphnev on Dec 11, 2012, 01:18 pm
what have you set to the SHSW pin ? grd or vcc ?

I'm starting down a project using a uPD3799 & Due,
similar except 5000 pixels & i want to run at 1Msps .. 
Title: Re: Controlling an ILX511 Linear CCD Sensor
Post by: AWOL on Dec 11, 2012, 01:54 pm
Code: [Select]
float pulsetimer = 0;
Are you figuring on having fractional pulses?

Code: [Select]
CLKState = digitalRead(CLKPin);
You've made it an output, yet you're reading it.
Title: Re: Controlling an ILX511 Linear CCD Sensor
Post by: Bumpasticka77 on Dec 11, 2012, 06:15 pm
Thanks for the replies.

ralphnev,
I'm using the SHSW mode (set to grd).  It gives a smoother plot of data points compared to not using it, which outputs waves of different amplitudes.  Although, if I actually got the sensor to change pixels, not using the SHSW mode may be useful in distinguishing what pixel gave what reading because the output gives a constant voltage when clock pulses are LOW and then outputs the reading of the next pixel in line when the clock pulse is HIGH.  This way, you can see the shifting from pixel to pixel.  Keep me posted on your progress.

AWOL,
Right now, I'm not using fractional pulses.  Would I gain anything from this other than not having to count to as high as 12568?
Also, digitalReading an output pin will still return the state it is in. 
Title: Re: Controlling an ILX511 Linear CCD Sensor
Post by: HazardsMind on Dec 11, 2012, 06:25 pm
Why isn't the CLKPin set in the setup() as pinMode(CLKPin, INPUT) or pinMode(CLKPin, OUTPUT)?

Title: Re: Controlling an ILX511 Linear CCD Sensor
Post by: AWOL on Dec 11, 2012, 06:28 pm
Quote
Also, digitalReading an output pin will still return the state it is in.

But you wrote the state it is in!
Title: Re: Controlling an ILX511 Linear CCD Sensor
Post by: HazardsMind on Dec 11, 2012, 06:38 pm
This is not the FULL code is it?
Title: Re: Controlling an ILX511 Linear CCD Sensor
Post by: HazardsMind on Dec 11, 2012, 08:01 pm
Quote
DDRD = B00101000;  //Pins 3 and 5 as outputs

Nevermind my previous post
Quote
Why isn't the CLKPin set in the setup() as pinMode(CLKPin, INPUT) or pinMode(CLKPin, OUTPUT)?


I didn't know "B00101000" was possible to do with arduino.
Title: Re: Controlling an ILX511 Linear CCD Sensor
Post by: Bumpasticka77 on Dec 11, 2012, 08:04 pm
I appreciate ya'll checking my code

AWOL,
I realize that I'm writing what state it is in.  The point of reading it is to check the state and set it to the opposite state.  If it's high, set to low.  If it's low, set to high.

HazardsMind,
And yes this is the full code.  I tried keeping it simple since I'm reading and writing so often, and it is imperative that the clock pulses remain consistent.

I'm looking for advice on generating square wave pulses with a constant frequency and duty cycle, and reading the outputs of a sensor in between the pulses.  Or suggestions if anyone has interfaced a CCD sensor with arduino.
Title: Re: Controlling an ILX511 Linear CCD Sensor
Post by: Riva on Apr 20, 2013, 06:25 pm
Did you get anywhere with your project?
I have started to mess about with an ILX511 but found it started to get warm at one end when grounding pin 4 to do S/H mode so stuck with pin 4 to VCC. What circuit did you use for S/H mode?
Below is some code I just wrote to test (for non S/H mode) but have not tried plotting it's results yet to know if it works.
As the UNO does not have enough memory to read the entire CCD I sample every other pixel and right shift the result 2 places to fit result into a byte.

Code: [Select]
#define CLK 5
#define ROG 11
#define LED 13
#define CLKSPEED 50

#define FASTADC 1
// defines for setting and clearing register bits
#ifndef cbi
  #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
  #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

byte sampleArray[1044];
unsigned long sampleTime;

void setup() {
  Serial.begin(115200);
  #if FASTADC
    // set prescale to 16
    sbi(ADCSRA,ADPS2) ;
    cbi(ADCSRA,ADPS1) ;
    cbi(ADCSRA,ADPS0) ;
  #endif
 
  pinMode(ROG,OUTPUT);
  digitalWrite(ROG,HIGH);
  pinMode(CLK,OUTPUT);
  digitalWrite(CLK,LOW);
  pinMode(LED,OUTPUT);
  delay(1000);
}

void loop() {
  digitalWrite(LED,HIGH);
  digitalWrite(CLK,HIGH);
  delayMicroseconds(500);
  digitalWrite(ROG,LOW);
  delayMicroseconds(1000);
  digitalWrite(ROG,HIGH);
  delayMicroseconds(500);
  for( int x = 0; x < 2088; x++){
    digitalWrite(CLK,LOW);
   
    sampleTime = micros();
    while ((sampleTime + CLKSPEED) > micros()){
    }
    digitalWrite(CLK,HIGH);
   
    sampleTime = micros();
    if (x & 1) {
      int y = analogRead(A0);
      sampleArray[x >> 1] = y >> 2;
    }
    while ((sampleTime + CLKSPEED) > micros()){
    }
  }
  digitalWrite(CLK,LOW);
  digitalWrite(LED,LOW);
  delay(100);
 
}
Title: Re: Controlling an ILX511 Linear CCD Sensor
Post by: Bumpasticka77 on May 30, 2013, 07:29 pm
Hi Riva,

I never got past being able to read only the first pixel.  I even checked the logic with an analyzer and still didn't get an entire array of pixel data.  The circuit I was using was the one directly from the datasheet for the sensor.  I used an arduino with the sensor and collected data with an external data acquisition device I had lying around at work using Labview.  Were you actually able to receive data from the whole array of pixels?  If so, what did your circuit look like?  Were the CLK and ROG pins on the sensor connected directly to the arduino, or did you have additional circuitry in between?  I might have to come back to this project now haha.
Title: Re: Controlling an ILX511 Linear CCD Sensor
Post by: Riva on May 31, 2013, 10:39 am
No luck yet reading the entire pixel data. Like you I only seem to have the first pixel as the level raises/lowers when I cover only one end of the array.
I'm not even reading the dummy pixels or the optical black before the first actual pixel so suspect I'm not close yet.
After the array heating up I discovered a poor ground was to fault and though I may have fried the CCD but trying a new CCD gave the same results.
I still have a few ideas to try but am beginning to wonder if the arduino UNO & MEGA are maybe to slow at clocking & reading the device. The datasheet does not give upper limits on most signal timings but there is a large difference between something like 3000ns and 20us that is as fast as I can analogue sample the data using arduino.
I will let you know if I manage to get it working.
Title: Re: Controlling an ILX511 Linear CCD Sensor
Post by: Riva on Jun 02, 2013, 04:22 pm
In my tweaks & tests today I noticed that even if I disconnect ROG & CLK lines from the arduino I still get the same (first pixel) waveform as with them connected so they seem to have no effect.
Maybe CLK is not running quick enough though I cannot go much faster as it takes 24uS to analogue sample and store a pixel and with CLK running at 64uS PP I only have 8uS overhead when sampling.
Title: Re: Controlling an ILX511 Linear CCD Sensor
Post by: Riva on Jun 15, 2013, 06:02 pm
Hi Bumpasticka,

I laid out the hardware again as the old board was a bodge and also used a faster transistor for amplifying Vout and I am starting to get something now. The CCD is very sensitive to light so after applying an electrical tape mask and working in a dim room I managed to get an output.
First is covering the entire CCD with my finger and as expected the trace is flat but I am getting the dummy pixels before and maybe after (harder to see) the effective pixels.
The second picture is with my finger hovering over the middle of the CCD. It's not as good as expected as I think the setup is in need of a lens to focus light and mask off stray ambient light.
Title: Re: Controlling an ILX511 Linear CCD Sensor
Post by: dmzz on Feb 16, 2014, 02:29 pm
Hi guys,

perhaps you have a huge progress already on interfacing  ILX511 with Arduino.
Could you please post some complete wiring scheme and sample code for basic reading from the sensor. 
I'm complete nub, so will be thankful for any details here or on the WIKI.
Title: Re: Controlling an ILX511 Linear CCD Sensor
Post by: mdma on Apr 01, 2014, 05:43 am
This might be a silly question, but do you have to use a transistor to amplify the Vout? Is it possible to just connect directly to an analogue input? I realize I'll lose resolution, but that's not so important here.

I have the ILX511 wired up to the arduino, with CLK and ROG connected to digital outputs. I pulse ROG low for 5000us, then wait 1000us before alternating the clock - I've tried different frequences from 10us up to 10ms.  SHSW is held low so that I activate the internal S/H circuit.  I record the minimum and maximum values read, which are around 250-380.

Title: Re: Controlling an ILX511 Linear CCD Sensor
Post by: Riva on Apr 01, 2014, 07:56 am

This might be a silly question, but do you have to use a transistor to amplify the Vout? Is it possible to just connect directly to an analogue input? I realize I'll lose resolution, but that's not so important here.

I have never tried without a transistor on the output so cannot say.
Title: Re: Controlling an ILX511 Linear CCD Sensor
Post by: Bumpasticka77 on Jul 23, 2014, 12:39 am
So, since this was my first attempt at anything with electronics, I realized I was way over my head and needed to learn the basics.  Recently, I picked up coding again and came back to this project.  Using the Timer1 library, I got something that works, granted it will only control the ILX511 sensor.  You need an oscilloscope to view the output.

Code: [Select]
#include <TimerOne.h>
#define pwmRegister OCR1A

const int rog_pin = 4;
const int clock_pin = 9;
long period = 1;
long duty = 512;
unsigned long current = 0;
unsigned long previous = 0;
unsigned long difference = 0;

void setup() {
  pinMode(rog_pin, OUTPUT);
  pinMode(clock_pin, OUTPUT);
  Timer1.initialize(period);
  PORTB = B000010;
  PORTD = B00010000;
  Timer1.pwm(clock_pin, duty);
}

void loop() {
  current = micros();
  difference = current - previous;
  if(difference >= 2087) {
    Timer1.disablePwm(clock_pin);
    PORTB = B000010;
    delayMicroseconds(500);
    PORTD = B00000000;
    delayMicroseconds(500);
    PORTD = B00010000;
    delayMicroseconds(500);
    previous = micros();
    Timer1.pwm(clock_pin, duty);
  }
}


It works very well.  The long microsecond delays are to make it easier to view the end of the pixels on an oscilloscope.  As it is now, it will pulse the clock_pin at 1 Mhz.  The major problem with the code is that upon reinitializing pwm at the beginning of each read, the duty cycle is sometime distorted from 50% for the 1st pixel.  Also, the same goes for the last pulse when pwm is paused.  If anybody has ideas, that would be awesome.  I'll need to optimize that portion at some point...and then figure out how I'm going to store the pixel data at 500k - 1M hz  :smiley-eek-blue:
Title: Re: Controlling an ILX511 Linear CCD Sensor
Post by: TeamAlpha on Feb 27, 2015, 05:14 am
Bumpasticka,

Do you mind posting your schematic or pin wiring for the arduino with the sensor?  Also, did you use a transistor as suggested in the previous posts or did you just leave Vout un-amplified? 

Have you tried running this with other arduinos?  I believe the mega, for instance, prefers timer3 instead of timer1 because of the output pins. 

Thanks!
Title: Re: Controlling an ILX511 Linear CCD Sensor
Post by: Riva on Jun 14, 2015, 05:18 pm
I also revisited this project as I was considering using a faster MCU but in the end found the voltage translation needed between 3.3V & 5V to much hassle so tweaked and tested my original Mega code to confirm it still worked okay.
You have to be aware the CCD is very sensitive and to reduce the light levels enough to do a finger test I have to put a piece of thin card on the CCD, my finder on this card and then another piece of cardboard to shade direct light from the ceiling light falling on my finger/CCD.

Attached is the Mega sketch, logic analyser capture of CLK/ROG output + test pin output used to determine time spent in different sections of the timer ISR.
Also attached are the outputs with my finger on the middle of the CCD and one with no finger. They were make with a simple sketch written in processing.
Title: Re: Controlling an ILX511 Linear CCD Sensor
Post by: Riva on Jun 14, 2015, 05:26 pm
Attached is the processing sketch used to read out the data from the ILX511 CCD running on the Arduino Mega.
Code: [Select]
boolean myDebug = false;

int sampleBufferSize = 2201;                                // The sample buffer
int[] sampleBuffer = new int[sampleBufferSize + 1];         // Samples
int sampleCount = 0;                                        // Sample position counter
int timeout = 0;                                            // Used for timeout counter while waiting for Serial data

import processing.serial.*;
Serial arduinoSerial;                                       // The serial port

void setup() {
  if (myDebug)
    println(Serial.list());                                 // List all the available serial ports
  else {
    //arduinoSerial = new Serial(this, Serial.list()[0], 230400);// Open the port you are using at the rate you want:
    arduinoSerial = new Serial(this, Serial.list()[0], 115200);// Open the port you are using at the rate you want:
    arduinoSerial.clear();                                  // Flush serial buffers
  }
  println("*******************************");
  println("* -= ILX511 Scanner v5 MEGA=- *");
  println("*******************************");
  if (!myDebug)
    delay(500);                                             // Delay some to allow scanner to reboot and start sending serial data

  if (myDebug) {                                            // Put some data in the buffer if debugging
    for (int x=0; x < sampleBufferSize; x++) {
      sampleBuffer[x] = x & 255;
    }
  }

  size((sampleBufferSize+10)/2, 300);                       // Display size just wider than sample buffer size
  frameRate(15);                                            // Reduce framerate to save CPU load
}

void serialEvent(Serial arduinoSerial) {
  if (millis() > timeout + 50) {                            // Timeout if no serial received for 50 milliseconds or more
    //print("Timeout ");
    //println(millis());
    sampleCount = 0;                                        // Timout so reset counter
  }
  sampleBuffer[sampleCount++] = arduinoSerial.read();       // Add value to buffer
  if (sampleCount > sampleBufferSize) {                     // End of buffer?
    print("Overflow ");
    println(millis());
    sampleCount = 0;                                        // zero it
  }
  timeout = millis();                                       // Get current time
}

void draw() {
  int y = 0;
  background(180);                                          // Clear to background colour
  doScale();                                                // Paint on the scale
  stroke(255, 255, 0);                                      // Set pen colour
  for (int x = 0; x < sampleBufferSize; x++) {              // Draw the buffer data
    if ((x % 2) == 0) {
      y = sampleBuffer[x] * 256;
    }
    else {
      y = y + sampleBuffer[x];
      //line((x/2)+5, sampleBuffer[x], (x/2)+5, 280);
      //point((x/2)+5, sampleBuffer[x]/2);
      point((x/2)+5, 280 - (y / 4));
    }
  }
}

void doScale() {
  stroke(0);
  line(0+5, 280, 0+5, 280 - 255);
  line(16+5, 280, 16+5, 280 - 255);
  line(1040+5, 280, 1040+5, 280 - 255);
  line(1043+5, 280, 1043+5, 280 - 255);
}