avrdude-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[avrdude-dev] Arduino double reset before programming (TIOCM_DTR clear/s


From: spike
Subject: [avrdude-dev] Arduino double reset before programming (TIOCM_DTR clear/set swapped?)
Date: Wed, 24 Jan 2018 03:54:44 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.5.2

Hi all,

TLDR: I think I've hit a bug in the Arduino programmer interface (arduino.c) 
but I wanted to make sure I'm not missing the obvious before posting stuff to 
the bugtracker. I'm pretty sure, the TIOCM_DTR bit is cleared when it should be 
set and vice versa.

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

Yes, avrdude still works as expected. At least for the devices I had to hand 
(m1284p, m32, m328p, t13). 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 

Am I missing the obvious here or could this actually be a bug and it was 
intended to pull DTR low for 250ms in the first place? Any input is greatly 
appreciated!

Cheers, Christian




reply via email to

[Prev in Thread] Current Thread [Next in Thread]