Ripping Up an Old Scanner
A long time since I posted, having been swamped with work in real life, but
here's a quick post on a random piece of hardware recycling.
The Victim
This is a defunct HP "combo" scanner and printer, the PSC-1317. There's a
few interesting pieces, but for this post I'll look at the scanner head itself and wiring it
up to a pcDuino.
The Scanning Head
This is a CIS style scanner.
The scanner head consists of a bunch of LEDs to provide lighting, and strip of photodiode
light detectors.
When the scanner is running then the detectors are picking up the reflected
light from the scanned document - light areas will reflect and
darker sections will not; the detector will pick these variations up and we
will see a lower or higher voltages over the strip of detectors as a result.
To read the scan head then we expect to see a shift register style setup: To
reduce the wiring to sane level then the scanners will generally use a single
output pin, and have a clock signal which will output each detector value in turn.
So the board activates the lighting LEDs, and requests a scan, then the
detectors are read in sequence to give the reflected light from the
document, and this information gives the
scanner a single scan line image. Then
the motor cranks forward, and the scanner repeats this process for the next
line, and so on.
The Signals we Expect
We expect to see:
- LED controls
- Start Scan
- Clock
- Analog Output
The Signals we Got
There's a 22 pin header on the control PCB that goes to the scanner assembly. This
has 14 pins to the scan head, together with 6 wires to the position motor, and
a couple of unused pins to separate the two sections physically.
The scanner head itself is labelled as "CSI C26218-IR5H3", and has Red, Green and Blue LED lights.
LEDs
For the 14 pins going to the scan head then the last four are used for the
LEDs; pin 14 is a common supply, and pins 11, 12 and 13 are the RGB
activation lines. So pin 14 is the supply high voltage, and pulling one of the
other pins low (through a limiting resistor) will turn on the relevant LED colour.
Scan signals
There are three pins involved in triggering the scan, and a fourth for the output:
- Pin 7 is a continuous high speed clock running at about 2MHz(roughly 530nS per cycle)
- Pin 5 goes low every 3.2mS for about 9uS. The is probably the line start.
- Pin 9 is another clock.
- Pin 1 is the analog output value.
In general Pin 9 is aligned with Pin 7 (falling edges are in sync),
however when pin 5 activates this slows Pin 9 down to 4.5uS a cycle
for 2 cycles then it goes back to matching Pin 7.
When Pin 7 and 9 are both running fast then the falling edges match, but the
level goes high on Pin 7 slightly ahead of pin 9, and the analog output
appears valid when Pin 7 is high and Pin 9 is low.
For a clock cycle time of 530nS then the 3.2mS between strobes covers about 6038 clock.
cycles.
Other
Pins 6 and 8 are 0V. Pins 2 and 10 are VCC, which is 5V from the original PCB.
Pins 3 and 4 look to be analog outputs, but there aren't any obvious clues
otherwise, so leaving them as n/c for the moment.
Prototype Code/Wiring
Since I'm connecting this up to a pcDuino (not 5V tolerant) then I'm wiring
everything to 3v3. This might cause problems, and the LEDs will be dim, but
that beats blown ports.
For a pcDuino v2 then these are the headers I'm connecting to
(signals via limiting resistors, to protect the IO)
- Pin 1 : Ouput; J12-3 (Analog Input #2)
- Pin 2 : Vcc: 3v3
- Pin 3 : n/c
- Pin 4 : n/c
- Pin 5 : Line Strobe; J8-3 (GPIO 10)
- Pin 6 : 0V
- Pin 7 : Constant Clock; J8-2 (GPIO 9)
- Pin 8 : 0V
- Pin 9 : Logical Clock; J8-1 (GPIO 8)
- Pin 10 : Vcc: 3v3
- Pin 11 : Blue LED; J11-4 (GPIO 3)
- Pin 12 : Green LED; J11-6 (GPIO 5)
- Pin 13 : Red LED; J11-7 (GPIO 6)
- Pin 14 : LED Supply; 3v3
So, emulating the signals we see from the mainboard, we'll have much (much)
slower clocks, and running at 3v3 is an obvious source of trouble.
However with the following defines:
- CLOCKING_CYCLES: 6000, the number of clock cycles between line strobes
- PIN_CLOCK_CONST: Constant clock, GPIO 9
- PIN_CLOCK_LOGIC: Logical clock, GPIO 8
- PIN_STROBE: Line strobe, GPIO 10
with this code:
int warmups = 3;
doboth = false;
SetPinValue(PIN_CLOCK_CONST, HIGH);
SetPinValue(PIN_CLOCK_LOGIC, HIGH);
SetPinValue(PIN_STROBE, HIGH);
while (warmups-- > 0) {
for (i = 0 ; i < CLOCKING_CYCLES; i++) {
if (i == 0) {
SetPinValue(PIN_CLOCK_LOGIC, LOW);
SetPinValue(PIN_STROBE, LOW);
doboth = false;
}
else if (i == 4) {
SetPinValue(PIN_CLOCK_LOGIC, HIGH);
doboth = false;
}
else if (i == 8) {
SetPinValue(PIN_CLOCK_LOGIC, LOW);
doboth = false;
}
else if (i == 12) {
SetPinValue(PIN_CLOCK_LOGIC, HIGH);
doboth = false;
}
else if (i == 15) {
SetPinValue(PIN_STROBE, HIGH);
doboth = true;
}
else if ( i< 15) {
doboth = false;
}
else {
doboth = true;
}
rv = ClockPins(doboth);
samples[i] = rv;
}
}
where
static int ClockPins(bool bothpins) {
int ret;
SetPinValue(PIN_CLOCK_CONST, HIGH);
if (SAMPLE_DELAY > 0)
usleep (SAMPLE_DELAY); // Const Hi, Logic Low: This is the Sample Window....
ret = GetAdcValue();
if (bothpins) {
SetPinValue(PIN_CLOCK_LOGIC, HIGH);
SetPinValue(PIN_CLOCK_LOGIC, LOW);
}
SetPinValue(PIN_CLOCK_CONST, LOW);
return ret;
}
The "warmups" variable causes multiple scanning loops per pass, which appeared to reduce the
noise during testing. The clunky "if" sequence handles the early scan stage where
the logic clock slows during the strobe pin active.
Then we get "plausible" results from the scan, using an LED light directly on the sensor to emulate reflections.
In the dark the outputs (Sample number on X, ADC output on Y) are:
With an LED light at the "cable" end:
With an LED light at the far end:
And with an LED light in the middle:
So, bucketing up the sensors into groups of 100 and averaging values to reduce the noise element then we get fairly consistent results from our crappy old prototype.
And Next...
At this point we have a couple of ways to go. The scanner head needs a "proper" set of drive voltages
on the LEDs to bring up the brightness and to run at the correct (5V) VCC. Also a "proper" microcontroller
to run the clocks and sample the ADC at a reasonable rate and interfaces to hook 3v3 to 5V where necessary.
However the alignment out of the sensor to pick up a reflection is tight, and it's not as responsive to ambient light levels as I'd hoped for, so for now
I'm going to leave it with a simple LED driver wired, and use it as a multi-colour desk lamp, which is a little
underwhelming given all that, but beats throwing it away...