Thursday, February 6, 2014

Zero-wire serial auto-reset for Arduino

Various versions of the Arduino will reset the board by toggling the serial DTR line, a feature called auto-reset.  Since it relies on the DTR line, it won't work with TTL serial adapters that don't break out the DTR line.  After writing my half-duplex serial UART, I thought of using the TTL serial break signal which holds the line at 0V for several ms.  Normal serial communications would also send 0V, but at 57.6kbps, it would never last more than 160us before returning to the idle high voltage state.  So what I needed was a circuit would not reset when the line is low for 160us, but would reset when the line is low for 100ms or more.

This can be done with a simple Resistor-Capacitor or RC circuit.  The time for a capacitor to discharge by 63% is equal to the resistance in ohms times the capacitance in farads.  Picking a common 0.1uF capacitor and a 10kOhm resistor gives an RC time constant of 1ms, high enough above the 160us time to provide a good safety margin.  Another reason for picking those values is that most pro mini boards, including the Baite Pro mini I recently purchased, use those values for the DTR auto-reset feature.  My plan was to make use of the existing components for my auto-reset circuit.  I also needed a way to quickly charge the capacitor, since the idle time between bytes won't be long enough to fully charge the capacitor through the resistor.  A diode serves that purpose, so the whole circuit takes just 3 parts.
The pro mini already has a 0.1uF capacitor in series between the DTR and RST line, so I shorted DTR to GND to make the connection between the capacitor and ground.  I used tweezers to move the tiny chip resistor (actually 11kOhm on the Baite board) from near the button to the space between the RXD and RST pins:

To finish off the circuit, I trimmed the leads on a diode and soldered it between the RXD and RST pins.  I chose to solder it to the reset on the left side of the board to avoid messing up the chip resistor I soldered on the right side.

To test it, I connected the pro mini to a TTL serial adapter, set up putty to open a serial connection, then pressed Ctrl-Break to send a break sequence.  I then saw the quick flashes from optiboot, indicating the board reset.  I also tested serial communications with a small program that echos characters typed, to make sure it wouldn't reset with normal communications.  The ASCII code for '@' is 0x40, so it has 7 zero bits and makes a good test character.  There was no resets while sending regular characters - so far so good.

Having completed the hardware, the final part was the software.  I looked at Avrdude and found that the auto-reset feature is in the arduino_open function of arduino.c.  I generally do PC software development under Linux, so to learn something different I decided to modify the windows version of avrdude to support my break auto-reset.  A quick google search revealed how to send a break sequence, so I modified ser_set_dtr_rts() in ser_win32.c to send a break signal in addition to toggling DTR and RTS:

        if (is_on) {
                EscapeCommFunction(hComPort, SETDTR);
                EscapeCommFunction(hComPort, SETRTS);
                EscapeCommFunction(hComPort, CLRBREAK);
        } else {
                EscapeCommFunction(hComPort, CLRDTR);
                EscapeCommFunction(hComPort, CLRRTS);
                EscapeCommFunction(hComPort, SETBREAK);
        }

Modifying the code was the easy part; building it was going to take more work.  I found a page explaining how to build avrdude with MinGW, and tried to follow the directions.  The current version of libusb-win32 is slightly different.  Instead of usb.h the include file is named lusb0_usb.h.  I was building on a Window7 64-bit machine so I copied bin\ia64\libusb0.sys instead of libusb0_x86.dll to C:\MinGW\bin.  I also had to setup fstab as described here, by copying fstab.sample to fstab.  I thought I'd be ready to build, but when I ran configure I ran into the gcc.exe No Disk bug:

The machine has an internal USB flash memory reader, so rather than open up the computer and unplug it, I disabled "USB mass storage device" in the device manager.

Configure then ran without errors, and gave the following output:
Configuration summary:
----------------------
DON'T HAVE libelf
DO HAVE    libusb
DON'T HAVE libusb_1_0
DON'T HAVE libftdi1
DON'T HAVE libftdi
DO HAVE    libhid
DON'T HAVE pthread
DISABLED   doc
ENABLED    parport
DISABLED   linuxgpio

After compiling, I had a working avrdude.exe that supported my zero-wire auto-reset feature:
$ ./avrdude -c arduino -P com15 -p m328p -U flash:r:m328.bin:r

avrdude.exe: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.01s

avrdude.exe: Device signature = 0x1e950f
avrdude.exe: reading flash memory:

Reading | ################################################## | 100% 4.00s

avrdude.exe: writing output file "m328.bin"

avrdude.exe: safemode: Fuses OK (H:00, E:00, L:00)

avrdude.exe done.  Thank you.

The patch for ser_win32.c and the avrdude.exe are here.  I've submitted the patch to Joerg Wunsch so it can be included in the next release of avrdude.
Edit: Jeorg Wunsch seems to be a patch nazi, so it probably won't get added to the official avrdude while he's in control.

Update:

I ran into a problem when using PD0 for a GPIO.  When the pin goes low for several ms, it resets the AVR like a break.  So writing a 0 to PD0 resets the AVR, causing it to reboot.  I removed the 10k resistor and instead plug a 10k resistor between Rx and Rst when I want to flash the AVR, and remove it after I'm done.

7 comments:

  1. Wow, nicely done! It'd be great if avrdude gets the patch incorporated soon. USB serial adapters based on that nifty FT230X would probably be cheaper and definitely smaller like that one on tindie.com (https://www.tindie.com/products/jimparis/microftx-usb-serial-breakout-1/) This might come in handy for my eeZeeProp Propeller breakout too. Thanks for posting this!

    ReplyDelete
  2. I've forked avrdude and am in the process of pushing it to google code. For now I've posted a win32 avrdude binary here:
    http://162.248.164.251/files/
    The new FT230X modules look nice, but even from China, I've never seen FTDI modules for <$4, while you can get 10 of the PL2303HX modules for < $10 shipped from sellers on aliexpress.

    ReplyDelete
    Replies
    1. Careful about those cheap PL2303HX modules - 99% of those chips are fakes/copies and Prolific started to disable them in their Windows drivers.

      Delete
    2. Jan, you're right about the PL2303HX clones. The Linux kernel driver works fine with them, and for Windows you just need an old driver.
      http://nerdralph.blogspot.ca/2013/09/clone-pl-2303hx-usb-to-ttl-serial.html

      Delete
  3. This comment has been removed by the author.

    ReplyDelete
  4. I can't make this work. Avrdude errormessages. I'm trying to reset an Arduino Nano receiving serial at 115 200 baud from an ESP8266 that runs firmware that makes it a transparent bridge.
    Is the bitrate important for this solution to work?

    ReplyDelete
    Replies
    1. I'd suspect problems with the timing on the break signal. If the ESP8266 doesn't keep Tx low long enough then it won't reset the attached nano. And since the nano has an on-board USB-TTL chip with an auto-reset circuit, the hardware mods would be a bit different than for the pro mini.

      Delete