Skip to content

Commit

Permalink
Merge pull request #1171 from stefanrueger/urclock
Browse files Browse the repository at this point in the history
Provide Urclock programmer
  • Loading branch information
stefanrueger committed Nov 22, 2022
2 parents 2063671 + f9aea24 commit 02e02be
Show file tree
Hide file tree
Showing 22 changed files with 3,001 additions and 73 deletions.
3 changes: 3 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,9 @@ add_library(libavrdude
updi_readwrite.h
updi_state.c
updi_state.h
urclock.c
urclock.h
urclock_private.h
usbasp.c
usbasp.h
usbdevs.h
Expand Down
3 changes: 3 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ libavrdude_a_SOURCES = \
updi_readwrite.h \
updi_nvm.c \
updi_nvm.h \
urclock.c \
urclock.h \
urclock_private.h \
usbdevs.h \
usb_hidapi.c \
usb_libusb.c \
Expand Down
35 changes: 27 additions & 8 deletions src/avr.c
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ int avr_read_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, con
}
if (!failure)
return avr_mem_hiaddr(mem);
/* else: fall back to byte-at-a-time write, for historical reasons */
/* else: fall back to byte-at-a-time read, for historical reasons */
}

if (strcmp(mem->desc, "signature") == 0) {
Expand Down Expand Up @@ -1088,8 +1088,7 @@ int compare_memory_masked(AVRMEM * m, uint8_t b1, uint8_t b2) {
*
* Return the number of bytes verified, or -1 if they don't match.
*/
int avr_verify(const AVRPART * p, const AVRPART * v, const char * memtype, int size)
{
int avr_verify(const PROGRAMMER *pgm, const AVRPART *p, const AVRPART *v, const char *memtype, int size) {
int i;
unsigned char * buf1, * buf2;
int vsize;
Expand Down Expand Up @@ -1118,14 +1117,34 @@ int avr_verify(const AVRPART * p, const AVRPART * v, const char * memtype, int s
size = vsize;
}

int verror = 0, vroerror = 0, maxerrs = verbose >= MSG_DEBUG? size+1: 10;
for (i=0; i<size; i++) {
if ((b->tags[i] & TAG_ALLOCATED) != 0 && buf1[i] != buf2[i]) {
uint8_t bitmask = get_fuse_bitmask(a);
if((buf1[i] & bitmask) != (buf2[i] & bitmask)) {
if(pgm->readonly && pgm->readonly(pgm, p, a, i)) {
if(quell_progress < 2) {
if(vroerror < 10) {
if(!(verror + vroerror))
pmsg_warning("verification mismatch%s\n",
avr_mem_is_flash_type(a)? " in r/o areas, expected for vectors and/or bootloader": "");
imsg_warning("device 0x%02x != input 0x%02x at addr 0x%04x (read only location)\n",
buf1[i], buf2[i], i);
} else if(vroerror == 10)
imsg_warning("suppressing further mismatches in read-only areas\n");
}
vroerror++;
} else if((buf1[i] & bitmask) != (buf2[i] & bitmask)) {
// Mismatch is not just in unused bits
pmsg_error("verification mismatch, first encountered at addr 0x%04x\n", i);
imsg_error("device 0x%02x != input 0x%02x\n", buf1[i], buf2[i]);
return -1;
if(verror < maxerrs) {
if(!(verror + vroerror))
pmsg_warning("verification mismatch\n");
imsg_error("device 0x%02x != input 0x%02x at addr 0x%04x (error)\n", buf1[i], buf2[i], i);
} else if(verror == maxerrs) {
imsg_warning("suppressing further verification errors\n");
}
verror++;
if(verbose < 1)
return -1;
} else {
// Mismatch is only in unused bits
if ((buf1[i] | bitmask) != 0xff) {
Expand All @@ -1143,7 +1162,7 @@ int avr_verify(const AVRPART * p, const AVRPART * v, const char * memtype, int s
}
}

return size;
return verror? -1: size;
}


Expand Down
49 changes: 30 additions & 19 deletions src/avrcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,23 +204,6 @@ int avr_is_and(const unsigned char *s1, const unsigned char *s2, const unsigned
}


static int initCache(AVR_Cache *cp, const PROGRAMMER *pgm, const AVRPART *p) {
AVRMEM *basemem = avr_locate_mem(p, cp == pgm->cp_flash? "flash": "eeprom");

if(!basemem || !avr_has_paged_access(pgm, basemem))
return LIBAVRDUDE_GENERAL_FAILURE;

cp->size = basemem->size;
cp->page_size = basemem->page_size;
cp->offset = basemem->offset;
cp->cont = cfg_malloc("initCache()", cp->size);
cp->copy = cfg_malloc("initCache()", cp->size);
cp->iscached = cfg_malloc("initCache()", cp->size/cp->page_size);

return LIBAVRDUDE_SUCCESS;
}


static int cacheAddress(int addr, const AVR_Cache *cp, const AVRMEM *mem) {
int cacheaddr = addr + (int) (mem->offset - cp->offset);

Expand Down Expand Up @@ -261,6 +244,29 @@ static int loadCachePage(AVR_Cache *cp, const PROGRAMMER *pgm, const AVRPART *p,
}


static int initCache(AVR_Cache *cp, const PROGRAMMER *pgm, const AVRPART *p) {
AVRMEM *basemem = avr_locate_mem(p, cp == pgm->cp_flash? "flash": "eeprom");

if(!basemem || !avr_has_paged_access(pgm, basemem))
return LIBAVRDUDE_GENERAL_FAILURE;

cp->size = basemem->size;
cp->page_size = basemem->page_size;
cp->offset = basemem->offset;
cp->cont = cfg_malloc("initCache()", cp->size);
cp->copy = cfg_malloc("initCache()", cp->size);
cp->iscached = cfg_malloc("initCache()", cp->size/cp->page_size);

if((pgm->prog_modes & PM_SPM) && avr_mem_is_flash_type(basemem)) { // Could be vector bootloader
// Caching the vector page gives control to the progammer that then can patch the reset vector
if(loadCachePage(cp, pgm, p, basemem, 0, 0, 0) < 0)
return LIBAVRDUDE_GENERAL_FAILURE;
}

return LIBAVRDUDE_SUCCESS;
}


static int writeCachePage(AVR_Cache *cp, const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, int base, int nlOnErr) {
// Write modified page cont to device; if unsuccessful try bytewise access
if(avr_write_page_default(pgm, p, mem, base, cp->cont + base) < 0) {
Expand Down Expand Up @@ -597,11 +603,15 @@ int avr_read_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *
* - Used if paged routines available and if memory is EEPROM or flash
* - Otherwise fall back to pgm->write_byte()
* - Out of memory addr: synchronise cache with device and return whether successful
* - If programmer indicates a readonly spot, return LIBAVRDUDE_SOFTFAIL
* - Cache is automagically created and initialised if needed
*/
int avr_write_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem,
unsigned long addr, unsigned char data) {

if(pgm->readonly && pgm->readonly(pgm, p, mem, addr))
return LIBAVRDUDE_SOFTFAIL;

// Use pgm->write_byte() if not EEPROM/flash or no paged access
if(!avr_has_paged_access(pgm, mem))
return fallback_write_byte(pgm, p, mem, addr, data);
Expand Down Expand Up @@ -636,9 +646,10 @@ int avr_chip_erase_cached(const PROGRAMMER *pgm, const AVRPART *p) {
{ avr_locate_mem(p, "flash"), pgm->cp_flash, 1 },
{ avr_locate_mem(p, "eeprom"), pgm->cp_eeprom, 0 },
};
int rc;

if(pgm->chip_erase(pgm, p) < 0)
return LIBAVRDUDE_GENERAL_FAILURE;
if((rc = pgm->chip_erase(pgm, p)) < 0)
return rc;

for(size_t i = 0; i < sizeof mems/sizeof*mems; i++) {
AVRMEM *mem = mems[i].mem;
Expand Down
120 changes: 114 additions & 6 deletions src/avrdude.1
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,17 @@ programming mode. The programmer type is ``wiring''. Note that the -D option
will likely be required in this case, because the bootloader will rewrite the
program memory, but no true chip erase can be performed.
.Pp
The Arduino (which is very similar to the STK500 1.x) is supported via
its own programmer type specification ``arduino''. This programmer works for
the Arduino Uno Rev3 or any AVR that runs the Optiboot bootloader.
Serial bootloaders that run a skeleton of the STK500 1.x protocol are
supported via their own programmer type ``arduino''. This programmer works
for the Arduino Uno Rev3 or any AVR that runs the Optiboot bootloader.
.Pp
Urprotocol is a leaner version of the STK500 1.x protocol that is designed
to be backwards compatible with STK500 v1.x, and allows bootloaders to be
much smaller, eg, as implemented in the urboot project
https://github.com/stefanrueger/urboot. The programmer type ``urclock''
caters for these urboot programmers. Owing to its backward compatibility,
any bootloader that can be served by the arduino programmer can normally
also be served by the urclock programmer.
.Pp
The BusPirate is a versatile tool that can also be used as an AVR programmer.
A single BusPirate can be connected to up to 3 independent AVRs. See
Expand Down Expand Up @@ -397,8 +405,8 @@ programming requires the memory be erased to 0xFF beforehand.
.Fl A
should be used when the programmer hardware, or bootloader
software for that matter, does not carry out chip erase and
instead handles the memory erase on a page level. The popular
Arduino bootloader exhibits this behaviour; for this reason
instead handles the memory erase on a page level. Popular
Arduino bootloaders exhibit this behaviour; for this reason
.Fl A
is engaged by default when specifying
. Fl c
Expand Down Expand Up @@ -432,7 +440,7 @@ contents would exclusively cause bits to be programmed from the value
.Ql 1
to
.Ql 0 .
Note that in order to reprogram EERPOM cells, no explicit prior chip
Note that in order to reprogram EEPROM cells, no explicit prior chip
erase is required since the MCU provides an auto-erase cycle in that
case before programming the cell.
.It Xo Fl E Ar exitspec Ns
Expand Down Expand Up @@ -1141,6 +1149,106 @@ programmer creates errors during initial sequence.
Specify how many connection retry attemps to perform before exiting.
Defaults to 10 if not specified.
.El
.It Ar Urclock
.Bl -tag -offset indent -width indent
.It Ar showall
Show all info for the connected part, then exit. The -xshow... options
below can be used to assemble a bespoke response consisting of a subset
(or only one item) of all available relevant information about the
connected part and bootloader.
.It Ar showid
Show a unique Urclock ID stored in either flash or EEPROM of the MCU, then exit.
.It Ar id=<E|F>.<addr>.<len>
Historically, the Urclock ID was a six-byte unique little-endian number
stored in Urclock boards at EEPROM address 257. The location of this
number can be set by the -xid=<E|F>.<addr>.<len> extended parameter. E
stands for EEPROM and F stands for flash. A negative address addr counts
from the end of EEPROM and flash, respectively. The length len of the
Urclock ID can be between 1 and 8 bytes.
.It Ar showdate
Show the last-modified date of the input file for the flash application,
then exit. If the input file was stdin, the date will be that of the
programming.
.It Ar showfilename
Show the input filename (or title) of the last flash writing session, then exit.
.It Ar title=<string>
When set, <string> will be used in lieu of the input filename. The maximum
string length for the title/filename field is 254 bytes including
terminating nul.
.It Ar showapp
Show the size of the programmed application, then exit.
.It Ar showstore
Show the size of the unused flash between the application and metadata, then exit.
.It Ar showmeta
Show the size of the metadata just below the bootloader, then exit.
.It Ar showboot
Show the size of the bootloader, then exit.
.It Ar showversion
Show bootloader version and capabilities, then exit.
.It Ar showvector
Show the vector number and name of the interrupt table vector used by the
bootloader for starting the application, then exit. For hardware-supported
bootloaders this will be vector 0 (Reset), and for vector bootloaders this
will be any other vector number of the interrupt vector table or the slot
just behind the vector table with the name VBL_ADDITIONAL_VECTOR.
.It Ar showpart
Show the part for which the bootloader was compiled, then exit.
.It Ar bootsize=<size>
Manual override for bootloader size. Urboot bootloaders put the number of used
bootloader pages into a table at the top of flash, so the urclock programmer can
look up the bootloader size itself. In backward-compatibility mode, when programming
via other bootloaders, this option can be used to tell the programmer the
size, and therefore the location, of the bootloader.
.It Ar vectornum=<arg>
Manual override for vector number. Urboot bootloaders put the vector
number used by a vector bootloader into a table at the top of flash, so
this option is normally not needed for urboot bootloaders. However, it is
useful in backward-compatibility mode (or when the urboot bootloader does
not offer flash read). Specifying a vector number in these circumstances
implies a vector bootloader whilst the default assumption would be a
hardware-supported bootloader.
.It Ar eepromrw
Manual override for asserting EEPROM read/write capability. Not normally
needed for urboot bootloaders, but useful for in backward-compatibility
mode if the bootloader offers EEPROM read/write.
.It Ar emulate_ce
If an urboot bootloader does not offer a chip erase command it will tell
the urclock programmer so during handshake. In this case the urclock
programmer emulates a chip erase, if warranted by user command line
options, by filling the remainder of unused flash below the bootloader
with 0xff. If this option is specified, the urclock programmer will assume
that the bootloader cannot erase the chip itself. The option is useful
for backwards-compatible bootloaders that do not implement chip erase.
.It Ar restore
Upload unchanged flash input files and trim below the bootloader if
needed. This is most useful when one has a backup of the full flash and
wants to play that back onto the device. No metadata are written in this
case and no vector patching happens either if it is a vector bootloader.
However, for vector bootloaders, even under the option -xrestore an
input file will not be uploaded for which the reset vector does not point
to the vector bootloader. This is to avoid writing an input file to the
device that would render the vector bootloader not functional as it would
not be reached after reset.
.It Ar initstore
On writing to flash fill the store space between the flash application and
the metadata section with 0xff.
.It Ar nofilename
On writing to flash do not store the application input filename (nor a title).
.It Ar nodate
On writing to flash do not store the application input filename (nor a
title) and no date either.
.It Ar nometadata
On writing to flash do not store any metadata. The full flash below the
bootloader is available for the application. In particular, no data store
frame is programmed.
.It Ar delay=<n>
Add a <n> ms delay after reset. This can be useful if a board takes a
particularly long time to exit from external reset. <n> can be negative,
in which case the default 80 ms delay after issuing reset will be
shortened accordingly.
.It Ar help
Show this help menu and exit
.El
.It Ar buspirate
.Bl -tag -offset indent -width indent
.It Ar reset={cs,aux,aux2}
Expand Down
15 changes: 14 additions & 1 deletion src/avrdude.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
# prog_modes = PM_<i/f> {| PM_<i/f>} # interfaces, eg, PM_SPM|PM_ISP|PM_HVPP|PM_debugWIRE
# mcuid = <num>; # unique id in 0..2039 for 8-bit AVRs
# n_interrupts = <num>; # number of interrupts, used for vector bootloaders
# n_page_erase = <num>; # if set, number of pages erased during NVM erase
# n_page_erase = <num>; # if set, number of pages erased during SPM erase
# hvupdi_variant = <num> ; # numeric -1 (n/a) or 0..2
# devicecode = <num> ; # deprecated, use stk500_devcode
# stk500_devcode = <num> ; # numeric
Expand Down Expand Up @@ -756,6 +756,19 @@ programmer
connection_type = serial;
;

#------------------------------------------------------------
# urclock
#------------------------------------------------------------

# See https://github.com/stefanrueger/urboot
programmer
id = "urclock";
desc = "Urclock programmer for urboot bootloaders using urprotocol";
type = "urclock";
prog_modes = PM_SPM;
connection_type = serial;
;

#------------------------------------------------------------
# xbee
#------------------------------------------------------------
Expand Down
10 changes: 5 additions & 5 deletions src/avrintel.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
* Atmel AVR8L, AVR8, XMEGA and AVR8X family description of interrupts and more
*
* published under GNU General Public License, version 3 (GPL-3.0)
* meta-author: Stefan Rueger <stefan.rueger@urclocks.com>
* meta-author Stefan Rueger <stefan.rueger@urclocks.com>
*
* v 1.1
* 30.08.2022
* 20.11.2022
*
*/

Expand Down Expand Up @@ -256,9 +256,9 @@ const uPcore_t uP_table[] = { // Value of -1 typically means unknown
{"ATA8515", 224, F_AVR8, {0x1E, 0x95, 0x63}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42, vtab_ata8515}, // atdf
{"ATA664251", 225, F_AVR8, {0x1E, 0x94, 0x87}, 0, 0x04000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20, vtab_attiny167}, // atdf, avr-gcc 12.2.0
{"M3000", 226, F_AVR8, {0xff, -1, -1}, 0, 0x10000, -1, -1, -1, -1, -1, -1, 0x1000, 0x1000, -1, -1, 0, NULL}, // avr-gcc 12.2.0
{"LGT8F88P", 227, F_AVR8, {0x1E, 0x93, 0x0F}, 0, 0x02000, 0x040, -1, -1, 0, 0x0200, 4, -1, -1, -1, -1, 0, NULL}, // avrdude
{"LGT8F168P", 228, F_AVR8, {0x1E, 0x94, 0x0B}, 0, 0x04000, 0x080, -1, -1, 0, 0x0200, 4, -1, -1, -1, -1, 0, NULL}, // avrdude
{"LGT8F328P", 229, F_AVR8, {0x1E, 0x95, 0x0F}, 0, 0x08000, 0x080, -1, -1, 0, 0x0400, 4, -1, -1, -1, -1, 0, NULL}, // avrdude
{"LGT8F88P", 227, F_AVR8, {0x1E, 0x93, 0x0F}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26, vtab_atmega328p}, // avrdude, from ATmega88
{"LGT8F168P", 228, F_AVR8, {0x1E, 0x94, 0x0B}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26, vtab_atmega328p}, // avrdude, from ATmega168P
{"LGT8F328P", 229, F_AVR8, {0x1E, 0x95, 0x0F}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 26, vtab_atmega328p}, // avrdude, from ATmega328P

{"ATxmega8E5", 230, F_XMEGA, {0x1E, 0x93, 0x41}, 0, 0x02800, 0x080, 1, 0x0800, 0, 0x0200, 32, 0x2000, 0x0400, 7, 1, 43, vtab_atxmega32e5}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega16A4", 231, F_XMEGA, {0x1E, 0x94, 0x41}, 0, 0x05000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x0800, 6, 1, 94, vtab_atxmega32a4}, // atdf, avr-gcc 12.2.0, avrdude
Expand Down
4 changes: 2 additions & 2 deletions src/avrintel.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* meta-author Stefan Rueger <stefan.rueger@urclocks.com>
*
* v 1.1
* 30.08.2022
* 20.11.2022
*
*/

Expand Down Expand Up @@ -770,7 +770,7 @@ typedef struct { // Value of -1 typically means unknown
#define vts_avr128da64 64
#define vts_avr128db64 65

// Suggested vector bootloader interrupt number (first unused vector or, failing that, slot just above vector table)
// Suggested vector bootloader interrupt: first unused vector or slot just above vector table
#define vbu_attiny4 10
#define vbu_attiny5 11
#define vbu_attiny9 10
Expand Down
Loading

0 comments on commit 02e02be

Please sign in to comment.