mirror of
https://github.com/avrdudes/avrdude.git
synced 2026-06-02 09:46:34 +03:00
Merge pull request #2060 from stefanrueger/bus-device
Ignore leading zeros in -P usb:<bus>:<device> numbers and improve `-P` documentation
This commit is contained in:
@@ -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:<busdir>:<devicefile>.
|
||||
.Pp
|
||||
For USBasp, multiple devices can also be also distinguished using -P
|
||||
usb:<busdir>:<devicefile> or using the serial number -P usb:<serialno>.
|
||||
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 <pid> using -P usb::<pid> and the vendor and product
|
||||
IDs with hexadecimal numbers <vid> and <pid> using -P usb:<vid>:<pid>. The
|
||||
form -P usb:<serialno> requests AVRDUDE select the PICkit5 programmer with
|
||||
a serial number that ends in <serialno> (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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
63
src/dfu.c
63
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:<busdir>:<devicefile>". 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:<busdir>:<devicefile>\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:<busdir>:<devicefile>
|
||||
* (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 <pid> in config or USB address via -P usb:<busdir>:<devicefile>\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) {
|
||||
|
||||
@@ -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=<n>} 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{<directory from which application loaded>/../etc/avrdude.conf}
|
||||
@code{@var{directory from which application loaded}/../etc/avrdude.conf}
|
||||
|
||||
@item
|
||||
@code{<directory from which application loaded>/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=<n>
|
||||
Shortcut for @code{-x init -x seed=<n>} (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=<n>
|
||||
Shortcut for @code{-x random -x seed=<n>}
|
||||
@item random=@var{n}
|
||||
Shortcut for @code{-x random -x seed=@var{n}}
|
||||
|
||||
@item seed=<n>
|
||||
@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=<E|F>.<addr>.<len>
|
||||
@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=<E|F>.<addr>.<len>} 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=<string>
|
||||
When set, <string> 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=<size>
|
||||
@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=<n>
|
||||
@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=<n>
|
||||
Add a <n> ms delay after reset. This can be useful if a board takes a
|
||||
particularly long time to exit from external reset. <n> 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=<n>
|
||||
@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=<n>
|
||||
Add a <n> milliseconds delay after reset. This can be useful if a board
|
||||
takes a particularly long time to exit from external reset. <n> 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:
|
||||
!<line> : run the shell <line> 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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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:<busdir>:<devicefile>\n", port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Calculate bus and device names from -P usb:<busdir>:<devicefile> 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:<busdir>:<devicefile> 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:<busdir>:<devicefile>\n", port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!pdata->usb_handle) {
|
||||
pmsg_error("cannot find device with Micronucleus bootloader (%04X:%04X)\n", vid, pid);
|
||||
return -1;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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:<vid>:<pid> or -P usb:<serialno>\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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
25
src/teensy.c
25
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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
47
src/usbasp.c
47
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:<busdir>:<devicefile> or -P usb:<serialno>\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
|
||||
*/
|
||||
|
||||
@@ -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:<busdir>:<devicefile>\n", port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Calculate bus and device names from -P usb:<busdir>:<devicefile> 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:<busdir>:<devicefile> 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:<busdir>:<devicefile>\n", port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!my.usb_handle) {
|
||||
pmsg_error("cannot find USBtiny device (0x%x/0x%x)\n", vid, pid);
|
||||
return -1;
|
||||
|
||||
Reference in New Issue
Block a user