Compare commits

...

22 Commits

Author SHA1 Message Date
Joerg Wunsch 7b79b72794 PR #872 done 2022-02-11 22:17:24 +01:00
Jörg Wunsch 76a17be4d0
Merge pull request #872 from MCUdude/jtag-string-formatting
Tweak programmer info formatting strings
2022-02-11 22:16:39 +01:00
MCUdude 80f1d96e07 Tweak programmer info formatting strings
Now all colons are on a straight line, just like #853 did to all jtag3 compatible programmers
2022-02-11 22:10:52 +01:00
Joerg Wunsch 09fe08e51c PR #853 done 2022-02-11 21:45:31 +01:00
Jörg Wunsch f2c73c2bb8
Merge pull request #853 from MCUdude/jtag3-clock-update
Print JTAG3 clocks after configuration + string formatting
2022-02-11 21:44:54 +01:00
MCUdude b581d14823 String formatting
Allign colons, only print clocks that are actually present (>0 kHz)
2022-02-11 21:35:07 +01:00
Joerg Wunsch 354a1c4f1f PR #869 closed 2022-02-11 21:17:01 +01:00
Jörg Wunsch 23a09a6197
Merge pull request #869 from MCUdude/alias-memories
Add fuse name aliases to avrdude.conf + tweak update.c
2022-02-11 21:15:34 +01:00
MCUdude 3fc39c47ad Print memory name alias together with the canonical name if present
in avrdude.conf. An example would be "avrdude: reading fuse0/wdtcfg memory:"
2022-02-11 21:10:05 +01:00
MCUdude d6ccf7a3ff Add memory alias names for megaAVR0/tinyAVR0,1,2/AVR-Dx/AVR-Ex fuses 2022-02-10 22:34:33 +01:00
Joerg Wunsch 452f673f38 Back out the last "alias" commit (search for existing alias).
It breaks the alias handling completely as the search happens
way too late. So instead, just keep any possibly duplicate
name as it won't be in our way anyway.
2022-02-10 21:26:05 +01:00
Joerg Wunsch 38a3af37e2 Mention PRs #863 and #868. 2022-02-10 20:39:51 +01:00
Jörg Wunsch d134dc8fff
Alias keyword (#868)
Implementation for an "alias" keyword.

By now, only applied inside memory descriptions.

* Make "mem_alias" a separate nonterminal.

The previous implementation attempt caused a syntax error in
yacc code, and separating mem_alias on the same level as
mem_spec appears to be the cleaner solution anyway.

* Maintain real memory aliases.

Instead of duplicating the aliased memory with a new name, maintain a
second list of memory aliases (per device) that contains a pointer to
the memory area it is aliased to. That way, a memory name can be
clearly distinguished between the canonical one and any aliases.

* Check p->mem_alias != NULL before touching it

* Add avr_find_memalias()

This takes a memory region as input, and searches whether an
alias can be found for it.

* We need to add a list structure for the mem_alias list, always.

By that means, mem_alias won't ever be NULL, so no need to check
later.

Also, in avr_dup_part(), duplicate the alias list.

* In a memory alias, actually remember the current name.

* In avr_dup_part(), adjust pointers of aliased memories

While walking the list of memories, for each entry, see if there is an
alias pointing to it. If so, allocate a duplicated one, and fix its
aliased_mem pointer to point to the duplicated memory region instead
of the original one.

* Add avr_locate_mem_noalias()

When looking whether any memory region has already been defined for
the current part while parsing the config file, only non-aliased names
must be considered. Otherwise, a newly defined alias would kick out
the memory definition it is being aliased to.

* When defining a mem_alias, drop any existing one of that name.

* Actually use avr_find_memalias() to find aliases

* Add declaration for avr_find_memalias()

* When defining a memory, also search for an existing alias

If the newly defined name has the same as an existing alias, the alias
can be removed.

Note that we do explicitly *not* remove any memory by the same name of
a later defined alias, as this might invalidate another alias'es
pointer. If someone defines that, the alias name just won't ever be
found by avr_locate_mem().
2022-02-10 20:39:19 +01:00
Jörg Wunsch ba314f23e9
Merge pull request #863 from MCUdude/jtag3-read-memory-alias
Add support for reading from more memory sections
2022-02-10 20:35:06 +01:00
MCUdude a43f220ef9 Add support for reading from more memory sections
It's now possible to read the following memories if present: osccal16, osccal20, tempsense, osc16err, osc20err
2022-02-07 21:51:35 +01:00
Joerg Wunsch 1c0b70da89 PR #859 done 2022-02-05 22:03:59 +01:00
Jörg Wunsch b6a6c681df
Merge pull request #859 from dl8dtl/safemode-removal
Remove the "safemode" feature.
2022-02-05 22:03:12 +01:00
Joerg Wunsch 3eda1d15f9 Mention PR #858 2022-02-05 21:59:04 +01:00
Marius Greuel c6438532f0
Merge pull request #858 from yegorich/cmake-install-fix
CMake: use CMAKE_CURRENT_BINARY_DIR to locate avrdude.conf
2022-02-05 21:46:38 +01:00
Joerg Wunsch 8c6c6a14ec Remove the "safemode" feature.
This feature has been designed with the sometimes quite flakey direct
(parallel or serial port attached) bitbang programming adapters in
mind that were quite common about two decades ago.

With parallel ports vanishing from modern PCs almost completely, and
the advent of various USB-attached low-cost programming devices,
this class of programmers disappeared almost completely.

Furthermore, the fuse combinations that were covered by the feature
are no longer around on all recent AVR devices, so for an ever
increasing number of devices, safemode already became meaningless and
was turned off anyway.

With the prospective version 7.x release, it's a good point in time to
introduce a major change like this one.
2022-01-31 20:44:32 +01:00
Yegor Yefremov 7ed3632902 CMake: use CMAKE_CURRENT_BINARY_DIR to locate avrdude.conf
With the split CMakeLists.txt infrastructure avrdude.conf
will be created in the build/src and not build folder. Hence,
fix its location in the install command.
2022-01-31 07:18:59 +01:00
MCUdude f6bbaadfa6 Print clock info after the correct clock speeds has been set
The "new" clock speed set by the -B flag wasn't reflected in the output log
2022-01-23 22:45:54 +01:00
19 changed files with 299 additions and 815 deletions

14
NEWS
View File

@ -13,6 +13,11 @@ Changes since version 6.4:
- Started to add CMake (by now, parallel with autoconf/automake)
- New-architecture devices (AVR8X mega and tiny) can access all
fuses, and memory display shows meaningful alias names
- The "safemode" feature has been removed. The major class of
programmers it has been designed for (lowlevel bitbang
programmers on parallel or serial ports) virtually doesn't exist
anymore, and the fuse combination that was covered by it do not
match the fuses of modern AVR devices anyway.
* New devices supported:
@ -119,10 +124,19 @@ Changes since version 6.4:
- Fix libusb-1.0 error strings #850
- Assign proper type to msg[] in errstr() #857
- Fix Arduino retry attempts #855
- CMake: use CMAKE_CURRENT_BINARY_DIR to locate avrdude.conf #858
- Remove the "safemode" feature. #859
- Add support for reading from more memory sections #863
- Alias keyword #868
- Add fuse name aliases to avrdude.conf + tweak update.c #869
- Print JTAG3 clocks after configuration + string formatting #853
- Tweak programmer info formatting strings #872
* Internals:
- Development moved to Github
- Addition of "alias" keyword to avrdude.conf.in syntax; used
for fuse name aliases right now
Version 6.4:

View File

@ -173,7 +173,6 @@ add_library(libavrdude
ppi.c
ppi.h
ppiwin.c
safemode.c
serbb.h
serbb_posix.c
serbb_win32.c
@ -268,5 +267,5 @@ install(TARGETS libavrdude
ARCHIVE DESTINATION lib
PUBLIC_HEADER DESTINATION include COMPONENT dev
)
install(FILES "${PROJECT_BINARY_DIR}/avrdude.conf" TYPE SYSCONF)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/avrdude.conf" TYPE SYSCONF)
install(FILES avrdude.1 TYPE MAN)

View File

@ -148,7 +148,6 @@ libavrdude_a_SOURCES = \
ppi.c \
ppi.h \
ppiwin.c \
safemode.c \
serbb.h \
serbb_posix.c \
serbb_win32.c \

View File

@ -791,30 +791,6 @@ int avr_write_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
int avr_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
unsigned long addr, unsigned char data)
{
unsigned char safemode_lfuse;
unsigned char safemode_hfuse;
unsigned char safemode_efuse;
unsigned char safemode_fuse;
/* If we write the fuses, then we need to tell safemode that they *should* change */
safemode_memfuses(0, &safemode_lfuse, &safemode_hfuse, &safemode_efuse, &safemode_fuse);
if (strcmp(mem->desc, "fuse")==0) {
safemode_fuse = data;
}
if (strcmp(mem->desc, "lfuse")==0) {
safemode_lfuse = data;
}
if (strcmp(mem->desc, "hfuse")==0) {
safemode_hfuse = data;
}
if (strcmp(mem->desc, "efuse")==0) {
safemode_efuse = data;
}
safemode_memfuses(1, &safemode_lfuse, &safemode_hfuse, &safemode_efuse, &safemode_fuse);
return pgm->write_byte(pgm, p, mem, addr, data);
}

View File

@ -607,40 +607,11 @@ Posix systems (by now).
.It Fl q
Disable (or quell) output of the progress bar while reading or writing
to the device. Specify it a second time for even quieter operation.
.It Fl s
Disable safemode prompting. When safemode discovers that one or more
fuse bits have unintentionally changed, it will prompt for
confirmation regarding whether or not it should attempt to recover the
fuse bit(s). Specifying this flag disables the prompt and assumes
that the fuse bit(s) should be recovered without asking for
confirmation first.
.It Fl t
Tells
.Nm
to enter the interactive ``terminal'' mode instead of up- or downloading
files. See below for a detailed description of the terminal mode.
.It Fl u
Disable the safemode fuse bit checks. Safemode is enabled by default
and is intended to prevent unintentional fuse bit changes. When
enabled, safemode will issue a warning if the any fuse bits are found
to be different at program exit than they were when
.Nm
was invoked. Safemode won't alter fuse bits itself, but rather will
prompt for instructions, unless the terminal is non-interactive, in
which case safemode is disabled. See the
.Fl s
option to disable safemode prompting.
.Pp
If one of the configuration files has a line
.Dl "default_safemode = no;"
safemode is disabled by default.
The
.Fl u
option's effect is negated in that case, i. e. it
.Em enables
safemode.
.Pp
Safemode is always disabled for AVR32, Xmega and TPI devices.
.It Xo Fl U Ar memtype Ns
.Ar \&: Ns Ar op Ns
.Ar \&: Ns Ar filename Ns

View File

@ -339,10 +339,6 @@ default_parallel = "@DEFAULT_PAR_PORT@";
default_serial = "@DEFAULT_SER_PORT@";
# default_bitclock = 2.5;
# Turn off safemode by default
#default_safemode = no;
#
# PROGRAMMER DEFINITIONS
#
@ -16632,9 +16628,7 @@ part
;
memory "wdtcfg"
size = 1;
offset = 0x1280;
readsize = 1;
alias "fuse0";
;
memory "fuse1"
@ -16644,9 +16638,7 @@ part
;
memory "bodcfg"
size = 1;
offset = 0x1281;
readsize = 1;
alias "fuse1";
;
memory "fuse2"
@ -16656,9 +16648,7 @@ part
;
memory "osccfg"
size = 1;
offset = 0x1282;
readsize = 1;
alias "fuse2";
;
memory "fuse4"
@ -16668,9 +16658,7 @@ part
;
memory "tcd0cfg"
size = 1;
offset = 0x1284;
readsize = 1;
alias "fuse4";
;
memory "fuse5"
@ -16680,9 +16668,7 @@ part
;
memory "syscfg0"
size = 1;
offset = 0x1285;
readsize = 1;
alias "fuse5";
;
memory "fuse6"
@ -16692,9 +16678,7 @@ part
;
memory "syscfg1"
size = 1;
offset = 0x1286;
readsize = 1;
alias "fuse6";
;
memory "fuse7"
@ -16704,9 +16688,11 @@ part
;
memory "append"
size = 1;
offset = 0x1287;
readsize = 1;
alias "fuse7";
;
memory "codesize"
alias "fuse7";
;
memory "fuse8"
@ -16716,9 +16702,11 @@ part
;
memory "bootend"
size = 1;
offset = 0x1288;
readsize = 1;
alias "fuse8";
;
memory "bootsize"
alias "fuse8";
;
memory "lock"
@ -17900,9 +17888,7 @@ part
;
memory "wdtcfg"
size = 1;
offset = 0x1050;
readsize = 1;
alias "fuse0";
;
memory "fuse1"
@ -17912,9 +17898,7 @@ part
;
memory "bodcfg"
size = 1;
offset = 0x1051;
readsize = 1;
alias "fuse1";
;
memory "fuse2"
@ -17924,9 +17908,7 @@ part
;
memory "osccfg"
size = 1;
offset = 0x1052;
readsize = 1;
alias "fuse2";
;
memory "fuse4"
@ -17936,9 +17918,7 @@ part
;
memory "tcd0cfg"
size = 1;
offset = 0x1054;
readsize = 1;
alias "fuse4";
;
memory "fuse5"
@ -17948,9 +17928,7 @@ part
;
memory "syscfg0"
size = 1;
offset = 0x1055;
readsize = 1;
alias "fuse5";
;
memory "fuse6"
@ -17960,9 +17938,7 @@ part
;
memory "syscfg1"
size = 1;
offset = 0x1056;
readsize = 1;
alias "fuse6";
;
memory "fuse7"
@ -17972,15 +17948,11 @@ part
;
memory "codesize"
size = 1;
offset = 0x1057;
readsize = 1;
alias "fuse7";
;
memory "append"
size = 1;
offset = 0x1057;
readsize = 1;
alias "fuse7";
;
memory "fuse8"
@ -17990,15 +17962,11 @@ part
;
memory "bootsize"
size = 1;
offset = 0x1058;
readsize = 1;
alias "fuse8";
;
memory "bootend"
size = 1;
offset = 0x1058;
readsize = 1;
alias "fuse8";
;
memory "lock"

View File

@ -260,6 +260,21 @@ AVRMEM * avr_new_memtype(void)
return m;
}
AVRMEM_ALIAS * avr_new_memalias(void)
{
AVRMEM_ALIAS * m;
m = (AVRMEM_ALIAS *)malloc(sizeof(*m));
if (m == NULL) {
avrdude_message(MSG_INFO, "avr_new_memalias(): out of memory\n");
exit(1);
}
memset(m, 0, sizeof(*m));
return m;
}
/*
* Allocate and initialize memory buffers for each of the device's
@ -326,6 +341,17 @@ AVRMEM * avr_dup_mem(AVRMEM * m)
return n;
}
AVRMEM_ALIAS * avr_dup_memalias(AVRMEM_ALIAS * m)
{
AVRMEM_ALIAS * n;
n = avr_new_memalias();
*n = *m;
return n;
}
void avr_free_mem(AVRMEM * m)
{
int i;
@ -348,7 +374,36 @@ void avr_free_mem(AVRMEM * m)
free(m);
}
AVRMEM * avr_locate_mem(AVRPART * p, char * desc)
void avr_free_memalias(AVRMEM_ALIAS * m)
{
free(m);
}
AVRMEM_ALIAS * avr_locate_memalias(AVRPART * p, char * desc)
{
AVRMEM_ALIAS * m, * match;
LNODEID ln;
int matches;
int l;
l = strlen(desc);
matches = 0;
match = NULL;
for (ln=lfirst(p->mem_alias); ln; ln=lnext(ln)) {
m = ldata(ln);
if (strncmp(desc, m->desc, l) == 0) {
match = m;
matches++;
}
}
if (matches == 1)
return match;
return NULL;
}
AVRMEM * avr_locate_mem_noalias(AVRPART * p, char * desc)
{
AVRMEM * m, * match;
LNODEID ln;
@ -373,11 +428,54 @@ AVRMEM * avr_locate_mem(AVRPART * p, char * desc)
}
AVRMEM * avr_locate_mem(AVRPART * p, char * desc)
{
AVRMEM * m, * match;
AVRMEM_ALIAS * alias;
LNODEID ln;
int matches;
int l;
l = strlen(desc);
matches = 0;
match = NULL;
for (ln=lfirst(p->mem); ln; ln=lnext(ln)) {
m = ldata(ln);
if (strncmp(desc, m->desc, l) == 0) {
match = m;
matches++;
}
}
if (matches == 1)
return match;
/* not yet found: look for matching alias name */
alias = avr_locate_memalias(p, desc);
if (alias != NULL)
return alias->aliased_mem;
return NULL;
}
AVRMEM_ALIAS * avr_find_memalias(AVRPART * p, AVRMEM * m_orig)
{
AVRMEM_ALIAS * m;
LNODEID ln;
for (ln=lfirst(p->mem_alias); ln; ln=lnext(ln)) {
m = ldata(ln);
if (m->aliased_mem == m_orig)
return m;
}
return NULL;
}
void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, AVRPART * p,
int type, int verbose)
{
static LNODEID ln;
static AVRMEM * n;
static unsigned int prev_mem_offset, prev_mem_size;
int i, j;
char * optr;
@ -398,25 +496,14 @@ void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, AVRPART * p,
prefix, prefix, prefix);
}
// Get the next memory section, and stop before going out of band
if (ln == NULL)
ln = lnext(lfirst(p->mem));
else
ln = lnext(ln);
if (ln != NULL)
n = ldata(ln);
// Only print memory section if the previous section printed isn't identical
if(prev_mem_offset != m->offset || prev_mem_size != m->size || (strcmp(p->family_id, "") == 0)) {
prev_mem_offset = m->offset;
prev_mem_size = m->size;
AVRMEM_ALIAS *ap = avr_find_memalias(p, m);
/* Show alias if the current and the next memory section has the same offset
and size, we're not out of band and a family_id is present */
char * mem_desc_alias = m->offset == n->offset && \
m->size == n->size && \
ln != NULL && \
strcmp(p->family_id, "") != 0 ?
n->desc : "";
char * mem_desc_alias = ap? ap->desc: "";
fprintf(f,
"%s%-11s %-8s %4d %5d %5d %4d %-6s %6d %4d %6d %5d %5d 0x%02x 0x%02x\n",
prefix,
@ -488,6 +575,7 @@ AVRPART * avr_new_part(void)
p->ocdrev = -1;
p->mem = lcreat(NULL, 0);
p->mem_alias = lcreat(NULL, 0);
return p;
}
@ -496,19 +584,35 @@ AVRPART * avr_new_part(void)
AVRPART * avr_dup_part(AVRPART * d)
{
AVRPART * p;
LISTID save;
LNODEID ln;
LISTID save, save2;
LNODEID ln, ln2;
int i;
p = avr_new_part();
save = p->mem;
save2 = p->mem_alias;
*p = *d;
p->mem = save;
p->mem_alias = save2;
for (ln=lfirst(d->mem); ln; ln=lnext(ln)) {
ladd(p->mem, avr_dup_mem(ldata(ln)));
AVRMEM *m = ldata(ln);
AVRMEM *m2 = avr_dup_mem(m);
ladd(p->mem, m2);
// see if there is any alias for it
for (ln2=lfirst(d->mem_alias); ln2; ln2=lnext(ln2)) {
AVRMEM_ALIAS *a = ldata(ln2);
if (a->aliased_mem == m) {
// yes, duplicate it
AVRMEM_ALIAS *a2 = avr_dup_memalias(a);
// ... adjust the pointer ...
a2->aliased_mem = m2;
// ... and add to new list
ladd(p->mem_alias, a2);
}
}
}
for (i = 0; i < AVR_OP_MAX; i++) {
@ -523,6 +627,8 @@ void avr_free_part(AVRPART * d)
int i;
ldestroy_cb(d->mem, (void(*)(void *))avr_free_mem);
d->mem = NULL;
ldestroy_cb(d->mem_alias, (void(*)(void *))avr_free_memalias);
d->mem_alias = NULL;
for(i=0;i<sizeof(d->op)/sizeof(d->op[0]);i++)
{
if (d->op[i] != NULL)

View File

@ -36,7 +36,6 @@ char default_programmer[MAX_STR_CONST];
char default_parallel[PATH_MAX];
char default_serial[PATH_MAX];
double default_bitclock;
int default_safemode;
char string_buf[MAX_STR_CONST];
char *string_buf_ptr;
@ -48,6 +47,7 @@ AVRPART * current_part;
AVRMEM * current_mem;
LISTID part_list;
LISTID programmers;
bool is_alias;
int lineno;
const char * infile;
@ -73,6 +73,7 @@ int init_config(void)
current_mem = NULL;
part_list = lcreat(NULL, 0);
programmers = lcreat(NULL, 0);
is_alias = false;
lineno = 1;
infile = NULL;

View File

@ -54,6 +54,7 @@ extern int lineno;
extern const char * infile;
extern LISTID string_list;
extern LISTID number_list;
extern bool is_alias; // current entry is alias
#if !defined(HAS_YYSTYPE)

View File

@ -68,6 +68,7 @@ static int pin_name;
%token K_PAGE_SIZE
%token K_PAGED
%token K_ALIAS
%token K_BAUDRATE
%token K_BS2
%token K_BUFF
@ -77,7 +78,6 @@ static int pin_name;
%token K_DEFAULT_BITCLOCK
%token K_DEFAULT_PARALLEL
%token K_DEFAULT_PROGRAMMER
%token K_DEFAULT_SAFEMODE
%token K_DEFAULT_SERIAL
%token K_DESC
%token K_FAMILY_ID
@ -257,14 +257,6 @@ def :
K_DEFAULT_BITCLOCK TKN_EQUAL number_real TKN_SEMI {
default_bitclock = $3->value.number_real;
free_token($3);
} |
K_DEFAULT_SAFEMODE TKN_EQUAL yesno TKN_SEMI {
if ($3->primary == K_YES)
default_safemode = 1;
else if ($3->primary == K_NO)
default_safemode = 0;
free_token($3);
}
;
@ -1248,12 +1240,17 @@ part_parm :
{
AVRMEM * existing_mem;
existing_mem = avr_locate_mem(current_part, current_mem->desc);
existing_mem = avr_locate_mem_noalias(current_part, current_mem->desc);
if (existing_mem != NULL) {
lrmv_d(current_part->mem, existing_mem);
avr_free_mem(existing_mem);
}
ladd(current_part->mem, current_mem);
if (is_alias) {
avr_free_mem(current_mem); // alias mem has been already entered below
is_alias = false;
} else {
ladd(current_part->mem, current_mem);
}
current_mem = NULL;
} |
@ -1290,6 +1287,7 @@ yesno :
mem_specs :
mem_spec TKN_SEMI |
mem_alias TKN_SEMI |
mem_specs mem_spec TKN_SEMI
;
@ -1419,6 +1417,38 @@ mem_spec :
}
;
mem_alias :
K_ALIAS TKN_STRING
{
AVRMEM * existing_mem;
existing_mem = avr_locate_mem(current_part, $2->value.string);
if (existing_mem == NULL) {
yyerror("%s alias to non-existent memory %s",
current_mem->desc, $2->value.string);
free_token($2);
YYABORT;
}
// if this alias does already exist, drop the old one
AVRMEM_ALIAS * alias = avr_locate_memalias(current_part, current_mem->desc);
if (alias) {
lrmv_d(current_part->mem_alias, alias);
avr_free_memalias(alias);
}
is_alias = true;
alias = avr_new_memalias();
// alias->desc and current_mem->desc have the same length
// definition, thus no need to check for length here
strcpy(alias->desc, current_mem->desc);
alias->aliased_mem = existing_mem;
ladd(current_part->mem_alias, alias);
free_token($2);
}
;
%%

View File

@ -681,32 +681,6 @@ Posix systems (by now).
Disable (or quell) output of the progress bar while reading or writing
to the device. Specify it a second time for even quieter operation.
@item -u
Disables the default behaviour of reading out the fuses three times before
programming, then verifying at the end of programming that the fuses have not
changed. If you want to change fuses you will need to specify this option,
as avrdude will see the fuses have changed (even though you wanted to) and
will change them back for your "safety". This option was designed to
prevent cases of fuse bits magically changing (usually called @emph{safemode}).
If one of the configuration files contains a line
@code{default_safemode = no;}
safemode is disabled by default.
The @option{-u} option's effect is negated in that case, i. e. it
@emph{enables} safemode.
Safemode is always disabled for AVR32, Xmega and TPI devices.
@item -s
Disable safemode prompting. When safemode discovers that one or more
fuse bits have unintentionally changed, it will prompt for
confirmation regarding whether or not it should attempt to recover the
fuse bit(s). Specifying this flag disables the prompt and assumes
that the fuse bit(s) should be recovered without asking for
confirmation first.
@item -t
Tells AVRDUDE to enter the interactive ``terminal'' mode instead of up-
or downloading files. See below for a detailed description of the
@ -1133,8 +1107,6 @@ Reading | ################################################## | 100% 6.83s
avrdude: verifying ...
avrdude: 19278 bytes of flash verified
avrdude: safemode: Fuses OK
avrdude done. Thank you.
%
@ -1162,8 +1134,6 @@ Reading | ################################################## | 100% 46.10s
avrdude: writing output file "c:/diag flash.bin"
avrdude: safemode: Fuses OK
avrdude done. Thank you.
%
@ -1845,9 +1815,6 @@ flash pages of the application section.
Reading fuse and lock bits is fully supported.
Note that due to the inability to write the fuse bits, the safemode
functionality does not make sense for these boot loaders.
@end itemize
@c
@ -2021,9 +1988,6 @@ fuse, extended fuse) have no meaning whatsoever, as they have been
simply replaced by array of fuses: fuse0..9. Therefore you can simply
ignore this particular line of AVRDUDE output.
In connection to the above, @emph{safemode} has no meaning in context
of UPDI devices and should be ignored.
Currently available devices support only UPDI NVM programming model 0
and 2, but there is also experimental implementation of model 3 - not
yet tested.

View File

@ -1129,7 +1129,7 @@ static int jtag3_initialize(PROGRAMMER * pgm, AVRPART * p)
if (PDATA(pgm)->set_sck(pgm, parm) < 0)
return -1;
}
jtag3_print_parms1(pgm, progbuf);
if (conn == PARM3_CONN_JTAG)
{
avrdude_message(MSG_NOTICE2, "%s: jtag3_initialize(): "
@ -1968,6 +1968,18 @@ static int jtag3_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
cmd[3] = MTYPE_USERSIG;
} else if (strcmp(mem->desc, "prodsig") == 0) {
cmd[3] = MTYPE_PRODSIG;
} else if (strcmp(mem->desc, "sernum") == 0) {
cmd[3] = MTYPE_SIGN_JTAG;
} else if (strcmp(mem->desc, "osccal16") == 0) {
cmd[3] = MTYPE_SIGN_JTAG;
} else if (strcmp(mem->desc, "osccal20") == 0) {
cmd[3] = MTYPE_SIGN_JTAG;
} else if (strcmp(mem->desc, "tempsense") == 0) {
cmd[3] = MTYPE_SIGN_JTAG;
} else if (strcmp(mem->desc, "osc16err") == 0) {
cmd[3] = MTYPE_SIGN_JTAG;
} else if (strcmp(mem->desc, "osc20err") == 0) {
cmd[3] = MTYPE_SIGN_JTAG;
} else if (strcmp(mem->desc, "calibration") == 0) {
cmd[3] = MTYPE_OSCCAL_BYTE;
if (pgm->flag & PGM_FL_IS_DW)
@ -2364,14 +2376,12 @@ static void jtag3_display(PROGRAMMER * pgm, const char * p)
memmove(resp, resp + 3, status - 3);
resp[status - 3] = 0;
avrdude_message(MSG_INFO, "%sICE hardware version: %d\n", p, parms[0]);
avrdude_message(MSG_INFO, "%sICE firmware version: %d.%02d (rel. %d)\n", p,
avrdude_message(MSG_INFO, "%sICE HW version : %d\n", p, parms[0]);
avrdude_message(MSG_INFO, "%sICE FW version : %d.%02d (rel. %d)\n", p,
parms[1], parms[2],
(parms[3] | (parms[4] << 8)));
avrdude_message(MSG_INFO, "%sSerial number : %s\n", p, resp);
avrdude_message(MSG_INFO, "%sSerial number : %s", p, resp);
free(resp);
jtag3_print_parms1(pgm, p);
}
@ -2383,27 +2393,39 @@ static void jtag3_print_parms1(PROGRAMMER * pgm, const char * p)
return;
avrdude_message(MSG_INFO, "%sVtarget : %.2f V\n", p,
b2_to_u16(buf) / 1000.0);
b2_to_u16(buf) / 1000.0);
if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_MEGA_PROG, buf, 2) < 0)
return;
avrdude_message(MSG_INFO, "%sJTAG clock megaAVR/program: %u kHz\n", p,
b2_to_u16(buf));
if (b2_to_u16(buf) > 0) {
avrdude_message(MSG_INFO, "%sJTAG clock megaAVR/program : %u kHz\n", p,
b2_to_u16(buf));
}
if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_MEGA_DEBUG, buf, 2) < 0)
return;
avrdude_message(MSG_INFO, "%sJTAG clock megaAVR/debug: %u kHz\n", p,
b2_to_u16(buf));
if (b2_to_u16(buf) > 0) {
avrdude_message(MSG_INFO, "%sJTAG clock megaAVR/debug : %u kHz\n", p,
b2_to_u16(buf));
}
if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_JTAG, buf, 2) < 0)
return;
avrdude_message(MSG_INFO, "%sJTAG clock Xmega: %u kHz\n", p,
b2_to_u16(buf));
if (b2_to_u16(buf) > 0) {
avrdude_message(MSG_INFO, "%sJTAG clock Xmega : %u kHz\n", p,
b2_to_u16(buf));
}
if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_PDI, buf, 2) < 0)
return;
avrdude_message(MSG_INFO, "%sPDI clock Xmega : %u kHz\n", p,
b2_to_u16(buf));
if (b2_to_u16(buf) > 0) {
avrdude_message(MSG_INFO, "%sPDI/UPDI clock Xmega/megaAVR : %u kHz\n\n", p,
b2_to_u16(buf));
}
}
static void jtag3_print_parms(PROGRAMMER * pgm)
@ -2440,14 +2462,11 @@ static unsigned int jtag3_memaddr(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, uns
* Non-Xmega device.
*/
if (p->flags & AVRPART_HAS_UPDI) {
if (strcmp(m->desc, "fuses") == 0) {
addr += m->offset;
if (m->size == 1) {
addr = m->offset;
}
else if (matches(m->desc, "fuse")) {
addr = m->offset;
}
else if (strcmp(m->desc, "flash") != 0) {
addr += m->offset;
else if (m->size > 1) {
addr += m->offset;
}
}
return addr;

View File

@ -1275,8 +1275,8 @@ static void jtagmkI_display(PROGRAMMER * pgm, const char * p)
jtagmkI_getparm(pgm, PARM_SW_VERSION, &fw) < 0)
return;
avrdude_message(MSG_INFO, "%sICE hardware version: 0x%02x\n", p, hw);
avrdude_message(MSG_INFO, "%sICE firmware version: 0x%02x\n", p, fw);
avrdude_message(MSG_INFO, "%sICE HW version: 0x%02x\n", p, hw);
avrdude_message(MSG_INFO, "%sICE FW version: 0x%02x\n", p, fw);
jtagmkI_print_parms1(pgm, p);
@ -1320,9 +1320,9 @@ static void jtagmkI_print_parms1(PROGRAMMER * pgm, const char * p)
clk = 1e6;
}
avrdude_message(MSG_INFO, "%sVtarget : %.1f V\n", p,
avrdude_message(MSG_INFO, "%sVtarget : %.1f V\n", p,
6.25 * (unsigned)vtarget / 255.0);
avrdude_message(MSG_INFO, "%sJTAG clock : %s (%.1f us)\n", p, clkstr,
avrdude_message(MSG_INFO, "%sJTAG clock : %s (%.1f us)\n", p, clkstr,
1.0e6 / clk);
return;

View File

@ -2688,11 +2688,11 @@ static void jtagmkII_display(PROGRAMMER * pgm, const char * p)
jtagmkII_getparm(pgm, PAR_FW_VERSION, fw) < 0)
return;
avrdude_message(MSG_INFO, "%sM_MCU hardware version: %d\n", p, hw[0]);
avrdude_message(MSG_INFO, "%sM_MCU firmware version: %d.%02d\n", p, fw[1], fw[0]);
avrdude_message(MSG_INFO, "%sS_MCU hardware version: %d\n", p, hw[1]);
avrdude_message(MSG_INFO, "%sS_MCU firmware version: %d.%02d\n", p, fw[3], fw[2]);
avrdude_message(MSG_INFO, "%sSerial number: %02x:%02x:%02x:%02x:%02x:%02x\n",
avrdude_message(MSG_INFO, "%sM_MCU HW version: %d\n", p, hw[0]);
avrdude_message(MSG_INFO, "%sM_MCU FW version: %d.%02d\n", p, fw[1], fw[0]);
avrdude_message(MSG_INFO, "%sS_MCU HW version: %d\n", p, hw[1]);
avrdude_message(MSG_INFO, "%sS_MCU FW version: %d.%02d\n", p, fw[3], fw[2]);
avrdude_message(MSG_INFO, "%sSerial number : %02x:%02x:%02x:%02x:%02x:%02x\n",
p, PDATA(pgm)->serno[0], PDATA(pgm)->serno[1], PDATA(pgm)->serno[2], PDATA(pgm)->serno[3], PDATA(pgm)->serno[4], PDATA(pgm)->serno[5]);
jtagmkII_print_parms1(pgm, p);

View File

@ -117,6 +117,7 @@ SIGN [+-]
<strng>\n { yyerror("unterminated character constant");
return YYERRCODE; }
alias { yylval=NULL; return K_ALIAS; }
allowfullpagebitstream { yylval=NULL; return K_ALLOWFULLPAGEBITSTREAM; }
avr910_devcode { yylval=NULL; return K_AVR910_DEVCODE; }
bank_size { yylval=NULL; return K_PAGE_SIZE; }
@ -137,7 +138,6 @@ dedicated { yylval=new_token(K_DEDICATED); return K_DEDICATED; }
default_bitclock { yylval=NULL; return K_DEFAULT_BITCLOCK; }
default_parallel { yylval=NULL; return K_DEFAULT_PARALLEL; }
default_programmer { yylval=NULL; return K_DEFAULT_PROGRAMMER; }
default_safemode { yylval=NULL; return K_DEFAULT_SAFEMODE; }
default_serial { yylval=NULL; return K_DEFAULT_SERIAL; }
delay { yylval=NULL; return K_DELAY; }
desc { yylval=NULL; return K_DESC; }

View File

@ -261,6 +261,7 @@ typedef struct avrpart {
OPCODE * op[AVR_OP_MAX]; /* opcodes */
LISTID mem; /* avr memory definitions */
LISTID mem_alias; /* memory alias definitions */
char config_file[PATH_MAX]; /* config file where defined */
int lineno; /* config file line number */
} AVRPART;
@ -292,6 +293,11 @@ typedef struct avrmem {
OPCODE * op[AVR_OP_MAX]; /* opcodes */
} AVRMEM;
typedef struct avrmem_alias {
char desc[AVR_MEMDESCLEN]; /* alias name ("syscfg0" etc.) */
AVRMEM *aliased_mem;
} AVRMEM_ALIAS;
#ifdef __cplusplus
extern "C" {
#endif
@ -307,10 +313,15 @@ int avr_get_output_index(OPCODE * op);
/* Functions for AVRMEM structures */
AVRMEM * avr_new_memtype(void);
AVRMEM_ALIAS * avr_new_memalias(void);
int avr_initmem(AVRPART * p);
AVRMEM * avr_dup_mem(AVRMEM * m);
void avr_free_mem(AVRMEM * m);
void avr_free_memalias(AVRMEM_ALIAS * m);
AVRMEM * avr_locate_mem(AVRPART * p, char * desc);
AVRMEM * avr_locate_mem_noalias(AVRPART * p, char * desc);
AVRMEM_ALIAS * avr_locate_memalias(AVRPART * p, char * desc);
AVRMEM_ALIAS * avr_find_memalias(AVRPART * p, AVRMEM * m_orig);
void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, AVRPART * p,
int type, int verbose);
@ -831,30 +842,6 @@ int fileio(int op, char * filename, FILEFMT format,
#endif
/* formerly safemode.h */
#ifdef __cplusplus
extern "C" {
#endif
/* Writes the specified fuse in fusename (can be "lfuse", "hfuse", or "efuse") and verifies it. Will try up to tries
amount of times before giving up */
int safemode_writefuse (unsigned char fuse, char * fusename, PROGRAMMER * pgm, AVRPART * p, int tries);
/* Reads the fuses three times, checking that all readings are the same. This will ensure that the before values aren't in error! */
int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse, unsigned char * efuse, unsigned char * fuse, PROGRAMMER * pgm, AVRPART * p);
/* This routine will store the current values pointed to by lfuse, hfuse, and efuse into an internal buffer in this routine
when save is set to 1. When save is 0 (or not 1 really) it will copy the values from the internal buffer into the locations
pointed to be lfuse, hfuse, and efuse. This allows you to change the fuse bits if needed from another routine (ie: have it so
if user requests fuse bits are changed, the requested value is now verified */
int safemode_memfuses (int save, unsigned char * lfuse, unsigned char * hfuse, unsigned char * efuse, unsigned char * fuse);
#ifdef __cplusplus
}
#endif
/* formerly update.h */
enum {
@ -926,7 +913,6 @@ extern char default_programmer[];
extern char default_parallel[];
extern char default_serial[];
extern double default_bitclock;
extern int default_safemode;
/* This name is fixed, it's only here for symmetry with
* default_parallel and default_serial. */

View File

@ -122,9 +122,6 @@ static void usage(void)
" is performed in the order specified.\n"
" -n Do not write anything to the device.\n"
" -V Do not verify.\n"
" -u Disable safemode, default when running from a script.\n"
" -s Silent safemode operation, will not ask you if\n"
" fuses should be changed back.\n"
" -t Enter terminal mode.\n"
" -E <exitspec>[,<exitspec>] List programmer exit specifications.\n"
" -x <extended_param> Pass <extended_param> to programmer.\n"
@ -349,19 +346,11 @@ int main(int argc, char * argv [])
int baudrate; /* override default programmer baud rate */
double bitclock; /* Specify programmer bit clock (JTAG ICE) */
int ispdelay; /* Specify the delay for ISP clock */
int safemode; /* Enable safemode, 1=safemode on, 0=normal */
int silentsafe; /* Don't ask about fuses, 1=silent, 0=normal */
int init_ok; /* Device initialization worked well */
int is_open; /* Device open succeeded */
char * logfile; /* Use logfile rather than stderr for diagnostics */
enum updateflags uflags = UF_AUTO_ERASE; /* Flags for do_op() */
unsigned char safemode_lfuse = 0xff;
unsigned char safemode_hfuse = 0xff;
unsigned char safemode_efuse = 0xff;
unsigned char safemode_fuse = 0xff;
char * safemode_response;
int fuses_updated = 0;
#if !defined(WIN32)
char * homedir;
#endif
@ -394,7 +383,6 @@ int main(int argc, char * argv [])
default_parallel[0] = 0;
default_serial[0] = 0;
default_bitclock = 0.0;
default_safemode = -1;
init_config();
@ -434,8 +422,6 @@ int main(int argc, char * argv [])
baudrate = 0;
bitclock = 0.0;
ispdelay = 0;
safemode = 1; /* Safemode on by default */
silentsafe = 0; /* Ask by default */
is_open = 0;
logfile = NULL;
@ -581,19 +567,10 @@ int main(int argc, char * argv [])
quell_progress++ ;
break;
case 's' : /* Silent safemode */
silentsafe = 1;
safemode = 1;
break;
case 't': /* enter terminal mode */
terminal = 1;
break;
case 'u' : /* Disable safemode */
safemode = 0;
break;
case 'U':
upd = parse_op(optarg);
if (upd == NULL) {
@ -975,29 +952,6 @@ int main(int argc, char * argv [])
}
}
if (default_safemode == 0) {
/* configuration disables safemode: revert meaning of -u */
if (safemode == 0)
/* -u was given: enable safemode */
safemode = 1;
else
/* -u not given: turn off */
safemode = 0;
}
if (isatty(STDIN_FILENO) == 0 && silentsafe == 0)
safemode = 0; /* Turn off safemode if this isn't a terminal */
if(p->flags & AVRPART_AVR32) {
safemode = 0;
}
if(p->flags & (AVRPART_HAS_PDI | AVRPART_HAS_TPI)) {
safemode = 0;
}
if (avr_initmem(p) != 0)
{
avrdude_message(MSG_INFO, "\n%s: failed to initialize memories\n",
@ -1281,36 +1235,6 @@ int main(int argc, char * argv [])
}
}
if (init_ok && safemode == 1) {
/* If safemode is enabled, go ahead and read the current low, high,
and extended fuse bytes as needed */
rc = safemode_readfuses(&safemode_lfuse, &safemode_hfuse,
&safemode_efuse, &safemode_fuse, pgm, p);
if (rc != 0) {
//Check if the programmer just doesn't support reading
if (rc == -5)
{
avrdude_message(MSG_NOTICE, "%s: safemode: Fuse reading not supported by programmer.\n"
" Safemode disabled.\n", progname);
}
else
{
avrdude_message(MSG_INFO, "%s: safemode: To protect your AVR the programming "
"will be aborted\n",
progname);
exitrc = 1;
goto main_exit;
}
} else {
//Save the fuses as default
safemode_memfuses(1, &safemode_lfuse, &safemode_hfuse, &safemode_efuse, &safemode_fuse);
}
}
if (uflags & UF_AUTO_ERASE) {
if ((p->flags & AVRPART_HAS_PDI) && pgm->page_erase != NULL &&
lsize(updates) > 0) {
@ -1386,169 +1310,6 @@ int main(int argc, char * argv [])
}
}
/* Right before we exit programming mode, which will make the fuse
bits active, check to make sure they are still correct */
if (safemode == 1) {
/* If safemode is enabled, go ahead and read the current low,
* high, and extended fuse bytes as needed */
unsigned char safemodeafter_lfuse = 0xff;
unsigned char safemodeafter_hfuse = 0xff;
unsigned char safemodeafter_efuse = 0xff;
unsigned char safemodeafter_fuse = 0xff;
unsigned char failures = 0;
char yes[1] = {'y'};
if (quell_progress < 2) {
avrdude_message(MSG_INFO, "\n");
}
//Restore the default fuse values
safemode_memfuses(0, &safemode_lfuse, &safemode_hfuse, &safemode_efuse, &safemode_fuse);
/* Try reading back fuses, make sure they are reliable to read back */
if (safemode_readfuses(&safemodeafter_lfuse, &safemodeafter_hfuse,
&safemodeafter_efuse, &safemodeafter_fuse, pgm, p) != 0) {
/* Uh-oh.. try once more to read back fuses */
if (safemode_readfuses(&safemodeafter_lfuse, &safemodeafter_hfuse,
&safemodeafter_efuse, &safemodeafter_fuse, pgm, p) != 0) {
avrdude_message(MSG_INFO, "%s: safemode: Sorry, reading back fuses was unreliable. "
"I have given up and exited programming mode\n",
progname);
exitrc = 1;
goto main_exit;
}
}
AVRMEM * m;
/* Now check what fuses are against what they should be */
m = avr_locate_mem(p, "fuse");
if (compare_memory_masked(m, safemodeafter_fuse, safemode_fuse)) {
fuses_updated = 1;
avrdude_message(MSG_INFO, "%s: safemode: fuse changed! Was %x, and is now %x\n",
progname, safemode_fuse, safemodeafter_fuse);
/* Ask user - should we change them */
if (silentsafe == 0)
safemode_response = terminal_get_input("Would you like this fuse to be changed back? [y/n] ");
else
safemode_response = yes;
if (tolower((int)(safemode_response[0])) == 'y') {
/* Enough chit-chat, time to program some fuses and check them */
if (safemode_writefuse (safemode_fuse, "fuse", pgm, p,
10) == 0) {
avrdude_message(MSG_INFO, "%s: safemode: and is now rescued\n", progname);
}
else {
avrdude_message(MSG_INFO, "%s: and COULD NOT be changed\n", progname);
failures++;
}
}
}
/* Now check what fuses are against what they should be */
m = avr_locate_mem(p, "lfuse");
if (compare_memory_masked(m, safemodeafter_lfuse, safemode_lfuse)) {
fuses_updated = 1;
avrdude_message(MSG_INFO, "%s: safemode: lfuse changed! Was %x, and is now %x\n",
progname, safemode_lfuse, safemodeafter_lfuse);
/* Ask user - should we change them */
if (silentsafe == 0)
safemode_response = terminal_get_input("Would you like this fuse to be changed back? [y/n] ");
else
safemode_response = yes;
if (tolower((int)(safemode_response[0])) == 'y') {
/* Enough chit-chat, time to program some fuses and check them */
if (safemode_writefuse (safemode_lfuse, "lfuse", pgm, p,
10) == 0) {
avrdude_message(MSG_INFO, "%s: safemode: and is now rescued\n", progname);
}
else {
avrdude_message(MSG_INFO, "%s: and COULD NOT be changed\n", progname);
failures++;
}
}
}
/* Now check what fuses are against what they should be */
m = avr_locate_mem(p, "hfuse");
if (compare_memory_masked(m, safemodeafter_hfuse, safemode_hfuse)) {
fuses_updated = 1;
avrdude_message(MSG_INFO, "%s: safemode: hfuse changed! Was %x, and is now %x\n",
progname, safemode_hfuse, safemodeafter_hfuse);
/* Ask user - should we change them */
if (silentsafe == 0)
safemode_response = terminal_get_input("Would you like this fuse to be changed back? [y/n] ");
else
safemode_response = yes;
if (tolower((int)(safemode_response[0])) == 'y') {
/* Enough chit-chat, time to program some fuses and check them */
if (safemode_writefuse(safemode_hfuse, "hfuse", pgm, p,
10) == 0) {
avrdude_message(MSG_INFO, "%s: safemode: and is now rescued\n", progname);
}
else {
avrdude_message(MSG_INFO, "%s: and COULD NOT be changed\n", progname);
failures++;
}
}
}
/* Now check what fuses are against what they should be */
m = avr_locate_mem(p, "efuse");
if (compare_memory_masked(m, safemodeafter_efuse, safemode_efuse)) {
fuses_updated = 1;
avrdude_message(MSG_INFO, "%s: safemode: efuse changed! Was %x, and is now %x\n",
progname, safemode_efuse, safemodeafter_efuse);
/* Ask user - should we change them */
if (silentsafe == 0)
safemode_response = terminal_get_input("Would you like this fuse to be changed back? [y/n] ");
else
safemode_response = yes;
if (tolower((int)(safemode_response[0])) == 'y') {
/* Enough chit-chat, time to program some fuses and check them */
if (safemode_writefuse (safemode_efuse, "efuse", pgm, p,
10) == 0) {
avrdude_message(MSG_INFO, "%s: safemode: and is now rescued\n", progname);
}
else {
avrdude_message(MSG_INFO, "%s: and COULD NOT be changed\n", progname);
failures++;
}
}
}
if (quell_progress < 2) {
avrdude_message(MSG_INFO, "%s: safemode: ", progname);
if (failures == 0) {
avrdude_message(MSG_INFO, "Fuses OK (E:%02X, H:%02X, L:%02X)\n",
safemodeafter_efuse, safemodeafter_hfuse, safemodeafter_lfuse);
}
else {
avrdude_message(MSG_INFO, "Fuses not recovered, sorry\n");
}
}
if (fuses_updated) {
exitrc = 1;
}
}
main_exit:
/*

View File

@ -1,318 +0,0 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* avrdude is Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
*
* This file: Copyright (C) 2005-2007 Colin O'Flynn <coflynn@newae.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include "ac_cfg.h"
#include "avrdude.h"
#include "libavrdude.h"
/* This value from ac_cfg.h */
/*
* Writes the specified fuse in fusename (can be "lfuse", "hfuse", or
* "efuse") and verifies it. Will try up to tries amount of times
* before giving up
*/
int safemode_writefuse (unsigned char fuse, char * fusename, PROGRAMMER * pgm,
AVRPART * p, int tries)
{
AVRMEM * m;
unsigned char fuseread;
int returnvalue = -1;
m = avr_locate_mem(p, fusename);
if (m == NULL) {
return -1;
}
/* Keep trying to write then read back the fuse values */
while (tries > 0) {
if (avr_write_byte(pgm, p, m, 0, fuse) != 0)
{
continue;
}
if (pgm->read_byte(pgm, p, m, 0, &fuseread) != 0)
{
continue;
}
/* Report information to user if needed */
avrdude_message(MSG_NOTICE, "%s: safemode: Wrote %s to %x, read as %x. %d attempts left\n",
progname, fusename, fuse, fuseread, tries-1);
/* If fuse wrote OK, no need to keep going */
if (fuse == fuseread) {
tries = 0;
returnvalue = 0;
}
tries--;
}
return returnvalue;
}
/*
* Reads the fuses three times, checking that all readings are the
* same. This will ensure that the before values aren't in error!
*/
int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse,
unsigned char * efuse, unsigned char * fuse,
PROGRAMMER * pgm, AVRPART * p)
{
unsigned char value;
unsigned char fusegood = 0;
unsigned char allowfuseread = 1;
unsigned char safemode_lfuse;
unsigned char safemode_hfuse;
unsigned char safemode_efuse;
unsigned char safemode_fuse;
AVRMEM * m;
safemode_lfuse = *lfuse;
safemode_hfuse = *hfuse;
safemode_efuse = *efuse;
safemode_fuse = *fuse;
/* Read fuse three times */
fusegood = 2; /* If AVR device doesn't support this fuse, don't want
to generate a verify error */
m = avr_locate_mem(p, "fuse");
if (m != NULL) {
fusegood = 0; /* By default fuse is a failure */
if(pgm->read_byte(pgm, p, m, 0, &safemode_fuse) != 0)
{
allowfuseread = 0;
}
avrdude_message(MSG_DEBUG, "%s: safemode read 1, fuse value: %x\n",progname, safemode_fuse);
if(pgm->read_byte(pgm, p, m, 0, &value) != 0)
{
allowfuseread = 0;
}
avrdude_message(MSG_DEBUG, "%s: safemode read 2, fuse value: %x\n",progname, value);
if (value == safemode_fuse) {
if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
{
allowfuseread = 0;
}
avrdude_message(MSG_DEBUG, "%s: safemode read 3, fuse value: %x\n",progname, value);
if (value == safemode_fuse)
{
fusegood = 1; /* Fuse read OK three times */
}
}
}
//Programmer does not allow fuse reading.... no point trying anymore
if (allowfuseread == 0)
{
return -5;
}
if (fusegood == 0) {
avrdude_message(MSG_INFO, "%s: safemode: Verify error - unable to read fuse properly. "
"Programmer may not be reliable.\n", progname);
return -1;
}
else if (fusegood == 1) {
avrdude_message(MSG_NOTICE, "%s: safemode: fuse reads as %X\n", progname, safemode_fuse);
}
/* Read lfuse three times */
fusegood = 2; /* If AVR device doesn't support this fuse, don't want
to generate a verify error */
m = avr_locate_mem(p, "lfuse");
if (m != NULL) {
fusegood = 0; /* By default fuse is a failure */
if (pgm->read_byte(pgm, p, m, 0, &safemode_lfuse) != 0)
{
allowfuseread = 0;
}
avrdude_message(MSG_DEBUG, "%s: safemode read 1, lfuse value: %x\n",progname, safemode_lfuse);
if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
{
allowfuseread = 0;
}
avrdude_message(MSG_DEBUG, "%s: safemode read 2, lfuse value: %x\n",progname, value);
if (value == safemode_lfuse) {
if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
{
allowfuseread = 0;
}
avrdude_message(MSG_DEBUG, "%s: safemode read 3, lfuse value: %x\n",progname, value);
if (value == safemode_lfuse){
fusegood = 1; /* Fuse read OK three times */
}
}
}
//Programmer does not allow fuse reading.... no point trying anymore
if (allowfuseread == 0)
{
return -5;
}
if (fusegood == 0) {
avrdude_message(MSG_INFO, "%s: safemode: Verify error - unable to read lfuse properly. "
"Programmer may not be reliable.\n", progname);
return -1;
}
else if (fusegood == 1) {
avrdude_message(MSG_NOTICE, "%s: safemode: lfuse reads as %X\n", progname, safemode_lfuse);
}
/* Read hfuse three times */
fusegood = 2; /* If AVR device doesn't support this fuse, don't want
to generate a verify error */
m = avr_locate_mem(p, "hfuse");
if (m != NULL) {
fusegood = 0; /* By default fuse is a failure */
if (pgm->read_byte(pgm, p, m, 0, &safemode_hfuse) != 0)
{
allowfuseread = 0;
}
avrdude_message(MSG_DEBUG, "%s: safemode read 1, hfuse value: %x\n",progname, safemode_hfuse);
if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
{
allowfuseread = 0;
}
avrdude_message(MSG_DEBUG, "%s: safemode read 2, hfuse value: %x\n",progname, value);
if (value == safemode_hfuse) {
if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
{
allowfuseread = 0;
}
avrdude_message(MSG_DEBUG, "%s: safemode read 3, hfuse value: %x\n",progname, value);
if (value == safemode_hfuse){
fusegood = 1; /* Fuse read OK three times */
}
}
}
//Programmer does not allow fuse reading.... no point trying anymore
if (allowfuseread == 0)
{
return -5;
}
if (fusegood == 0) {
avrdude_message(MSG_INFO, "%s: safemode: Verify error - unable to read hfuse properly. "
"Programmer may not be reliable.\n", progname);
return -2;
}
else if (fusegood == 1){
avrdude_message(MSG_NOTICE, "%s: safemode: hfuse reads as %X\n", progname, safemode_hfuse);
}
/* Read efuse three times */
fusegood = 2; /* If AVR device doesn't support this fuse, don't want
to generate a verify error */
m = avr_locate_mem(p, "efuse");
if (m != NULL) {
fusegood = 0; /* By default fuse is a failure */
if (pgm->read_byte(pgm, p, m, 0, &safemode_efuse) != 0)
{
allowfuseread = 0;
}
avrdude_message(MSG_DEBUG, "%s: safemode read 1, efuse value: %x\n",progname, safemode_efuse);
if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
{
allowfuseread = 0;
}
avrdude_message(MSG_DEBUG, "%s: safemode read 2, efuse value: %x\n",progname, value);
if (value == safemode_efuse) {
if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
{
allowfuseread = 0;
}
avrdude_message(MSG_DEBUG, "%s: safemode read 3, efuse value: %x\n",progname, value);
if (value == safemode_efuse){
fusegood = 1; /* Fuse read OK three times */
}
}
}
//Programmer does not allow fuse reading.... no point trying anymore
if (allowfuseread == 0)
{
return -5;
}
if (fusegood == 0) {
avrdude_message(MSG_INFO, "%s: safemode: Verify error - unable to read efuse properly. "
"Programmer may not be reliable.\n", progname);
return -3;
}
else if (fusegood == 1) {
avrdude_message(MSG_NOTICE, "%s: safemode: efuse reads as %X\n", progname, safemode_efuse);
}
*lfuse = safemode_lfuse;
*hfuse = safemode_hfuse;
*efuse = safemode_efuse;
*fuse = safemode_fuse;
return 0;
}
/*
* This routine will store the current values pointed to by lfuse,
* hfuse, and efuse into an internal buffer in this routine when save
* is set to 1. When save is 0 (or not 1 really) it will copy the
* values from the internal buffer into the locations pointed to be
* lfuse, hfuse, and efuse. This allows you to change the fuse bits if
* needed from another routine (ie: have it so if user requests fuse
* bits are changed, the requested value is now verified
*/
int safemode_memfuses (int save, unsigned char * lfuse, unsigned char * hfuse,
unsigned char * efuse, unsigned char * fuse)
{
static unsigned char safemode_lfuse = 0xff;
static unsigned char safemode_hfuse = 0xff;
static unsigned char safemode_efuse = 0xff;
static unsigned char safemode_fuse = 0xff;
switch (save) {
/* Save the fuses as safemode setting */
case 1:
safemode_lfuse = *lfuse;
safemode_hfuse = *hfuse;
safemode_efuse = *efuse;
safemode_fuse = *fuse;
break;
/* Read back the fuses */
default:
*lfuse = safemode_lfuse;
*hfuse = safemode_hfuse;
*efuse = safemode_efuse;
*fuse = safemode_fuse;
break;
}
return 0;
}

View File

@ -227,6 +227,13 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
return -1;
}
AVRMEM_ALIAS * alias_mem = avr_find_memalias(p, mem);
char alias_mem_desc[AVR_DESCLEN + 1] = "";
if(alias_mem) {
strcat(alias_mem_desc, "/");
strcat(alias_mem_desc, alias_mem->desc);
}
if (upd->op == DEVICE_READ) {
/*
* read out the specified device memory and write it to a file
@ -238,14 +245,14 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
return -1;
}
if (quell_progress < 2) {
avrdude_message(MSG_INFO, "%s: reading %s memory:\n",
progname, mem->desc);
avrdude_message(MSG_INFO, "%s: reading %s%s memory:\n",
progname, mem->desc, alias_mem_desc);
}
report_progress(0,1,"Reading");
rc = avr_read(pgm, p, upd->memtype, 0);
if (rc < 0) {
avrdude_message(MSG_INFO, "%s: failed to read all of %s memory, rc=%d\n",
progname, mem->desc, rc);
avrdude_message(MSG_INFO, "%s: failed to read all of %s%s memory, rc=%d\n",
progname, mem->desc, alias_mem_desc, rc);
return -1;
}
report_progress(1,1,NULL);
@ -288,8 +295,8 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
* write the buffer contents to the selected memory type
*/
if (quell_progress < 2) {
avrdude_message(MSG_INFO, "%s: writing %s (%d bytes):\n",
progname, mem->desc, size);
avrdude_message(MSG_INFO, "%s: writing %s%s (%d bytes):\n",
progname, mem->desc, alias_mem_desc, size);
}
if (!(flags & UF_NOWRITE)) {
@ -306,16 +313,16 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
}
if (rc < 0) {
avrdude_message(MSG_INFO, "%s: failed to write %s memory, rc=%d\n",
progname, mem->desc, rc);
avrdude_message(MSG_INFO, "%s: failed to write %s%s memory, rc=%d\n",
progname, mem->desc, alias_mem_desc, rc);
return -1;
}
vsize = rc;
if (quell_progress < 2) {
avrdude_message(MSG_INFO, "%s: %d bytes of %s written\n", progname,
vsize, mem->desc);
avrdude_message(MSG_INFO, "%s: %d bytes of %s%s written\n", progname,
vsize, mem->desc, alias_mem_desc);
}
}
@ -327,11 +334,11 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
pgm->vfy_led(pgm, ON);
if (quell_progress < 2) {
avrdude_message(MSG_INFO, "%s: verifying %s memory against %s:\n",
progname, mem->desc, upd->filename);
avrdude_message(MSG_INFO, "%s: verifying %s%s memory against %s:\n",
progname, mem->desc, alias_mem_desc, upd->filename);
avrdude_message(MSG_NOTICE2, "%s: load data %s data from input file %s:\n",
progname, mem->desc, upd->filename);
avrdude_message(MSG_NOTICE2, "%s: load data %s%s data from input file %s:\n",
progname, mem->desc, alias_mem_desc, upd->filename);
}
rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1);
@ -345,15 +352,15 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
if (quell_progress < 2) {
avrdude_message(MSG_NOTICE2, "%s: input file %s contains %d bytes\n",
progname, upd->filename, size);
avrdude_message(MSG_NOTICE2, "%s: reading on-chip %s data:\n",
progname, mem->desc);
avrdude_message(MSG_NOTICE2, "%s: reading on-chip %s%s data:\n",
progname, mem->desc, alias_mem_desc);
}
report_progress (0,1,"Reading");
rc = avr_read(pgm, p, upd->memtype, v);
if (rc < 0) {
avrdude_message(MSG_INFO, "%s: failed to read all of %s memory, rc=%d\n",
progname, mem->desc, rc);
avrdude_message(MSG_INFO, "%s: failed to read all of %s%s memory, rc=%d\n",
progname, mem->desc, alias_mem_desc, rc);
pgm->err_led(pgm, ON);
avr_free_part(v);
return -1;
@ -375,8 +382,8 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
}
if (quell_progress < 2) {
avrdude_message(MSG_INFO, "%s: %d bytes of %s verified\n",
progname, rc, mem->desc);
avrdude_message(MSG_INFO, "%s: %d bytes of %s%s verified\n",
progname, rc, mem->desc, alias_mem_desc);
}
pgm->vfy_led(pgm, OFF);