I have further investigated the problems when running ArduinoISP on leonardo. There are indeed two of them: first is an unintentional auto reset and a second one is a loss of serial data.
The unintentional autoreset is a funny one. The leonardo only autoresets when DTR gets set when the speed at that time is 1200 baud. So normally, avrdude can toggle DTR as much as it wants: as long as the speed is not 1200 baud the leonardo won't reboot.
But guess what happens if you first upload the ArduinoISP sketch to the leonardo:
- The ide resets the leonardo by "touching" the serial port: it sets DTR when the speed is 1200 baud.
It does not use avrdude to do this.
- Avrdude downloads the sketch at the baudrate specified in boards.txt. When it is done, avrdude nicely sets the speed back to what it was before: 1200 baud.
Then you decide to burn a bootloader to your target:
3.The ide makes its first call to avrdude. Again, when avrdude is done, just before it closes the port it sets the speed back to what it was: 1200 baud. Closing the port toggles DTR and the leoardo reboots!
- The ide makes its second call to avrdude, but the leonardo is not yet up and you get the 'not in sync' error.
Moreover the behavior is timing dependent: if there is little time between 3. and 4. (a fast pc) it may be that the autoreset is cancelled by the second call to avrdude. (See autoreset cancellation code in CDC.cpp).
I'll issue a change request. A possible solution is that the ide sets the baud rate back to what it was, when it is done resetting the leonardo (or at least sets it to another value than 1200). Otherwise this is a recipe for spurious autoresets.
In mean time there is a simple workaround: after uploading the sketch, briefly open the serial monitor and set the baudrate to a value different from 1200. Close the serial monitor again. Then burn the bootloader to your target.
Loss of serial data. When flashing, avrdude provides 128 bytes in one command. USB provides the data so fast that the device cannot keep up. Changing SERIAL_BUFFER_SIZE to say 150 (in CDC.cpp!), allows you to burn a bootloader. But that is a poor work around. No bytes should be lost even with a buffer of 64 bytes: USB has built in handshaking: if a device cannot accept more data it should send NAK's to the host (the pc) and the host will retry later. The USB controller in the device (leonardo) should do this by itself. I modified the code in CDC.cpp such that it only takes data from the controller's fifo when there is room in its serial buffer. Apparently the USB device controller does the rest.
in CDC.cpp:
void Serial_::accept(void)
{
ring_buffer *buffer = &cdc_rx_buffer;
int i = (unsigned int)(buffer->head+1) % SERIAL_BUFFER_SIZE;
// if we should be storing the received character into the location
// just before the tail (meaning that the head would advance to the
// current location of the tail), we're about to overflow the buffer
// and so we don't write the character or advance the head.
// while we have room to store a byte
while (i != buffer->tail) {
int c = USB_Recv(CDC_RX);
if (c == -1)
break; // no more data, we're done
buffer->buffer[buffer->head] = c;
buffer->head = i;
i = (unsigned int)(buffer->head+1) % SERIAL_BUFFER_SIZE;
}
}
And in USBCore.cpp:
...
#ifdef CDC_ENABLED
USB_Flush(CDC_TX); // Send a tx frame if found
if (USB_Available(CDC_RX)) // Handle received bytes (if any)
Serial.accept();
#endif
...
With these changes in place, ArduinoISP on the leonardo works nicely. Any sketch that reads serial data can benefit from this change (of coarse more testing is needed).
I tried this on kubuntu/linux, with avrdude 5.10 as well as 5.11.