Saturday, 20 January 2018

Recycling Scanner Hardware

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...