How the Arduino Uno programming works
We spent some time trying to debug programming the Arduino Uno over a link that didn’t have the DTR signal available and discovered it’s a problem.
The RTS signal
The Arduino IDE uses the RTS signal to reset the Arduino microcontroller, which causes its bootloader to briefly run. With the bootloader listening for comms the Arduino IDE then starts UART comms with it to transfer the new program which the bootloader then dutifully burns into the microcontrollers flash memory.
Basically what happens when you look on a scope or logic analyser is that the RTS signal goes low, there’s a delay and then UART comms start. The RTS signal stays low the entire time and only returns high when programming completes or times out. If the programming doesn’t work the Arduino IDE seems to retry over and over again, but these retries don’t affect the RTS signal, it remains low. So that original low edge causing the microcontroller to reset is all important.
On an Arduino UNO there is a second ATMEGA microcontroller that acts as a USB to UART interface, but you can replace it with a cable like a FTDI USB to serial cable no problem, the same 3 signals are used (RTS, TXD and RXD) to achieve programming.
Capturing comms on the Arduino for a normal USB cable program
Two 0xF0 bytes appear from the ATMEGA16U2 USB interface microcontroller on the UNO approximately 260mS before it creates the reset pulse.
The Reset pulse is passed via a 100nF capacitor, so is seen at the UNOs ATMEGA328P as a low edge that immediately decays back to high over around 1.5mS.
This is the DTR signal that’s been exerted from the USB to serial link the ATMEGA16U2 is providing.
330mS after the reset pulse 0x30 0x20 bytes appear from the Arduino IDE and the Uno responds with 0x14 0x10. From here the programming process gets underway.
So what if you want to connect just using the TX and RX pins, without the DTR signal?
Those 0xF0 bytes seem damn handy, but they don’t appear from the Arduino IDE. When we replaced the link with a UART serial cable with just TX and RX (no DTR), those bytes don’t appear. They are presumably created by the ATMEGA16U2 in the UNO. So we have to ignore them.
What you are left with is trying to generate the reset pulse from the 0x30 0x20 bytes. In theory this could be possible by using a new microcontroller you add to see when they appear and then generate them again when the Arduino IDE retries comms (11 secs after they are first seen and then every 10 secs for a minute after which the IDE aborts). We tried a simple hit the reset button 7-9.5 secs after when we saw them on the scope approach and couldn’t get it to work. Not sure why. The bootloader can’t have some special timing test on the reset pin, all it can know is that it has been started up after the reset pin was applied. So, why that wouldn’t work…not sure. We gave up but its presumably solvable by spending a bit more effort on the problem. However, you’re adding another microcontroller to the mix which is not ideal.
Another approach could be to sample the RX pin in your application code and cause a reset to the bootloader say 9 secs after seeing that first 0x30 byte appear. The issues with this are 1) it relies on your code working (if you upload duff code that crases your program you’ll have to get a cable out to reprogram the Arduino, and 2) there doesn’t seem to be a nice jump to bootloader call you can make from the Arduino API. You’re into the world of figuring out what bootloader your Arduino is running and hacky code to get it to jump to the right place in it after it’s tested to see if a reset pin reset has occurred (so the bootloader actually runs). Wasn’t for us on this project so we abandoned this without trying it.