Computing stuff tied to the physical world

Direct relay switching – part 2

In Hardware on Mar 17, 2013 at 00:01

Yesterday’s post turns out to uncover a lot of trouble spots and mistakes on my end w.r.t. switching small relays. Get ready for some scope shots ahead, to see what’s going on…

But first, the code I’ve been using:

void setup() {}

static void setLatch (bool on) {
  pinMode(5, OUTPUT);  // DIO2
  pinMode(15, OUTPUT); // AIO2
  pinMode(6, OUTPUT);  // DIO3
  pinMode(16, OUTPUT); // AIO3

  digitalWrite(5, on ? 0 : 1);
  digitalWrite(15, on ? 0 : 1);
  digitalWrite(6, on ? 1 : 0);
  digitalWrite(16, on ? 1 : 0);

  pinMode(5, INPUT);
  pinMode(15, INPUT);
  pinMode(6, INPUT);
  pinMode(16, INPUT);

void loop() {

Basic idea: set the pins as outputs, set the levels right, wait 3 ms, then set the pins as input again, i.e. in high-impedance mode, to stop driving the relays.

There are two very serious problems with this code. The first one is that the I/O pins are set to inputs at the end. This means there is no good path for the inductive kick energy to go, leading to this very nasty waveform across the relay – same as shown yesterday:


Note the extreme voltage levels across the coil – way beyond the ± 3.3V you’d want to see in a good 3.3V totem-pole configuration.

It turns out that there is a surprisingly simple solution for this – don’t make the I/O pins inputs, but put them all the same output level, so that no current flows through the relay (as before), but with the I/O pins still being outputs, i.e. able to conduct current.

Here’s is the entire pulse again, at maximum scale this time:


(the lines are so thick because the input is set to peak-detect mode in the scope)

No more funny business! A fairly clean on and off transition, just a bit of “sagging” as the two I/O pins in parallel struggle (successfully) to supply the required current. It looks like the inductive kickback is now absorbed by the output pins which are all set to “0”, i.e. conducting to GND.

I’m surprised by how well this seems to work. I’m guessing that the CMOS switches in the ATmega’s pin driver are able to conduct in both directions when enabled, and that the ESD protection diodes are absorbing any voltage excursions outside the 0 .. 3.3V range.

But a much bigger problem probably, is that the original sketch was shorting out the DIO and AIO pins against each other – producing a very bad intermediate voltage level:


The time scale is completely different now, and as you can see, the voltage level goes through a strange middle state. This is caused by the fact that the digitalWrite() code is very slow, compared to the actual speed of the ATmega. It’s taking 4 µs to process each call, and as the first one is set to one value, the other pin connected to it can still be in the other state. So this is – briefly – shorting out two I/O pins, set to different values!

Very very bad – this may well reduce the lifetime of the ATmega µC. As it turns out, my choice of I/O pins makes it impossible to set both I/O pins simultaneously. But the least I can do without re-soldering, is to use the much faster bitSet() and bitClear() calls – even though this makes the code slightly harder to understand:

static void setLatch (bool on) {
  if (on) {
    bitSet(PORTD, 5); // D.5 = DIO2
    bitSet(PORTC, 1); // A.1 = AIO2
  } else {
    bitSet(PORTD, 6); // D.6 = DIO3
    bitSet(PORTC, 2); // A.2 = AIO3


  bitClear(PORTD, 5); // D.5 = DIO2
  bitClear(PORTC, 1); // A.1 = AIO2
  bitClear(PORTD, 6); // D.6 = DIO3
  bitClear(PORTC, 2); // A.2 = AIO3

The switching times are now dramatically closer together, more like 0.12 µS in fact:


Note that you’re looking at the superposition of both the rising and the falling switching waveforms in this case, as an easy way to see both in one screen shot.

For more information about inductive kickback and protection diodes: there’s an article by Douglas Jones – it’s full of useful information, even though it’s geared towards driving DC motors and stepper motors. The same principles apply when driving the coil in a relay.

So the conclusion seems to be that this specific relay could be driven from 4 I/O pins, without requiring any further circuitry. And since it’s a latching relay, this can easily be done on battery power: it merely takes a 3 ms pulse to make it switch, i.e. about the same amount of energy as sending out one RF12 packet!

  1. Just to be clear — you do have an external diode in parallel with the relay’s windings? I wouldn’t subject the poor AVR’s diodes to this harsh kickback…

    • Not at the moment.

    • The relay winding is 250 Ω, i.e. the current is 10..15 mA. I agree that there must be an inductive kickback, but the currents involved are probably not that huge.

  2. To prevent the two-step pin setting, two options -being an arduino nitwit- come to mind: is it possible with JeeNodes to choose a different set of pins that allow you to set pins concurrently by changing the output state register with a byte rather than per bit? this article seems to address the problem, search “PORTB |= B1100;” Or likewise, can you use your current code, then prior to switching the relay first make the output pins input pins, bitknit the desired new pin levels, then turn the four pins into output pins with one instruction?

    • It would change the problem, not solve it: setting the pins as outputs at exactly the same time is not possible for AIO pins and DIO pins – the AIO pins are located on ATmega PORTC, the DIO pins on PORTD.

  3. Could you set pins to input, set desired bit pattern, then make them output in one instruction? Likewise, could you set all pins in one instruction? The arduino portmanipulation page suggests such near the text PORTB |= B1100. But JeeNodes maybe have different pins available?

    • The solution will be to put both sides on the same ATmega port, i.e. DIO2 in parallel with DIO3, and AIO2 in parallel with AIO3. Then I can use straight bit manipulation to set both pins at the same time.

  4. @william, unfortunately, the standard diode technique does not work here – it is a single winding, pulsed in one direction to set and then the opposite direction to unset. The alternative is to use back to back zeners (or the hobbyist’s economical substitute, back to back red LED’s).

    • What I did try was a bridge rectifier across both I/O groups. The forward voltage of the bridge was slightly lower than the ones I measured in the chip, but it didn’t seem to affect the output waveform.

  5. @jcw, forgive my naievety, but what would be the effect of using pairings AIO2+AI03 and DIO2+DI03 instead AI02+DI02 etc, I can at least understand that one switching cycle will be slower than the other, but would it not improve timings? I dont have a scope, and am a beginner!

    EDIT: I see you sort of answered the question in another reply, but I am more interested in the results of what you would see in the scope, as you identified in your original post.

    • Exactly – that would be the right approach, because then it’s possible to set both pins with a single instruction. I didn’t think it through when I wired up this thing.

  6. No flyback (zener)diode, and shorting of two ports together? I hope you are not using this for an automotive or medical purpose… Why not use something like the TC4424 in your motor plug as a buffer?

    • I know, I know… pretty harsh. I’m just exploring how far one can take this. Impossible to tell how much this will affect the lifetime of the ATmega chip, though.

  7. Keep in mind that an inductor is a device that keep the current flowing through it constant. Therefore, if 15 mA is flowing through the coil just before you turn it off, then 15 mA will go from one grounded side to the other shortly afterwards (until the energy in the coil is spent). So, effecively, the former high side of your switch will have a sufficiently negative voltage that 15mA do enter the coil.

    That voltage is visible as the negative offshoot at the lower right of your combined graph. If this stays below -0.5V, the ATmega won’t be hurt. If not, two Schottky diodes from ground to your output pins should solve the problem.

  8. This ebay sale is for the 5V version of the relay. The data sheet says there’s a 3V version available. That version might be switchable with just one I/O pin.

    • The 3V version has an even lower coil resistance. The 5V relay is switching just fine on 3.3V, though. Well, this unit, anyway – it will no doubt be marginal.

  9. Too bad that you shouldn’t directly switch 230V with this relay.

    The data sheet says you could, but UL approval is only for 110V, for good reason (input and output are too close to each other).

    • I’m willing to try it anyway for light loads, such as a lamp or a charger.

      The other thing you could do, is switch a heavier 230V relay with this one, or the gate of a zero-crossing Triac, for example.

    • @Matthias: What WOULD you want to switch in a modern home? The 30W LED does nice with this switch. And if you need to switch heavier appliances (name one, please), why would that be done by a JeeNode? It could be done in a ‘central box’ using an SSR, to which you need 3…32V, which necessitates a power supply for continued operation, which only makes sense when 220V is available anyway, which makes the whole thing a laugh. So this relay has its applications, where low power is required (JeeNode) and available (battery) and needed (LED illumination?) Or… (talk @ jeeday ;-)

  10. @eljonco – I take your point. For switching a heavy load to have meaning, there is power there to be switched, therefore plenty of power to feed the control logic. Apart from the intellectual satisfaction of knowing the control logic is consuming minimal energy, is it worth the trouble?

    For the general case, perhaps not. One application area worth exploring is when the zone has multiple energy sources – decisions about where energy gets routed (priority loads, temporary storage, discard etc) can be made with a net of sensors and a few control points. There is benefit in making the sensor nodes mains-wiring and maintenance free – perhaps also some control points. Of course, there are many ways to kill the cat – this just provides another option.

  11. One example I have of switching mains load, but on battery supply is controlling pumps. In my scenario I would like to (haven’t done this yet), is time duration of a power outage, keep the relay closed for less than 2-3sec outages, that way the if the power comes back on there isn’t to much back pressure of water returning to the pumps, after a couple of session a big volume of water is returning back through the pumps so at 3sec, open the relay so that if the power comes on in the next 3mins (time it takes to empty the pipes) keep the pumps off. Any duration after that close the relay so that when the power comes back on the pumps start.

  12. @Tim: it sounds more you need a set of check valves than a latching relay ;-)

    • @eljonco at first you might think that, how ever in my situation I really dont want check valves for a bunch of other reasons. They reduce flow and I work with low power hi flow pumps. (55000lph at 700W). I actually do need to be able back flush the allowing them to.drain. And even with check valves I plan to do staggered starts after long duration outages, so I need a fair amount of control over the pumps so short duration outage control is a simple.bonus once I start mqnqging pump startup. All thses reasons make sense for me :-) oh and my arduino/jeenode plus some relays is cheaper than multiple 100mm checkvalves :-) Cheers.

Comments are closed.