Skip to content

Commit

Permalink
UPDI: Only write fuses whose value needs to be changed. This fixes an… (
Browse files Browse the repository at this point in the history
#11)

* UPDI: Only write fuses whose value needs to be changed. This fixes an issue where writing the fuses locks the device. It seems writing any value to lockbits (including "valid key" 0xC5") will lock the device, and the library always wrote all fuses including lockbits. Not writing fuses whose values have not changed fixes this.

* Fix formatting

Co-authored-by: Peter Kooiman <[email protected]>
  • Loading branch information
pkooiman and Peter Kooiman authored Jan 26, 2022
1 parent 4c0a545 commit dcaaa13
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 3 deletions.
22 changes: 19 additions & 3 deletions Adafruit_UPDIProg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ bool Adafruit_AVRProg::updi_run_tasks(uint16_t tasks, uint8_t *data,
uint8_t saved_fuses[AVR_NUM_FUSES];
if (tasks & UPDI_TASK_WRITE_FUSES) {
// we need to preserve the fuses through the device setup process
// g_updi.fuses contains the new fuse values
for (uint8_t i = 0; i < AVR_NUM_FUSES; i++)
saved_fuses[i] = g_updi.fuses[i];
}
Expand Down Expand Up @@ -570,8 +571,10 @@ bool Adafruit_AVRProg::updi_run_tasks(uint16_t tasks, uint8_t *data,
// info was previously fetched for all operations
}

// save fuses into updi array
if (tasks & UPDI_TASK_READ_FUSES) {
// save fuses into updi array, also read before writing the fuses
// to determine which ones actually need to be changed
// New fuse values have been saved in saved_fuses on function entry
if ((tasks & UPDI_TASK_READ_FUSES) || (tasks & UPDI_TASK_WRITE_FUSES)) {
Serial.printf("Reading fuses\n");

for (uint8_t i = 0; i < AVR_NUM_FUSES; i++) {
Expand All @@ -584,8 +587,18 @@ bool Adafruit_AVRProg::updi_run_tasks(uint16_t tasks, uint8_t *data,
if (tasks & UPDI_TASK_WRITE_FUSES) {
Serial.printf("Writing fuses\n");

// Only write fuses whose value needs to be changed
// Especially important for lockbits, as writing any value
// to lockbits (including 'valid key' 0xC5) seems to lock the device
for (uint8_t i = 0; i < AVR_NUM_FUSES; i++) {
updi_write_fuse(i, saved_fuses[i]);
if (saved_fuses[i] != g_updi.fuses[i]) {
DEBUG_FUSES("Write fuse %d: 0x%02X -> 0x%02X\n", i, g_updi.fuses[i],
saved_fuses[i]);
updi_write_fuse(i, saved_fuses[i]);
} else {
DEBUG_FUSES("Skip fuse %d: 0x%02X -> 0x%02X\n", i, g_updi.fuses[i],
saved_fuses[i]);
}
}
}

Expand Down Expand Up @@ -1033,6 +1046,9 @@ uint8_t Adafruit_AVRProg::updi_read_fuse(uint8_t fuse) {
bool Adafruit_AVRProg::updi_write_fuse(uint8_t fuse, uint8_t value) {
uint8_t data;

DEBUG_FUSES("updi_write_fuse: fuse %d value 0x%02X\n", fuse, value);
// Serial.print("Write fuse "); Serial.println(fuse, DEC);

if (!updi_is_prog_mode()) {
DEBUG_VERBOSE("in updi_write_fuse() error: not in prog mode\n");
return false;
Expand Down
3 changes: 3 additions & 0 deletions Adafruit_UPDIProg.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ SOFTWARE.
//#define DEBUG_PHYSICAL(fmt, ...) Serial.printf(fmt, ##__VA_ARGS__)
#define DEBUG_PHYSICAL(fmt, ...) {}

#define DEBUG_FUSES(fmt, ...) Serial.printf(fmt, ##__VA_ARGS__)
//#define DEBUG_FUSES(fmt, ...) {}

// clang-format on

#define UPDI_BREAK 0x00
Expand Down

0 comments on commit dcaaa13

Please sign in to comment.