diff --git a/src/avrdude.1 b/src/avrdude.1 index d5903494..5d90c4fc 100644 --- a/src/avrdude.1 +++ b/src/avrdude.1 @@ -1185,14 +1185,20 @@ bits before, and 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. -.El -.Pp -The PICkit 4 and the Power Debugger also supports high-voltage UPDI programming. -This is used to enable a UPDI pin that has previously been set to RESET or -GPIO mode. High-voltage UPDI can be utilized by using an extended parameter: -.Bl -tag -offset indent -width indent .It Ar hvupdi -Enable high-voltage UPDI initialization for targets that supports this. +.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 +.Ar -xhvupdi +to enable high-voltage UPDI initialization for targets that supports this. +.It Ar vtarg=VALUE, vtarg +.Nm Power Debugger only +.sp 0.5 +The voltage generator can be enabled by setting a target voltage. +The current set-voltage can be read by +.Ar -xvtarg +alone. .It Ar help Show help menu and exit. .El @@ -1228,6 +1234,51 @@ Also note that the smaller Xplained Nano boards does not have a target power swi .It Ar help Show help menu and exit. .El +.It Ar Curiosity Nano +.Bl -tag -offset indent -width indent +.It Ar vtarg=VALUE, vtarg +The generated on-board target voltage can be changed by specifying a new voltage. +The current set-voltage can be read by +.Ar -xvtarg +alone. +.It Ar help +Show help menu and exit. +.El +.It Ar STK500 +.It Ar STK600 +.Bl -tag -offset indent -width indent +.It Ar vtarg=VALUE, vtarg +The generated on-board target voltage can be changed by specifying a new voltage. +The current set-voltage can be read by +.Ar -xvtarg +alone. +.It Ar fosc=VALUE[MHz|M|kHz|k|Hz], fosc +Set the programmable oscillator frequency. The current frequency can be read by +.Ar -xfosc +alone. +.It Ar varef=VALUE, varef +The generated on-board analog reference voltage can be changed by specifying +a new reference voltage. The current reference voltage can be read by +.Ar -xvaref +alone. +.It Ar varef[0,1]=VALUE, varef[0,1] +.Nm STK600 only +.sp 0.5 +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 +.Ar -xvaref0 +or +.Ar -xvaref1 +alone. +.It Ar attemps[=<1..99>] +.Nm STK500V1 only +.sp 0.5 +Specify how many connection retry attemps to perform before exiting. +Defaults to 10 if not specified. +.It Ar help +Show help menu and exit. +.El .It Ar AVR910 .Bl -tag -offset indent -width indent .It Ar devcode=VALUE @@ -1260,6 +1311,8 @@ Show help menu and exit. .It Ar attemps[=<1..99>] Specify how many connection retry attemps to perform before exiting. Defaults to 10 if not specified. +.It Ar help +Show help menu and exit. .El .It Ar Urclock .Bl -tag -offset indent -width indent @@ -1534,14 +1587,6 @@ line. .It Ar help Show help menu and exit. .El -.It Ar STK500 -.Bl -tag -offset indent -width indent -.It Ar attemps[=<1..99>] -Specify how many connection retry attemps to perform before exiting. -Defaults to 10 if not specified. -.It Ar help -Show help menu and exit. -.El .It Ar serialupdi .Bl -tag -offset indent -width indent .It Ar rtsdtr=low,high @@ -1563,6 +1608,7 @@ the CS line being managed outside the application. .It Ar help Show help menu and exit. .El +.El .Sh FILES .Bl -tag -offset indent -width /dev/ppi0XXX .It Pa /dev/ppi0 diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index 89ea5953..685d08c8 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -71,6 +71,10 @@ # # - HAS_VTARG_SWITCH: Programer has a programmable target power switch # # - HAS_VTARG_ADJ: Programmer has an adjustable target power source that can # # be controlled with Avrdude +# # - HAS_FOSC_ADJ: Programmer has a programable frequency generator that +# # can clock an AVR directly through its XTAL1 pin +# # - HAS_VAREF_ADJ: Programmer has an adjustable analog reference voltage that +# # can be controlled with Avrdude # # # # (3) Not all programmer types can process a list of PIDs # @@ -1285,6 +1289,7 @@ programmer desc = "Atmel STK500"; type = "stk500generic"; prog_modes = PM_ISP; + extra_features = HAS_VTARG_ADJ | HAS_VTARG_READ | HAS_FOSC_ADJ | HAS_VAREF_ADJ; connection_type = serial; ; @@ -1297,6 +1302,7 @@ programmer desc = "Atmel STK500 version 1.x firmware"; type = "stk500"; prog_modes = PM_ISP; + extra_features = HAS_VTARG_ADJ | HAS_VTARG_READ | HAS_FOSC_ADJ | HAS_VAREF_ADJ; connection_type = serial; ; @@ -1321,6 +1327,7 @@ programmer desc = "Atmel STK500 version 2.x firmware"; type = "stk500v2"; prog_modes = PM_TPI | PM_ISP; + extra_features = HAS_VTARG_ADJ | HAS_VTARG_READ | HAS_FOSC_ADJ | HAS_VAREF_ADJ; connection_type = serial; ; @@ -1333,6 +1340,7 @@ programmer desc = "Atmel STK500 v2 in parallel programming mode"; type = "stk500pp"; prog_modes = PM_HVPP; + extra_features = HAS_VTARG_ADJ | HAS_VTARG_READ | HAS_FOSC_ADJ | HAS_VAREF_ADJ; connection_type = serial; ; @@ -1345,6 +1353,7 @@ programmer desc = "Atmel STK500 v2 in high-voltage serial programming mode"; type = "stk500hvsp"; prog_modes = PM_HVSP; + extra_features = HAS_VTARG_ADJ | HAS_VTARG_READ | HAS_FOSC_ADJ | HAS_VAREF_ADJ; connection_type = serial; ; @@ -1357,7 +1366,7 @@ programmer desc = "Atmel STK600"; type = "stk600"; prog_modes = PM_TPI | PM_ISP | PM_PDI; - extra_features = HAS_VTARG_ADJ | HAS_VTARG_READ; + extra_features = HAS_VTARG_ADJ | HAS_VTARG_READ | HAS_FOSC_ADJ | HAS_VAREF_ADJ; connection_type = usb; ; @@ -1370,7 +1379,7 @@ programmer desc = "Atmel STK600 in parallel programming mode"; type = "stk600pp"; prog_modes = PM_HVPP; - extra_features = HAS_VTARG_ADJ | HAS_VTARG_READ; + extra_features = HAS_VTARG_ADJ | HAS_VTARG_READ | HAS_FOSC_ADJ | HAS_VAREF_ADJ; connection_type = usb; ; @@ -1383,7 +1392,7 @@ programmer desc = "Atmel STK600 in high-voltage serial programming mode"; type = "stk600hvsp"; prog_modes = PM_HVSP; - extra_features = HAS_VTARG_ADJ | HAS_VTARG_READ; + extra_features = HAS_VTARG_ADJ | HAS_VTARG_READ | HAS_FOSC_ADJ | HAS_VAREF_ADJ; connection_type = usb; ; diff --git a/src/config.c b/src/config.c index 32bbd9f9..e280bd4f 100644 --- a/src/config.c +++ b/src/config.c @@ -336,26 +336,28 @@ TOKEN *new_constant(const char *con) { tkn->value.type = V_NUM; tkn->value.number = - !strcmp("PM_SPM", con)? PM_SPM: - !strcmp("PM_TPI", con)? PM_TPI: - !strcmp("PM_ISP", con)? PM_ISP: - !strcmp("PM_PDI", con)? PM_PDI: - !strcmp("PM_UPDI", con)? PM_UPDI: - !strcmp("PM_HVSP", con)? PM_HVSP: - !strcmp("PM_HVPP", con)? PM_HVPP: - !strcmp("PM_debugWIRE", con)? PM_debugWIRE: - !strcmp("PM_JTAG", con)? PM_JTAG: - !strcmp("PM_JTAGmkI", con)? PM_JTAGmkI: - !strcmp("PM_XMEGAJTAG", con)? PM_XMEGAJTAG: - !strcmp("PM_AVR32JTAG", con)? PM_AVR32JTAG: - !strcmp("PM_aWire", con)? PM_aWire: - !strcmp("HAS_SUFFER", con)? HAS_SUFFER: - !strcmp("HAS_VTARG_SWITCH", con)? HAS_VTARG_SWITCH: - !strcmp("HAS_VTARG_ADJ", con)? HAS_VTARG_ADJ: - !strcmp("HAS_VTARG_READ", con)? HAS_VTARG_READ: - !strcmp("pseudo", con)? 2: - !strcmp("yes", con) || !strcmp("true", con)? 1: - !strcmp("no", con) || !strcmp("false", con)? 0: + str_eq(con, "PM_SPM")? PM_SPM: + str_eq(con, "PM_TPI")? PM_TPI: + str_eq(con, "PM_ISP")? PM_ISP: + str_eq(con, "PM_PDI")? PM_PDI: + str_eq(con, "PM_UPDI")? PM_UPDI: + str_eq(con, "PM_HVSP")? PM_HVSP: + str_eq(con, "PM_HVPP")? PM_HVPP: + str_eq(con, "PM_debugWIRE")? PM_debugWIRE: + str_eq(con, "PM_JTAG")? PM_JTAG: + str_eq(con, "PM_JTAGmkI")? PM_JTAGmkI: + str_eq(con, "PM_XMEGAJTAG")? PM_XMEGAJTAG: + str_eq(con, "PM_AVR32JTAG")? PM_AVR32JTAG: + str_eq(con, "PM_aWire")? PM_aWire: + str_eq(con, "HAS_SUFFER")? HAS_SUFFER: + str_eq(con, "HAS_VTARG_SWITCH")? HAS_VTARG_SWITCH: + str_eq(con, "HAS_VTARG_ADJ")? HAS_VTARG_ADJ: + str_eq(con, "HAS_VTARG_READ")? HAS_VTARG_READ: + str_eq(con, "HAS_FOSC_ADJ")? HAS_FOSC_ADJ: + str_eq(con, "HAS_VAREF_ADJ")? HAS_VAREF_ADJ: + str_eq(con, "pseudo")? 2: + str_eq(con, "yes") || str_eq(con, "true")? 1: + str_eq(con, "no") || str_eq(con, "false")? 0: (assigned = 0); if(!assigned) { @@ -495,7 +497,7 @@ const char *cache_string(const char *p) { hs = hstrings[h] = (char **) cfg_realloc("cache_string()", NULL, (16+1)*sizeof**hstrings); for(k=0; hs[k]; k++) - if(*p == *hs[k] && !strcmp(p, hs[k])) + if(*p == *hs[k] && str_eq(p, hs[k])) return hs[k]; if(k && k%16 == 0) @@ -520,7 +522,7 @@ COMMENT *locate_comment(const LISTID comments, const char *where, int rhs) { if(comments) for(LNODEID ln=lfirst(comments); ln; ln=lnext(ln)) { COMMENT *n = ldata(ln); - if(n && rhs == n->rhs && n->kw && strcmp(where, n->kw) == 0) + if(n && rhs == n->rhs && n->kw && str_eq(where, n->kw)) return n; } @@ -563,7 +565,7 @@ void capture_comment_str(const char *com, int lineno) { // Capture assignments (keywords left of =) and associate comments to them void capture_lvalue_kw(const char *kw, int lineno) { - if(!strcmp(kw, "memory")) { // Push part comments and start memory comments + if(str_eq(kw, "memory")) { // Push part comments and start memory comments if(!cfg_pushed) { // config_gram.y pops the part comments cfg_pushed = 1; cfg_pushedcomms = cfg_strctcomms; @@ -571,7 +573,7 @@ void capture_lvalue_kw(const char *kw, int lineno) { } } - if(!strcmp(kw, "programmer") || !strcmp(kw, "part") || !strcmp(kw, "memory")) + if(str_eq(kw, "programmer") || str_eq(kw, "part") || str_eq(kw, "memory")) kw = "*"; // Show comment before programmer/part/memory if(lkw) diff --git a/src/developer_opts.c b/src/developer_opts.c index 11524c41..594d5e0c 100644 --- a/src/developer_opts.c +++ b/src/developer_opts.c @@ -256,6 +256,10 @@ static char *extra_features_str(int m) { strcat(mode, " | HAS_VTARG_ADJ"); if(m & HAS_VTARG_READ) strcat(mode, " | HAS_VTARG_READ"); + if(m & HAS_FOSC_ADJ) + strcat(mode, " | HAS_FOSC_ADJ"); + if(m & HAS_VAREF_ADJ) + strcat(mode, " | HAS_VAREF_ADJ"); return mode + (mode[1] == 0? 0: 4); } diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index 5c26de90..a37a6d82 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -940,14 +940,19 @@ after, @var{BB} bits before, and @var{BA} 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. -@end table -The PICkit 4 and the Power Debugger also supports high-voltage UPDI programming. -This is used to enable a UPDI pin that has previously been set to RESET or -GPIO mode. High-voltage UPDI can be utilized by using an extended parameter: -@table @code @item @samp{hvupdi} -Enable high-voltage UPDI initialization for targets that supports this. +@var{Power Debugger and Pickit 4 only} +@* +High-voltage UPDI programming is used to enable a UPDI pin that has previously +been set to RESET or GPIO mode. Use @samp{-xhvupdi} to enable high-voltage UPDI +initialization for supported targets. + +@item @samp{vtarg=VALUE, vtarg} +@var{Power Debugger only} +@* +The voltage generator can be enabled by setting a target voltage. +The current set-voltage can be read by @samp{-xvtarg} alone. @item @samp{help} Show help menu and exit. @@ -988,6 +993,51 @@ Also note that the smaller Xplained Nano boards does not have a target power swi Show help menu and exit. @end table +@cindex @code{-x} Curiosity Nano +@item Curiosity Nano + +The Curiosity Nano board accepts the following extended parameter: +@table @code +@item @samp{vtarg=VALUE, vtarg} +The generated on-board target voltage can be changed by specifying a new voltage. +The current set-voltage can be read by @samp{-xvtarg} alone. +@item @samp{help} +Show help menu and exit. +@end table + +@cindex @code{-x} STK500 +@cindex @code{-x} STK600 +@item STK500 +@item STK600 + +The STK500 and STK600 boards accept the following extended parameters: +@table @code +@item @samp{vtarg=VALUE, vtarg} +The generated on-board target voltage can be changed by specifying a new voltage. +The current set-voltage can be read by @samp{-xvtarg} alone. +@item @samp{fosc=VALUE[MHz|M|kHz|k|Hz], fosc} +Set the programmable oscillator frequency in MHz, kHz or Hz. +The current frequency can be read by @samp{-xfosc} alone. +@item @samp{varef=VALUE, varef} +The generated on-board analog reference voltage can be changed by specifying +a new reference voltage. The current reference voltage can be read by +@samp{-xvaref} alone. +@item @samp{varef[0,1]=VALUE, varef[0,1]} +@var{STK600 only} +@* +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 @samp{-xvaref0} or +@samp{-xvaref1} alone. +@item @samp{attemps[=<1..99>]} +@var{STK500V1 only} +@* +Specify how many connection retry attemps to perform before exiting. +Defaults to 10 if not specified. +@item @samp{help} +Show help menu and exit. +@end table + @cindex @code{-x} AVR910 @item AVR910 diff --git a/src/jtag3.c b/src/jtag3.c index cb9541e4..3669a783 100644 --- a/src/jtag3.c +++ b/src/jtag3.c @@ -84,6 +84,11 @@ struct pdata bool vtarg_switch_set; unsigned char vtarg_switch_data[2]; + /* Get/set flags for adjustable target voltage */ + bool vtarg_get; + bool vtarg_set; + double vtarg_data; + /* Function to set the appropriate clock parameter */ int (*set_sck)(const PROGRAMMER *, unsigned char *); }; @@ -1099,7 +1104,7 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) { if (PDATA(pgm)->set_sck(pgm, parm) < 0) return -1; } - jtag3_print_parms1(pgm, progbuf, stderr); + if (conn == PARM3_CONN_JTAG) { pmsg_notice2("jtag3_initialize(): " "trying to set JTAG daisy-chain info to %d,%d,%d,%d\n", @@ -1109,6 +1114,9 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) { return -1; } + if (verbose && quell_progress < 2) + jtag3_print_parms1(pgm, progbuf, stderr); + // Read or write SUFFER register if (PDATA(pgm)->suffer_get || PDATA(pgm)->suffer_set) { // Read existing SUFFER value @@ -1144,6 +1152,26 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) { } } + // Read or write target voltage + if (PDATA(pgm)->vtarg_get || PDATA(pgm)->vtarg_set) { + // Read current target voltage set value + unsigned char buf[2]; + if (jtag3_getparm(pgm, SCOPE_GENERAL, 1, PARM3_VADJUST, buf, 2) < 0) + return -1; + double vtarg_read = b2_to_u16(buf) / 1000.0; + if (PDATA(pgm)->vtarg_get) + msg_info("Target voltage value read as %.2fV\n", vtarg_read); + // Write target voltage value + else { + u16_to_b2(buf, (unsigned)(PDATA(pgm)->vtarg_data * 1000)); + msg_info("Changing target voltage from %.2f to %.2fV\n", vtarg_read, PDATA(pgm)->vtarg_data); + if (jtag3_setparm(pgm, SCOPE_GENERAL, 1, PARM3_VADJUST, buf, sizeof(buf)) < 0) { + msg_warning("Cannot set target voltage %.2fV\n", PDATA(pgm)->vtarg_data); + return -1; + } + } + } + /* set device descriptor data */ if ((p->prog_modes & PM_PDI)) { struct xmega_device_desc xd; @@ -1528,6 +1556,29 @@ static int jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) { } } + else if (str_starts(extended_param, "vtarg")) { + if (pgm->extra_features & HAS_VTARG_ADJ) { + // Set target voltage + 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); + rv = -1; + break; + } + PDATA(pgm)->vtarg_set = true; + continue; + } + // Get target voltage + else if(str_eq(extended_param, "vtarg")) { + PDATA(pgm)->vtarg_get = true; + continue; + } + } + } + else if (str_eq(extended_param, "help")) { char *prg = (char *)ldata(lfirst(pgm->id)); msg_error("%s -c %s extended options:\n", progname, prg); @@ -1541,6 +1592,10 @@ static int jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) { 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) { + msg_error(" -xvtarg Read on-board target supply voltage\n"); + msg_error(" -xvtarg= Set on-board target supply voltage\n"); + } msg_error (" -xhelp Show this help menu and exit\n"); exit(0); } @@ -2496,7 +2551,7 @@ void jtag3_display(const PROGRAMMER *pgm, const char *p) { msg_info("%sICE HW version : %d\n", p, parms[0]); msg_info("%sICE FW version : %d.%02d (rel. %d)\n", p, parms[1], parms[2], (parms[3] | (parms[4] << 8))); - msg_info("%sSerial number : %s", p, sn); + msg_info("%sSerial number : %s\n", p, sn); free(resp); } @@ -2509,6 +2564,39 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp) { return; msg_info("%sVtarget : %.2f V\n", p, b2_to_u16(buf)/1000.0); + // Print clocks if programmer typ is not TPI + if (!str_eq(pgm->type, "JTAGICE3_TPI")) { + // Get current programming mode and target type from to determine what data to print + if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CONNECTION, prog_mode, 1) < 0) + return; + if (jtag3_getparm(pgm, SCOPE_AVR, 0, PARM3_ARCH, &prog_mode[1], 1) < 0) + return; + if (prog_mode[0] == PARM3_CONN_JTAG) { + if (prog_mode[1] == PARM3_ARCH_XMEGA) { + if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_JTAG, buf, 2) < 0) + return; + if (b2_to_u16(buf) > 0) + fmsg_out(fp, "%sJTAG clk Xmega : %u kHz\n", p, b2_to_u16(buf)); + } else { + if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_MEGA_PROG, buf, 2) < 0) + return; + if (b2_to_u16(buf) > 0) + fmsg_out(fp, "%sJTAG clk prog. : %u kHz\n", p, b2_to_u16(buf)); + + if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_MEGA_DEBUG, buf, 2) < 0) + return; + if (b2_to_u16(buf) > 0) + fmsg_out(fp, "%sJTAG clk debug : %u kHz\n", p, b2_to_u16(buf)); + } + } + else if (prog_mode[0] == PARM3_CONN_PDI || prog_mode[0] == PARM3_CONN_UPDI) { + if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_PDI, buf, 2) < 0) + return; + if (b2_to_u16(buf) > 0) + fmsg_out(fp, "%sPDI/UPDI clk : %u kHz\n", p, b2_to_u16(buf)); + } + } + // Print features unique to the Power Debugger for(LNODEID ln=lfirst(pgm->id); ln; ln=lnext(ln)) { if(str_starts(ldata(ln), "powerdebugger")) { @@ -2579,39 +2667,6 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp) { break; } } - - // Print clocks if programmer typ is not TPI - if (strcmp(pgm->type, "JTAGICE3_TPI")) { - // Get current programming mode and target type from to determine what data to print - if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CONNECTION, prog_mode, 1) < 0) - return; - if (jtag3_getparm(pgm, SCOPE_AVR, 0, PARM3_ARCH, &prog_mode[1], 1) < 0) - return; - if (prog_mode[0] == PARM3_CONN_JTAG) { - if (prog_mode[1] == PARM3_ARCH_XMEGA) { - if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_JTAG, buf, 2) < 0) - return; - if (b2_to_u16(buf) > 0) - fmsg_out(fp, "%sJTAG clk Xmega : %u kHz\n", p, b2_to_u16(buf)); - } else { - if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_MEGA_PROG, buf, 2) < 0) - return; - if (b2_to_u16(buf) > 0) - fmsg_out(fp, "%sJTAG clk prog. : %u kHz\n", p, b2_to_u16(buf)); - - if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_MEGA_DEBUG, buf, 2) < 0) - return; - if (b2_to_u16(buf) > 0) - fmsg_out(fp, "%sJTAG clk debug : %u kHz\n", p, b2_to_u16(buf)); - } - } - else if (prog_mode[0] == PARM3_CONN_PDI || prog_mode[0] == PARM3_CONN_UPDI) { - if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_PDI, buf, 2) < 0) - return; - if (b2_to_u16(buf) > 0) - fmsg_out(fp, "%sPDI/UPDI clk : %u kHz\n", p, b2_to_u16(buf)); - } - } fmsg_out(fp, "\n"); } @@ -2761,6 +2816,29 @@ static int jtag3_initialize_tpi(const PROGRAMMER *pgm, const AVRPART *p) { unsigned char* resp; int status; + // Read or write target voltage + if (PDATA(pgm)->vtarg_get || PDATA(pgm)->vtarg_set) { + // Read current target voltage set value + unsigned char buf[2]; + if (jtag3_getparm(pgm, SCOPE_GENERAL, 1, PARM3_VADJUST, buf, 2) < 0) + return -1; + double vtarg_read = b2_to_u16(buf) / 1000.0; + if (PDATA(pgm)->vtarg_get) + msg_info("Target voltage value read as %.2fV\n", vtarg_read); + // Write target voltage value + else { + u16_to_b2(buf, (unsigned)(PDATA(pgm)->vtarg_data * 1000)); + msg_info("Changing target voltage from %.2f to %.2fV\n", vtarg_read, PDATA(pgm)->vtarg_data); + if (jtag3_setparm(pgm, SCOPE_GENERAL, 1, PARM3_VADJUST, buf, sizeof(buf)) < 0) { + msg_warning("Cannot set target voltage %.2fV\n", PDATA(pgm)->vtarg_data); + return -1; + } + } + } + + if (verbose && quell_progress < 2) + jtag3_print_parms1(pgm, progbuf, stderr); + pmsg_notice2("jtag3_initialize_tpi() start\n"); cmd[0] = XPRG_CMD_ENTER_PROGMODE; @@ -2785,8 +2863,6 @@ static int jtag3_initialize_tpi(const PROGRAMMER *pgm, const AVRPART *p) { return -1; free(resp); - jtag3_print_parms1(pgm, progbuf, stderr); - return 0; } @@ -3100,6 +3176,9 @@ void jtag3_initpgm(PROGRAMMER *pgm) { pgm->page_size = 256; pgm->flag = PGM_FL_IS_JTAG; + /* + * hardware dependent functions + */ if (pgm->extra_features & HAS_VTARG_ADJ) pgm->set_vtarget = jtag3_set_vtarget; } @@ -3129,11 +3208,15 @@ void jtag3_dw_initpgm(PROGRAMMER *pgm) { pgm->paged_write = jtag3_paged_write; pgm->paged_load = jtag3_paged_load; pgm->print_parms = jtag3_print_parms; + pgm->parseextparams = jtag3_parseextparms; pgm->setup = jtag3_setup; pgm->teardown = jtag3_teardown; pgm->page_size = 256; pgm->flag = PGM_FL_IS_DW; + /* + * hardware dependent functions + */ if (pgm->extra_features & HAS_VTARG_ADJ) pgm->set_vtarget = jtag3_set_vtarget; } @@ -3165,11 +3248,15 @@ void jtag3_pdi_initpgm(PROGRAMMER *pgm) { pgm->page_erase = jtag3_page_erase; pgm->print_parms = jtag3_print_parms; pgm->set_sck_period = jtag3_set_sck_period; + pgm->parseextparams = jtag3_parseextparms; pgm->setup = jtag3_setup; pgm->teardown = jtag3_teardown; pgm->page_size = 256; pgm->flag = PGM_FL_IS_PDI; + /* + * hardware dependent functions + */ if (pgm->extra_features & HAS_VTARG_ADJ) pgm->set_vtarget = jtag3_set_vtarget; } @@ -3183,7 +3270,6 @@ void jtag3_updi_initpgm(PROGRAMMER *pgm) { * mandatory functions */ pgm->initialize = jtag3_initialize; - pgm->parseextparams = jtag3_parseextparms; pgm->display = jtag3_display; pgm->enable = jtag3_enable; pgm->disable = jtag3_disable; @@ -3202,6 +3288,7 @@ void jtag3_updi_initpgm(PROGRAMMER *pgm) { pgm->page_erase = jtag3_page_erase; pgm->print_parms = jtag3_print_parms; pgm->set_sck_period = jtag3_set_sck_period; + pgm->parseextparams = jtag3_parseextparms; pgm->setup = jtag3_setup; pgm->teardown = jtag3_teardown; pgm->page_size = 256; @@ -3209,6 +3296,9 @@ void jtag3_updi_initpgm(PROGRAMMER *pgm) { pgm->unlock = jtag3_unlock_erase_key; pgm->read_sib = jtag3_read_sib; + /* + * hardware dependent functions + */ if (pgm->extra_features & HAS_VTARG_ADJ) pgm->set_vtarget = jtag3_set_vtarget; } @@ -3238,6 +3328,7 @@ void jtag3_tpi_initpgm(PROGRAMMER *pgm) { pgm->paged_write = jtag3_paged_write_tpi; pgm->paged_load = jtag3_paged_load_tpi; pgm->print_parms = jtag3_print_parms; + pgm->parseextparams = jtag3_parseextparms; pgm->setup = jtag3_setup; pgm->teardown = jtag3_teardown; pgm->page_size = 256; diff --git a/src/lexer.l b/src/lexer.l index 69360995..7b811bad 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -145,7 +145,7 @@ SIGN [+-] (?x: PM_(SPM|TPI|ISP|PDI|UPDI|HVSP|HVPP|debugWIRE|JTAG|JTAGmkI|XMEGAJTAG|AVR32JTAG|aWire) | - HAS_(SUFFER|VTARG_SWITCH|VTARG_ADJ|VTARG_READ) | + HAS_(SUFFER|VTARG_SWITCH|VTARG_ADJ|VTARG_READ|FOSC_ADJ|VAREF_ADJ) | yes|no|pseudo | true|false ) { /* Constants */ yylval = new_constant(yytext); return TKN_NUMBER; diff --git a/src/libavrdude.h b/src/libavrdude.h index e27e3dae..18be7631 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -215,6 +215,8 @@ typedef struct opcode { #define HAS_VTARG_SWITCH 2 #define HAS_VTARG_ADJ 4 #define HAS_VTARG_READ 8 +#define HAS_FOSC_ADJ 16 +#define HAS_VAREF_ADJ 32 #define AVR_FAMILYIDLEN 7 #define AVR_SIBLEN 16 diff --git a/src/stk500.c b/src/stk500.c index 6984fb1f..d45a6ef7 100644 --- a/src/stk500.c +++ b/src/stk500.c @@ -45,6 +45,18 @@ #define STK500_XTAL 7372800U #define MAX_SYNC_ATTEMPTS 10 +static double f_to_kHz_MHz(double f, const char **unit) { + if (f > 1e6) { + f /= 1e6; + *unit = "MHz"; + } else if (f > 1e3) { + f /= 1000; + *unit = "kHz"; + } else + *unit = "Hz"; + return f; +} + static int stk500_getparm(const PROGRAMMER *pgm, unsigned parm, unsigned *value); static int stk500_setparm(const PROGRAMMER *pgm, unsigned parm, unsigned value); static void stk500_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp); @@ -557,6 +569,73 @@ static int stk500_initialize(const PROGRAMMER *pgm, const AVRPART *p) { } } + // Read or write target voltage + if (PDATA(pgm)->vtarg_get || PDATA(pgm)->vtarg_set) { + // Read current target voltage set value + unsigned int vtarg_read; + stk500_getparm(pgm, Parm_STK_VTARGET, &vtarg_read); + if (PDATA(pgm)->vtarg_get) + msg_info("Target voltage value read as %.2fV\n", (vtarg_read / 10.0)); + // Write target voltage value + else { + msg_info("Changing target voltage from %.2f to %.2fV\n", (vtarg_read / 10.0), PDATA(pgm)->vtarg_data); + if(pgm->set_vtarget(pgm, PDATA(pgm)->vtarg_data) < 0) + return -1; + } + } + + // Read or write analog reference voltage + if (PDATA(pgm)->varef_get || PDATA(pgm)->varef_set) { + // Read current analog reference voltage + unsigned int varef_read; + stk500_getparm(pgm, Parm_STK_VADJUST, &varef_read); + if (PDATA(pgm)->varef_get) + msg_info("Analog reference voltage value read as %.2fV\n", (varef_read / 10.0)); + // Write analog reference voltage + else { + msg_info("Changing analog reference voltage from %.2f to %.2fV\n", + (varef_read / 10.0), PDATA(pgm)->varef_data); + if(pgm->set_varef(pgm, 0, PDATA(pgm)->varef_data) < 0) + return -1; + } + } + + // Read or write clock generator frequency + if (PDATA(pgm)->fosc_get || PDATA(pgm)->fosc_set) { + // Read current target voltage set value + unsigned int osc_pscale; + unsigned int osc_cmatch; + const char *unit_get = {"Hz"}; + double f_get = 0.0; + stk500_getparm(pgm, Parm_STK_OSC_PSCALE, &osc_pscale); + stk500_getparm(pgm, Parm_STK_OSC_CMATCH, &osc_cmatch); + if(osc_pscale) { + int prescale = 1; + f_get = STK500_XTAL / 2; + switch (osc_pscale) { + case 2: prescale = 8; break; + case 3: prescale = 32; break; + case 4: prescale = 64; break; + case 5: prescale = 128; break; + case 6: prescale = 256; break; + case 7: prescale = 1024; break; + } + f_get /= prescale; + f_get /= (osc_cmatch + 1); + f_get = f_to_kHz_MHz(f_get, &unit_get); + } + if (PDATA(pgm)->fosc_get) + msg_info("Oscillator currently set to %.3f %s\n", f_get, unit_get); + // Write target voltage value + else { + const char *unit_set; + double f_set = f_to_kHz_MHz(PDATA(pgm)->fosc_data, &unit_set); + msg_info("Changing oscillator frequency from %.3f %s to %.3f %s\n", f_get, unit_get, f_set, unit_set); + if(pgm->set_fosc(pgm, PDATA(pgm)->fosc_data) < 0) + return -1; + } + } + return pgm->program_enable(pgm, p); } @@ -570,17 +649,122 @@ static int stk500_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) for (ln = lfirst(extparms); ln; ln = lnext(ln)) { extended_param = ldata(ln); - if (sscanf(extended_param, "attempts=%2d", &attempts) == 1) { - PDATA(pgm)->retry_attempts = attempts; - pmsg_info("setting number of retry attempts to %d\n", attempts); - continue; - } + if (sscanf(extended_param, "attempts=%2d", &attempts) == 1) { + PDATA(pgm)->retry_attempts = attempts; + pmsg_info("setting number of retry attempts to %d\n", attempts); + continue; + } + + else if (str_starts(extended_param, "vtarg")) { + if (pgm->extra_features & HAS_VTARG_ADJ) { + // Set target voltage + 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); + rv = -1; + break; + } + PDATA(pgm)->vtarg_set = true; + continue; + } + // Get target voltage + else if(str_eq(extended_param, "vtarg")) { + PDATA(pgm)->vtarg_get = true; + continue; + } + } + } + + else if (str_starts(extended_param, "varef")) { + if (pgm->extra_features & HAS_VAREF_ADJ) { + int sscanf_success = 0; + double varef_set_val = 0; + // Get new analog reference voltage for channel 0 + if (str_starts(extended_param, "varef=")) { + sscanf_success = sscanf(extended_param, "varef=%lf", &varef_set_val); + PDATA(pgm)->varef_set = true; + } + // Get new analog reference voltage for channel 0 + else if(str_starts(extended_param, "varef0=")) { + sscanf_success = sscanf(extended_param, "varef0=%lf", &varef_set_val); + PDATA(pgm)->varef_set = true; + } + // Get current analog reference voltage for channel 0 + else if(str_eq(extended_param, "varef") || str_eq(extended_param, "varef0")) { + PDATA(pgm)->varef_get = true; + continue; + } + // Set analog reference voltage + if (PDATA(pgm)->varef_set) { + PDATA(pgm)->varef_data = (double)((int)(varef_set_val * 100 + .5)) / 100; + if (sscanf_success < 1 || varef_set_val < 0) { + pmsg_error("invalid varef value '%s'\n", extended_param); + PDATA(pgm)->varef_set = false; + rv = -1; + break; + } + continue; + } + } + } + + else if (str_starts(extended_param, "fosc")) { + if (pgm->extra_features & HAS_VAREF_ADJ) { + // Set clock generator frequency + if (str_starts(extended_param, "fosc=")) { + char fosc_str[16] = {0}; + int sscanf_success = sscanf(extended_param, "fosc=%10s", fosc_str); + if (sscanf_success < 1) { + pmsg_error("invalid fosc value '%s'\n", extended_param); + rv = -1; + break; + } + char *endp; + double v = strtod(fosc_str, &endp); + if (endp == fosc_str){ + if (str_eq(fosc_str, "off")) + PDATA(pgm)->fosc_data = 0.0; + else { + pmsg_error("cannot parse fosc value %s\n", fosc_str); + rv = -1; + break; + } + } + if (*endp == 'm' || *endp == 'M') + PDATA(pgm)->fosc_data = v * 1e6; + else if (*endp == 'k' || *endp == 'K') + PDATA(pgm)->fosc_data = v * 1e3; + PDATA(pgm)->fosc_set = true; + continue; + } + // Get clock generator frequency + else if(str_eq(extended_param, "fosc")) { + PDATA(pgm)->fosc_get = true; + continue; + } + } + } else if (str_eq(extended_param, "help")) { char *prg = (char *)ldata(lfirst(pgm->id)); msg_error("%s -c %s extended options:\n", progname, prg); - msg_error(" -xattempts= Specify no. connection retry attempts\n"); - msg_error(" -xhelp Show this help menu and exit\n"); + msg_error(" -xattempts= Specify no. connection retry attempts\n"); + if (pgm->extra_features & HAS_VTARG_ADJ) { + msg_error(" -xvtarg Read target supply voltage\n"); + msg_error(" -xvtarg= Set target supply voltage\n"); + } + if (pgm->extra_features & HAS_VAREF_ADJ) { + msg_error(" -xvaref Read analog reference voltage\n"); + msg_error(" -xvaref= Set analog reference voltage\n"); + } + if (pgm->extra_features & HAS_FOSC_ADJ) { + msg_error(" -xfosc Read oscillator clock frequency\n"); + msg_error(" -xfosc=[M|k]|off Set oscillator clock frequency\n"); + } + msg_error(" -xhelp Show this help menu and exit\n"); exit(0); } @@ -966,7 +1150,7 @@ static int stk500_set_vtarget(const PROGRAMMER *pgm, double v) { } if (uaref > utarg) { - pmsg_error("reducing V[aref] from %.1f to %.1f\n", uaref / 10.0, v); + pmsg_warning("reducing V[aref] from %.1f to %.1f\n", uaref / 10.0, v); if (stk500_setparm(pgm, Parm_STK_VADJUST, utarg) != 0) return -1; } @@ -1282,7 +1466,6 @@ void stk500_initpgm(PROGRAMMER *pgm) { * mandatory functions */ pgm->initialize = stk500_initialize; - pgm->parseextparams = stk500_parseextparms; pgm->display = stk500_display; pgm->enable = stk500_enable; pgm->disable = stk500_disable; @@ -1300,11 +1483,19 @@ void stk500_initpgm(PROGRAMMER *pgm) { pgm->paged_write = stk500_paged_write; pgm->paged_load = stk500_paged_load; pgm->print_parms = stk500_print_parms; - pgm->set_vtarget = stk500_set_vtarget; - pgm->set_varef = stk500_set_varef; - pgm->set_fosc = stk500_set_fosc; pgm->set_sck_period = stk500_set_sck_period; + pgm->parseextparams = stk500_parseextparms; pgm->setup = stk500_setup; pgm->teardown = stk500_teardown; pgm->page_size = 256; + + /* + * hardware dependent functions + */ + if (pgm->extra_features & HAS_VTARG_ADJ) + pgm->set_vtarget = stk500_set_vtarget; + if (pgm->extra_features & HAS_VAREF_ADJ) + pgm->set_varef = stk500_set_varef; + if (pgm->extra_features & HAS_FOSC_ADJ) + pgm->set_fosc = stk500_set_fosc; } diff --git a/src/stk500.h b/src/stk500.h index 3d28b064..fa7818f6 100644 --- a/src/stk500.h +++ b/src/stk500.h @@ -42,6 +42,21 @@ struct pdata { unsigned char ext_addr_byte; // Record ext-addr byte set in the target device (if used) int retry_attempts; // Number of connection attempts provided by the user int xbeeResetPin; // Piggy back variable used by xbee programmmer + + // Get/set flags for adjustable target voltage + bool vtarg_get; + bool vtarg_set; + double vtarg_data; + + // Get/set flags for adjustable analog reference voltage + bool varef_get; + bool varef_set; + double varef_data; + + // Get/set flags for programmable clock generator + bool fosc_get; + bool fosc_set; + double fosc_data; }; #define PDATA(pgm) ((struct pdata *)(pgm->cookie)) diff --git a/src/stk500v2.c b/src/stk500v2.c index 9766a7ec..acd76744 100644 --- a/src/stk500v2.c +++ b/src/stk500v2.c @@ -377,6 +377,28 @@ b2_to_u16(unsigned char *b) return l; } +static void +u16_to_b2(unsigned char *b, unsigned short l) +{ + b[0] = l & 0xff; + b[1] = (l >> 8) & 0xff; +} + +static double +f_to_kHz_MHz(double f, const char **unit) +{ + if (f > 1e6) { + f /= 1e6; + *unit = "MHz"; + } else if (f > 1e3) { + f /= 1000; + *unit = "kHz"; + } else + *unit = "Hz"; + + return f; +} + static int stk500v2_send_mk2(const PROGRAMMER *pgm, unsigned char *data, size_t len) { if (serial_send(&pgm->fd, data, len) != 0) { pmsg_error("unable to send command to serial port\n"); @@ -1223,6 +1245,109 @@ static int stk500v2_initialize(const PROGRAMMER *pgm, const AVRPART *p) { // stk600_setup_isp(pgm); [moved to pgm->enable()] } + // Read or write target voltage + if (PDATA(pgm)->vtarg_get || PDATA(pgm)->vtarg_set) { + // Read current target voltage set value + unsigned char vtarg_read; + stk500v2_getparm(pgm, PARAM_VTARGET, &vtarg_read); + if (PDATA(pgm)->vtarg_get) + msg_info("Target voltage value read as %.2fV\n", (vtarg_read / 10.0)); + // Write target voltage value + else { + msg_info("Changing target voltage from %.2f to %.2fV\n", (vtarg_read / 10.0), PDATA(pgm)->vtarg_data); + if(pgm->set_vtarget(pgm, PDATA(pgm)->vtarg_data) < 0) + return -1; + } + } + + // Read or write analog reference voltage + if (PDATA(pgm)->varef_get || PDATA(pgm)->varef_set) { + if(PDATA(pgm)->pgmtype == PGMTYPE_STK500) { + // STK500: Read current analog reference voltage + unsigned char varef_read; + stk500v2_getparm(pgm, PARAM_VADJUST, &varef_read); + if (PDATA(pgm)->varef_get) + msg_info("Analog reference voltage value read as %.2fV\n", (varef_read / 10.0)); + // STK500: Write analog reference voltage + else { + msg_info("Changing analog reference voltage from %.2f to %.2fV\n", + (varef_read / 10.0), PDATA(pgm)->varef_data); + if(pgm->set_varef(pgm, 0, PDATA(pgm)->varef_data) < 0) + return -1; + } + } else if(PDATA(pgm)->pgmtype == PGMTYPE_STK600) { + // STK600: Read current target voltage set value + unsigned int varef_read; + stk500v2_getparm2(pgm, PDATA(pgm)->varef_channel == 0 ? PARAM2_AREF0 : PARAM2_AREF1, &varef_read); + if (PDATA(pgm)->varef_get) + msg_info("Analog reference channel %d voltage read as %.2fV\n", PDATA(pgm)->varef_channel, (varef_read / 100.0)); + // STK600: Write target voltage value for channel n + else { + msg_info("Changing analog reference channel %d voltage from %.2f to %.2fV\n", + PDATA(pgm)->varef_channel, (varef_read / 100.0), PDATA(pgm)->varef_data); + if(pgm->set_varef(pgm, PDATA(pgm)->varef_channel, PDATA(pgm)->varef_data) < 0) + return -1; + } + } + } + + // Read or write clock generator frequency + if (PDATA(pgm)->fosc_get || PDATA(pgm)->fosc_set) { + if(PDATA(pgm)->pgmtype == PGMTYPE_STK500) { + // Read current target voltage set value + unsigned char osc_pscale; + unsigned char osc_cmatch; + const char *unit_get = {"Hz"}; + double f_get = 0.0; + stk500v2_getparm(pgm, PARAM_OSC_PSCALE, &osc_pscale); + stk500v2_getparm(pgm, PARAM_OSC_CMATCH, &osc_cmatch); + if(osc_pscale) { + int prescale = 1; + f_get = STK500V2_XTAL / 2; + switch (osc_pscale) { + case 2: prescale = 8; break; + case 3: prescale = 32; break; + case 4: prescale = 64; break; + case 5: prescale = 128; break; + case 6: prescale = 256; break; + case 7: prescale = 1024; break; + } + f_get /= prescale; + f_get /= (osc_cmatch + 1); + f_get = f_to_kHz_MHz(f_get, &unit_get); + } + if (PDATA(pgm)->fosc_get) + msg_info("Oscillator currently set to %.3f %s\n", f_get, unit_get); + // Write target voltage value + else { + const char *unit_set; + double f_set = f_to_kHz_MHz(PDATA(pgm)->fosc_data, &unit_set); + msg_info("Changing oscillator frequency from %.3f %s to %.3f %s\n", f_get, unit_get, f_set, unit_set); + if(pgm->set_fosc(pgm, PDATA(pgm)->fosc_data) < 0) + return -1; + } + } else if(PDATA(pgm)->pgmtype == PGMTYPE_STK600) { + // Read current target voltage set value + unsigned int clock_conf; + stk500v2_getparm2(pgm, PARAM2_CLOCK_CONF, &clock_conf); + unsigned int oct = (clock_conf & 0xf000) >> 12u; + unsigned int dac = (clock_conf & 0x0ffc) >> 2u; + double f_get = pow(2, (double)oct) * 2078.0 / (2 - (double)dac / 1024.0); + const char *unit_get = {"Hz"}; + f_get = f_to_kHz_MHz(f_get, &unit_get); + if (PDATA(pgm)->fosc_get) + msg_info("Oscillator currently set to %.3f %s\n", f_get, unit_get); + // Write target voltage value + else { + const char *unit_set; + double f_set = f_to_kHz_MHz(PDATA(pgm)->fosc_data, &unit_set); + msg_info("Changing oscillator frequency from %.3f %s to %.3f %s\n", f_get, unit_get, f_set, unit_set); + if(pgm->set_fosc(pgm, PDATA(pgm)->fosc_data) < 0) + return -1; + } + } + } + /* * Examine the avrpart's memory definitions, and initialize the page * caches. For devices/memory that are not page oriented, treat @@ -1350,6 +1475,26 @@ static int stk500v2_jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) { } } + // Read or write target voltage + if (PDATA(pgm)->vtarg_get || PDATA(pgm)->vtarg_set) { + // Read current target voltage set value + unsigned char buf[2]; + if (jtag3_getparm(pgmcp, SCOPE_GENERAL, 1, PARM3_VADJUST, buf, 2) < 0) + return -1; + double vtarg_read = b2_to_u16(buf) / 1000.0; + if (PDATA(pgm)->vtarg_get) + msg_info("Target voltage value read as %.2fV\n", vtarg_read); + // Write target voltage value + else { + u16_to_b2(buf, (unsigned)(PDATA(pgm)->vtarg_data * 1000)); + msg_info("Changing target voltage from %.2f to %.2fV\n", vtarg_read, PDATA(pgm)->vtarg_data); + if (jtag3_setparm(pgmcp, SCOPE_GENERAL, 1, PARM3_VADJUST, buf, sizeof(buf)) < 0) { + msg_warning("Cannot set target voltage %.2fV\n", PDATA(pgm)->vtarg_data); + return -1; + } + } + } + free(pgmcp); /* @@ -1415,6 +1560,109 @@ static int stk500hv_initialize(const PROGRAMMER *pgm, const AVRPART *p, enum hvm return -1; } + // Read or write target voltage + if (PDATA(pgm)->vtarg_get || PDATA(pgm)->vtarg_set) { + // Read current target voltage set value + unsigned char vtarg_read; + stk500v2_getparm(pgm, PARAM_VTARGET, &vtarg_read); + if (PDATA(pgm)->vtarg_get) + msg_info("Target voltage value read as %.2fV\n", (vtarg_read / 10.0)); + // Write target voltage value + else { + msg_info("Changing target voltage from %.2f to %.2fV\n", (vtarg_read / 10.0), PDATA(pgm)->vtarg_data); + if(pgm->set_vtarget(pgm, PDATA(pgm)->vtarg_data) < 0) + return -1; + } + } + + // Read or write analog reference voltage + if (PDATA(pgm)->varef_get || PDATA(pgm)->varef_set) { + if(PDATA(pgm)->pgmtype == PGMTYPE_STK500) { + // STK500: Read current analog reference voltage + unsigned char varef_read; + stk500v2_getparm(pgm, PARAM_VADJUST, &varef_read); + if (PDATA(pgm)->varef_get) + msg_info("Analog reference voltage value read as %.2fV\n", (varef_read / 10.0)); + // STK500: Write analog reference voltage + else { + msg_info("Changing analog reference voltage from %.2f to %.2fV\n", + (varef_read / 10.0), PDATA(pgm)->varef_data); + if(pgm->set_varef(pgm, 0, PDATA(pgm)->varef_data) < 0) + return -1; + } + } else if(PDATA(pgm)->pgmtype == PGMTYPE_STK600) { + // STK600: Read current target voltage set value + unsigned int varef_read; + stk500v2_getparm2(pgm, PDATA(pgm)->varef_channel == 0 ? PARAM2_AREF0 : PARAM2_AREF1, &varef_read); + if (PDATA(pgm)->varef_get) + msg_info("Analog reference channel %d voltage read as %.2fV\n", PDATA(pgm)->varef_channel, (varef_read / 100.0)); + // STK600: Write target voltage value for channel n + else { + msg_info("Changing analog reference channel %d voltage from %.2f to %.2fV\n", + PDATA(pgm)->varef_channel, (varef_read / 100.0), PDATA(pgm)->varef_data); + if(pgm->set_varef(pgm, PDATA(pgm)->varef_channel, PDATA(pgm)->varef_data) < 0) + return -1; + } + } + } + + // Read or write clock generator frequency + if (PDATA(pgm)->fosc_get || PDATA(pgm)->fosc_set) { + if(PDATA(pgm)->pgmtype == PGMTYPE_STK500) { + // Read current target voltage set value + unsigned char osc_pscale; + unsigned char osc_cmatch; + const char *unit_get = {"Hz"}; + double f_get = 0.0; + stk500v2_getparm(pgm, PARAM_OSC_PSCALE, &osc_pscale); + stk500v2_getparm(pgm, PARAM_OSC_CMATCH, &osc_cmatch); + if(osc_pscale) { + int prescale = 1; + f_get = STK500V2_XTAL / 2; + switch (osc_pscale) { + case 2: prescale = 8; break; + case 3: prescale = 32; break; + case 4: prescale = 64; break; + case 5: prescale = 128; break; + case 6: prescale = 256; break; + case 7: prescale = 1024; break; + } + f_get /= prescale; + f_get /= (osc_cmatch + 1); + f_get = f_to_kHz_MHz(f_get, &unit_get); + } + if (PDATA(pgm)->fosc_get) + msg_info("Oscillator currently set to %.3f %s\n", f_get, unit_get); + // Write target voltage value + else { + const char *unit_set; + double f_set = f_to_kHz_MHz(PDATA(pgm)->fosc_data, &unit_set); + msg_info("Changing oscillator frequency from %.3f %s to %.3f %s\n", f_get, unit_get, f_set, unit_set); + if(pgm->set_fosc(pgm, PDATA(pgm)->fosc_data) < 0) + return -1; + } + } else if(PDATA(pgm)->pgmtype == PGMTYPE_STK600) { + // Read current target voltage set value + unsigned int clock_conf; + stk500v2_getparm2(pgm, PARAM2_CLOCK_CONF, &clock_conf); + unsigned int oct = (clock_conf & 0xf000) >> 12u; + unsigned int dac = (clock_conf & 0x0ffc) >> 2u; + double f_get = pow(2, (double)oct) * 2078.0 / (2 - (double)dac / 1024.0); + const char *unit_get = {"Hz"}; + f_get = f_to_kHz_MHz(f_get, &unit_get); + if (PDATA(pgm)->fosc_get) + msg_info("Oscillator currently set to %.3f %s\n", f_get, unit_get); + // Write target voltage value + else { + const char *unit_set; + double f_set = f_to_kHz_MHz(PDATA(pgm)->fosc_data, &unit_set); + msg_info("Changing oscillator frequency from %.3f %s to %.3f %s\n", f_get, unit_get, f_set, unit_set); + if(pgm->set_fosc(pgm, PDATA(pgm)->fosc_data) < 0) + return -1; + } + } + } + /* * Examine the avrpart's memory definitions, and initialize the page * caches. For devices/memory that are not page oriented, treat @@ -1563,6 +1811,157 @@ static void stk500v2_enable(PROGRAMMER *pgm, const AVRPART *p) { return; } +static int stk500v2_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) { + LNODEID ln; + const char *extended_param; + int rv = 0; + + for (ln = lfirst(extparms); ln; ln = lnext(ln)) { + extended_param = ldata(ln); + + if (str_starts(extended_param, "vtarg")) { + if (pgm->extra_features & HAS_VTARG_ADJ) { + // Set target voltage + 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); + rv = -1; + break; + } + PDATA(pgm)->vtarg_set = true; + continue; + } + // Get target voltage + else if(str_eq(extended_param, "vtarg")) { + PDATA(pgm)->vtarg_get = true; + continue; + } + } + } + + else if (str_starts(extended_param, "varef")) { + if (pgm->extra_features & HAS_VAREF_ADJ) { + int sscanf_success = 0; + double varef_set_val = 0; + // Get new analog reference voltage for channel 0 + if (str_starts(extended_param, "varef=")) { + sscanf_success = sscanf(extended_param, "varef=%lf", &varef_set_val); + PDATA(pgm)->varef_channel = 0; + PDATA(pgm)->varef_set = true; + } + // Get new analog reference voltage for channel 0 + else if(str_starts(extended_param, "varef0=")) { + sscanf_success = sscanf(extended_param, "varef0=%lf", &varef_set_val); + PDATA(pgm)->varef_channel = 0; + PDATA(pgm)->varef_set = true; + } + // Get new analog reference voltage for channel 1 + else if (str_starts(extended_param, "varef1=") && str_contains(pgm->type, "STK600")) { + sscanf_success = sscanf(extended_param, "varef1=%lf", &varef_set_val); + PDATA(pgm)->varef_channel = 1; + PDATA(pgm)->varef_set = true; + } + // Get current analog reference voltage for channel 0 + else if(str_eq(extended_param, "varef") || str_eq(extended_param, "varef0")) { + PDATA(pgm)->varef_get = true; + PDATA(pgm)->varef_channel = 0; + continue; + } + // Get current analog reference voltage for channel 1 + else if(str_eq(extended_param, "varef1") && str_contains(pgm->type, "STK600")) { + PDATA(pgm)->varef_get = true; + PDATA(pgm)->varef_channel = 1; + continue; + } + // Set analog reference voltage + if (PDATA(pgm)->varef_set) { + PDATA(pgm)->varef_data = (double)((int)(varef_set_val * 100 + .5)) / 100; + if (sscanf_success < 1 || varef_set_val < 0) { + pmsg_error("invalid varef value '%s'\n", extended_param); + PDATA(pgm)->varef_set = false; + rv = -1; + break; + } + continue; + } + } + } + + else if (str_starts(extended_param, "fosc")) { + if (pgm->extra_features & HAS_VAREF_ADJ) { + // Set clock generator frequency + if (str_starts(extended_param, "fosc=")) { + char fosc_str[16] = {0}; + int sscanf_success = sscanf(extended_param, "fosc=%10s", fosc_str); + if (sscanf_success < 1) { + pmsg_error("invalid fosc value '%s'\n", extended_param); + rv = -1; + break; + } + char *endp; + double v = strtod(fosc_str, &endp); + if (endp == fosc_str){ + if (str_eq(fosc_str, "off")) + PDATA(pgm)->fosc_data = 0.0; + else { + pmsg_error("cannot parse fosc value %s\n", fosc_str); + rv = -1; + break; + } + } + if (*endp == 'm' || *endp == 'M') + PDATA(pgm)->fosc_data = v * 1e6; + else if (*endp == 'k' || *endp == 'K') + PDATA(pgm)->fosc_data = v * 1e3; + PDATA(pgm)->fosc_set = true; + continue; + } + // Get clock generator frequency + else if(str_eq(extended_param, "fosc")) { + PDATA(pgm)->fosc_get = true; + continue; + } + } + } + + else if (str_eq(extended_param, "help")) { + char *prg = (char *)ldata(lfirst(pgm->id)); + msg_error("%s -c %s extended options:\n", progname, prg); + if (pgm->extra_features & HAS_VTARG_ADJ) { + msg_error(" -xvtarg Read target supply voltage\n"); + msg_error(" -xvtarg= Set target supply voltage\n"); + } + if (pgm->extra_features & HAS_VAREF_ADJ) { + if (str_contains(pgm->type, "STK500")) { + msg_error(" -xvaref Read analog reference voltage\n"); + msg_error(" -xvaref= Set analog reference voltage\n"); + } + else if (str_contains(pgm->type, "STK600")) { + msg_error(" -xvaref Read channel 0 analog reference voltage\n"); + msg_error(" -xvaref0 Alias for -xvaref\n"); + msg_error(" -xvaref1 Read channel 1 analog reference voltage\n"); + msg_error(" -xvaref= Set channel 0 analog reference voltage\n"); + msg_error(" -xvaref0= Alias for -xvaref=\n"); + msg_error(" -xvaref1= Set channel 1 analog reference voltage\n"); + } + } + if (pgm->extra_features & HAS_FOSC_ADJ) { + msg_error(" -xfosc Read oscillator clock frequency\n"); + msg_error(" -xfosc=[M|k]|off Set oscillator clock frequency\n"); + } + msg_error(" -xhelp Show this help menu and exit\n"); + exit(0); + } + + pmsg_error("invalid extended parameter '%s'\n", extended_param); + rv = -1; + } + return rv; +} + static int stk500v2_jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) { LNODEID ln; const char *extended_param; @@ -1619,6 +2018,29 @@ static int stk500v2_jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extp } } + else if (str_starts(extended_param, "vtarg")) { + if (pgm->extra_features & HAS_VTARG_ADJ) { + // Set target voltage + 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); + rv = -1; + break; + } + PDATA(pgm)->vtarg_set = true; + } + // Get target voltage + else if(str_eq(extended_param, "vtarg")) + PDATA(pgm)->vtarg_get = true; + else + break; + continue; + } + } + else if (str_eq(extended_param, "help")) { char *prg = (char *)ldata(lfirst(pgm->id)); msg_error("%s -c %s extended options:\n", progname, prg); @@ -1628,6 +2050,10 @@ static int stk500v2_jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extp 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) { + msg_error(" -xvtarg Read on-board target supply voltage\n"); + msg_error(" -xvtarg= Set on-board target supply voltage\n"); + } msg_error (" -xhelp Show this help menu and exit\n"); exit(0); } @@ -2925,7 +3351,6 @@ static int stk600_set_vtarget(const PROGRAMMER *pgm, double v) { unsigned char utarg; unsigned int uaref; int rv; - utarg = (unsigned)((v + 0.049) * 10); if (stk500v2_getparm2(pgm, PARAM2_AREF0, &uaref) != 0) { @@ -3206,7 +3631,6 @@ static void stk500v2_display(const PROGRAMMER *pgm, const char *p) { PROGRAMMER *pgmcp = pgm_dup(pgm); pgmcp->cookie = PDATA(pgm)->chained_pdata; jtag3_display(pgmcp, p); - msg_info("\n"); pgm_free(pgmcp); } stk500v2_print_parms1(pgm, p, stderr); @@ -3214,20 +3638,6 @@ static void stk500v2_display(const PROGRAMMER *pgm, const char *p) { return; } -static double -f_to_kHz_MHz(double f, const char **unit) -{ - if (f > 1e6) { - f /= 1e6; - *unit = "MHz"; - } else if (f > 1e3) { - f /= 1000; - *unit = "kHz"; - } else - *unit = "Hz"; - - return f; -} static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp) { unsigned char vtarget = 0, vadjust = 0, osc_pscale = 0, osc_cmatch = 0, sck_duration =0; //XXX 0 is not correct, check caller @@ -3301,7 +3711,7 @@ static void stk500v2_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp pgmcp->id = lcreat(NULL, 0); // Copy pgm->id contents over to pgmcp->id for(LNODEID ln=lfirst(pgm->id); ln; ln=lnext(ln)) - ladd(pgmcp->id, cfg_strdup("stk500v2_print_parms1()", ldata(ln))); + ladd(pgmcp->id, cfg_strdup("stk500v2_display()", ldata(ln))); jtag3_print_parms1(pgmcp, p, fp); pgm_free(pgmcp); } @@ -4280,14 +4690,14 @@ static void stk600_setup_xprog(PROGRAMMER * pgm) */ static void stk600_setup_isp(PROGRAMMER * pgm) { - pgm->program_enable = stk500v2_program_enable; - pgm->disable = stk500v2_disable; - pgm->read_byte = stk500isp_read_byte; - pgm->write_byte = stk500isp_write_byte; - pgm->paged_load = stk500v2_paged_load; - pgm->paged_write = stk500v2_paged_write; - pgm->page_erase = stk500v2_page_erase; - pgm->chip_erase = stk500v2_chip_erase; + pgm->program_enable = stk500v2_program_enable; + pgm->disable = stk500v2_disable; + pgm->read_byte = stk500isp_read_byte; + pgm->write_byte = stk500isp_write_byte; + pgm->paged_load = stk500v2_paged_load; + pgm->paged_write = stk500v2_paged_write; + pgm->page_erase = stk500v2_page_erase; + pgm->chip_erase = stk500v2_chip_erase; } const char stk500v2_desc[] = "Atmel STK500 Version 2.x firmware"; @@ -4317,14 +4727,22 @@ void stk500v2_initpgm(PROGRAMMER *pgm) { pgm->paged_load = stk500v2_paged_load; pgm->page_erase = stk500v2_page_erase; pgm->print_parms = stk500v2_print_parms; - pgm->set_vtarget = stk500v2_set_vtarget; - pgm->set_varef = stk500v2_set_varef; - pgm->set_fosc = stk500v2_set_fosc; pgm->set_sck_period = stk500v2_set_sck_period; pgm->perform_osccal = stk500v2_perform_osccal; + pgm->parseextparams = stk500v2_parseextparms; pgm->setup = stk500v2_setup; pgm->teardown = stk500v2_teardown; pgm->page_size = 256; + + /* + * hardware dependent functions + */ + if (pgm->extra_features & HAS_VTARG_ADJ) + pgm->set_vtarget = stk500v2_set_vtarget; + if (pgm->extra_features & HAS_VAREF_ADJ) + pgm->set_varef = stk500v2_set_varef; + if (pgm->extra_features & HAS_FOSC_ADJ) + pgm->set_fosc = stk500v2_set_fosc; } const char stk500pp_desc[] = "Atmel STK500 V2 in parallel programming mode"; @@ -4352,13 +4770,21 @@ void stk500pp_initpgm(PROGRAMMER *pgm) { pgm->paged_write = stk500pp_paged_write; pgm->paged_load = stk500pp_paged_load; pgm->print_parms = stk500v2_print_parms; - pgm->set_vtarget = stk500v2_set_vtarget; - pgm->set_varef = stk500v2_set_varef; - pgm->set_fosc = stk500v2_set_fosc; pgm->set_sck_period = stk500v2_set_sck_period; + pgm->parseextparams = stk500v2_parseextparms; pgm->setup = stk500v2_setup; pgm->teardown = stk500v2_teardown; pgm->page_size = 256; + + /* + * hardware dependent functions + */ + if (pgm->extra_features & HAS_VTARG_ADJ) + pgm->set_vtarget = stk500v2_set_vtarget; + if (pgm->extra_features & HAS_VAREF_ADJ) + pgm->set_varef = stk500v2_set_varef; + if (pgm->extra_features & HAS_FOSC_ADJ) + pgm->set_fosc = stk500v2_set_fosc; } const char stk500hvsp_desc[] = "Atmel STK500 V2 in high-voltage serial programming mode"; @@ -4386,13 +4812,21 @@ void stk500hvsp_initpgm(PROGRAMMER *pgm) { pgm->paged_write = stk500hvsp_paged_write; pgm->paged_load = stk500hvsp_paged_load; pgm->print_parms = stk500v2_print_parms; - pgm->set_vtarget = stk500v2_set_vtarget; - pgm->set_varef = stk500v2_set_varef; - pgm->set_fosc = stk500v2_set_fosc; pgm->set_sck_period = stk500v2_set_sck_period; + pgm->parseextparams = stk500v2_parseextparms; pgm->setup = stk500v2_setup; pgm->teardown = stk500v2_teardown; pgm->page_size = 256; + + /* + * hardware dependent functions + */ + if (pgm->extra_features & HAS_VTARG_ADJ) + pgm->set_vtarget = stk500v2_set_vtarget; + if (pgm->extra_features & HAS_VAREF_ADJ) + pgm->set_varef = stk500v2_set_varef; + if (pgm->extra_features & HAS_FOSC_ADJ) + pgm->set_fosc = stk500v2_set_fosc; } const char stk500v2_jtagmkII_desc[] = "Atmel JTAG ICE mkII in ISP mode"; @@ -4487,9 +4921,6 @@ void stk500v2_dragon_pp_initpgm(PROGRAMMER *pgm) { pgm->paged_write = stk500pp_paged_write; pgm->paged_load = stk500pp_paged_load; pgm->print_parms = stk500v2_print_parms; - pgm->set_vtarget = stk500v2_set_vtarget; - pgm->set_varef = stk500v2_set_varef; - pgm->set_fosc = stk500v2_set_fosc; pgm->set_sck_period = stk500v2_set_sck_period_mk2; pgm->setup = stk500v2_jtagmkII_setup; pgm->teardown = stk500v2_jtagmkII_teardown; @@ -4521,9 +4952,6 @@ void stk500v2_dragon_hvsp_initpgm(PROGRAMMER *pgm) { pgm->paged_write = stk500hvsp_paged_write; pgm->paged_load = stk500hvsp_paged_load; pgm->print_parms = stk500v2_print_parms; - pgm->set_vtarget = stk500v2_set_vtarget; - pgm->set_varef = stk500v2_set_varef; - pgm->set_fosc = stk500v2_set_fosc; pgm->set_sck_period = stk500v2_set_sck_period_mk2; pgm->setup = stk500v2_jtagmkII_setup; pgm->teardown = stk500v2_jtagmkII_teardown; @@ -4562,6 +4990,7 @@ void stk600_initpgm(PROGRAMMER *pgm) { pgm->set_fosc = stk600_set_fosc; pgm->set_sck_period = stk600_set_sck_period; pgm->perform_osccal = stk500v2_perform_osccal; + pgm->parseextparams = stk500v2_parseextparms; pgm->setup = stk500v2_setup; pgm->teardown = stk500v2_teardown; pgm->page_size = 256; @@ -4596,6 +5025,7 @@ void stk600pp_initpgm(PROGRAMMER *pgm) { pgm->set_varef = stk600_set_varef; pgm->set_fosc = stk600_set_fosc; pgm->set_sck_period = stk600_set_sck_period; + pgm->parseextparams = stk500v2_parseextparms; pgm->setup = stk500v2_setup; pgm->teardown = stk500v2_teardown; pgm->page_size = 256; @@ -4630,6 +5060,7 @@ void stk600hvsp_initpgm(PROGRAMMER *pgm) { pgm->set_varef = stk600_set_varef; pgm->set_fosc = stk600_set_fosc; pgm->set_sck_period = stk600_set_sck_period; + pgm->parseextparams = stk500v2_parseextparms; pgm->setup = stk500v2_setup; pgm->teardown = stk500v2_teardown; pgm->page_size = 256; @@ -4644,7 +5075,6 @@ void stk500v2_jtag3_initpgm(PROGRAMMER *pgm) { * mandatory functions */ pgm->initialize = stk500v2_jtag3_initialize; - pgm->parseextparams = stk500v2_jtag3_parseextparms; pgm->display = stk500v2_display; pgm->enable = stk500v2_enable; pgm->disable = stk500v2_jtag3_disable; @@ -4665,10 +5095,14 @@ void stk500v2_jtag3_initpgm(PROGRAMMER *pgm) { pgm->print_parms = stk500v2_print_parms; pgm->set_sck_period = stk500v2_jtag3_set_sck_period; pgm->perform_osccal = stk500v2_perform_osccal; + pgm->parseextparams = stk500v2_jtag3_parseextparms; pgm->setup = stk500v2_jtag3_setup; pgm->teardown = stk500v2_jtag3_teardown; pgm->page_size = 256; + /* + * hardware dependent functions + */ if (pgm->extra_features & HAS_VTARG_ADJ) pgm->set_vtarget = jtag3_set_vtarget; } diff --git a/src/stk500v2_private.h b/src/stk500v2_private.h index b58cc5b4..c160d866 100644 --- a/src/stk500v2_private.h +++ b/src/stk500v2_private.h @@ -280,6 +280,22 @@ struct pdata bool vtarg_switch_set; unsigned char vtarg_switch_data[2]; + /* Get/set flags for adjustable target voltage */ + bool vtarg_get; + bool vtarg_set; + double vtarg_data; + + /* Get/set flags for adjustable analog reference voltage */ + bool varef_get; + bool varef_set; + int varef_channel; + double varef_data; + + /* Get/set flags for programmable clock generator */ + bool fosc_get; + bool fosc_set; + double fosc_data; + const AVRPART *lastpart; /* Start address of Xmega boot area */