spontaneous latch up issue?

Hi all,

Quick background: I built a water sampler with an on-board data logger for recording the volume of liquid pumped. I had it set up and working well, and after numerous short-term runs, I deployed it for a 3-week test run off a 12V battery. Everything worked great! However, after that long deployment, it started behaving very strangely.

Attached is a breadboard diagram of the circuit as a whole (the three dangling wires at the bottom go to a flow meter), but the issue is specifically with the motor-control circuit.

I'm controlling a 12V DC water pump with a 3.3V 8MHz arduino pro mini, using a 2N2222 NPN transistor. I have a 120-ohm resistor running from pin 6 to the transistor base, and have it programmed so that the pin goes HIGH for about 1 second every 2 minutes. I have the motor ground line connected to the transistor collector, and the emitter is connected to ground. I soldered a 1N4001 diode across the motor terminals as a flyback.

The issue is that after working great for a long time, the arduino pin now gets stuck in the HIGH position when I power the circuit on. Curiously, it's not the arduino hanging-- it's clearly looping through all it's other functions just fine. After poking around with my multimeter, I became concerned that perhaps voltage was flowing back from the transistor base, and so I inserted a 1N5817 diode (just because it was handy) in series with the pin. That didn't solve the issue. Then I checked to see if maybe the pin was damaged. However, when I remove the motor from the circuit, the pin behaves correctly from the get-go. When I add the motor back in, power it up and then hit the reset button, it also works normally. I've tried using different pins, but all with the same result. My conclusion is the pin isn't the issue.

From combing through the forums, I suspect my issue is latch up, but I'm afraid I don't know enough about the phenomenon to know why it's happening all of a sudden, and what I can do to fix it. The current being drawn from the arduino pin to the transistor base is about 14mA, which seems reasonable. The motor is only pulling at most 350mA from the battery, which is in spec with the 2N2222. My only hunch is that I might fare better using a TIP-120 MOSFET, but I have no basis for this other than I can't think of what else to try.

Any thoughts are extremely appreciated, I've been banging my head on this for days.

120R base resistor seems low to me, try stepping up to 270 or 330, in your Fritz picture the transistor is backwards, but that wouldn't work at all, please post your code and a well focused photo of your project.

2N2222A.pdf (298 KB)

The motor is only pulling at most 350mA from the battery, which is in spec with the 2N2222.

The stall current is probably much higher than this, and the motor will briefly draw the stall current (or attempt to draw it), every time it starts up.

Also, motors inject severe electrical noise into the system and the wimpy 2N2222 transistor may have been damaged. By all means use a TIP120 or better, a logic level MOSFET (with 150 Ohm/10K gate resistors).

You should bypass the motor terminals with a 100 nF capacitor, and in bad cases with 3 capacitors as described here: Pololu - 9. Dealing with Motor Noise

A 120ohm resistor is (3.3 - 0.7) / 120 = <=22mA base current on a 3.3volt Arduino.
Within specs, but it might not be enough to drive the 2N2222 into saturation.

350mA motor current might be 1.5A stall (startup) current.
That would need 150mA base current, assuming a 1:10 base:collector current ratio for saturation.
Out of specs for the 2N2222.

Could be that the transistor is shorted between collector and base (HIGH on the Arduino pin) from this abuse.

Good idea to replace the 2N2222 with a TIP120 darlington.
A 330ohm resistor would be ok for up to 1.5A collector current, assuming a 1:250 base:collector current ratio for a darlington.
Leo..

Hi,

Question, is your device still on a push lead type of breadboard? If so you should consider a soldered breadboard of some sort.

I don't see a ground between the USB+Pro Mini and the Flow meter board + motor.

You should have a local filter on both the USB+Pro Mini and the Motor and associated Ckt. Say an 10µF // 0.1µF.

I agree with the suggestion to use a mosfet.

I 'm not sure why you need the diode in the 2N2222a base ckt

As suggested before, the motor current on startup is many time more than the 350 ma you quoted. See if the motor has a stall current stated. If so that would be your peak current at the very beginning of the startup.

In general power devices are cheap. A mosfet with a TO-220 case might seem overkill but the economics of making literally billions of TO-220 devices a year makes that package the go to for most power switching application. I agree a 40 amp device might seem overkill here but unless you are designing a consumer product it is the best way to go.

The diode in the base line is going to slow down switch off for no good reason (in fact that will
increase switching dissipation in the 2N2222).

My main observation is that the 2N2222 may not be able to take the stall current of the motor
as its only rated for 1A, and a 0.35A motor will likely have a stall current in the 2A to 4A range.
Over currenting the 2N2222 will degrade it over time. Once the 2N2222 failed it overloaded
the Arduino pin by feeding 12V to it through the low value resistor and sending it into latchup
(by pushing heavy current through the protection diode on the pin).

Its a possible theory. Yes I vote for a higher current switching device too.

Thanks all for your replies and great suggestions,

I'll need some time to try them all, but here's a quick update: I just tried using the TIP120, and got the same results. Changing the resistor to the base from the arduino also had no effect-- I went all the way up to 5K and all that changed was the motor was working from a lower voltage.

I'll upload my code and a picture of my circuit in a little bit and think through your comments some more.

I'll upload my code

You should have done that in your first post. Use code tags.

Also, please avoid the inevitably misleading, confusing, and incorrect "Fritzing for the brain dead" diagrams.

We really appreciate clear, even hand drawn schematic diagrams.

Code below, and a schematic that is updated to reflect the TIP120, the base diode removed, and the larger resistor value. I'm reluctant to post photos because it's currently a rats nest of wires and probably wouldn't contribute much.

JohnRob-- I am using a push lead breadboard, but would that contribute to my issue? I currently have the flow totalizer grounded to the main ground rail, though I've had it grounded to the pro mini before. It didn't seem to make much difference. I'll try adding filters to the pro mini and the motor.

JRemington-- Good tip, I'll try adding bypass caps to the motor.

It's still odd to me that adding the TIP120 didn't do anything, it seems like that should be plenty beefy enough to handle the current draw. My code hasn't changed since it was working properly, but it's possible that there's something in there confusing things.

#include <AltSoftSerial.h> //AltSoftSerial uses pins 8 and 9 for RX and TX, respectively
#include <LowPower.h>
#include <Wire.h>
#include <SD.h>

const int chipSelect = 7;
File logfile;

const int MOSFET = 6;
char flow_data[48];                //we make a 48 byte character array to hold incoming data from the Flow Meter Totalizer.
byte received_from_sensor = 0;     //we need to know how many characters have been received.

float total_flow = 0;              //used to hold a floating point number that is the total volume flow.
float flow_per_time;               //used to hold a floating point number that is the flow rate per X time [hour, min, sec]

char *total;                       //char pointer used in string parsing
char *FPT;                         //char pointer used in string parsing [FPT= flow per time]

void error(char *str)
{
  digitalWrite(LED_BUILTIN, HIGH);
  while(1);
}
AltSoftSerial altSerial;

void setup() {
    //#######SD Initialization###########
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(10, OUTPUT);

  // The chipSelect pin you use should also be set to output
  pinMode(chipSelect, OUTPUT);

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
   // Serial.println("Card failed, or not present");
    digitalWrite(LED_BUILTIN, HIGH);
    // don't do anything more:
    return;
  }
  // create a new file
  char filename[] = "LOGGER00.CSV";
  for (uint8_t i = 0; i < 100; i++) {
    filename[6] = i/10 + '0';
    filename[7] = i%10 + '0';
    if (! SD.exists(filename)) {
      // only open a new file if it doesn't exist
      logfile = SD.open(filename, FILE_WRITE); 
      break;  // leave the loop!
    }
  }
  
  if (! logfile) {
    error("couldnt create file");
  }
  
 // ###########Motor and Totalizer Initialization
  pinMode (MOSFET, OUTPUT);
  digitalWrite(MOSFET, LOW);
  Serial.begin(9600);          //enable the hardware serial port
  altSerial.begin(9600);        //enable the software serial port
  altSerial.print("C,0\r");
  altSerial.print("sleep\r");
}


void loop() {
  delay(50);
  altSerial.print("\r");
  delay(250);
  altSerial.flush();
  digitalWrite(MOSFET, HIGH);
  delay(1000);
  if (altSerial.available() > 0) {
    altSerial.print("R\r");
    altSerial.flush();
    while (altSerial.available() > 0) {
      received_from_sensor = altSerial.readBytesUntil(13, flow_data, 48); //we read the data sent from Flow Meter Totalizer until we see a <CR>. We also count how many character have been received.
      flow_data[received_from_sensor] = 0; //we add a 0 to the spot in the array just after the last character we received. This will stop us from transmitting incorrect data that may have been left in the buffer.
      if ((flow_data[0] >= 48) && (flow_data[0] <= 57)) { //if flow_data[0] is a digit and not a letter
        pars_data();
        digitalWrite(MOSFET, LOW);
        delay(3000);
        break;
      }
      else {
        Serial.println(flow_data);            //if the data from the Flow Meter Totalizer does not start with a number transmit that data to the serial monitor.
        logfile.println(flow_data);
        Serial.flush();
        logfile.flush();
      }
    }
  }

  altSerial.print("sleep\r");
  altSerial.flush();
         int var = 0;
 while(var < 16){
  var++;
  LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); 
  }
}


void pars_data() {

  total = strtok(flow_data, ",");         //let's pars the string at each comma.
  FPT = strtok(NULL, ",");                //let's pars the string at each comma.

  Serial.print("total_flow=");           //We now print each value we parsed separately.
  Serial.println(total);                 //this is the total_flow.
  logfile.print("total_flow="); 
  logfile.print(", ");
    logfile.print(total);  
  logfile.print(", ");

  Serial.print("FPT=");                  //We now print each value we parsed separately.
  Serial.println(FPT);                   //this is the the flow rate per X time.
  logfile.print("FPT=");                  
  logfile.print(", ");
  logfile.println(FPT);


  Serial.println();                      //this just makes the output easier to read.
  Serial.flush();
  logfile.println();                     
  logfile.flush();

}

bsosik:
Thanks all for your replies and great suggestions,

I'll need some time to try them all, but here's a quick update: I just tried using the TIP120, and got the same results. Changing the resistor to the base from the arduino also had no effect-- I went all the way up to 5K and all that changed was the motor was working from a lower voltage.

I'll upload my code and a picture of my circuit in a little bit and think through your comments some more.

So I guess the pin is fried - not that surprising if it went into latchup previously... Try another pin?