[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
- [avrdude-dev] Arduino double reset before programming (TIOCM_DTR clear/set swapped?),
spike <=