[bug #56584] Arduino double reset before programming (TIOCM_DTR clear/set swapped)

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

[bug #56584] Arduino double reset before programming (TIOCM_DTR clear/set swapped)

Kevin Cuzner-2
URL:
  <https://savannah.nongnu.org/bugs/?56584>

                 Summary: Arduino double reset before programming (TIOCM_DTR
clear/set swapped)
                 Project: AVR Downloader/UploaDEr
            Submitted by: spike
            Submitted on: Sun 07 Jul 2019 03:01:17 AM UTC
                Category: None
                Severity: 3 - Normal
                Priority: 5 - Normal
              Item Group: None
                  Status: None
                 Privacy: Public
             Assigned to: None
         Originator Name: spike
        Originator Email:
             Open/Closed: Open
                 Release: SVN snapshot
         Discussion Lock: Any
     Programmer hardware:
             Device type: arduino

    _______________________________________________________

Details:

Whenever I'm using the Arduino programmer (i.e. -carduino) the device to be
programmed is reset twice, roughly within 250ms before the DTR pin is actually
pulled low and data is pushed out the usb port. I've made some screenshots to
illustrate the point:

On Linux:
https://gist.githubusercontent.com/spike77453/891a1131232420a0937964cc944c3b49/raw/c2c84f56ce8b2f0c35fafec6e495f1216250ae23/DTR_Linux.png
On Windows 7:
https://gist.githubusercontent.com/spike77453/891a1131232420a0937964cc944c3b49/raw/c2c84f56ce8b2f0c35fafec6e495f1216250ae23/DTR_Win7.png

Looking at the source code (arduino.c) there's a comment referring to
unloading the RESET capacitor (which e.g. on the Arduino UNO R3 would be C5),
which would generate a falling edge on the RESET pin and therefore resetting
the microcontroller so the bootloader can do its thing:

  /* Clear DTR and RTS to unload the RESET capacitor
   * (for example in Arduino) */
  serial_set_dtr_rts(&pgm->fd, 0);
  usleep(250*1000);
  /* Set DTR and RTS back to high */
  serial_set_dtr_rts(&pgm->fd, 1);
  usleep(50*1000);

Unfortunately, the code seems to do the opposite, i.e. setting DTR high
instead of low. If one looks into 'ser_posix.c' for example, the relevant
function is 'ser_set_dtr_rts'. Depending on the value of 'is_on' it sets or
clears the TIOCM_DTR and TIOCM_RTS bits:

  if (is_on) {
    /* Set DTR and RTS */
    ctl |= (TIOCM_DTR | TIOCM_RTS);
  }
  else {
    /* Clear DTR and RTS */
    ctl &= ~(TIOCM_DTR | TIOCM_RTS);
  }

This seems to be the wrong way around: DTR (and RTS) are active low as far as
I know, so setting the TIOCM_DTR bit actually pulls the output low. And it
seems to be the reason why the DTR pin is high for roughly 250ms. I would have
expected it to be low for about 250ms to unload the capacitor and generate the
reset edge, as was probably intended by the author/commenter of the code
above.
I've swapped it around
(https://gist.githubusercontent.com/spike77453/891a1131232420a0937964cc944c3b49/raw/c2c84f56ce8b2f0c35fafec6e495f1216250ae23/AVRDude_ClearDTR.patch):

  serial_set_dtr_rts(&pgm->fd, 1);
  usleep(250*1000);
  /* Set DTR and RTS back to high */
  serial_set_dtr_rts(&pgm->fd, 0);

and now the DTR pin seems to behave properly:

On Linux after patch:
https://gist.githubusercontent.com/spike77453/891a1131232420a0937964cc944c3b49/raw/c2c84f56ce8b2f0c35fafec6e495f1216250ae23/DTR_PatchedAVRDude_Linux.png
On Windows 7 after patch:
https://gist.githubusercontent.com/spike77453/891a1131232420a0937964cc944c3b49/raw/c2c84f56ce8b2f0c35fafec6e495f1216250ae23/DTR_PatchedAVRDude_Win7.png

I've tested a couple of devices (m1284p, m32, m328p, t13) and avrdude still
works as expected. Why there are two reset pulses in the first place when
clearing TIOCM_DTR while it's idling high is beyond me. It seems pure
coincidence to me but then again I know very little about the I/O subsystem.
The double reset is not actually a big deal. It seems to work just fine for a
lot of people after all. There seem to be some rare intermittent timeouts on
'regular' Arduinos (pro mini, don't recall exactly) on Windows which might be
just timing related.
But there are a few oddball systems that implement the Arduino 'auto-reset'
circuit, i.e. a series capacitor and a diode across the reset pullup resistor,
but use RTS instead of DTR. That works fine on Linux (it actually generates
the exact same two resets) but fails on Windows. Apparently since there's a
quirk in Windows's usbser.sys which doesn't generate an edge when the pin is
already high on RTS (but does so on DTR). Also: Two resets are just not
necessary




    _______________________________________________________

Reply to this item at:

  <https://savannah.nongnu.org/bugs/?56584>

_______________________________________________
  Message sent via Savannah
  https://savannah.nongnu.org/


_______________________________________________
avrdude-dev mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/avrdude-dev
Reply | Threaded
Open this post in threaded view
|

[bug #56584] Arduino double reset before programming (TIOCM_DTR clear/set swapped)

Kevin Cuzner-2
Follow-up Comment #1, bug #56584 (project avrdude):

Pretty much the same patch was already submitted (along with a really nice
explanation) back in 2011:
https://savannah.nongnu.org/patch/download.php?file_id=23541

Discussion here: https://savannah.nongnu.org/patch/?7559

This should also fix https://savannah.nongnu.org/patch/?9004 which I vaguely
recall hitting at some point myself:

[comment #0 original submission:]
> There seem to be some rare intermittent timeouts on 'regular' Arduinos (pro
mini, don't recall exactly) on Windows

    _______________________________________________________

Reply to this item at:

  <https://savannah.nongnu.org/bugs/?56584>

_______________________________________________
  Message sent via Savannah
  https://savannah.nongnu.org/


_______________________________________________
avrdude-dev mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/avrdude-dev
Reply | Threaded
Open this post in threaded view
|

[bug #56584] Arduino double reset before programming (TIOCM_DTR clear/set swapped)

Kevin Cuzner-2
Follow-up Comment #2, bug #56584 (project avrdude):

Hello.  The existing code in AVRDUDE is correct.  We need to set DTR to 0 for
some time to ensure that the the DTR pin is high and that the capacitor
discharges.  (Both sides of the capacitor will be high after it discharges.)
Then we need to set DTR to 1, which causes a falling edge on the DTR pin,
which sends a low  pulse to the AVR's reset line.  The reset line gradually
rises back to a high level as the capacitor charges.

This code is probably redundant on some operating systems, like macOS, where
DTR line automatically gets set high when you connect to a serial port.  But
it's needed on Windows with usbser.sys, and in general.


    _______________________________________________________

Reply to this item at:

  <https://savannah.nongnu.org/bugs/?56584>

_______________________________________________
  Message sent via Savannah
  https://savannah.nongnu.org/