5x7 LED Matrix (Common Cath) + MAX7221; Can't program

Hey all,

I’m using an Arduino Uno and a MAX7221 to drive a 5x7 LED matrix. When I try to program the MAX to light a single LED on the matrix, I get weird output behavior where all LEDs would be turned on (at full brightness) regardless of what I send to the control and data registers. Moreover, when I tested the “DOUT” signal of the MAX chip (which you will recall is just the data sent to the chip after it has propagated through the chip), I did not see the propagated signal. This leads me to believe that the MAX is not operating properly.

I followed the wiring schematic found here.
Datasheet for my LED Matrix is here.
Datasheet for the MAX chip is here.

Rset = 30k

The MAX7221-LED pin mapping is the following:
SEG_DP - 13
SEG_A - 3
SEG_B - 11 & 4
SEG_C - 10
SEG_D - 6

DIG0 - 9
DIG1 - 14
DIG2 - 8
DIG3 - 5 & 12
DIG4 - 1
DIG5 - 7
DIG6 - 2

The attached picture shows my logic analyzer output when Rset = 10k and when power to the chip is 5V. I also included a picture of what the output from the LED array looks like. Attached is also the code.

I'm unsure if the max chip is actually behaving the way it should or if I did not connect components to the chip properly or if I did not code correctly. I want to be able to address a single LED in the array.

ElusiveTau:
I'm unsure if the max chip is actually behaving the way it should or if I did not connect components to the chip properly or if I did not code correctly. I want to be able to address a single LED in the array.

The code you posted there is nonsense.

You have to set up all the correct registers in the MAX7219 in order to display something.

/* Loop scanner demonstration
Code for MAX7219 from maxim, reduced & optimised for using multiple 7219 cascaded.
______________________________________

General notes: 

- if using only one max7219, then use maxSingle function to control
the module --- maxSingle(register (1-8), column (0-255))

- if using more then one max7219, and all should work the same, use maxAll
function --- maxAll(register (1-8), collum (0-255))

- if using more than one max7219 and want to change something on one module only,
then use maxOne function 
--- maxOne(module you want to control [1=first], register [1-8], column [0-255])

 During initiation, be sure to send every part to every max7219 and then upload it.
For example, if you have five max7219's, you have to send the scanLimit 5 times
before you load it, otherwise not every max7219 will get the data. the (fixed)
variable maxInUse keeps track of this, just tell it how many max7219 you are using.
*/

int dataIn = 12;            // "DIN" on module
int load = 6;              // "CS" on module
int clock = 13;             // "CLK" on module
const int ledPin =  13;    // LED pin number

int maxInUse = 1;          // set how many MAX7219's used
int ledState = LOW;        // initialise the LED

int e = 0;                 // just a varialble

// define max7219 registers
byte max7219_reg_noop        = 0x00;
byte max7219_reg_digit0      = 0x01;
byte max7219_reg_digit1      = 0x02;
byte max7219_reg_digit2      = 0x03;
byte max7219_reg_digit3      = 0x04;
byte max7219_reg_digit4      = 0x05;
byte max7219_reg_digit5      = 0x06;
byte max7219_reg_digit6      = 0x07;
byte max7219_reg_digit7      = 0x08;
byte max7219_reg_decodeMode  = 0x09;
byte max7219_reg_intensity   = 0x0a;
byte max7219_reg_scanLimit   = 0x0b;
byte max7219_reg_shutdown    = 0x0c;
byte max7219_reg_displayTest = 0x0f;


void putByte(byte data) {
  byte i = 8;
  byte mask;
  while(i > 0) {
    mask = 0x01 << (i - 1);      // get bitmask
    digitalWrite( clock, LOW);   // tick
    if (data & mask) {           // choose bit
      digitalWrite(dataIn, HIGH);// send 1
    } else {
      digitalWrite(dataIn, LOW); // send 0
    }
    digitalWrite(clock, HIGH);   // tock
    --i;                         // move to lesser bit
  }
}

// maxSingle is the "easy" function to use for a single max7219
void maxSingle( byte reg, byte col) {    
  digitalWrite(load, LOW);  // begin     
  putByte(reg);             // specify register
  putByte(col);             //((data & 0x01) * 256) + data >> 1); // put data   
  digitalWrite(load,HIGH); 
}

// initialize all MAX7219's
void maxAll( byte reg, byte col) {
  int c = 0;
  digitalWrite(load, LOW);
  for ( c =1; c<= maxInUse; c++) {
  putByte(reg);             // specify register
  putByte(col);             //((data & 0x01) * 256) + data >> 1); // put data
    }
  digitalWrite(load,HIGH);
}

// for adressing different MAX7219's while cascaded
void maxOne(byte maxNr, byte reg, byte col) {    
  int c = 0;
  digitalWrite(load, LOW);  // begin     
  for ( c = maxInUse; c > maxNr; c--) {
    putByte(0);             // no operation
    putByte(0);             // no operation
  }

  putByte(reg);             // specify register
  putByte(col);             //((data & 0x01) * 256) + data >> 1); // put data 

  for ( c = maxNr-1; c >= 1; c--) {
    putByte(0);             // no operation
    putByte(0);             // no operation
  }
  digitalWrite(load,HIGH); 
}

void putCol( byte colno, byte coldat) {
// Interprets colno as (zero ref) index in combined array
    byte t;
    t = colno >> 3;
    byte u;
    u = colno & 0x07;
    maxOne(t+1, u+1, coldat);
}


void dispon() {
 maxAll(max7219_reg_shutdown, 0x01);               // Display on
}  

void dispoff() {
 maxAll(max7219_reg_shutdown, 0x00);              // Display off
}  

byte irow = 0;          // Row index
byte icol = 0;          // Column index
byte pattern;           // bit mask
byte lcol;              // left border
byte rcol;              // right border
byte trow;              // top row marker
byte brow;              // bottom row marker

int s_vert;             // Vertical switch
int s_horz;             // Horizontal switch

void worker () {

  if (pattern == 0) pattern = trow;            // pattern must be set
  if (s_vert != 0) {
    if (s_vert == -1) {                     // moving upward
      pattern = pattern >> 1;
      if (pattern == trow) {                   // hit the top
        s_vert = 0; s_horz = 1;
      }
    } else {
      pattern = pattern << 1;               // moving downward
      if (pattern == brow) {                // hit the bottom
        s_vert = 0; s_horz = -1;
      }
    }
    putCol(icol,pattern);              // Show the column.
    return;
  }

  if (s_horz != 0) {
    putCol(icol,0);                    // blank previous column.
    if (s_horz == -1) {                     // moving left
      icol--;
      if (icol == lcol) {                      // hit the side
        s_horz = 0; s_vert = -1;
      }
    } else {
      icol++;                               // moving right
      if (icol == rcol) {                      // hit the side
        s_horz = 0; s_vert = 1;
      }
    }
    putCol(icol,pattern);              // Show the column.
  }
 }
  
// the follow variable is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval = 60;           // interval at which to step (milliseconds)
long previousMillis = 0;      // will store last time LED was updated


void setup () {

  pinMode(dataIn, OUTPUT);
  pinMode(clock,  OUTPUT);
  pinMode(load,   OUTPUT);
  pinMode(ledPin, OUTPUT);      

  //Serial begin(9600);
  digitalWrite(13, HIGH);  

//initiation of the max 7219
  maxAll(max7219_reg_displayTest, 0x00); // no display test
  maxAll(max7219_reg_scanLimit, 0x07);   // all columns in use   
  maxAll(max7219_reg_decodeMode, 0x00);  // using a LED matrix (not digits)
  maxAll(max7219_reg_shutdown, 0x01);    // not in shutdown mode
  for (e=1; e<=8; e++) {                 // empty registers, turn all LEDs off 
    maxAll(e,0);
  }
  maxAll(max7219_reg_intensity, 0x08 & 0x0f);  // middle argument is intensity value
                                               // range: 0x00 to 0x0f
                                                 
  pattern = 0;
  s_vert = 0;
  s_horz = 1;

// define edges of loop
  lcol = 1;              // left border
  rcol = 6;              // right border
  trow = 0x02;           // top row marker
  brow = 0x40;           // bottom row marker      
      
}  

void loop () {

  unsigned long currentMillis = millis();
 
// Active waiting for next event
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW) { ledState = HIGH;  } else { ledState = LOW; }
    // Timed process:
    
    worker();

    // set the LED according to ledState:
    digitalWrite(ledPin, ledState);
    }

}

Thank you for the sample code. I read it over and didn't understand what work() did or why the LED on pin 13 is being lit.

May I verify that you wanted me to call these functions:

maxSingle(max7219_reg_displayTest, 0x00);
maxSingle(max7219_reg_scanLimit, 0x07);
maxSingle(max7219_reg_decodeMode, 0x00);
maxSingle(max7219_reg_shutdown, 0x01);
maxSingle(max7219_reg_intensity, 0x08 & 0x0f);

to "set up" the chip before displaying something?

Paul__B:
The code you posted there is nonsense.

You have to set up all the correct registers in the MAX7219 in order to display something.

/* Loop scanner demonstration

Code for MAX7219 from maxim, reduced & optimised for using multiple 7219 cascaded.


General notes:

  • if using only one max7219, then use maxSingle function to control
    the module --- maxSingle(register (1-8), column (0-255))

  • if using more then one max7219, and all should work the same, use maxAll
    function --- maxAll(register (1-8), collum (0-255))

  • if using more than one max7219 and want to change something on one module only,
    then use maxOne function
    --- maxOne(module you want to control [1=first], register [1-8], column [0-255])

During initiation, be sure to send every part to every max7219 and then upload it.
For example, if you have five max7219's, you have to send the scanLimit 5 times
before you load it, otherwise not every max7219 will get the data. the (fixed)
variable maxInUse keeps track of this, just tell it how many max7219 you are using.
*/

int dataIn = 12;            // "DIN" on module
int load = 6;              // "CS" on module
int clock = 13;            // "CLK" on module
const int ledPin =  13;    // LED pin number

int maxInUse = 1;          // set how many MAX7219's used
int ledState = LOW;        // initialise the LED

int e = 0;                // just a varialble

// define max7219 registers
byte max7219_reg_noop        = 0x00;
byte max7219_reg_digit0      = 0x01;
byte max7219_reg_digit1      = 0x02;
byte max7219_reg_digit2      = 0x03;
byte max7219_reg_digit3      = 0x04;
byte max7219_reg_digit4      = 0x05;
byte max7219_reg_digit5      = 0x06;
byte max7219_reg_digit6      = 0x07;
byte max7219_reg_digit7      = 0x08;
byte max7219_reg_decodeMode  = 0x09;
byte max7219_reg_intensity  = 0x0a;
byte max7219_reg_scanLimit  = 0x0b;
byte max7219_reg_shutdown    = 0x0c;
byte max7219_reg_displayTest = 0x0f;

void putByte(byte data) {
  byte i = 8;
  byte mask;
  while(i > 0) {
    mask = 0x01 << (i - 1);      // get bitmask
    digitalWrite( clock, LOW);  // tick
    if (data & mask) {          // choose bit
      digitalWrite(dataIn, HIGH);// send 1
    } else {
      digitalWrite(dataIn, LOW); // send 0
    }
    digitalWrite(clock, HIGH);  // tock
    --i;                        // move to lesser bit
  }
}

// maxSingle is the "easy" function to use for a single max7219
void maxSingle( byte reg, byte col) {   
  digitalWrite(load, LOW);  // begin   
  putByte(reg);            // specify register
  putByte(col);            //((data & 0x01) * 256) + data >> 1); // put data 
  digitalWrite(load,HIGH);
}

// initialize all MAX7219's
void maxAll( byte reg, byte col) {
  int c = 0;
  digitalWrite(load, LOW);
  for ( c =1; c<= maxInUse; c++) {
  putByte(reg);            // specify register
  putByte(col);            //((data & 0x01) * 256) + data >> 1); // put data
    }
  digitalWrite(load,HIGH);
}

// for adressing different MAX7219's while cascaded
void maxOne(byte maxNr, byte reg, byte col) {   
  int c = 0;
  digitalWrite(load, LOW);  // begin   
  for ( c = maxInUse; c > maxNr; c--) {
    putByte(0);            // no operation
    putByte(0);            // no operation
  }

putByte(reg);            // specify register
  putByte(col);            //((data & 0x01) * 256) + data >> 1); // put data

for ( c = maxNr-1; c >= 1; c--) {
    putByte(0);            // no operation
    putByte(0);            // no operation
  }
  digitalWrite(load,HIGH);
}

void putCol( byte colno, byte coldat) {
// Interprets colno as (zero ref) index in combined array
    byte t;
    t = colno >> 3;
    byte u;
    u = colno & 0x07;
    maxOne(t+1, u+1, coldat);
}

void dispon() {
maxAll(max7219_reg_shutdown, 0x01);              // Display on
}

void dispoff() {
maxAll(max7219_reg_shutdown, 0x00);              // Display off
}

byte irow = 0;          // Row index
byte icol = 0;          // Column index
byte pattern;          // bit mask
byte lcol;              // left border
byte rcol;              // right border
byte trow;              // top row marker
byte brow;              // bottom row marker

int s_vert;            // Vertical switch
int s_horz;            // Horizontal switch

void worker () {

if (pattern == 0) pattern = trow;            // pattern must be set
  if (s_vert != 0) {
    if (s_vert == -1) {                    // moving upward
      pattern = pattern >> 1;
      if (pattern == trow) {                  // hit the top
        s_vert = 0; s_horz = 1;
      }
    } else {
      pattern = pattern << 1;              // moving downward
      if (pattern == brow) {                // hit the bottom
        s_vert = 0; s_horz = -1;
      }
    }
    putCol(icol,pattern);              // Show the column.
    return;
  }

if (s_horz != 0) {
    putCol(icol,0);                    // blank previous column.
    if (s_horz == -1) {                    // moving left
      icol--;
      if (icol == lcol) {                      // hit the side
        s_horz = 0; s_vert = -1;
      }
    } else {
      icol++;                              // moving right
      if (icol == rcol) {                      // hit the side
        s_horz = 0; s_vert = 1;
      }
    }
    putCol(icol,pattern);              // Show the column.
  }
}
 
// the follow variable is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval = 60;          // interval at which to step (milliseconds)
long previousMillis = 0;      // will store last time LED was updated

void setup () {

pinMode(dataIn, OUTPUT);
  pinMode(clock,  OUTPUT);
  pinMode(load,  OUTPUT);
  pinMode(ledPin, OUTPUT);

//Serial begin(9600);
  digitalWrite(13, HIGH);

//initiation of the max 7219
  maxAll(max7219_reg_displayTest, 0x00); // no display test
  maxAll(max7219_reg_scanLimit, 0x07);  // all columns in use 
  maxAll(max7219_reg_decodeMode, 0x00);  // using a LED matrix (not digits)
  maxAll(max7219_reg_shutdown, 0x01);    // not in shutdown mode
  for (e=1; e<=8; e++) {                // empty registers, turn all LEDs off
    maxAll(e,0);
  }
  maxAll(max7219_reg_intensity, 0x08 & 0x0f);  // middle argument is intensity value
                                              // range: 0x00 to 0x0f
                                               
  pattern = 0;
  s_vert = 0;
  s_horz = 1;

// define edges of loop
  lcol = 1;              // left border
  rcol = 6;              // right border
  trow = 0x02;          // top row marker
  brow = 0x40;          // bottom row marker     
     
}

void loop () {

unsigned long currentMillis = millis();

// Active waiting for next event
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

// if the LED is off turn it on and vice-versa:
    if (ledState == LOW) { ledState = HIGH;  } else { ledState = LOW; }
    // Timed process:
   
    worker();

// set the LED according to ledState:
    digitalWrite(ledPin, ledState);
    }

}

What would I have to call to get an LED in the array to light up?

Back up to a simpler code.
5 SPI transfers in setup() to load the 5 control registers:

digitalWrite (ssPin, LOW);
SPI.transfer(registerAddress);
SPI.transfer(dataToSend);
digitalWrite (ssPin, HIGH);

No Decode Mode
Display Test off
scan limit set to 7 (7 columns x 5 rows)
intensity set to some level (like midway)
Normal mode on

Then in loop, have 7 bytes that represent the seven columns and send those out using SPI.transfers:

for (x=0; x<7; x=x+1){
digitalWrite (ssPin, LOW);
SPI.transfer (x+1); // register are 1 to 7
SPI.transfer(dataArray[x]); // data to display in dataArray[], bits 0-4 of each byte used
digitalWrite (ssPin, HIGH);
}

ElusivePi:
Thank you for the sample code. I read it over and didn't understand what work() did or why the LED on pin 13 is being lit.

Hey! First things first!

Did you actually load and run that code, and did it work? That is the critical question! It is "known good" code - uses no libraries, machine/ processor-independent. If it works, you are in business. If it does not, you have a hardware problem.

ElusivePi:
May I verify that you wanted me to call these functions ... to "set up" the chip before displaying something?

Sure do!

  maxSingle(max7219_reg_displayTest, 0x00); // Not strictly necessary as default is 0x00, but turns off test mode. 
  maxSingle(max7219_reg_scanLimit, 0x07);  // Sets eight columns - may be different, depending on how 5 by 7 is wired.
  maxSingle(max7219_reg_decodeMode, 0x00); // Not strictly necessary as default is 0x00, but turns off 7-segment mode.
  maxSingle(max7219_reg_shutdown, 0x01);   // Turns the display on!
  maxSingle(max7219_reg_intensity, 0x08 & 0x0f);  // Sets 50% brightness

Oh yes, you also should have a 22k pull-up on the latch line.

Before I ran your code I made a change: const int ledPin = 13; // LED pin number
I changed this to pin 8 since 13 is reserved for clk.

I loaded and ran your code but did not get any response from the LED array so I agree -- I may have improperly hooked up the hardware. I didn't have a 22k pull-up on the latch line. I will add that later today.

For the hardware, the pin mappings from the MAX7221 to the LED Array are those I mentioned in the original post. Additionally:

  • Led is connected to MCU's IO pin 8

  • Din is connected directly to MCU at IO pin 12

  • Load/~CS pin from chip is connected to MCU's IO pin 6

  • 2 ground connections from chip (at chip pin 4, 9) is connected to MCU's gnd

  • Clk pin from chip is connected to MCU's IO pin 13

  • Iset pin from chip is in series with a 30kohm, connected to 5V (MCU's 5V)

  • V+ pin from chip is connected to MCU's 5V line

  • Dout, SEG_E,F,G are free-floating.

  • MCU's 5V is connected to chip's V+, Grounds between chip and MCU are connected

Paul__B:
Hey! First things first!

Did you actually load and run that code, and did it work? That is the critical question! It is "known good" code - uses no libraries, machine/ processor-independent. If it works, you are in business. If it does not, you have a hardware problem.
Sure do!

  maxSingle(max7219_reg_displayTest, 0x00); // Not strictly necessary as default is 0x00, but turns off test mode. 

maxSingle(max7219_reg_scanLimit, 0x07);  // Sets eight columns - may be different, depending on how 5 by 7 is wired.
  maxSingle(max7219_reg_decodeMode, 0x00); // Not strictly necessary as default is 0x00, but turns off 7-segment mode.
  maxSingle(max7219_reg_shutdown, 0x01);  // Turns the display on!
  maxSingle(max7219_reg_intensity, 0x08 & 0x0f);  // Sets 50% brightness




Oh yes, you also should have a 22k pull-up on the latch line.

What gets transferred in the first and second transfer call?

Does the first transfer "choose" a cathode pin (DIG_0-7) and the second choose an anode pin (SEG_DP-G)?

CrossRoads:
Then in loop, have 7 bytes that represent the seven columns and send those out using SPI.transfers:

for (x=0; x<7; x=x+1){

digitalWrite (ssPin, LOW);
SPI.transfer (x+1); // register are 1 to 7
SPI.transfer(dataArray[x]); // data to display in dataArray[], bits 0-4 of each byte used
digitalWrite (ssPin, HIGH);
}

No. The register is the column of data that will be updated.
The next is the byte that goes in to that column.

Picture anodes being connected horizontally by the Segment Pins, and then each column is the common cathode for those LEDs. So your Internal Circuit Diagram turned counter clockwise 1/4 turn. 5 anodes going across the page driven by segments, 7 columns down the page driven by digits.

The segment data is the byte you write into the register for a digit.

You are quite right. I changed my pin numbers to match yours, and overlooked that I had a use for the built-in LED as a monitor of the operation.

Your alteration was correct, I cannot fault the connections you describe and if my code did not then work, I have to conclude that your MAX7219 is crook!

I believe it was a connection issue. I unsoldered the LED Matrix from my current setup, implemented the circuit on a protoboard and used a different arduino uno, keeping all other components the same (with no pull-up resistors on SS pin).

I can now address each individual LED.

I'm sorry for the trouble (as I had blundered the hardware portion) but I did learn about the control and data registers and how to set the byte. Thanks for the help!

Here is the final code I had used:

//Pin Assignments
int load = 11;  //"~CS" pin
int dataIn = 10;//"DIN" pin
int clock = 12; //"CLK" pin
int led = 13;   //Status LED

//Variables


//Define MAX7221 Control Registers
byte max7221_reg_noop        = 0x00;
byte max7221_reg_digit0      = 0x01;
byte max7221_reg_digit1      = 0x02;
byte max7221_reg_digit2      = 0x03;
byte max7221_reg_digit3      = 0x04;
byte max7221_reg_digit4      = 0x05;
byte max7221_reg_digit5      = 0x06;
byte max7221_reg_digit6      = 0x07;
byte max7221_reg_digit7      = 0x08;
byte max7221_reg_decodeMode  = 0x09;
byte max7221_reg_intensity   = 0x0a;
byte max7221_reg_scanLimit   = 0x0b;
byte max7221_reg_shutdown    = 0x0c;
byte max7221_reg_displayTest = 0x0f;

//Generates clock signals and controls data line (dataIn) to clock 'data' into MAX's register 
void putByte(byte data)
{
  byte i = 8;
  byte mask;
  while(i > 0) {
    mask = 0x01 << (i - 1);      // get bitmask
    digitalWrite( clock, LOW);   // tick
    if (data & mask) {           // choose bit
      digitalWrite(dataIn, HIGH);// send 1
    } else {
      digitalWrite(dataIn, LOW); // send 0
    }
    digitalWrite(clock, HIGH);   // tock
    --i;                         // move to lesser bit
  }
}

//INITATION FUNCTIONS
void initPins()
{
  pinMode(load,   OUTPUT);
  pinMode(dataIn, OUTPUT); 
  pinMode(clock,  OUTPUT);
  pinMode(led,    OUTPUT); 
}

void initWReg(byte addr, byte data)
{  
  digitalWrite(load, LOW);   // begin     
  putByte(addr);             // specify register
  putByte(data);             //((data & 0x01) * 256) + data >> 1); // put data   
  digitalWrite(load,HIGH); 
}

//Initiate MAX7221 Control Registers
void initRegs()
{  
  initWReg(max7221_reg_shutdown, 0x01);         //1 = Normal Op       (ACK)
  initWReg(max7221_reg_displayTest, 0x00);      //1 = Light all LEDS  (ACK)
  initWReg(max7221_reg_decodeMode, 0x00);       //Decode Mode Off     (Untested)
  initWReg(max7221_reg_scanLimit, 0x07);        //Scan Limit set to 7 (????) 
  initWReg(max7221_reg_intensity, 0x08 & 0x0f); //Set Intensity       (????) 
}

//PROGRAM FUNCTIONS
/*
      16-bits sent with each sending
      D15 is MSB, D0 LSB
      D0-D7 data; D7=DP seg, D6=A seg, D5=B seg, etc...
      D8-D11 register address
      D12-D15 ignored      
*/ 
//Clears LEDs
void clearLeds()
{
  
}
//Turn on LED at specified row/col, top left = (0,0)
void setLed(int row, int col)
{
  byte ledSegs[] = {128, 64, 32, 16, 8, 4, 2, 0};
  byte ledCath[] = {1, 2, 3 , 4, 5, 6, 7, 8};
  digitalWrite(load, LOW); 
  putByte(ledCath[row]); 
  putByte(ledSegs[col]);
  digitalWrite(load, HIGH); 
}


//MAIN PROGRAM
void setup()
{
  initPins();  //Set pins modes
  initRegs();  //Initiate MAX7221 Control Registers
}

void loop()
{
 setLed(2,2); 
}

ElusivePi:
I believe it was a connection issue.

Had to be something.

Often just as well to perform the hardware version of the Standard Windoze Corrective Manoeuvre (SWCM).

Two nasty problems with the Chinese pre-made jumper leads from eBay are, connector pins not connected, and lacquer coating the pins.