diff --git a/src/avrdude.1 b/src/avrdude.1 index 6b8e197a..e38ac81f 100644 --- a/src/avrdude.1 +++ b/src/avrdude.1 @@ -41,7 +41,7 @@ .Op Fl i Ar delay .Op Fl l, \-logfile Ar logfile .Op Fl n, \-test-memory -.Op Fl O, \-osccal +.Op Fl O, \-osccal .Op Fl P, \-port Ar port .Op Fl r, \-reconnect .Op Fl q, \-quell @@ -607,6 +607,14 @@ or from the configuration file are used. If you need to use a different port, use this option to specify the alternate port name. .Pp +USB-only programmers normally do not need the port option be specified as +they are automatically identified via their vendor and product IDs from +avrdude.conf or .avrduderc. Only when there are multiple programmers of +the same type plugged into the host computer is the -P option needed, see +below. Some -c programmers, however, ignore the -P option altogether, eg, +teensy, ch341a or avrftdi; these cannot distinguish multiple plugged-in +programmers. +.Pp If .Nm has been configured with libserialport support, a serial port can be specified @@ -663,20 +671,38 @@ The match is done after stripping any existing colons from the given serial number, and right-to-left, so only the least significant bytes from the serial number need to be given. .Pp +avrdude -v -P usb:xyz -c jtag2 -p ... 2>&1 | grep ^Found +.Pp +lists all JTAG ICEs +attached to USB, see the section +.Em Example Command Line Invocations +in the detailed pdf documentation. +.Pp As the AVRISP mkII device can only be talked to over USB, the very same method of specifying the port is required there. .Pp -For the USB programmer "AVR-Doper" running in HID mode, the port must +For the USB programmer AVR-Doper running in HID mode, the port must be specified as .Ar avrdoper. Libhidapi support is required on Unix and Mac OS but not on Windows. For more information about AVR-Doper see https://www.obdev.at/products/vusb/avrdoper.html. .Pp -For the USBtinyISP, which is a simplistic device not implementing -serial numbers, multiple devices can be distinguished by their -location in the USB hierarchy. See the respective +For the USBtinyISP, which is a simplistic device not implementing serial +numbers, multiple devices can be distinguished by their location in the +USB hierarchy using -P usb::. +.Pp +For USBasp, multiple devices can also be also distinguished using -P +usb:: or using the serial number -P usb:. +For examples, see the respective .Em Troubleshooting -entry in the detailed documentation for examples. +entry in the detailed pdf documentation. +.Pp +The -c pickit5 programmer allows overriding the product ID with a +hexadecimal number using -P usb:: and the vendor and product +IDs with hexadecimal numbers and using -P usb::. The +form -P usb: requests AVRDUDE select the PICkit5 programmer with +a serial number that ends in (and with vid/pid from the +configuration files). .Pp For the XBee programmer the target MCU is to be programmed wirelessly over a ZigBee mesh using the XBeeBoot bootloader. The ZigBee 64-bit address for the @@ -968,10 +994,13 @@ The .Ar addr and .Ar len -parameters of the dump, read, disasm, write, save and erase commands can be -negative with the same syntax as substring computations in perl or python. -The table below details their meaning with respect to an example memory of size -sz=0x800 (2048 bytes). +parameters of the dump, read, disasm, write, save and erase commands can +be negative with the same syntax as substring computations in perl or +python. The table below defines the effective memory interval +.Ar [start , +.Ar end], +given the memory size +.Ar sz : .Pp .nf addr len Memory interval Comment @@ -982,6 +1011,19 @@ addr len Memory interval Comment sz+addr+len-1] neg neg [sz+addr, sz+len] Combining above two cases any 0 empty set No action +.fi +.Pp +Note that addr must be in the range [-sz, sz-1]. After computing the memory interval +[start, end] as per above table, the effective length end-start + 1 must not be negative; if +the effective length is zero then no action is carried out. End may be beyond the available +memory for the dump, read or disasm commands, in which case the operation wraps around +the memory end, but the effective length is always limited to the memory size. +.Pp +Here some examples for a memory with size sz of 0x800 (2048) bytes: +.Pp +.nf +addr len Memory interval Comment +------------------------------------------------------------------------ 0x700 12 [0x700, 0x70b] Conventional use 1024 -257 [0x400, 0x6ff] Size of memory is 2048 or 0x800 -512 512 [0x600, 0x7ff] Last 512 bytes @@ -989,6 +1031,11 @@ addr len Memory interval Comment 0 49 [0, 48] First 49 bytes 0 -49 [0, 1999] All but the last 48 = |len+1| bytes 0 -1 [0, 0x7ff] All memory without knowing its size + 2046 4 [0x7fe, 0x801] Wrap around for read but error for write + 2046 4096 [0x7fe, 0x17fe] Read wrap around stops at 0x7fd + -1 -1 [0x7ff, 0x7ff] One byte at 0x7ff is addressed + -1 -2 [0x7ff, 0x7fe] No action: effective length is zero + -1 -3 [0x7ff, 0x7fd] Error: effective length is negative .fi .Pp The following commands are implemented for all programmers: @@ -1639,7 +1686,7 @@ to the target. If there is already a valid voltage applied to the VTG Pin, this setting will be ignored. When AVRDUDE detects an external voltage outside of this range, it will terminate the operation. You can disable this check by setting the voltage to 0 V. If an XMEGA part was selected, a requested voltage -above 3.49 V will lead to an abort of operation. +above 3.49 V will lead to an abort of operation. .It Ar hvupdi High-voltage UPDI programming is used to enable a UPDI pin that has previously been set to RESET or GPIO mode. Use -x hvupdi to enable high-voltage UPDI diff --git a/src/avrftdi.c b/src/avrftdi.c index d0cbeccd..61dc4e45 100644 --- a/src/avrftdi.c +++ b/src/avrftdi.c @@ -641,6 +641,10 @@ static int avrftdi_open(PROGRAMMER *pgm, const char *port) { Avrftdi_data *pdata = to_pdata(pgm); + pmsg_debug("%s(\"%s\")\n", __func__, port); + if(!str_eq(port, "usb")) + pmsg_warning("option -P %s ignored\n", port); + // Parameter validation // Use vid/pid in following priority: config, defaults cmd-line is currently not supported diff --git a/src/ch341a.c b/src/ch341a.c index 653ffb1a..b719f5ac 100644 --- a/src/ch341a.c +++ b/src/ch341a.c @@ -201,7 +201,9 @@ static int ch341a_open(PROGRAMMER *pgm, const char *port) { int errorCode = USB_ERROR_NOTFOUND; libusb_device_handle *handle = NULL; - pmsg_trace("ch341a_open(\"%s\")\n", port); + pmsg_debug("%s(\"%s\")\n", __func__, port); + if(!str_eq(port, "usb")) + pmsg_warning("option -P %s ignored\n", port); if(!my.USB_init) { my.USB_init = 1; diff --git a/src/dfu.c b/src/dfu.c index 6bf51a56..f2a0c6fb 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -92,25 +92,26 @@ static char *get_usb_string(usb_dev_handle *dev_handle, int index); struct dfu_dev *dfu_open(const char *port_spec) { struct dfu_dev *dfu; - char *bus_name = NULL; - char *dev_name = NULL; + char *bus_name = NULL, *dev_name = NULL; - /* The following USB device spec parsing code was copied from usbtiny.c. The - * expected format is "usb:BUS:DEV" where BUS and DEV are the bus and device - * names. We stash these away in the dfu_dev structure for the dfu_init() - * function, where we actually open the device. + /* + * The following USB device spec parsing code was copied from usbtiny.c. + * The expected format is "usb::". We stash these + * away in the dfu_dev structure for the dfu_init() function, where we + * actually open the device. */ - if(!str_starts(port_spec, "usb")) { - pmsg_error("invalid port specification %s for USB device\n", port_spec); + pmsg_debug("%s(\"%s\")\n", __func__, port_spec); + + if(!str_starts(port_spec, "usb:") && !str_eq(port_spec, "usb")) { + pmsg_error("invalid -P %s; drop this option or use -P usb::\n", port_spec); return NULL; } if(':' == port_spec[3]) { bus_name = mmt_strdup(port_spec + 3 + 1); - dev_name = strchr(bus_name, ':'); - if(NULL != dev_name) + if((dev_name = strchr(bus_name, ':'))) *dev_name++ = '\0'; } @@ -138,17 +139,19 @@ int dfu_init(struct dfu_dev *dfu, unsigned short vid, unsigned short pid) { struct usb_device *dev; struct usb_bus *bus; - /* At last, we reach out through the USB bus to the part. There are three - * ways to specify the part: by USB address, by USB vendor and product id, - * and by part name. To specify the part by USB address, the user specifies - * a port parameter in the form "usb:BUS:DEV" (see dfu_open()). To specify - * the part by vendor and product, the user must specify a usbvid and usbpid - * in the configuration file. Finally, if the user specifies the part only, - * we use the default vendor and product id. + /* + * At last, we reach out through the USB bus to the part. There are + * three ways to specify the part: by USB address, by USB vendor and + * product id, and by part name. To specify the part by USB address, the + * user specifies a port parameter in the form usb:: + * (see dfu_open()). To specify the part by vendor and product, the user + * must specify a usbvid and usbpid in the configuration file. Finally, + * if the user specifies the part only, we use the default vendor and + * product id. */ if(pid == 0 && dfu->dev_name == NULL) { - pmsg_error("no DFU support for part; specify PID in config or USB address (via -P) to override\n"); + pmsg_error("no DFU support for part; specify in config or USB address via -P usb::\n"); return -1; } @@ -164,10 +167,14 @@ int dfu_init(struct dfu_dev *dfu, unsigned short vid, unsigned short pid) { for(bus = usb_busses; !found && bus != NULL; bus = bus->next) { for(dev = bus->devices; !found && dev != NULL; dev = dev->next) { - if(dfu->bus_name != NULL && !str_eq(bus->dirname, dfu->bus_name)) + if(vid == dev->descriptor.idVendor && pid == dev->descriptor.idProduct) + pmsg_notice("found device with vendorID=0x%04x and productID=0x%04x, busdir:devicefile = %s:%s\n", + vid, pid, bus->dirname, dev->filename); + + if(dfu->bus_name && !str_busdev_eq(bus->dirname, dfu->bus_name)) continue; - if(dfu->dev_name != NULL) { - if(!str_eq(dev->filename, dfu->dev_name)) + if(dfu->dev_name) { + if(!str_busdev_eq(dev->filename, dfu->dev_name)) continue; } else if(vid != dev->descriptor.idVendor) continue; @@ -187,7 +194,7 @@ int dfu_init(struct dfu_dev *dfu, unsigned short vid, unsigned short pid) { return -1; } - pmsg_notice2("found VID=0x%04x PID=0x%04x at %s:%s\n", + pmsg_notice2("using VID=0x%04x PID=0x%04x at %s:%s\n", found->descriptor.idVendor, found->descriptor.idProduct, found->bus->dirname, found->filename); dfu->dev_handle = usb_open(found); @@ -223,14 +230,10 @@ int dfu_init(struct dfu_dev *dfu, unsigned short vid, unsigned short pid) { void dfu_close(struct dfu_dev *dfu) { if(dfu->dev_handle != NULL) usb_close(dfu->dev_handle); - if(dfu->bus_name != NULL) - mmt_free(dfu->bus_name); - if(dfu->manf_str != NULL) - mmt_free(dfu->manf_str); - if(dfu->prod_str != NULL) - mmt_free(dfu->prod_str); - if(dfu->serno_str != NULL) - mmt_free(dfu->serno_str); + mmt_free(dfu->bus_name); + mmt_free(dfu->manf_str); + mmt_free(dfu->prod_str); + mmt_free(dfu->serno_str); } int dfu_getstatus(struct dfu_dev *dfu, struct dfu_status *status) { diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index 520c47ab..c0c37a0e 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -366,7 +366,7 @@ caters for these urboot bootloaders. Owing to its backward compatibility, bootloaders that can be served by the arduino programmer can normally also be served by the urclock programmer. This may require specifying the size of (to AVRDUDE) @emph{unknown} bootloaders in bytes using the @code{-x -bootsize=} option, which is necessary for the urclock programmer to +bootsize=@var{n}} option, which is necessary for the urclock programmer to enable it to protect the bootloader from being overwritten. If an unknown bootloader has EEPROM read/write capability then the option @code{-x eepromrw} informs @code{avrdude -c urclock} of that capability. @@ -637,10 +637,10 @@ two locations: @enumerate @item -@code{/../etc/avrdude.conf} +@code{@var{directory from which application loaded}/../etc/avrdude.conf} @item -@code{/avrdude.conf} +@code{@var{directory from which application loaded}/avrdude.conf} @end enumerate @@ -824,9 +824,17 @@ specification, system-dependent default values @code{default_parallel}, the configuration file are used. If you need to use a different port, use this option to specify the alternate port name. +USB-only programmers normally do not need the port option be specified as +they are automatically identified via their vendor and product IDs from +@code{avrdude.conf} or @code{.avrduderc}. Only when there are multiple +programmers of the same type plugged into the host computer is the +@code{-P} option needed, see below. Some @code{-c} programmers, however, +ignore the @code{-P} option altogether, eg, teensy, ch341a or avrftdi; +these cannot distinguish multiple plugged-in programmers. + If avrdude has been configured with libserialport support, a serial port can be specified using a predefined serial adapter type in -@var{avrdude.conf} or @var{.avrduderc}, e.g., @code{ch340} or +@code{avrdude.conf} or @code{.avrduderc}, e.g., @code{ch340} or @code{ft232r}. If more than one serial adapter of the same type is connected, they can be distinguished by appending a serial number, e.g., @code{ft232r:12345678}. Note that the USB to serial chip has to have a @@ -842,31 +850,41 @@ list of all possible serial adapters known to avrdude use @code{-P ?sa}. Depending on the used shell, @code{?} may need to be quoted as in @code{"?"} or @code{\?}. -For the JTAG ICE mkII, if AVRDUDE has been built with libusb support, -@var{port} may alternatively be specified as -@code{usb}[:@var{serialno}]. In that case, the JTAG ICE mkII will be -looked up on USB. If @var{serialno} is also specified, it will be -matched against the serial number read from any JTAG ICE mkII found on -USB. The match is done after stripping any existing colons from the -given serial number, and right-to-left, so only the least significant -bytes from the serial number need to be given. -For a trick how to find out the serial numbers of all JTAG ICEs +For the JTAG ICE mkII, if AVRDUDE has been built with libusb support, the +port can be specified as @code{usb}[:@var{serialno}]. In that case, the +JTAG ICE mkII will be looked up on USB. If @var{serialno} is also +specified, it will be matched against the serial number read from any JTAG +ICE mkII found on USB. The match is done after stripping any existing +colons from the given serial number, and right-to-left, so only the least +significant bytes from the serial number need to be given. +@code{avrdude -v -P usb:xyz -c jtag2 -p ... 2>&1 | grep ^Found} lists all JTAG ICEs attached to USB, see @ref{Example Command Line Invocations}. As the AVRISP mkII device can only be talked to over USB, the very same method of specifying the port is required there. -For the USB programmer "AVR-Doper" running in HID mode, the port must -be specified as @var{avrdoper}. Libhidapi support is required on Unix -and Mac OS but not on Windows. For more information about AVR-Doper see +For the USB programmer AVR-Doper running in HID mode, the port must be +specified as @code{-P avrdoper}. Libhidapi support is required on Unix and +Mac OS but not on Windows. For more information about AVR-Doper see @url{https://www.obdev.at/products/vusb/avrdoper.html}. -For the USBtinyISP, which is a simplistic device not implementing -serial numbers, multiple devices can be distinguished by their -location in the USB hierarchy. -For USBasp, multiple devices can be distinguished by either USB connection -or serial number. -See the respective @ref{Troubleshooting} entry for examples. +For the USBtinyISP, which is a simplistic device not implementing serial +numbers, multiple devices can be distinguished by their location in the +USB hierarchy using @code{-P usb:@var{busdir}:@var{devicefile}}. + +For USBasp, multiple devices can also be also distinguished using @code{-P +usb:@var{busdir}:@var{devicefile}} or using the serial number @code{-P +usb:@var{serialno}}. The USBasp serial number is matched from the end, so +only the unique least significant bytes are needed. For examples, see the +respective entry in @ref{Troubleshooting}. + +The @code{-c pickit5} programmer allows overriding the product ID with a +hexadecimal number @var{pid} using @code{-P usb::@var{pid}} and the vendor +and product IDs with hexadecimal numbers @var{vid} and @var{pid} using +@code{-P usb:@var{vid}:@var{pid}}. The form @code{-P usb:@var{serialno}} +requests AVRDUDE select the PICkit5 programmer with a serial number that +ends in @var{serialno} (and with @var{vid}/@var{pid} from the +configuration files). For the XBee programmer the target MCU is to be programmed wirelessly over a ZigBee mesh using the XBeeBoot bootloader. The ZigBee 64-bit @@ -877,10 +895,9 @@ directly contactable XBee device associated with the same mesh (with a default baud rate of 9600). This may look similar to: @code{0013a20000000001@/dev/tty.serial}. -For diagnostic purposes, if the target MCU with an XBeeBoot -bootloader is connected directly to the serial port, the -64-bit address field can be omitted. In this mode the -default baud rate will be 19200. +For diagnostic purposes, if the target MCU with an XBeeBoot bootloader is +connected directly to the serial port, the 64-bit address field can be +omitted. In this mode the default baud rate will be 19200. For programmers that attach to a serial port using some kind of higher level protocol (as opposed to bit-bang style programmers), @@ -898,8 +915,7 @@ The port is assumed to be properly configured, for example using a transparent 8-bit data connection without parity at 115200 Baud for a STK500. -Note: The ability to handle IPv6 hostnames and addresses is limited to -Posix systems (by now). +Note: IPv6 hostnames and addresses are limited to Posix systems. @item -r @item --reconnect @@ -1309,8 +1325,8 @@ flash:r:-:I}. Patterns in flash memory are executable and represent benign AVR code, ie, no I/O memory access. Choose a fixed seed for reproducible results. -@item init= -Shortcut for @code{-x init -x seed=} (see below) +@item init=@var{n} +Shortcut for @code{-x init -x seed=@var{n}} (see below) @cindex @code{flash} @item random @@ -1319,10 +1335,10 @@ randomly configured with respect to bootloader, data and code length. Random code in flash will be benign, that is, not accessing I/O memories, SRAM or flash. Choose a fixed seed for reproducible results. -@item random= -Shortcut for @code{-x random -x seed=} +@item random=@var{n} +Shortcut for @code{-x random -x seed=@var{n}} -@item seed= +@item seed=@var{n} Seed random number generator with @var{n}; the default is @code{time(NULL)}. Setting this option with a fixed positive @var{n} will make the random choices reproducible, ie, they will stay the same between @@ -1518,7 +1534,7 @@ The generated on-board analog reference voltage for channel 0 or channel 1 can be changed by specifying a new reference voltage. The current reference voltage can be read by @code{-x varef0} or @code{-x varef1} alone. -@item attempts[=<1..99>] +@item attempts[=@var{1..99}] @var{STK500V1 only} @* Specify how many connection retry attempts to perform before exiting. @@ -1571,7 +1587,7 @@ programmer creates errors during initial sequence. The Arduino programmer type accepts the following extended parameter: @table @code -@item attempts[=<1..99>] +@item attempts[=@var{1..99}] Specify how many connection retry attempts to perform before exiting. Defaults to 10 if not specified. @item noautoreset @@ -1596,10 +1612,10 @@ connected part and bootloader. @cindex @code{eeprom} @item showid Show a unique Urclock ID stored in either flash or EEPROM of the MCU, then exit. -@item id=.. +@item id=@var{E|F}.@var{addr}.@var{len} Historically, the Urclock ID was a six-byte unique little-endian number stored in Urclock boards at EEPROM address 257. The location of this -number can be set by the @code{-x id=..} extended parameter. @code{E} +number can be set by the @code{-x id=@var{E|F}.@var{addr}.@var{len}} extended parameter. @code{E} stands for EEPROM and @code{F} stands for flash. A negative address addr counts from the end of EEPROM and flash, respectively. The length len of the Urclock ID can be between 1 and 8 bytes. @@ -1613,8 +1629,8 @@ programmer stores by default in high flash just under the bootloader; see also @code{-x nometadata}. @item showfilename Show the input filename (or title) of the last flash writing session, then exit. -@item title= -When set, will be used in lieu of the input filename. The maximum +@item title=@var{string} +When set, @var{string} will be used in lieu of the input filename. The maximum string length for the title/filename field is 254 bytes including terminating nul. @item showapp @@ -1637,7 +1653,7 @@ just behind the vector table with the name @code{VBL_ADDITIONAL_VECTOR}. @item showpart Show the part for which the bootloader was compiled, then exit. @cindex @code{flash} -@item bootsize= +@item bootsize=@var{size} Manual override for bootloader size. Urboot bootloaders put the number of used bootloader pages into a table at the top of the bootloader section, i.e., typically top of flash, so the urclock programmer can look up the @@ -1645,7 +1661,7 @@ bootloader size itself. In backward-compatibility mode, when programming via other bootloaders, this option can be used to tell the programmer the size, and therefore the location, of the bootloader. @cindex @code{flash} -@item vectornum= +@item vectornum=@var{n} Manual override for vector number. Urboot bootloaders put the vector number used by a vector bootloader into a table at the top of flash, so this option is normally not needed for urboot bootloaders. However, it is @@ -1711,9 +1727,9 @@ that a @code{-x showall} query on flash prepared with @code{-x nometadata} yields useful results. @item noautoreset Do not toggle RTS/DTR lines on port open to prevent a hardware reset. -@item delay= -Add a ms delay after reset. This can be useful if a board takes a -particularly long time to exit from external reset. can be negative, +@item delay=@var{n} +Add a @var{n} ms delay after reset. This can be useful if a board takes a +particularly long time to exit from external reset. @var{n} can be negative, in which case the default 120 ms delay after issuing reset will be shortened accordingly. @item strict @@ -1750,26 +1766,26 @@ aux or aux2). Otherwise the SPI traffic in one active circuit may interfere with programming the AVR in the other design. @item spifreq=@var{0..7} -@multitable @columnfractions .05 .3 -@item @code{0} @tab 30 kHz (default) -@item @code{1} @tab 125 kHz -@item @code{2} @tab 250 kHz -@item @code{3} @tab 1 MHz -@item @code{4} @tab 2 MHz -@item @code{5} @tab 2.6 MHz -@item @code{6} @tab 4 MHz -@item @code{7} @tab 8 MHz +@multitable @columnfractions 0.05 0.05 0.3 +@item @tab @code{0} @tab 30 kHz (default) +@item @tab @code{1} @tab 125 kHz +@item @tab @code{2} @tab 250 kHz +@item @tab @code{3} @tab 1 MHz +@item @tab @code{4} @tab 2 MHz +@item @tab @code{5} @tab 2.6 MHz +@item @tab @code{6} @tab 4 MHz +@item @tab @code{7} @tab 8 MHz @end multitable @item rawfreq=0..3 Sets the SPI speed and uses the Bus Pirate's binary ``raw-wire'' mode instead of the default binary SPI mode: -@multitable @columnfractions .05 .3 -@item @code{0} @tab 5 kHz -@item @code{1} @tab 50 kHz -@item @code{2} @tab 100 kHz (Firmware v4.2+ only) -@item @code{3} @tab 400 kHz (v4.2+) +@multitable @columnfractions 0.05 0.05 0.7 +@item @tab @code{0} @tab 5 kHz +@item @tab @code{1} @tab 50 kHz +@item @tab @code{2} @tab 100 kHz (Firmware v4.2+ only) +@item @tab @code{3} @tab 400 kHz (v4.2+) @end multitable The only advantage of the ``raw-wire'' mode is that different SPI frequencies @@ -1863,13 +1879,13 @@ device is plugged in. The Wiring programmer type accepts the following extended parameters: @table @code -@item snooze= +@item snooze=@var{n} After performing the port open phase, AVRDUDE will wait/snooze for @var{snooze} milliseconds before continuing to the protocol sync phase. No toggling of DTR/RTS is performed if @var{snooze} > 0. -@item delay= -Add a milliseconds delay after reset. This can be useful if a board -takes a particularly long time to exit from external reset. can be +@item delay=@var{n} +Add a @var{n} milliseconds delay after reset. This can be useful if a board +takes a particularly long time to exit from external reset. @var{n} can be negative, in which case the default 100 ms delay after issuing reset will be shortened accordingly. @end table @@ -1881,14 +1897,14 @@ be shortened accordingly. @item PICkit2 Connection to the PICkit2 programmer: -@multitable @columnfractions .05 .3 -@item @code{(AVR)} @tab @code{(PICkit2)} -@item @code{RST} @tab @code{VPP/MCLR (1) } -@item @code{VDD} @tab @code{VDD Target (2) -- possibly optional if AVR self powered } -@item @code{GND} @tab @code{GND (3) } -@item @code{SDI} @tab @code{PGD (4) } -@item @code{SCLK} @tab @code{PDC (5) } -@item @code{OSI} @tab @code{AUX (6) } +@multitable @columnfractions 0.05 0.15 0.8 +@headitem @tab @strong{AVR} @tab @strong{PICkit2} +@item @tab @code{RST} @tab @code{VPP/MCLR (1)} +@item @tab @code{VDD} @tab @code{VDD Target (2)} -- optional if AVR self powered +@item @tab @code{GND} @tab @code{GND (3)} +@item @tab @code{SDI} @tab @code{PGD (4)} +@item @tab @code{SCLK} @tab @code{PDC (5)} +@item @tab @code{SDO} @tab @code{AUX (6)} @end multitable The PICkit2 programmer type accepts the following extended parameters: @@ -1921,7 +1937,7 @@ Only applicable to TPI devices (ATtiny 4/5/9/10/20/40). The xbee programmer type accepts the following extended parameter: @table @code @item xbeeresetpin=@var{1..7} -Select the XBee pin @code{DIO<1..7>} that is connected to the MCU's +Select the XBee pin @code{DIO@var{1..7}} that is connected to the MCU's @code{/RESET} line. The programmer needs to know which DIO pin to use to reset into the bootloader. The default (3) is the @code{DIO3} pin (XBee pin 17), but some commercial products use a different XBee @@ -2199,16 +2215,16 @@ verbosity level: @smallexample @cartouche -$ avrdude -c jtag2 -p m128 -P usb:xxx -v +$ avrdude -c jtag2 -p m128 -P usb:xyz -v -Using port : usb:xxx +Using port : usb:xyz Using programmer : jtag2fast Programmer baud rate : 115200 -Usbdev_open(): Found JTAG ICE, serno: 00A000001C6B -Usbdev_open(): Found JTAG ICE, serno: 00A000001C3A -Usbdev_open(): Found JTAG ICE, serno: 00A000001C30 -Error: did not find any (matching) USB device usb:xxx (03eb:2103) -Error: unable to open port usb:xxx for programmer jtag2fast +Found JTAG ICE with serno: 00A000001C6B +Found JTAG ICE with serno: 00A000001C3A +Found JTAG ICE with serno: 00A000001C30 +Error: did not find any (matching) USB device usb:xyz (03eb:2103) +Error: unable to open port usb:xyz for programmer jtag2fast Avrdude done. Thank you. @end cartouche @@ -2254,7 +2270,7 @@ Valid commands: For more details about a terminal command cmd type cmd -? Other: - ! : run the shell in a subshell, eg, !ls *.hex + !@var{line} : run the shell @var{line} in a subshell, eg, !ls *.hex # ... : ignore rest of line (eg, used as comments in scripts) Note that not all programmer derivatives support all commands. Flash and @@ -2552,64 +2568,64 @@ recalled and edited. The @var{addr} and @var{len} parameters of the dump, read, disasm, write, save and erase commands can be negative with the same syntax as substring -computations in perl or python. The table below details their meaning with -respect to an example memory of size @code{sz=0x800} (2048 bytes). +computations in perl or python. The table below defines the effective +memory interval [@var{start}, @var{end}], given the memory size @var{sz}: -@multitable {0/negativ}{negativ}{@code{[addr, addr+len-1]}}{End is @code{|len|} bytes below memory size @code{sz}} -@headitem @code{addr} -@tab @code{len} +@multitable {0/positive}{negative}{[@var{sz}+@var{addr}, @var{sz}+@var{addr}+@var{len}-1]}{End is |@var{len}| bytes below mem size @var{sz}} +@headitem @code{@var{addr}} +@tab @code{@var{len}} @tab Memory interval @tab Comment @item 0/positive @tab positive -@tab @code{[addr, addr+len-1]} -@tab Note: @code{len = end-start + 1} +@tab [@var{addr}, @var{addr}+@var{len}-1] +@tab Note: @var{len} = @var{end}-@var{start} + 1 @item 0/positive @tab negative -@tab @code{[addr, sz+len]} -@tab End is @code{|len|} bytes below memory size @code{sz} +@tab [@var{addr}, @var{sz}+@var{len}] +@tab End is |@var{len}| bytes below mem size @var{sz} @item negative @tab positive -@tab @code{[sz+addr, @dots{}]} -@tab Start is @code{|addr|} bytes below memory size +@tab [@var{sz}+@var{addr}, @var{sz}+@var{addr}+@var{len}-1] +@tab Start is |@var{addr}| bytes below mem size @item negative @tab negative -@tab @code{[sz+addr, sz+len]} +@tab [@var{sz}+@var{addr}, @var{sz}+@var{len}] @tab Combining above two cases @item any @tab zero @tab empty set @tab No action -@item @verb{|0x700|} -@tab @verb{| 12|} -@tab @code{[0x700, 0x70b]} -@tab Conventional use -@item @verb{| 1024|} -@tab @verb{| -257|} -@tab @code{[0x400, 0x6ff]} -@tab Size of memory is @code{2048} or @code{0x800} -@item @verb{| -512|} -@tab @verb{| 512|} -@tab @code{[0x600, 0x7ff]} -@tab Last 512 bytes -@item @verb{| -256|} -@tab @verb{| -1|} -@tab @code{[0x700, 0x7ff]} -@tab Last 256 bytes -@item @verb{| 0|} -@tab @verb{| 49|} -@tab @code{[0, 48]} -@tab First 49 bytes -@item @verb{| 0|} -@tab @verb{| -49|} -@tab @code{[0, 1999]} -@tab All but the last @code{48 = |len+1|} bytes -@item @verb{| 0|} -@tab @verb{| -1|} -@tab @code{[0, 0x7ff]} -@tab All memory without knowing its size @end multitable +@noindent +Note that @var{addr} must be in the range [-@var{sz}, @var{sz}-1]. After +computing the memory interval [@var{start}, @var{end}] as per above table, +the @emph{effective} length @var{end}-@var{start} + 1 must not be +negative; if the effective length is zero then no action is carried out. +@var{end} may be beyond the available memory for the dump, read or disasm +commands, in which case the operation wraps around the memory end, but the +effective length is always limited to the memory size. + +Here some examples for a memory with size @var{sz} of 0x800 (2048) bytes: + +@multitable {0/positive}{negative}{Memory interval}{Wrap around for read but error for write} +@headitem @code{@var{addr}} @tab @code{@var{len}} @tab Memory interval @tab Comment +@item 0x700 @tab 12 @tab [0x700, 0x70b] @tab Conventional use +@item 1024 @tab -257 @tab [0x400, 0x6ff] @tab 0x6ff = 2048-257 +@item -512 @tab 512 @tab [0x600, 0x7ff] @tab Last 512 bytes +@item -256 @tab -1 @tab [0x700, 0x7ff] @tab Last 256 bytes +@item 0 @tab 49 @tab [0, 48] @tab First 49 bytes +@item 0 @tab -49 @tab [0, 1999] @tab All but the last 48 = |@var{len}+1| bytes +@item 0 @tab -1 @tab [0, 0x7ff] @tab All memory without knowing its size +@item 2046 @tab 4 @tab [0x7fe, 0x801] @tab Wrap around for read but error for write +@item 2046 @tab 4096 @tab [0x7fe, 0x17fe] @tab Read wrap around stops at 0x7fd +@item -1 @tab -1 @tab [0x7ff, 0x7ff] @tab One byte at 0x7ff is addressed +@item -1 @tab -2 @tab [0x7ff, 0x7fe] @tab No action: effective length is zero +@item -1 @tab -3 @tab [0x7ff, 0x7fd] @tab Error: effective length is negative +@end multitable + +@page @noindent The following commands are implemented for all programmers: @@ -2793,62 +2809,62 @@ access, depending on the programmer, might also have flash and EEPROM directly accessed without cache. Items @var{data} can have the following formats: -@multitable @columnfractions .32 .42 .20 -@item @strong{Type} +@multitable { }{Hexadecimal integer}{@code{C:/My\ projects/blink.hex}}{1, 2, 4 or 8} +@headitem @tab @strong{Type} @tab @strong{Example} @tab @strong{Size (bytes)} @c -@item String +@item @tab String @tab @code{"Hello, world\n"} @tab varying @c -@item File +@item @tab File @tab @code{C:/My\ projects/blink.hex} @tab varying @c -@item File with format +@item @tab File with format @tab @code{blink.hex:i} @tab varying @c -@item Character +@item @tab Character @tab @code{'A'} @tab 1 @c -@item Binary integer +@item @tab Binary integer @tab @code{0b101010} -@tab 1, 2, 4, or 8 +@tab 1, 2, 4 or 8 @c -@item Octal integer +@item @tab Octal integer @tab @code{012345} -@tab 1, 2, 4, or 8 +@tab 1, 2, 4 or 8 @c -@item Decimal integer +@item @tab Decimal integer @tab @code{12345} -@tab 1, 2, 4, or 8 +@tab 1, 2, 4 or 8 @c -@item Hexadecimal integer +@item @tab Hexadecimal integer @tab @code{0x12345} -@tab 1, 2, 4, or 8 +@tab 1, 2, 4 or 8 @c -@item Decimal float +@item @tab Decimal float @tab @code{3.1415926} @tab 4 @c -@item Hexadecimal float +@item @tab Hexadecimal float @tab @code{0xA.8p2} @tab 4 @c -@item Decimal double +@item @tab Decimal double @tab @code{3.141592653589793D} @tab 8 @c -@item Hexadecimal double +@item @tab Hexadecimal double @tab @code{0xA.8p2D} @tab 8 @c @end multitable -@var{data} +@var{Data} can be binary, octal, decimal or hexadecimal integers, floating point numbers or C-style strings and characters. If nothing matches, @code{data} will be interpreted as a name of a file containing data, which will be @@ -2868,14 +2884,14 @@ work (in contrast to @code{-U} operations). For integers, an optional case-insensitive suffix specifies the data size: -@multitable {@code{H} or @code{S}}{8 bytes (64 bits) } -@item @code{LL} +@multitable { }{@code{H} or @code{S}}{8 bytes (64 bits) } +@item @tab @code{LL} @tab 8 bytes (64 bits) -@item @code{L} +@item @tab @code{L} @tab 4 bytes (32 bits) -@item @code{H} or @code{S} +@item @tab @code{H} or @code{S} @tab 2 bytes (16 bits) -@item @code{HH} +@item @tab @code{HH} @tab 1 byte (8 bits) @end multitable @@ -3122,11 +3138,11 @@ Display the device signature bytes. @cindex Programming mode @cindex Variants of parts Display the current part information, including supported programming modes, -memory and variants tables. Use @var{-m} to only print the memory table, -and @var{-v} to only print the variants table. +memory and variants tables. Use @code{-m} to only print the memory table, +and @code{-v} to only print the variants table. -@item verbose @var{]level]} -@cindex @code{verbose} @var{]level]} +@item verbose @var{[level]} +@cindex @code{verbose} @var{[level]} Change (when @var{level} is provided), or display the verbosity level. The initial verbosity level is controlled by the number of @code{-v} options @@ -3691,7 +3707,7 @@ Assign the default programmer id. Can be overridden using the @option{-c} option. @item default_baudrate = "@var{default-baudrate}"; -Assign the default baudrate value that will be used if the programmer doesn't +Assign the default baudrate value that will be used if the programmer does not provide its specific @code{baudrate} entry. Can be overridden using the @option{-b} option. @@ -4905,17 +4921,17 @@ support parallel port programming under macOS. The following table lists the default names for a given system. -@multitable @columnfractions .30 .30 .30 -@item @strong{System} +@multitable @columnfractions 0.05 .15 .30 .30 +@item @tab @strong{System} @tab @strong{Default Parallel Port} @tab @strong{Default Serial Port} -@item FreeBSD +@item @tab FreeBSD @tab @code{/dev/ppi0} @tab @code{/dev/cuad0} -@item Linux +@item @tab Linux @tab @code{/dev/parport0} @tab @code{/dev/ttyS0} -@item Solaris +@item @tab Solaris @tab @code{/dev/printers/0} @tab @code{/dev/term/a} @end multitable @@ -5264,9 +5280,7 @@ Solution: This problem seems to appear with certain versions of Cygwin. Specifyi @item Problem: I'm using Linux and my AVR910 programmer is really slow. -Solution (short): @code{setserial @var{port} low_latency} - -Solution (long): +Solution: There are two problems here. First, the system may wait some time before it passes data from the serial port to the program. Under Linux the following command works around this (you may need root privileges for this). @@ -5276,7 +5290,8 @@ command works around this (you may need root privileges for this). Secondly, the serial interface chip may delay the interrupt for some time. This behaviour can be changed by setting the FIFO-threshold to one. Under Linux this can only be done by changing the kernel source in @code{drivers/char/serial.c}. -Search the file for @code{UART_FCR_TRIGGER_8} and replace it with @code{UART_FCR_TRIGGER_1}. Note that overall performance might suffer if there +Search the file for @code{UART_FCR_TRIGGER_8} and replace it with @code{UART_FCR_TRIGGER_1}. +Note that overall performance might suffer if there is high throughput on serial lines. Also note that you are modifying the kernel at your own risk. @@ -5284,33 +5299,32 @@ your own risk. @item Problem: I'm not using Linux and my AVR910 programmer is really slow. -Solutions: The reasons for this are the same as above. +Solution: The reasons for this are the same as above. If you know how to work around this on your OS, please let us know. @cindex @code{eeprom} @item -Problem: Page-mode programming the EEPROM (using the -U option) does +Problem: Page-mode programming the EEPROM using the -U option does not erase EEPROM cells before writing, and thus cannot necessarily overwrite -previous values that are different to 0xff. +non-0xff values. -Solution: None. This is an inherent feature of the way JTAG EEPROM -programming works, and is documented that way in the Atmel AVR -datasheets. -In order to successfully program the EEPROM that way, a prior chip -erase (with the EESAVE fuse unprogrammed) is required. -This also applies to the STK500 and STK600 in high-voltage programming mode. +Solution: This is an inherent feature of how JTAG EEPROM programming +works, and is documented as such in the datasheets. In order to +successfully program the EEPROM, a prior chip erase with the EESAVE fuse +unprogrammed is required. This also applies to the STK500 and STK600 in +high-voltage programming mode. -Programming the EEPROM in the terminal, however, will recognise that the -programmer struggles to write to EEPROM and read the flash, EEPROM and, if -present, bootrow contents, perform a chip erase and then write the -memories back. This happens when flushing the cache or leaving the -terminal and, out of necessity, take some time. +The terminal, however, recognises that the programmer struggles to write +to EEPROM. It then reads flash, EEPROM and, if present, bootrow contents, +performs a chip erase and then writes these memories back. This happens +when flushing the cache or leaving the terminal and takes some time. +EESAVE needs to be unprogrammed for this. @item -Problem: How do I turn off the @var{DWEN} fuse? +Problem: How do I turn off the @code{DWEN} fuse? -Solution: If the @var{DWEN} (debugWIRE enable) fuse is activated, -the @var{/RESET} pin is not functional anymore, so normal ISP +Solution: If the @code{DWEN} (debugWIRE enable) fuse is activated, +the @code{/RESET} pin is not functional anymore, so normal ISP communication cannot be established. There are two options to deactivate that fuse again: high-voltage programming, or getting the JTAG ICE mkII talk debugWIRE, and @@ -5319,9 +5333,9 @@ prepare the target AVR to accept normal ISP communication again. The first option requires a programmer that is capable of high-voltage programming (either serial or parallel, depending on the AVR device), for example the STK500. In high-voltage programming mode, the -@var{/RESET} pin is activated initially using a 12 V pulse (thus the +@code{/RESET} pin is activated initially using a 12 V pulse (thus the name @emph{high voltage}), so the target AVR can subsequently be -reprogrammed, and the @var{DWEN} fuse can be cleared. Typically, this +reprogrammed, and the @code{DWEN} fuse can be cleared. Typically, this operation cannot be performed while the AVR is located in the target circuit though. @@ -5329,58 +5343,61 @@ The second option requires a JTAG ICE mkII that can talk the debugWIRE protocol. The ICE needs to be connected to the target using the JTAG-to-ISP adapter, so the JTAG ICE mkII can be used as a debugWIRE initiator as well as an ISP programmer. AVRDUDE will then be activated -using the @var{jtag2isp} programmer type. The initial ISP +using the @code{jtag2isp} programmer type. The initial ISP communication attempt will fail, but AVRDUDE then tries to initiate a debugWIRE reset. When successful, this will leave the target AVR in a state where it can accept standard ISP communication. The ICE is then signed off (which will make it signing off from the USB as well), so AVRDUDE has to be called again afterwards. This time, standard ISP -communication can work, so the @var{DWEN} fuse can be cleared. - +communication can work, so the @code{DWEN} fuse can be cleared. The pin mapping for the JTAG-to-ISP adapter is: -@multitable @columnfractions .2 .2 -@item @strong{JTAG pin} @tab @strong{ISP pin} -@item 1 @tab 3 -@item 2 @tab 6 -@item 3 @tab 1 -@item 4 @tab 2 -@item 6 @tab 5 -@item 9 @tab 4 +@multitable @columnfractions 0.1 .1 .1 +@item @tab @strong{JTAG} @tab @strong{ISP} +@item @tab 1 @tab 3 +@item @tab 2 @tab 6 +@item @tab 3 @tab 1 +@item @tab 4 @tab 2 +@item @tab 6 @tab 5 +@item @tab 9 @tab 4 @end multitable @item -Problem: Multiple USBasp or USBtinyISP programmers connected simultaneously are not -found. +Problem: Differentiate multiple USBtinyISP (or USBasp) programmers -Solution: The USBtinyISP code supports distinguishing multiple -programmers based on their bus:device connection tuple that describes -their place in the USB hierarchy on a specific host. This tuple can -be added to the @var{-P usb} option, similar to adding a serial number -on other USB-based programmers. - -The actual naming convention for the bus and device names is -operating-system dependent; AVRDUDE will print out what it found -on the bus when running it with (at least) one @var{-v} option. -By specifying a string that cannot match any existing device -(for example, @var{-P usb:xxx}), the scan will list all possible -candidate devices found on the bus. - -Examples: -@example -avrdude -c usbtiny -p atmega8 -P usb:003:025 (Linux) -avrdude -c usbtiny -p atmega8 -P usb:/dev/usb:/dev/ugen1.3 (FreeBSD 8+) -avrdude -c usbtiny -p atmega8 \ - -P usb:bus-0:\\.\libusb0-0001--0x1781-0x0c9f (Windows) -@end example - -For USBasp, the same format for @var{-P usb} can be used to match usb bus/device. Alternatively, -device serial number can be specified as follows (for serial number '1234'). +Solution: The @code{-c usbtiny} programmer distinguishes multiple physical +USBtinyISP devices based on their busdir:devicefile pairs that describe +their place in the USB hierarchy on a specific host. This pair can be +specified in the @code{-P usb:@var{busdir}:@var{devicefile}} option. The +naming convention for the bus and device depends on the operating system. +Examples for Linux, FreeBSD and Windows, respectively: @example -avrdude -c USBasp -p atmega8 -P usb:1234 +$ avrdude -c usbtiny -p atmega8 -P usb:003:025 +$ avrdude -c usbtiny -p atmega8 -P usb:/dev/usb:/dev/ugen1.3 +$ avrdude -c usbtiny -p atmega8 \ + -P 'usb:bus-0:\\?\usb#vid_16c0&pid_05dc#0001#@{a5...ed@}--WinUSB' @end example +The Windows device name contains the backslash file separator, so the +@code{-P} option will need appropriate quoting on the command line, eg, +in bash with single quotes. + +For USBasp the same @code{-P usb:@var{busdir}:@var{devicefile}} as with +USBtiny selects the right device. Alternatively, USBasp can select the +device via its serial number using @code{-P usb:@var{serialno}}. + +Note that @code{avrdude -v -P usb:xyz} will print out suitable programmers +on the bus assuming xyz does not match any device. + +@noindent +@example +$ avrdude -v -Pusb:xyz -c usbasp -p m328p 2>&1 | grep ^Found +Found USBasp with busdir:devicefile = 001:008, serial_number = 0001 +Found USBasp with busdir:devicefile = 001:009, serial_number = 1234 + +$ avrdude -qq -c USBasp -p atmega8 -P usb:34 +@end example @item Problem: I cannot do @dots{} when the target is in debugWIRE mode. @@ -5389,8 +5406,8 @@ Solution: debugWIRE mode imposes several limitations. The debugWIRE protocol is Atmel's proprietary one-wire (plus ground) protocol to allow an in-circuit emulation of the smaller AVR devices, -using the @var{/RESET} line. -DebugWIRE mode is initiated by activating the @var{DWEN} +using the @code{/RESET} line. +DebugWIRE mode is initiated by activating the @code{DWEN} fuse, and then power-cycling the target. While this mode is mainly intended for debugging/emulation, it also offers limited programming capabilities. @@ -5419,19 +5436,19 @@ with the kit, yet I don't have it. Solution: Use the following pin mapping: -@multitable @columnfractions .2 .2 .2 .2 -@item @strong{JTAGICE} @tab @strong{Target} @tab @strong{Squid cab-} @tab @strong{PDI} -@item @strong{mkII probe} @tab @strong{pins} @tab @strong{le colors} @tab @strong{header} -@item 1 (TCK) @tab @tab Black @tab -@item 2 (GND) @tab GND @tab White @tab 6 -@item 3 (TDO) @tab @tab Grey @tab -@item 4 (VTref) @tab VTref @tab Purple @tab 2 -@item 5 (TMS) @tab @tab Blue @tab -@item 6 (nSRST) @tab PDI_CLK @tab Green @tab 5 -@item 7 (N.C.) @tab @tab Yellow @tab -@item 8 (nTRST) @tab @tab Orange @tab -@item 9 (TDI) @tab PDI_DATA @tab Red @tab 1 -@item 10 (GND) @tab @tab Brown @tab +@multitable @columnfractions 0.05 0.2 0.2 0.2 0.2 +@item @tab @strong{JTAG ICE} @tab @strong{Target} @tab @strong{Squid cable} @tab @strong{PDI} +@item @tab @strong{mkII probe} @tab @strong{pins} @tab @strong{colors} @tab @strong{header} +@item @tab 1 (TCK) @tab @tab Black @tab +@item @tab 2 (GND) @tab GND @tab White @tab 6 +@item @tab 3 (TDO) @tab @tab Grey @tab +@item @tab 4 (VTref) @tab VTref @tab Purple @tab 2 +@item @tab 5 (TMS) @tab @tab Blue @tab +@item @tab 6 (nSRST) @tab PDI_CLK @tab Green @tab 5 +@item @tab 7 (N.C.) @tab @tab Yellow @tab +@item @tab 8 (nTRST) @tab @tab Orange @tab +@item @tab 9 (TDI) @tab PDI_DATA @tab Red @tab 1 +@item @tab 10 (GND) @tab @tab Brown @tab @end multitable @item @@ -5440,15 +5457,15 @@ Xmega device through PDI. Solution: Use the 6 pin ISP header on the Dragon and the following pin mapping: -@multitable @columnfractions .2 .2 -@item @strong{Dragon} @tab @strong{Target} -@item @strong{ISP Header} @tab @strong{pins} -@item 1 (SDI) @tab PDI_DATA -@item 2 (VCC) @tab VCC -@item 3 (SCK) @tab -@item 4 (SDO) @tab -@item 5 (RESET) @tab PDI_CLK / RST -@item 6 (GND) @tab GND +@multitable @columnfractions 0.05 0.2 0.3 +@item @tab @strong{Dragon} @tab @strong{Target} +@item @tab @strong{ISP Header} @tab @strong{pins} +@item @tab 1 (SDI) @tab PDI_DATA +@item @tab 2 (VCC) @tab VCC +@item @tab 3 (SCK) @tab +@item @tab 4 (SDO) @tab +@item @tab 5 (RESET) @tab PDI_CLK / RST +@item @tab 6 (GND) @tab GND @end multitable @item @@ -5457,15 +5474,15 @@ ATtiny4/5/9/10 device through TPI. How to connect the pins? Solution: Use the following pin mapping: -@multitable @columnfractions .2 .2 .2 -@item @strong{AVRISP} @tab @strong{Target} @tab @strong{ATtiny} -@item @strong{connector} @tab @strong{pins} @tab @strong{pin #} -@item 1 (SDI) @tab TPIDATA @tab 1 -@item 2 (VTref) @tab Vcc @tab 5 -@item 3 (SCK) @tab TPICLK @tab 3 -@item 4 (SDO) @tab @tab -@item 5 (RESET) @tab /RESET @tab 6 -@item 6 (GND) @tab GND @tab 2 +@multitable @columnfractions 0.05 .2 .2 .2 +@item @tab @strong{AVRISP} @tab @strong{Target} @tab @strong{ATtiny} +@item @tab @strong{connector} @tab @strong{pins} @tab @strong{pin #} +@item @tab 1 (SDI) @tab TPIDATA @tab 1 +@item @tab 2 (VTref) @tab Vcc @tab 5 +@item @tab 3 (SCK) @tab TPICLK @tab 3 +@item @tab 4 (SDO) @tab @tab +@item @tab 5 (RESET) @tab /RESET @tab 6 +@item @tab 6 (GND) @tab GND @tab 2 @end multitable @item @@ -5473,13 +5490,13 @@ Problem: I want to program an ATtiny4/5/9/10 device using a serial/parallel bitbang programmer. How to connect the pins? Solution: Since TPI has only 1 pin for bi-directional data transfer, both -@var{SDI} and @var{SDO} pins should be connected to the @var{TPIDATA} pin +@code{SDI} and @code{SDO} pins should be connected to the @code{TPIDATA} pin on the ATtiny device. -However, a 1K resistor should be placed between the @var{SDO} and @var{TPIDATA}. -The @var{SDI} pin connects to @var{TPIDATA} directly. -The @var{SCK} pin is connected to @var{TPICLK}. +However, a 1K resistor should be placed between the @code{SDO} and @code{TPIDATA}. +The @code{SDI} pin connects to @code{TPIDATA} directly. +The @code{SCK} pin is connected to @code{TPICLK}. -In addition, the @var{Vcc}, @var{/RESET} and @var{GND} pins should +In addition, the @code{Vcc}, @code{/RESET} and @code{GND} pins should be connected to their respective ports on the ATtiny device. @item @@ -5487,7 +5504,7 @@ Problem: How can I use a FTDI FT232R USB-to-Serial device for bitbang programmin Solution: When connecting the FT232 directly to the pins of the target Atmel device, the polarity of the pins defined in the @code{programmer} definition should be -inverted by prefixing a tilde. For example, the @var{dasa} programmer would +inverted by prefixing a tilde. For example, the @code{dasa} programmer would look like this when connected via a FT232R device (notice the tildes in front of pins 7, 4, 3 and 8): @@ -5514,7 +5531,7 @@ Solution: Mind the limited programming supply voltage range of these devices. In-circuit programming through TPI is only guaranteed by the datasheet -at Vcc = 5 V. +at Vcc = 5@w{ }V. @item Problem: My ATxmega@dots{}A1/A2/A3 cannot be programmed through PDI with @@ -5545,7 +5562,7 @@ speed (e.g. through the @code{CLKPR} register), further ISP connection attempts fail. Or a programmer cannot initialize communication with a brand new chip. -Solution: Even though ISP starts with pulling @var{/RESET} low, the +Solution: Even though ISP starts with pulling @code{/RESET} low, the target continues to run at the internal clock speed either as defined by the firmware running before or as set by the factory. Therefore, the ISP clock speed must be reduced appropriately (to less than 1/4 of the @@ -5570,8 +5587,8 @@ erase cycle. AVRDUDE supports the programmers below: the left column lists the programmer's id as used for @code{-c}, whilst the right column contains a -short description and the list of available programming interface(s) in -brackets; see @ref{Programmer Definitions}). There is more detail about +short description and the list of available programming interfaces in +brackets; see @ref{Programmer Definitions}. There is more detail about each programmer in the AVRDUDE configuration file. @multitable @columnfractions .24 .75 diff --git a/src/fileio.c b/src/fileio.c index e0754f6a..c0feeac5 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -1701,6 +1701,12 @@ int segment_normalise(const AVRMEM *mem, Segment *segp) { return -1; } + if(len > 0 && addr+len-1 >= maxsize) { + pmsg_error("segment length %d with starting address 0x%0*x reaches beyond memory end 0x%0*x\n", + segp->len, digits, addr, digits, maxsize-1); + return -1; + } + segp->addr = addr; segp->len = len; diff --git a/src/ft245r.c b/src/ft245r.c index 2cf7eff3..bcc4ad8c 100644 --- a/src/ft245r.c +++ b/src/ft245r.c @@ -811,6 +811,8 @@ static int ft245r_open(PROGRAMMER *pgm, const char *port) { int devnum = -1; char device[9] = ""; + pmsg_debug("%s(\"%s\")\n", __func__, port); + rv = pins_check(pgm, pin_checklist, sizeof(pin_checklist)/sizeof(pin_checklist[0]), true); if(rv) { diff --git a/src/jtagmkII.c b/src/jtagmkII.c index 816faf8d..b72e45ae 100644 --- a/src/jtagmkII.c +++ b/src/jtagmkII.c @@ -1384,7 +1384,7 @@ static int jtagmkII_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) static int jtagmkII_open(PROGRAMMER *pgm, const char *port) { union pinfo pinfo; - pmsg_notice2("jtagmkII_open()\n"); + pmsg_notice2("%s(\"%s\")\n", __func__, port); /* * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon @@ -1434,7 +1434,7 @@ static int jtagmkII_open(PROGRAMMER *pgm, const char *port) { static int jtagmkII_open_dw(PROGRAMMER *pgm, const char *port) { union pinfo pinfo; - pmsg_notice2("jtagmkII_open_dw()\n"); + pmsg_notice2("%s(\"%s\")\n", __func__, port); /* * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon @@ -1484,7 +1484,7 @@ static int jtagmkII_open_dw(PROGRAMMER *pgm, const char *port) { static int jtagmkII_open_pdi(PROGRAMMER *pgm, const char *port) { union pinfo pinfo; - pmsg_notice2("jtagmkII_open_pdi()\n"); + pmsg_notice2("%s(\"%s\")\n", __func__, port); /* * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon @@ -1540,7 +1540,7 @@ static int jtagmkII_open_pdi(PROGRAMMER *pgm, const char *port) { static int jtagmkII_dragon_open(PROGRAMMER *pgm, const char *port) { union pinfo pinfo; - pmsg_notice2("jtagmkII_dragon_open()\n"); + pmsg_notice2("%s(\"%s\")\n", __func__, port); /* * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon @@ -1590,7 +1590,7 @@ static int jtagmkII_dragon_open(PROGRAMMER *pgm, const char *port) { static int jtagmkII_dragon_open_dw(PROGRAMMER *pgm, const char *port) { union pinfo pinfo; - pmsg_notice2("jtagmkII_dragon_open_dw()\n"); + pmsg_notice2("%s(\"%s\")\n", __func__, port); /* * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon @@ -1640,7 +1640,7 @@ static int jtagmkII_dragon_open_dw(PROGRAMMER *pgm, const char *port) { static int jtagmkII_dragon_open_pdi(PROGRAMMER *pgm, const char *port) { union pinfo pinfo; - pmsg_notice2("jtagmkII_dragon_open_pdi()\n"); + pmsg_notice2("%s(\"%s\")\n", __func__, port); /* * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon @@ -3222,7 +3222,7 @@ static int jtagmkII_open32(PROGRAMMER *pgm, const char *port) { unsigned char buf[6], *resp; union pinfo pinfo; - pmsg_notice2("jtagmkII_open32()\n"); + pmsg_notice2("%s(\"%s\")\n", __func__, port); /* * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon diff --git a/src/libavrdude.h b/src/libavrdude.h index fc82f4a6..dd8f9df5 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -1680,6 +1680,7 @@ extern "C" { int str_casematched_by(const char *string, const char *pattern); int str_is_pattern(const char *str); int str_is_in_list(const char *s, const char **l, size_t nl, int (*f)(const char *, const char *)); + int str_busdev_eq(const char *s, const char *t); char *str_sprintf(const char *fmt, ...) #if defined(__GNUC__) // Ask gcc to check whether format and parameters match __attribute__((format(printf, 1, 2))) diff --git a/src/micronucleus.c b/src/micronucleus.c index 7f015c20..4d34de8d 100644 --- a/src/micronucleus.c +++ b/src/micronucleus.c @@ -577,34 +577,26 @@ static int micronucleus_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) { } static int micronucleus_open(PROGRAMMER *pgm, const char *port) { - pmsg_debug("micronucleus_open(\"%s\")\n", port); + pmsg_debug("%s(\"%s\")\n", __func__, port); if(pgm->bitclock) pmsg_warning("-c %s does not support adjustable bitclock speed; ignoring -B\n", pgmid); struct pdata *pdata = &my; - const char *bus_name = NULL; - char *dev_name = NULL; + const char *bus_name = NULL, *dev_name = NULL; - // If no -P was given or '-P usb' was given - if(str_eq(port, "usb")) { - port = NULL; - } else { - // Calculate bus and device names from -P option - if(str_starts(port, "usb") && ':' == port[3]) { - bus_name = port + 4; - dev_name = strchr(bus_name, ':'); - if(dev_name != NULL) { - *dev_name = '\0'; - dev_name++; - } - } - } - - if(port != NULL && dev_name == NULL) { - pmsg_error("invalid -P %s; use -P usb:bus:device\n", port); + if(!str_starts(port, "usb:") && !str_eq(port, "usb")) { + pmsg_error("invalid -P %s; drop this option or use -P usb::\n", port); return -1; } + + // Calculate bus and device names from -P usb:: option if present + if(str_starts(port, "usb:")) { + bus_name = port + 4; + if((dev_name = strchr(bus_name, ':'))) + dev_name++; + } + // Determine VID/PID int vid = pgm->usbvid? pgm->usbvid: MICRONUCLEUS_VID; int pid = MICRONUCLEUS_PID; @@ -652,15 +644,13 @@ static int micronucleus_open(PROGRAMMER *pgm, const char *port) { continue; } - pmsg_notice("found device with Micronucleus V%d.%d, bus:device: %s:%s\n", + pmsg_notice("found device with Micronucleus V%d.%d, busdir:devicefile = %s:%s\n", pdata->major_version, pdata->minor_version, bus->dirname, device->filename); - // If -P was given, match device by device name and bus name - if(port != NULL) { - if(dev_name == NULL || !str_eq(bus->dirname, bus_name) || !str_eq(device->filename, dev_name)) { + // If -P usb:: was given, skip non-matching busdir:devicefile + if(bus_name && dev_name) + if(!str_busdev_eq(bus->dirname, bus_name) || !str_busdev_eq(device->filename, dev_name)) continue; - } - } if(pdata->major_version > MICRONUCLEUS_MAX_MAJOR_VERSION) { pmsg_warning("device with unsupported Micronucleus version V%d.%d\n", @@ -697,6 +687,11 @@ static int micronucleus_open(PROGRAMMER *pgm, const char *port) { break; } + if(bus_name && !dev_name) { // Delayed error message, so found devices are printed with -P usb:xyz + pmsg_error("invalid -P %s; drop -P option or use -P usb::\n", port); + return -1; + } + if(!pdata->usb_handle) { pmsg_error("cannot find device with Micronucleus bootloader (%04X:%04X)\n", vid, pid); return -1; diff --git a/src/pickit2.c b/src/pickit2.c index c75bd421..f0726f41 100644 --- a/src/pickit2.c +++ b/src/pickit2.c @@ -172,6 +172,10 @@ static int pickit2_open(PROGRAMMER *pgm, const char *port) { if((pgm->ispdelay > 0 || pgm->bitclock > 0) && !(pgm->extra_features & HAS_BITCLOCK_ADJ)) pmsg_warning("setting bitclock despite HAS_BITCLOCK_ADJ missing in pgm->extra_features\n"); + pmsg_debug("%s(\"%s\")\n", __func__, port); + if(!str_eq(port, "usb")) + pmsg_warning("option -P %s ignored\n", port); + #ifdef WIN32 my.usb_handle = open_hid(PICKIT2_VID, PICKIT2_PID); diff --git a/src/pickit5.c b/src/pickit5.c index 2f53ece0..d4e08266 100644 --- a/src/pickit5.c +++ b/src/pickit5.c @@ -634,23 +634,24 @@ static int pickit5_upload_data(const PROGRAMMER *pgm, const AVRPART *p, const un static int pickit5_open(PROGRAMMER *pgm, const char *port) { if(!pgm->cookie) // Sanity - return -1; + return LIBAVRDUDE_GENERAL_FAILURE; pmsg_debug("%s(\"%s\")\n", __func__, port); union pinfo pinfo; LNODEID usbpid; - int rv = -1; + int rv = LIBAVRDUDE_GENERAL_FAILURE; + size_t serial_num_len = 0; #if !defined(HAVE_LIBUSB) pmsg_error("need to be compiled with USB or HIDAPI support\n"); - return -1; + return LIBAVRDUDE_GENERAL_FAILURE; #endif - if(!str_starts(port, "usb")) { - pmsg_error("port names must start with usb\n"); - return -1; + if(!str_starts(port, "usb:") && !str_eq(port, "usb")) { + pmsg_error("invalid -P %s; drop -P option or else use -P usb:: or -P usb:\n", port); + return LIBAVRDUDE_GENERAL_FAILURE; } - unsigned int new_vid = 0, new_pid = 0; - char *vidp, *pidp; + unsigned int new_vid = 0, new_pid = 0, setids = 0; + const char *vidp, *pidp; /* * The syntax for usb devices is defined as: @@ -674,11 +675,12 @@ static int pickit5_open(PROGRAMMER *pgm, const char *port) { vidp += 1; pidp = strchr(vidp, ':'); if(pidp != NULL) { + setids = 1; if(vidp != pidp) { // User specified an VID // First: Handle VID input if(sscanf(vidp, "%x", &new_vid) != 1) { - pmsg_error("failed to parse -P VID input %s: unexpected format\n", vidp); - return -1; + pmsg_error("failed to parse -P VID input %s: expected hexadecimal number\n", vidp); + return LIBAVRDUDE_GENERAL_FAILURE; } } else { // VID space empty: default to Microchip new_vid = USB_VENDOR_MICROCHIP; @@ -686,16 +688,16 @@ static int pickit5_open(PROGRAMMER *pgm, const char *port) { // Now handle PID input if(sscanf(pidp + 1, "%x", &new_pid) != 1) { - pmsg_error("failed to parse -P PID input %s: unexpected format\n", pidp+1); - return -1; + pmsg_error("failed to parse -P PID input %s: expected hexadecimal number\n", pidp+1); + return LIBAVRDUDE_GENERAL_FAILURE; } - if((new_vid != 0) && (new_pid != 0)) { - pmsg_notice("overwriting VID:PID to %04x:%04x\n", new_vid, new_pid); - port = "usb"; // Overwrite the string to avoid confusing the libusb - } - } // pidp == NULL means vidp could point to serial number - } // vidp == NULL means just 'usb' + pmsg_notice("overwriting VID:PID to %04x:%04x\n", new_vid, new_pid); + port = "usb"; // Overwrite the string to avoid confusing the libusb + } else { // pidp == NULL means vidp points to serial number + serial_num_len = strlen(vidp); + } + } // vidp == NULL means dropped -P option or -P usb // If the config entry did not specify a USB PID, insert the default one if(lfirst(pgm->usbpid) == NULL) @@ -705,7 +707,7 @@ static int pickit5_open(PROGRAMMER *pgm, const char *port) { // PICkit 5 does not have support for HID, so no need to support it serdev = &usb_serdev; - if(new_pid != 0 && new_vid != 0) { // In case a specific VID/PID was specified + if(setids) { // In case a specific VID/PID was specified pinfo.usbinfo.vid = new_vid; pinfo.usbinfo.pid = new_pid; pinfo.usbinfo.flags = PINFO_FL_SILENT; @@ -795,8 +797,13 @@ static int pickit5_open(PROGRAMMER *pgm, const char *port) { serial_close(&pgm->fd); return LIBAVRDUDE_EXIT; } + if(serial_num_len) { + pmsg_error("no device found matching the specified serial number %s", vidp); + return LIBAVRDUDE_GENERAL_FAILURE; + } + pmsg_error("no device found matching VID 0x%04x and PID list: 0x%04x, 0x%04x, 0x%04x\n", USB_VENDOR_MICROCHIP, - USB_DEVICE_PICKIT5, USB_DEVICE_PICKIT4_PIC_MODE, USB_DEVICE_SNAP_PIC_MODE); + USB_DEVICE_PICKIT5, USB_DEVICE_PICKIT4_PIC_MODE, USB_DEVICE_SNAP_PIC_MODE); imsg_error("nor VID 0x%04x with PID list: 0x%04x, 0x%04x\n", USB_VENDOR_ATMEL, USB_DEVICE_PICKIT4_AVR_MODE, USB_DEVICE_SNAP_AVR_MODE); return LIBAVRDUDE_EXIT; } diff --git a/src/strutil.c b/src/strutil.c index d58f0c28..36c02281 100644 --- a/src/strutil.c +++ b/src/strutil.c @@ -241,6 +241,33 @@ int str_is_in_list(const char *s, const char **l, size_t nl, int (*f)(const char return 0; } +// Is the string a decimal bus/device number that ends in a colon or nul? +static int is_busdev_num(const char *s) { + const char *t = s; + + while(*t >= '0' && *t <= '9') + t++; + + return t > s && (*t == ':' || *t == 0); +} + +// Do the two strings represent the same decimal number or are they the same up to a limiting colon? +int str_busdev_eq(const char *s, const char *t) { + if(is_busdev_num(s) && is_busdev_num(t)) + if(strtoull(s, NULL, 10) == strtoull(t, NULL, 10)) + return 1; + + int len = 0; // Length of strings up to optional colon + while(s[len] && s[len] != ':' && t[len] && t[len] != ':') + len++; + + // Different length means strings are not the same + if((s[len] && s[len] != ':') || (t[len] && t[len] != ':')) + return 0; + + return !strncmp(s, t, len); +} + // Return a mmt_malloc'd string with the sprintf() result char *str_sprintf(const char *fmt, ...) { int size = 0; diff --git a/src/teensy.c b/src/teensy.c index ef6bdc76..f427acc6 100644 --- a/src/teensy.c +++ b/src/teensy.c @@ -305,34 +305,15 @@ static int teensy_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) { } static int teensy_open(PROGRAMMER *pgm, const char *port) { - pmsg_debug("teensy_open(\"%s\")\n", port); + pmsg_debug("%s(\"%s\")\n", __func__, port); + if(!str_eq(port, "usb")) + pmsg_warning("option -P %s ignored\n", port); if(pgm->bitclock) pmsg_warning("-c %s does not support adjustable bitclock speed; ignoring -B\n", pgmid); struct pdata *pdata = &my; - const char *bus_name = NULL; - char *dev_name = NULL; - // If no -P was given or '-P usb' was given - if(str_eq(port, "usb")) { - port = NULL; - } else { - // Calculate bus and device names from -P option - if(str_starts(port, "usb") && ':' == port[3]) { - bus_name = port + 4; - dev_name = strchr(bus_name, ':'); - if(dev_name != NULL) { - *dev_name = '\0'; - dev_name++; - } - } - } - - if(port != NULL && dev_name == NULL) { - pmsg_error("invalid -P %s; use -P usb:bus:device\n", port); - return -1; - } // Determine VID/PID int vid = pgm->usbvid? pgm->usbvid: TEENSY_VID; int pid = TEENSY_PID; diff --git a/src/urclock.c b/src/urclock.c index d5d2d86a..6cd0b1cd 100644 --- a/src/urclock.c +++ b/src/urclock.c @@ -2260,6 +2260,8 @@ static int urclock_open(PROGRAMMER *pgm, const char *port) { pgm->port = port; pinfo.serialinfo.baud = pgm->baudrate? pgm->baudrate: 115200; pinfo.serialinfo.cflags = SERIAL_8N1; + + pmsg_debug("%s(\"%s\")\n", __func__, port); if(serial_open(port, pinfo, &pgm->fd) == -1) return -1; diff --git a/src/usb_libusb.c b/src/usb_libusb.c index 62243ade..94d80452 100644 --- a/src/usb_libusb.c +++ b/src/usb_libusb.c @@ -142,7 +142,7 @@ static int usbdev_open(const char *port, union pinfo pinfo, union filedescriptor fd->usb.wep = 0x02; } - pmsg_notice("%s(): found %s, serno: %s\n", __func__, product, string); + pmsg_notice("found %s with serno = %s\n", product, string); if(*serno) { /* * See if the serial number requested by the user matches what we diff --git a/src/usbasp.c b/src/usbasp.c index 86e01772..4f8e74e9 100644 --- a/src/usbasp.c +++ b/src/usbasp.c @@ -418,22 +418,18 @@ static int usbasp_transmit(const PROGRAMMER *pgm, return nbytes; } -static int check_for_port_argument_match(const char *port, char *bus, char *device, char *serial_num) { +static int check_for_port_argument_match(const char *port, const char *bus, + const char *device, const char *serial_num) { - pmsg_debug("%s(): found USBasp, bus:device: %s:%s, serial_number: %s\n", __func__, bus, device, serial_num); - const size_t usb_len = strlen("usb"); + pmsg_notice("found USBasp with busdir:devicefile = %s:%s, serial_number = %s\n", bus, device, serial_num); - if(str_starts(port, "usb") && ':' == port[usb_len]) { - port += usb_len + 1; - char *colon_pointer = strchr(port, ':'); + if(str_starts(port, "usb:")) { + port += 4; + char *dev_name = strchr(port, ':'); + + if(dev_name) // Compare with busdir:devicefile + return str_busdev_eq(port, bus) && str_busdev_eq(dev_name+1, device); - if(colon_pointer) { - // Value contains ':' character. Compare with bus/device. - if(strncmp(port, bus, colon_pointer - port)) - return 0; - port = colon_pointer + 1; - return str_eq(port, device); - } // Serial number case return *port && str_ends(serial_num, port); } @@ -481,7 +477,7 @@ static int usbOpenDevice(const PROGRAMMER *pgm, libusb_device_handle **device, i continue; } errorCode = 0; - // Do the names match? if vendorName not given ignore it (any vendor matches) + // Do the names match? If vendorName not given ignore it (any vendor matches) r = libusb_get_string_descriptor_ascii(handle, descriptor.iManufacturer & 0xff, (unsigned char *) string, sizeof(string)); if(r < 0) { @@ -492,7 +488,7 @@ static int usbOpenDevice(const PROGRAMMER *pgm, libusb_device_handle **device, i } } else { pmsg_notice2("seen device from vendor >%s<\n", string); - if((vendorName != NULL) && (vendorName[0] != 0) && !str_eq(string, vendorName)) + if(vendorName && vendorName[0] && !str_eq(string, vendorName)) errorCode = USB_ERROR_NOTFOUND; } // If productName not given ignore it (any product matches) @@ -510,16 +506,15 @@ static int usbOpenDevice(const PROGRAMMER *pgm, libusb_device_handle **device, i errorCode = USB_ERROR_NOTFOUND; } if(errorCode == 0) { - if(!str_eq(port, "usb")) { + if(!str_eq(port, DEFAULT_USB)) { // -P option given libusb_get_string_descriptor_ascii(handle, descriptor.iSerialNumber, (unsigned char *) string, sizeof(string)); - char bus_num[21]; - sprintf(bus_num, "%d", libusb_get_bus_number(dev)); - char dev_addr[21]; + char bus_num[21], dev_addr[21]; + sprintf(bus_num, "%03d", libusb_get_bus_number(dev)); + sprintf(dev_addr, "%03d", libusb_get_device_address(dev)); - sprintf(dev_addr, "%d", libusb_get_device_address(dev)); if(!check_for_port_argument_match(port, bus_num, dev_addr, string)) errorCode = USB_ERROR_NOTFOUND; } @@ -620,11 +615,16 @@ static int usbOpenDevice(const PROGRAMMER *pgm, usb_dev_handle **device, int ven // Interface prog static int usbasp_open(PROGRAMMER *pgm, const char *port) { - pmsg_debug("usbasp_open(\"%s\")\n", port); + pmsg_debug("%s(\"%s\")\n", __func__, port); if(pgm->bitclock && !(pgm->extra_features & HAS_BITCLOCK_ADJ)) pmsg_warning("setting bitclock despite HAS_BITCLOCK_ADJ missing in pgm->extra_features\n"); + if(!str_starts(port, "usb:") && !str_eq(port, "usb")) { + pmsg_error("invalid -P %s; drop -P option or else use -P usb:: or -P usb:\n", port); + return -1; + } + // usb_init will be done in usbOpenDevice LNODEID usbpid = lfirst(pgm->usbpid); int pid, vid; @@ -644,12 +644,11 @@ static int usbasp_open(PROGRAMMER *pgm, const char *port) { USBASP_OLD_PID, "USBasp", port) == 0) { cx->usb_access_error = 0; - // Found USBasp with old IDs - pmsg_error("found USB device USBasp with old VID/PID; please update firmware of USBasp\n"); + pmsg_error("found USBasp with old VID/PID; please update its firmware\n"); return 0; } /* - * original USBasp is specified in config file, so no need to check it + * Original USBasp is specified in config file, so no need to check it * again here; no alternative found => fall through to generic error * message */ diff --git a/src/usbtiny.c b/src/usbtiny.c index 3b28e058..88f15831 100644 --- a/src/usbtiny.c +++ b/src/usbtiny.c @@ -279,26 +279,24 @@ static int usbtiny_avr_op(const PROGRAMMER *pgm, const AVRPART *p, int op, unsig // Find a device with the correct VID/PID match for USBtiny -static int usbtiny_open(PROGRAMMER *pgm, const char *name) { +static int usbtiny_open(PROGRAMMER *pgm, const char *port) { struct usb_bus *bus; struct usb_device *dev = 0; - const char *bus_name = NULL; - char *dev_name = NULL; + const char *bus_name = NULL, *dev_name = NULL; int vid, pid; - // If no -P was given or '-P usb' was given - if(str_eq(name, "usb")) - name = NULL; - else { - // Calculate bus and device names from -P option - const size_t usb_len = strlen("usb"); + pmsg_debug("%s(\"%s\")\n", __func__, port); - if(str_starts(name, "usb") && ':' == name[usb_len]) { - bus_name = name + usb_len + 1; - dev_name = strchr(bus_name, ':'); - if(NULL != dev_name) - *dev_name++ = '\0'; - } + if(!str_starts(port, "usb:") && !str_eq(port, "usb")) { + pmsg_error("invalid -P %s; drop this option or use -P usb::\n", port); + return -1; + } + + // Calculate bus and device names from -P usb:: option if present + if(str_starts(port, "usb:")) { + bus_name = port + 4; + if((dev_name = strchr(bus_name, ':'))) + dev_name++; } usb_init(); // Initialize the libusb system @@ -322,14 +320,17 @@ static int usbtiny_open(PROGRAMMER *pgm, const char *name) { pid = USBTINY_PRODUCT_DEFAULT; } - // Now we iterate through all the buses and devices + // Iterate through all the buses and devices for(bus = usb_busses; bus; bus = bus->next) { for(dev = bus->devices; dev; dev = dev->next) { if(dev->descriptor.idVendor == vid && dev->descriptor.idProduct == pid) { // Found match? - pmsg_debug("%s(): found USBtinyISP, bus:device: %s:%s\n", __func__, bus->dirname, dev->filename); - // If -P was given, match device by device name and bus name - if(name != NULL && (NULL == dev_name || !str_eq(bus->dirname, bus_name) || !str_eq(dev->filename, dev_name))) - continue; + pmsg_notice("found USBtiny with busdir:devicefile = %s:%s\n", bus->dirname, dev->filename); + + // If -P usb:: was given, skip non-matching busdir:devicefile + if(bus_name && dev_name) + if(!str_busdev_eq(bus->dirname, bus_name) || !str_busdev_eq(dev->filename, dev_name)) + continue; + my.usb_handle = usb_open(dev); // Attempt to connect to device // Wrong permissions or something? @@ -341,10 +342,11 @@ static int usbtiny_open(PROGRAMMER *pgm, const char *name) { } } - if(NULL != name && NULL == dev_name) { - pmsg_error("invalid -P %s; use -P usb:bus:device\n", name); + if(bus_name && !dev_name) { // Delayed error message, so found devices are printed with -P usb:xyz + pmsg_error("invalid -P %s; drop -P option or use -P usb::\n", port); return -1; } + if(!my.usb_handle) { pmsg_error("cannot find USBtiny device (0x%x/0x%x)\n", vid, pid); return -1;