Use -xmode to switch PICkit4 and SNAP application modes (#1596)

* Use libusb to switch a PICkit4 or SNAP to AVR mode

* Fix case

* implement -xmode=pic
Thanks Wireshark

* Print PIC switch info messages

* Fix typo

* Rename SNAP and PICkit4 USB PID

* Make it possible to enter avr mode even when the tool is in bootloader/recovery mode

* Add -xmode to docs

* Tweak grammar

* Add -xmode support for pickit4_isp and snap_isp
still need to figure out how to actually trigger the mode switch form stk500v2.c

* Don't print "unable to open port" error on pgm->open softfail

* Add const

* Simplify SNAP/PICkit4 mode switching code

* Formatting

* Add extra argument to jtag3_open_common
This makes it possible to switch SNAP/PK4 modes from stk500v2.c as well, using pickit4_isp and snap_isp

* Improve extended parameter parsing

* Improve error message

* Improve extended parameter parsing

* Immediately exit after a mode switch

* Remove unnecessary line

* Add missing serial_close

* Remove unnecessary else

* Minor code tweaks

* Update docs

* Formatting

* Improve external parameter parsing and error handling

* Remove unused parameter
This commit is contained in:
Hans
2024-01-03 14:02:24 +01:00
committed by GitHub
parent 06156d9c33
commit a245cd5370
9 changed files with 259 additions and 107 deletions

View File

@@ -1519,7 +1519,7 @@ bits after the target AVR, respectively.
Each AVR unit within the chain shifts by 4 bits.
Other JTAG units might require a different bit shift count.
.It Ar hvupdi
.Nm Power Debugger and Pickit 4 only
.Nm Power Debugger and PICkit 4 only
.sp 0.5
High-voltage UPDI programming is used to enable a UPDI pin that has previously
been set to RESET or GPIO mode. Use
@@ -1535,6 +1535,21 @@ alone.
.It Ar help
Show help menu and exit.
.El
.It Ar PICkit 4
.It Ar MPLAB SNAP
.Bl -tag -offset indent -width indent
.It Ar mode=avr,pic
Switch programmer to AVR or PIC mode, then exit: the PICkit 4 and MPLAB SNAP
programmer can only be utilised by
.Nm
when in AVR mode. Use
.Ar -xmode=avr
for switching to AVR mode, or
.Ar -xmode=pic
for switching to PIC mode.
.It Ar help
Show help menu and exit.
.El
.It Ar Xplained Mini (ISP and UPDI)
.Bl -tag -offset indent -width indent
.It Ar suffer=VALUE, suffer

View File

@@ -1146,6 +1146,22 @@ The current set-voltage can be read by @samp{-xvtarg} alone.
Show help menu and exit.
@end table
@cindex Option @code{-x} PICkit 4
@cindex Option @code{-x} MPLAB SNAP
@item PICkit 4
@item MPLAB SNAP
The PICkit 4 and MPLAB SNAP programmers accept the following extended parameters:
@table @code
@item @samp{mode=avr,pic}
Switch programmer to AVR or PIC mode, then exit: the PICkit 4 and MPLAB SNAP
programmer can only be utilised by Avrdude when in AVR mode.
Use @samp{-xmode=avr} for switching to AVR mode, or @samp{-xmode=pic}
for switching to PIC mode.
@item @samp{help}
Show help menu and exit.
@end table
@cindex Option @code{-x} Xplained Mini
@item Xplained Mini

View File

@@ -89,6 +89,9 @@ struct pdata
bool vtarg_set;
double vtarg_data;
/* Flag for PICkit4/SNAP mode switching */
int pk4_snap_mode;
/* SIB string cache */
char sib_string[AVR_SIBLEN];
@@ -1500,15 +1503,15 @@ static int jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
const char *extended_param;
int rv = 0;
for (ln = lfirst(extparms); ln; ln = lnext(ln)) {
for(ln = lfirst(extparms); ln; ln = lnext(ln)) {
extended_param = ldata(ln);
if (str_starts(extended_param, "jtagchain=") && (pgm->prog_modes & (PM_JTAG | PM_XMEGAJTAG | PM_AVR32JTAG))) {
if(str_starts(extended_param, "jtagchain=") && (pgm->prog_modes & (PM_JTAG | PM_XMEGAJTAG | PM_AVR32JTAG))) {
unsigned int ub, ua, bb, ba;
if (sscanf(extended_param, "jtagchain=%u,%u,%u,%u", &ub, &ua, &bb, &ba) != 4) {
pmsg_error("invalid JTAG chain '%s'\n", extended_param);
if(sscanf(extended_param, "jtagchain=%u,%u,%u,%u", &ub, &ua, &bb, &ba) != 4) {
pmsg_error("invalid JTAG chain %s\n", extended_param);
rv = -1;
continue;
break;
}
pmsg_notice2("jtag3_parseextparms(): JTAG chain parsed as:\n");
imsg_notice2("%u units before, %u units after, %u bits before, %u bits after\n",
@@ -1517,11 +1520,25 @@ static int jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
PDATA(pgm)->jtagchain[1] = ua;
PDATA(pgm)->jtagchain[2] = bb;
PDATA(pgm)->jtagchain[3] = ba;
continue;
}
else if ((str_eq(extended_param, "hvupdi")) && (lsize(pgm->hvupdi_support) > 1)) {
// HVUPDI
// All programmers that supports UPDI programming should have hvupdi_support=1 in avrdude.conf
// Type 0: 12V pulse on UPDI pin
// Type 1: No HV UPDI
// Type 2: 12V pulse on RESET pin
if(str_starts(extended_param, "hvupdi")) {
if(lsize(pgm->hvupdi_support) < 1) {
pmsg_error("programmer does not support high voltage UPDI programming\n");
rv = -1;
break;
}
if(!str_eq(extended_param, "hvupdi")) {
pmsg_error("invalid -xhvupdi value %s. Use -xhvupdi\n", extended_param);
rv = -1;
break;
}
PDATA(pgm)->use_hvupdi = true;
continue;
}
@@ -1532,12 +1549,12 @@ static int jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
// Bit 2 EOF: Agressive power-down, sleep after 5 seconds if no USB enumeration when set to 0
// Bit 1 LOWP: forces running at 1 MHz when bit set to 0
// Bit 0 FUSE: Fuses are safe-masked when bit sent to 1 Fuses are unprotected when set to 0
else if (str_starts(extended_param, "suffer") ) {
if(str_starts(extended_param, "suffer")) {
if(pgm->extra_features & HAS_SUFFER) {
// Set SUFFER value
if (str_starts(extended_param, "suffer=")) {
if (sscanf(extended_param, "suffer=%hhi", PDATA(pgm)->suffer_data+1) < 1) {
pmsg_error("invalid -xsuffer=<value> '%s'\n", extended_param);
if(str_starts(extended_param, "suffer=")) {
if(sscanf(extended_param, "suffer=%hhi", PDATA(pgm)->suffer_data+1) < 1) {
pmsg_error("invalid -xsuffer=<value> %s\n", extended_param);
rv = -1;
break;
}
@@ -1547,42 +1564,52 @@ static int jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
PDATA(pgm)->suffer_data[1]);
}
PDATA(pgm)->suffer_set = true;
continue;
}
// Get SUFFER value
else
if(str_eq(extended_param, "suffer")) {
PDATA(pgm)->suffer_get = true;
continue;
continue;
}
pmsg_error("invalid suffer setting %s. Use -xsuffer or -xsuffer=<arg>\n", extended_param);
rv = -1;
break;
}
}
else if (str_starts(extended_param, "vtarg_switch") ) {
if(str_starts(extended_param, "vtarg_switch")) {
if(pgm->extra_features & HAS_VTARG_SWITCH) {
// Set Vtarget switch value
if (str_starts(extended_param, "vtarg_switch=")) {
if(str_starts(extended_param, "vtarg_switch=")) {
int sscanf_success = sscanf(extended_param, "vtarg_switch=%hhi", PDATA(pgm)->vtarg_switch_data+1);
if (sscanf_success < 1 || PDATA(pgm)->vtarg_switch_data[1] > 1) {
pmsg_error("invalid vtarg_switch value '%s'\n", extended_param);
if(sscanf_success < 1 || PDATA(pgm)->vtarg_switch_data[1] > 1) {
pmsg_error("invalid vtarg_switch value %s\n", extended_param);
rv = -1;
break;
}
PDATA(pgm)->vtarg_switch_set = true;
continue;
}
// Get Vtarget switch value
else
if(str_eq(extended_param, "vtarg_switch")) {
PDATA(pgm)->vtarg_switch_get = true;
continue;
continue;
}
pmsg_error("invalid vtarg_switch setting %s. Use -xvtarg_switch or -xvtarg_switch=<0..1>\n", extended_param);
rv = -1;
break;
}
}
else if (str_starts(extended_param, "vtarg")) {
if (pgm->extra_features & HAS_VTARG_ADJ) {
if(str_starts(extended_param, "vtarg")) {
if(pgm->extra_features & HAS_VTARG_ADJ) {
// Set target voltage
if (str_starts(extended_param, "vtarg=") ) {
if(str_starts(extended_param, "vtarg=") ) {
double vtarg_set_val = 0;
int sscanf_success = sscanf(extended_param, "vtarg=%lf", &vtarg_set_val);
PDATA(pgm)->vtarg_data = (double)((int)(vtarg_set_val * 100 + .5)) / 100;
if (sscanf_success < 1 || vtarg_set_val < 0) {
pmsg_error("invalid vtarg value '%s'\n", extended_param);
if(sscanf_success < 1 || vtarg_set_val < 0) {
pmsg_error("invalid vtarg value %s\n", extended_param);
rv = -1;
break;
}
@@ -1594,37 +1621,61 @@ static int jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
PDATA(pgm)->vtarg_get = true;
continue;
}
pmsg_error("invalid vtarg setting %s. Use -xvtarg or -xvtarg=<arg>\n", extended_param);
rv = -1;
break;
}
}
else if (str_eq(extended_param, "help")) {
if(str_starts(extended_param, "mode") &&
(str_starts(pgmid, "pickit4") || str_starts(pgmid, "snap"))) {
// Flag a switch to AVR mode
if(str_caseeq(extended_param, "mode=avr")) {
PDATA(pgm)->pk4_snap_mode = PK4_SNAP_MODE_AVR;
continue;
}
// Flag a switch to PIC mode
if(str_caseeq(extended_param, "mode=pic")) {
PDATA(pgm)->pk4_snap_mode = PK4_SNAP_MODE_PIC;
continue;
}
pmsg_error("invalid mode setting %s. Use -xmode=avr or -xmode=pic\n", extended_param);
rv = -1;
break;
}
if(str_eq(extended_param, "help")) {
msg_error("%s -c %s extended options:\n", progname, pgmid);
if (str_eq(pgm->type, "JTAGICE3"))
if(str_eq(pgm->type, "JTAGICE3"))
msg_error(" -xjtagchain=UB,UA,BB,BA Setup the JTAG scan chain order\n");
if (str_eq(pgmid, "powerdebugger_updi") || str_eq(pgmid, "pickit4_updi"))
if(lsize(pgm->hvupdi_support) > 1)
msg_error(" -xhvupdi Enable high-voltage UPDI initialization\n");
if (str_starts(pgmid, "xplainedmini") && !str_eq(pgmid, "xplainedmini_tpi")) {
if(pgm->extra_features & HAS_SUFFER) {
msg_error(" -xsuffer Read SUFFER register value\n");
msg_error(" -xsuffer=<arg> Set SUFFER register value\n");
}
if(pgm->extra_features & HAS_VTARG_SWITCH) {
msg_error(" -xvtarg_switch Read on-board target voltage switch state\n");
msg_error(" -xvtarg_switch=<0..1> Set on-board target voltage switch state\n");
}
if (pgm->extra_features & HAS_VTARG_ADJ) {
if(pgm->extra_features & HAS_VTARG_ADJ) {
msg_error(" -xvtarg Read on-board target supply voltage\n");
msg_error(" -xvtarg=<arg> Set on-board target supply voltage\n");
}
if(str_starts(pgmid, "pickit4") || str_starts(pgmid, "snap"))
msg_error(" -xmode=avr|pic Set programmer to AVR or PIC mode, then exit\n");
msg_error (" -xhelp Show this help menu and exit\n");
exit(0);
}
pmsg_error("invalid extended parameter '%s'\n", extended_param);
pmsg_error("invalid extended parameter %s\n", extended_param);
rv = -1;
}
return rv;
}
int jtag3_open_common(PROGRAMMER *pgm, const char *port) {
int jtag3_open_common(PROGRAMMER *pgm, const char *port, int mode_switch) {
union pinfo pinfo;
LNODEID usbpid;
int rv = -1;
@@ -1639,20 +1690,15 @@ int jtag3_open_common(PROGRAMMER *pgm, const char *port) {
return -1;
}
if (pgm->usbvid)
pinfo.usbinfo.vid = pgm->usbvid;
else
pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
/* If the config entry did not specify a USB PID, insert the default one. */
// If the config entry did not specify a USB PID, insert the default one.
if (lfirst(pgm->usbpid) == NULL)
ladd(pgm->usbpid, (void *)USB_DEVICE_JTAGICE3);
pinfo.usbinfo.vid = pgm->usbvid? pgm->usbvid: USB_VENDOR_ATMEL;
#if defined(HAVE_LIBHIDAPI)
/*
* Try HIDAPI first. LibUSB is more generic, but might then cause
* troubles for HID-class devices in some OSes (like Windows).
*/
// Try HIDAPI first. LibUSB is more generic, but might
// cause trouble for HID-class devices in some OSes
serdev = &usbhid_serdev;
for (usbpid = lfirst(pgm->usbpid); rv < 0 && usbpid != NULL; usbpid = lnext(usbpid)) {
pinfo.usbinfo.flags = PINFO_FL_SILENT;
@@ -1685,44 +1731,51 @@ int jtag3_open_common(PROGRAMMER *pgm, const char *port) {
}
#endif
if (rv < 0) {
// Check if SNAP or PICkit4 is in PIC mode
// Check if SNAP or PICkit4 are in PIC mode
for(LNODEID ln=lfirst(pgm->id); ln; ln=lnext(ln)) {
if (str_starts(ldata(ln), "snap")) {
if (str_starts(ldata(ln), "snap") || str_starts(ldata(ln), "pickit4")) {
bool is_snap_pgm = str_starts(ldata(ln), "snap");
pinfo.usbinfo.vid = USB_VENDOR_MICROCHIP;
pinfo.usbinfo.pid = USB_DEVICE_SNAP_PIC_MODE;
pinfo.usbinfo.pid = is_snap_pgm? USB_DEVICE_SNAP_PIC_MODE: USB_DEVICE_PICKIT4_PIC_MODE;
const int bl_pid = is_snap_pgm? USB_DEVICE_SNAP_PIC_MODE_BL: USB_DEVICE_PICKIT4_PIC_MODE_BL;
const char *pgmstr = is_snap_pgm? "MPLAB SNAP": "PICkit 4";
const unsigned char exit_bl_cmd[] = {0xe6};
const unsigned char enter_avr_mode_cmd[] = {0xf0, 0x01};
const unsigned char reset_cmd[] = {0xed};
int pic_mode = serial_open(port, pinfo, &pgm->fd);
if(pic_mode < 0) {
// Retry with alternative USB PID
pinfo.usbinfo.pid = USB_DEVICE_SNAP_PIC_MODE_ALT;
// Retry with bootloader USB PID
pinfo.usbinfo.pid = bl_pid;
pic_mode = serial_open(port, pinfo, &pgm->fd);
}
if(pic_mode >= 0) {
msg_error("\n");
pmsg_error("MPLAB SNAP in PIC mode detected!\n");
imsg_error("Use MPLAB X or Microchip Studio to switch to AVR mode\n\n");
return -1;
}
} else if(str_starts(ldata(ln), "pickit4")) {
pinfo.usbinfo.vid = USB_VENDOR_MICROCHIP;
pinfo.usbinfo.pid = USB_DEVICE_PICKIT4_PIC_MODE;
int pic_mode = serial_open(port, pinfo, &pgm->fd);
if(pic_mode < 0) {
// Retry with alternative USB PID
pinfo.usbinfo.pid = USB_DEVICE_PICKIT4_PIC_MODE_ALT;
pic_mode = serial_open(port, pinfo, &pgm->fd);
}
if(pic_mode >= 0) {
msg_error("\n");
pmsg_error("PICkit4 in PIC mode detected!\n");
imsg_error("Use MPLAB X or Microchip Studio to switch to AVR mode\n\n");
return -1;
pmsg_error("%s in %s mode detected\n",
pgmstr, pinfo.usbinfo.pid == bl_pid? "bootloader": "PIC");
if(mode_switch == PK4_SNAP_MODE_AVR) {
imsg_error("switching to AVR mode\n");
if(pinfo.usbinfo.pid == bl_pid)
serial_send(&pgm->fd, exit_bl_cmd, sizeof(exit_bl_cmd));
else {
serial_send(&pgm->fd, enter_avr_mode_cmd, sizeof(enter_avr_mode_cmd));
usleep(250*1000);
serial_send(&pgm->fd, reset_cmd, sizeof(reset_cmd));
}
imsg_error("please run Avrdude again to continue the session\n\n");
} else {
imsg_error("to switch into AVR mode try\n");
imsg_error("avrdude -c%s -p%s -P%s -xmode=avr\n", pgmid, partdesc, port);
}
serial_close(&pgm->fd);
exit(0);
}
}
}
pmsg_error("no device found matching VID 0x%04x and PID list: ",
(unsigned) pinfo.usbinfo.vid);
int notfirst = 0;
for (usbpid = lfirst(pgm->usbpid); usbpid != NULL; usbpid = lnext(usbpid)) {
for (usbpid = lfirst(pgm->usbpid); usbpid; usbpid = lnext(usbpid)) {
if (notfirst)
msg_error(", ");
msg_error("0x%04x", (unsigned int)(*(int *)(ldata(usbpid))));
@@ -1732,15 +1785,17 @@ int jtag3_open_common(PROGRAMMER *pgm, const char *port) {
char *serno;
if ((serno = strchr(port, ':')))
msg_error(" with SN %s", ++serno);
msg_error("\n");
return -1;
}
if (mode_switch == PK4_SNAP_MODE_AVR)
pmsg_warning("programmer is already in AVR mode. Ignoring -xmode");
// The event EP has been deleted by usb_open(), so we are
// running on a CMSIS-DAP device, using EDBG protocol
if (pgm->fd.usb.eep == 0) {
/* The event EP has been deleted by usb_open(), so we are
running on a CMSIS-DAP device, using EDBG protocol */
pgm->flag |= PGM_FL_IS_EDBG;
pmsg_notice2("found CMSIS-DAP compliant device, using EDBG protocol\n");
}
@@ -1749,11 +1804,22 @@ int jtag3_open_common(PROGRAMMER *pgm, const char *port) {
if (serdev && serdev->usbsn)
pgm->usbsn = serdev->usbsn;
/*
* drain any extraneous input
*/
// Drain any extraneous input
jtag3_drain(pgm, 0);
// Switch from AVR to PIC mode
if (mode_switch == PK4_SNAP_MODE_PIC) {
imsg_error("switching to PIC mode\n");
unsigned char *resp, buf[] = {SCOPE_GENERAL, CMD3_FW_UPGRADE, 0x00, 0x00, 0x70, 0x6d, 0x6a};
if (jtag3_command(pgm, buf, sizeof(buf), &resp, "enter PIC mode") < 0) {
imsg_error("entering PIC mode failed\n");
return -1;
}
imsg_error("PIC mode switch successful\n");
serial_close(&pgm->fd);
exit(0);
}
return 0;
}
@@ -1762,8 +1828,9 @@ int jtag3_open_common(PROGRAMMER *pgm, const char *port) {
static int jtag3_open(PROGRAMMER *pgm, const char *port) {
pmsg_notice2("jtag3_open()\n");
if (jtag3_open_common(pgm, port) < 0)
return -1;
int rc = jtag3_open_common(pgm, port, PDATA(pgm)->pk4_snap_mode);
if (rc < 0)
return rc;
if (jtag3_getsync(pgm, PARM3_CONN_JTAG) < 0)
return -1;
@@ -1774,7 +1841,7 @@ static int jtag3_open(PROGRAMMER *pgm, const char *port) {
static int jtag3_open_dw(PROGRAMMER *pgm, const char *port) {
pmsg_notice2("jtag3_open_dw()\n");
if (jtag3_open_common(pgm, port) < 0)
if (jtag3_open_common(pgm, port, PDATA(pgm)->pk4_snap_mode) < 0)
return -1;
if (jtag3_getsync(pgm, PARM3_CONN_DW) < 0)
@@ -1786,7 +1853,7 @@ static int jtag3_open_dw(PROGRAMMER *pgm, const char *port) {
static int jtag3_open_pdi(PROGRAMMER *pgm, const char *port) {
pmsg_notice2("jtag3_open_pdi()\n");
if (jtag3_open_common(pgm, port) < 0)
if (jtag3_open_common(pgm, port, PDATA(pgm)->pk4_snap_mode) < 0)
return -1;
if (jtag3_getsync(pgm, PARM3_CONN_PDI) < 0)
@@ -1804,7 +1871,7 @@ static int jtag3_open_updi(PROGRAMMER *pgm, const char *port) {
msg_notice2(" %d", *(int *) ldata(ln));
msg_notice2("\n");
if (jtag3_open_common(pgm, port) < 0)
if (jtag3_open_common(pgm, port, PDATA(pgm)->pk4_snap_mode) < 0)
return -1;
if (jtag3_getsync(pgm, PARM3_CONN_UPDI) < 0)
@@ -3107,7 +3174,7 @@ static int jtag3_chip_erase_tpi(const PROGRAMMER *pgm, const AVRPART *p) {
static int jtag3_open_tpi(PROGRAMMER *pgm, const char *port) {
pmsg_notice2("jtag3_open_tpi()\n");
if (jtag3_open_common(pgm, port) < 0)
if (jtag3_open_common(pgm, port, PDATA(pgm)->pk4_snap_mode) < 0)
return -1;
return 0;
}

View File

@@ -25,7 +25,7 @@
extern "C" {
#endif
int jtag3_open_common(PROGRAMMER *pgm, const char *port);
int jtag3_open_common(PROGRAMMER *pgm, const char *port, int mode_switch);
int jtag3_send(const PROGRAMMER *pgm, unsigned char *data, size_t len);
int jtag3_recv(const PROGRAMMER *pgm, unsigned char **msg);
void jtag3_close(PROGRAMMER * pgm);

View File

@@ -115,6 +115,7 @@
#define CMD3_GET_ID 0x12
#define CMD3_START_DW_DEBUG 0x13
#define CMD3_MONCON_DISABLE 0x17
#define CMD3_FW_UPGRADE 0x50
/* AVR ISP scope: no commands of its own */
@@ -381,6 +382,11 @@
#define DATA_OFFSET 0x1000000
// Constants for setting a PICkit4 or SNAP in AVR or PIC mode
#define PK4_SNAP_MODE_DEFAULT 0 // Do not switch mode
#define PK4_SNAP_MODE_AVR 1 // Switch to AVR mode
#define PK4_SNAP_MODE_PIC 2 // Switch to PIC mode
#if !defined(JTAG3_PRIVATE_EXPORTED)
struct mega_device_desc {

View File

@@ -1994,7 +1994,7 @@ static int stk500v2_jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extp
const char *extended_param;
int rv = 0;
for (ln = lfirst(extparms); ln; ln = lnext(ln)) {
for(ln = lfirst(extparms); ln; ln = lnext(ln)) {
extended_param = ldata(ln);
// SUFFER bits
@@ -2003,11 +2003,11 @@ static int stk500v2_jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extp
// Bit 2 EOF: Agressive power-down, sleep after 5 seconds if no USB enumeration when set to 0
// Bit 1 LOWP: forces running at 1 MHz when bit set to 0
// Bit 0 FUSE: Fuses are safe-masked when bit sent to 1 Fuses are unprotected when set to 0
if (str_starts(extended_param, "suffer")) {
if(str_starts(extended_param, "suffer")) {
if(pgm->extra_features & HAS_SUFFER) {
// Set SUFFER value
if (str_starts(extended_param, "suffer=")) {
if (sscanf(extended_param, "suffer=%hhi", PDATA(pgm)->suffer_data+1) < 1) {
if(str_starts(extended_param, "suffer=")) {
if(sscanf(extended_param, "suffer=%hhi", PDATA(pgm)->suffer_data+1) < 1) {
pmsg_error("invalid -xsuffer=<value> %s\n", extended_param);
rv = -1;
break;
@@ -2018,68 +2018,102 @@ static int stk500v2_jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extp
PDATA(pgm)->suffer_data[1]);
}
PDATA(pgm)->suffer_set = true;
continue;
}
// Get SUFFER value
else
if(str_eq(extended_param, "suffer")) {
PDATA(pgm)->suffer_get = true;
continue;
continue;
}
pmsg_error("invalid suffer setting %s. Use -xsuffer or -xsuffer=<arg>\n", extended_param);
rv = -1;
break;
}
}
else if (str_starts(extended_param, "vtarg_switch")) {
if(str_starts(extended_param, "vtarg_switch")) {
if(pgm->extra_features & HAS_VTARG_SWITCH) {
// Set Vtarget switch value
if (str_starts(extended_param, "vtarg_switch=")) {
if(str_starts(extended_param, "vtarg_switch=")) {
int sscanf_success = sscanf(extended_param, "vtarg_switch=%hhi", PDATA(pgm)->vtarg_switch_data+1);
if (sscanf_success < 1 || PDATA(pgm)->vtarg_switch_data[1] > 1) {
if(sscanf_success < 1 || PDATA(pgm)->vtarg_switch_data[1] > 1) {
pmsg_error("invalid vtarg_switch value %s\n", extended_param);
rv = -1;
break;
}
PDATA(pgm)->vtarg_switch_set = true;
continue;
}
// Get Vtarget switch value
else
if(str_eq(extended_param, "vtarg_switch")) {
PDATA(pgm)->vtarg_switch_get = true;
continue;
continue;
}
pmsg_error("invalid vtarg_switch setting %s. Use -xvtarg_switch or -xvtarg_switch=<0..1>\n", extended_param);
rv = -1;
break;
}
}
else if (str_starts(extended_param, "vtarg")) {
if (pgm->extra_features & HAS_VTARG_ADJ) {
if(str_starts(extended_param, "vtarg")) {
if(pgm->extra_features & HAS_VTARG_ADJ) {
// Set target voltage
if (str_starts(extended_param, "vtarg=") ) {
if(str_starts(extended_param, "vtarg=") ) {
double vtarg_set_val = 0;
int sscanf_success = sscanf(extended_param, "vtarg=%lf", &vtarg_set_val);
PDATA(pgm)->vtarg_data = (double)((int)(vtarg_set_val * 100 + .5)) / 100;
if (sscanf_success < 1 || vtarg_set_val < 0) {
if(sscanf_success < 1 || vtarg_set_val < 0) {
pmsg_error("invalid vtarg value %s\n", extended_param);
rv = -1;
break;
}
PDATA(pgm)->vtarg_set = true;
continue;
}
// Get target voltage
else if(str_eq(extended_param, "vtarg"))
else if(str_eq(extended_param, "vtarg")) {
PDATA(pgm)->vtarg_get = true;
else
break;
continue;
continue;
}
pmsg_error("invalid vtarg setting %s. Use -xvtarg or -xvtarg=<arg>\n", extended_param);
rv = -1;
break;
}
}
else if (str_eq(extended_param, "help")) {
if(str_starts(extended_param, "mode") &&
(str_starts(pgmid, "pickit4") || str_starts(pgmid, "snap"))) {
// Flag a switch to AVR mode
if(str_caseeq(extended_param, "mode=avr")) {
PDATA(pgm)->pk4_snap_mode = PK4_SNAP_MODE_AVR;
continue;
}
// Flag a switch to PIC mode
if(str_caseeq(extended_param, "mode=pic")) {
PDATA(pgm)->pk4_snap_mode = PK4_SNAP_MODE_PIC;
continue;
}
pmsg_error("invalid mode setting %s. Use -xmode=avr or -xmode=pic\n", extended_param);
rv = -1;
break;
}
if(str_eq(extended_param, "help")) {
msg_error("%s -c %s extended options:\n", progname, pgmid);
if(str_starts(pgmid, "xplainedmini")) {
if(pgm->extra_features & HAS_SUFFER) {
msg_error(" -xsuffer Read SUFFER register value\n");
msg_error(" -xsuffer=<arg> Set SUFFER register value\n");
}
if(pgm->extra_features & HAS_VTARG_SWITCH) {
msg_error(" -xvtarg_switch Read on-board target voltage switch state\n");
msg_error(" -xvtarg_switch=<0..1> Set on-board target voltage switch state\n");
}
if (pgm->extra_features & HAS_VTARG_ADJ) {
if(pgm->extra_features & HAS_VTARG_ADJ) {
msg_error(" -xvtarg Read on-board target supply voltage\n");
msg_error(" -xvtarg=<arg> Set on-board target supply voltage\n");
}
if(str_starts(pgmid, "pickit4") || str_starts(pgmid, "snap"))
msg_error(" -xmode=avr|pic Set programmer to AVR or PIC mode, then exit\n");
msg_error (" -xhelp Show this help menu and exit\n");
exit(0);
}
@@ -4243,10 +4277,11 @@ static int stk500v2_jtag3_open(PROGRAMMER *pgm, const char *port) {
void *mycookie;
int rv;
pmsg_notice2("stk500v2_jtag3_open()\n");
pmsg_notice2("%s()\n", __func__);
if (jtag3_open_common(pgm, port) < 0)
return -1;
rv = jtag3_open_common(pgm, port, PDATA(pgm)->pk4_snap_mode);
if (rv < 0)
return rv;
mycookie = pgm->cookie;
pgm->cookie = PDATA(pgm)->chained_pdata;

View File

@@ -298,9 +298,12 @@ struct pdata
bool fosc_set;
double fosc_data;
// Set STK500 XTAL frequency
/* Set STK500 XTAL frequency */
unsigned xtal;
/* Flag for PICkit4/SNAP mode switching */
int pk4_snap_mode;
const AVRPART *lastpart;
/* Start address of Xmega boot area */

View File

@@ -147,6 +147,16 @@ static int usbdev_open(const char *port, union pinfo pinfo, union filedescriptor
pmsg_error("cannot read product name: %s\n", usb_strerror());
strcpy(product, "[unnamed product]");
}
/* We need to write to endpoint 2 to switch the PICkit4 and SNAP
* from PIC to AVR mode
*/
if(str_casestarts(product, "MPLAB") && (str_caseends(product, "Snap ICD")
|| str_caseends(product, "PICkit 4")))
{
pinfo.usbinfo.flags = 0;
fd->usb.wep = 2;
}
/*
* The CMSIS-DAP specification mandates the string
* "CMSIS-DAP" must be present somewhere in the

View File

@@ -41,10 +41,10 @@
#define USB_DEVICE_PKOBN 0x2175
#define USB_DEVICE_PICKIT4_AVR_MODE 0x2177
#define USB_DEVICE_PICKIT4_PIC_MODE 0x9012
#define USB_DEVICE_PICKIT4_PIC_MODE_ALT 0x9017
#define USB_DEVICE_PICKIT4_PIC_MODE_BL 0x9017 // PICkit4 in bootloader mode
#define USB_DEVICE_SNAP_AVR_MODE 0x2180
#define USB_DEVICE_SNAP_PIC_MODE 0x9018
#define USB_DEVICE_SNAP_PIC_MODE_ALT 0x9019
#define USB_DEVICE_SNAP_PIC_MODE_BL 0x9019 // SNAP in bootloader mode
#define USB_VENDOR_FTDI 0x0403
#define USB_DEVICE_FT2232 0x6010