Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Jan 3, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
e9685a0
Use libusb to switch a PICkit4 or SNAP to AVR mode
MCUdude Dec 18, 2023
2d68910
Fix case
MCUdude Dec 18, 2023
15154dd
implement -xmode=pic
MCUdude Dec 20, 2023
8d017c2
Print PIC switch info messages
MCUdude Dec 20, 2023
6afc703
Fix typo
MCUdude Dec 20, 2023
416e051
Rename SNAP and PICkit4 USB PID
MCUdude Dec 22, 2023
23818d6
Make it possible to enter avr mode even when the tool is in bootloade…
MCUdude Dec 25, 2023
28eaa44
Add -xmode to docs
MCUdude Dec 25, 2023
6edbf18
Tweak grammar
MCUdude Dec 25, 2023
2fc7826
Add -xmode support for pickit4_isp and snap_isp
MCUdude Dec 25, 2023
74c29f0
Don't print "unable to open port" error on pgm->open softfail
MCUdude Dec 25, 2023
244e8e1
Add const
MCUdude Dec 25, 2023
3b27fe4
Simplify SNAP/PICkit4 mode switching code
MCUdude Dec 25, 2023
42178e2
Formatting
MCUdude Dec 26, 2023
59dde79
Add extra argument to jtag3_open_common
MCUdude Dec 26, 2023
a88c5c1
Improve extended parameter parsing
MCUdude Dec 27, 2023
17a7853
Improve error message
MCUdude Dec 27, 2023
23ce3a4
Improve extended parameter parsing
MCUdude Dec 27, 2023
9920a23
Immediately exit after a mode switch
MCUdude Dec 27, 2023
8d7b7c4
Remove unnecessary line
MCUdude Dec 27, 2023
fc905fe
Add missing serial_close
MCUdude Dec 27, 2023
40f3553
Remove unnecessary else
MCUdude Dec 28, 2023
e7fb25c
Minor code tweaks
MCUdude Dec 28, 2023
f84bf23
Update docs
MCUdude Dec 28, 2023
4590e6a
Formatting
MCUdude Dec 29, 2023
8fcf72e
Improve external parameter parsing and error handling
MCUdude Jan 2, 2024
bc102f1
Remove unused parameter
MCUdude Jan 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion src/avrdude.1
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -1535,6 +1535,19 @@ 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
The PICkit 4 and MPLAB SNAP programmer can only be utilized by Avrdude when in
AVR mode. Use
.Ar -xmode=avr
for switching to AVR mode, or
.Ar -xmode=pic
for switching switch 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
Expand Down
15 changes: 15 additions & 0 deletions src/doc/avrdude.texi
Original file line number Diff line number Diff line change
Expand Up @@ -1146,6 +1146,21 @@ 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}
The PICkit 4 and MPLAB SNAP programmer can only be utilized by Avrdude when in
AVR mode. Use @samp{-xmode=avr} for switching to AVR mode, or @samp{-xmode=pic}
for switching switch PIC mode.
@item @samp{help}
Show help menu and exit.
@end table

@cindex Option @code{-x} Xplained Mini
@item Xplained Mini

Expand Down
135 changes: 88 additions & 47 deletions src/jtag3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];

Expand Down Expand Up @@ -1597,6 +1600,25 @@ static int jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
}
}

else 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
else if (str_caseeq(extended_param, "mode=pic")) {
PDATA(pgm)->pk4_snap_mode = PK4_SNAP_MODE_PIC;
continue;
}
else {
pmsg_error("invalid mode setting '%s'. Use -xmode=avr or -xmode=pic\n", extended_param);
rv = -1;
break;
}
}

else if (str_eq(extended_param, "help")) {
msg_error("%s -c %s extended options:\n", progname, pgmid);
if (str_eq(pgm->type, "JTAGICE3"))
Expand All @@ -1613,6 +1635,9 @@ static int jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
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\n");
}
msg_error (" -xhelp Show this help menu and exit\n");
exit(0);
}
Expand All @@ -1624,7 +1649,7 @@ static int jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
return rv;
}

int jtag3_open_common(PROGRAMMER *pgm, const char *port) {
int jtag3_open_common(PROGRAMMER *pgm, const char *port, const int mode_switch) {
union pinfo pinfo;
LNODEID usbpid;
int rv = -1;
Expand All @@ -1639,20 +1664,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;
Expand Down Expand Up @@ -1685,44 +1705,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;
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;
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;
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_PICKIT4_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("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))));
Expand All @@ -1732,15 +1759,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");
}
Expand All @@ -1749,11 +1778,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;
}

Expand All @@ -1762,8 +1802,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;
Expand All @@ -1774,7 +1815,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)
Expand All @@ -1786,7 +1827,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)
Expand All @@ -1804,7 +1845,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)
Expand Down Expand Up @@ -3107,7 +3148,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;
}
Expand Down
2 changes: 1 addition & 1 deletion src/jtag3.h
Original file line number Diff line number Diff line change
Expand Up @@ -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, const 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);
Expand Down
6 changes: 6 additions & 0 deletions src/jtag3_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down Expand Up @@ -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 {
Expand Down
28 changes: 25 additions & 3 deletions src/stk500v2.c
Original file line number Diff line number Diff line change
Expand Up @@ -2068,6 +2068,25 @@ static int stk500v2_jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extp
}
}

else 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
else if (str_caseeq(extended_param, "mode=pic")) {
PDATA(pgm)->pk4_snap_mode = PK4_SNAP_MODE_PIC;
continue;
}
else {
pmsg_error("invalid mode setting '%s'. Use -xmode=avr or -xmode=pic\n", extended_param);
rv = -1;
break;
}
}

else if (str_eq(extended_param, "help")) {
msg_error("%s -c %s extended options:\n", progname, pgmid);
if(str_starts(pgmid, "xplainedmini")) {
Expand All @@ -2080,6 +2099,8 @@ static int stk500v2_jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extp
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\n");
msg_error (" -xhelp Show this help menu and exit\n");
exit(0);
}
Expand Down Expand Up @@ -4243,10 +4264,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;
Expand Down
5 changes: 4 additions & 1 deletion src/stk500v2_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
Loading