stefanrueger / urboot

Small AVR bootloader using urprotocol
GNU General Public License v3.0
55 stars 8 forks source link

Can't connect to ATmega128RFA1, how to troubleshoot? #29

Closed tglaria closed 4 months ago

tglaria commented 5 months ago

I'm currently using Optiboot with a baudrate of 115.200bps on a board with 14.7456MHz.

Using AVRDUDESS (avrdude gui) on Windows, I can connect to it no problem.

But when flashing urboot, I can't get it to connect.

For optiboot I'm using: avrdude command: avrdude.exe -c arduino -P COM5 -b 115200 -p m8 Boot Flash size = 1024, Boot reset vector enabled.

For urboot I'm bootloader file: urboot_m128rfa1_1s_x14m7456_115k2_uart0_rxe0_txe1_no-led.hex Avrdude command: avrdude.exe -c urclock -P COM5 -b 115200 -p m8 Same fuses. But can't connect, I get the error:

WARNING: Unable to detect MCU

avrdude warning: attempt 1 of 10: not in sync
avrdude warning: attempt 2 of 10: not in sync
avrdude warning: attempt 3 of 10: not in sync
avrdude warning: attempt 4 of 10: not in sync
avrdude warning: attempt 5 of 10: not in sync
avrdude warning: attempt 6 of 10: not in sync
avrdude warning: attempt 7 of 10: not in sync
avrdude warning: attempt 8 of 10: not in sync
avrdude warning: attempt 9 of 10: not in sync
avrdude warning: attempt 10 of 10: not in sync
avrdude warning: programmer is not responding; try -xstrict and/or vary -xdelay=100
avrdude error: unable to open programmer urclock on port COM5

avrdude done.  Thank you.

Any help on how to troubleshoot this?

Probably a stupid little thing.

stefanrueger commented 5 months ago

Same fuses.

This will be the problem. If it's the first bootloader from this page (see screenshot below) with 256 bytes then the fuses need to be different: the MCU does not have provisions for hardware support of such a small bootloader, so fuses need to be set for the vector bootloading technique. The usage section of the urboot readme has details. LMK how you get on.

Out of curiosity: I do not recognise the reported warning WARNING: Unable to detect MCU, which avrdude version do you use? avrdude.exe -v

image

stefanrueger commented 5 months ago

BTW, the urboot bootloader tells AVRDUDE's -c urclock that it has been compiled for the ATmega128RFA1, so no need to specify -p and no need to pretend a different MCU (m8).

tglaria commented 5 months ago

Hi, thanks for answering so quickly.

About the fuses, I tried different possibles fuse configurations with no success (different bootloader size nad "boot restet fuse" enabled and disabled). I also tried another bootloader, the fifth one (512 bytes of usage) and still no connection. I'll recheck and try again.

About the avrdude version, I'm using AVRDUDESS GUI v2.15 which says it's using avrdude v7.2. There's a 'detect' button which tries to identify which microcontroller it's being used (it just sends a command through avrdude as far as I can tell).

I guess I'll just skip the GUI for now.

stefanrueger commented 5 months ago

I'll just skip the GUI for now

Good move :smile:

There's a 'detect' button which tries to identify which microcontroller it's being used

I wondered where you got the Optiboot bootloader for the Atmega128RFA1 from. Looks like the (working) optiboot was compiled for the ATmega8. Can you look at the board to see which MCU is on? Is it a board with two MCUs? One for providing the comms and another one? If so which MCU will the bootloader (optiboot/urboot) be burned on?

I guess the AVRDUDESS technique will be to enquire the signature, which fortunately is unique for the ATmega128RFA1 and almost unique the ATmega8:

$ avrdude -p*/At | grep ATmega128RFA1.signature.0x
.pt ATmega128RFA1   signature   0x1e 0xa7 0x01

$ avrdude -p*/At | grep 0x1e.0xa7.0x01
.pt ATmega128RFA1   signature   0x1e 0xa7 0x01

$ avrdude -p*/At | grep ATmega8.signature.0x
.pt ATmega8 signature   0x1e 0x93 0x07

$ avrdude -p*/At | grep 0x1e.0x93.0x07
.pt ATmega8 signature   0x1e 0x93 0x07
.pt ATmega8A    signature   0x1e 0x93 0x07

Optiboot does not ask the MCU what the real signature is, it just replies with the signature it was compiled for. Looks like the (working) optiboot was compiled for the ATmega8. So, if that works, why not try an urboot bootloader for the ATmega8?

tglaria commented 5 months ago

I wondered where you got the Optiboot bootloader for the Atmega128RFA1 from. Looks like the (working) optiboot was compiled for the ATmega8.

I compiled some time ago. (I believe I compiled it for ATmega1281 since the ATmega128RFA is derived from it (according to the datasheet, section 3.4))

Can you look at the board to see which MCU is on? Is it a board with two MCUs? One for providing the comms and another one? If so which MCU will the bootloader (optiboot/urboot) be burned on?

It's a custom board with a single ATega128RFA1 microcontroller. Logically, it's installed on that one.

I guess the AVRDUDESS technique will be to enquire the signature, which fortunately is unique for the ATmega128RFA1 and almost unique the ATmega8:

$ avrdude -p*/At | grep ATmega128RFA1.signature.0x
.pt   ATmega128RFA1   signature   0x1e 0xa7 0x01

$ avrdude -p*/At | grep 0x1e.0xa7.0x01
.pt   ATmega128RFA1   signature   0x1e 0xa7 0x01

$ avrdude -p*/At | grep ATmega8.signature.0x
.pt   ATmega8 signature   0x1e 0x93 0x07

$ avrdude -p*/At | grep 0x1e.0x93.0x07
.pt   ATmega8 signature   0x1e 0x93 0x07
.pt   ATmega8A    signature   0x1e 0x93 0x07

Optiboot does not ask the MCU what the real signature is, it just replies with the signature it was compiled for. Looks like the (working) optiboot was compiled for the ATmega8. So, if that works, why not try an urboot bootloader for the ATmega8?

For the times I've used it, it did inform the correct signature (0x1E A7 01), I'll have to recheck how did I compiled the bootloader.

(can't make any further tests now, I'm on a linux computer and it doesn't work with non-standard baudrates ... )

stefanrueger commented 5 months ago

I also tried another bootloader, the fifth one (512 bytes of usage) and still no connection.

You could try the sixth or seventh bootloader (1024 bytes, h in the features for hardware-supported bootloader) and set the fuse for bootloader size to 512 words and jump to bootloader on reset. The fuse setting here should be the same as for optiboot. If it's a shorter bootloader with j in the features, you need to change the fuses as described in earlier posts.

You can use -T config to show the fuse configuration like so

$ avrdude -qq -c dryrun -p m128rfa1 -T config
config sut_cksel=intrcosc_6ck_65ms # 34
config ckout=co_disabled # 1
config ckdiv8=by_8 # 0
config bootrst=application # 1
config bootsz=bs_4096w # 0
config eesave=ee_erased # 1
config wdton=wdt_programmable # 1
config spien=isp_enabled # 0
config jtagen=jtag_enabled # 0
config ocden=ocd_disabled # 1
config bodlevel=bod_disabled # 7
config lb=no_lock # 3
config blb0=no_lock_in_app # 3
config blb1=no_lock_in_boot # 3

You just need to replace dryrun with the name of the programmer that you use to upload the bootloader sketch onto your custom board. Pay attention to the lock bits lb, blb0 and blb1, too. Above example shows factory reset values.

tglaria commented 5 months ago

Update 2: OK, yes, it's a hardware problem. The board is not being reset.

I burned the bootloader again, the first one, the smallest one, and works when I manually reset the board. Using fuse for bootloader size of 512 words, and works.

So ... yep, sorry for wasting the time. I'll keep testing it now.

Thanks for the quick answers an sorry for wasting your time.

PD: Optiboot worked the first time, since the flash was erased. Why didn't urboot work? Shouldn't the 'program counter' go all the way until it found the bootloader?


Update: After further testing, it looks like I have a hardware problem. The board I'm testing isn't receiving the reset pulse.

I'll check this before further questions.


Ok, tried again, no luck.

avrdude done. Thank you.

stefanrueger commented 5 months ago

avrdude has its own fuse calculator:

$ avrdude -pATmega128RFA1 -cdryrun -qqT "write lfuse 0xe0; w hf 0x9e; w ef 0xf6; config"
config sut_cksel=extclk_6ck_65ms # 32
config ckout=co_disabled # 1
config ckdiv8=by_1 # 1
config bootrst=boot_section # 0
config bootsz=bs_512w # 3
config eesave=ee_erased # 1
config wdton=wdt_programmable # 1
config spien=isp_enabled # 0
config jtagen=jtag_enabled # 0
config ocden=ocd_disabled # 1
config bodlevel=bod_1v8 # 6
config lb=no_lock # 3
config blb0=no_lock_in_app # 3
config blb1=no_lock_in_boot # 3

This is suitable for a hardware-supported bootloader (note the bootrst=boot section), eg, the 1024 h-type urboot (sixth from top). For the smaller urclock bootloader (j-type) you want the high fuse to be 0x9f. (jump to application). If neither combo works, then I would look closely at the optiboot bootloader that works and try to use a similar one from the urboot section.

Haven't managed to use Atmel ICE programmer with avrdude.

Avrdude should work with the Atmel ICE

stefanrueger commented 5 months ago

And yes, not getting the reset pulse would explain the output you see.

stefanrueger commented 5 months ago

For manual reset I recommend the longer WDT timeout of 2 s. First press the reset button of the board and release it; then start avrdude by pressing enter of the previously typed command line within the WDTO time.

stefanrueger commented 5 months ago

And you can show which ports are available by avrdude -curclock -P\? (just to be sure COM5 is the one).

stefanrueger commented 5 months ago

Here Microchip's reference reset circuit, and here one that I know works (dtr or rts doesn't matter as avrdude plucks both):

It misses the clamping diode, but that diode would prevent HV programming.

stefanrueger commented 4 months ago

@tglaria How are you getting on?

What's Vcc? If > 5.5 V then this could result in a > 11 V peak on certain boards without a RESET clamp diode to Vcc using a pre-v7.3 -c urclock instance; the > 11 V peak might have triggered HV programming causing the observed time-out behaviour. If so, this is a hardware problem, but v7.3 changed -c urclock so that there would be no such drastic peak in boards that miss the clamp diode. So if Vcc > 5.5 V, try avrdude v7.3 that was recently released.

stefanrueger commented 4 months ago

Turns out that some counterfeit parts seem to have a lower HV programming threshold, and that even with Vcc = 4.75 V, using a v7.2 AVRDUDE and counterfeit parts and boards without a missing clamp diode between reset and Vcc the observed behaviour might occur

tglaria commented 4 months ago

@tglaria How are you getting on?

What's Vcc? If > 5.5 V then this could result in a > 11 V peak on certain boards without a RESET clamp diode to Vcc using a pre-v7.3 -c urclock instance; the > 11 V peak might have triggered HV programming causing the observed time-out behaviour. If so, this is a hardware problem, but v7.3 changed -c urclock so that there would be no such drastic peak in boards that miss the clamp diode. So if Vcc > 5.5 V, try avrdude v7.3 that was recently released.

Sorry, I was on vacations, no connection to PC. The board is powered from a 3.3V source, so shouldn't be a a high voltage problem.

I'm using the same circuit you showed (Microchip's reference reset circuit), so my theory is a busted cap. (still, hardware problem)

EDIT: So yeah, changed the capacitor and now (apparently) it works. (at least it is detected by avrdude)

> .\avrdude.exe -c urclock -P COM7 -b 125000
avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1ea701 (probably m128rfa1)

avrdude done.  Thank you.

(I don't remember which bootloader I used, but now I can test different ones)

stefanrueger commented 4 months ago

I don't remember which bootloader I used

Try avrdude -c urclock -P COM7 -b 125000 -xshowall and it might tell you

tglaria commented 4 months ago

I don't remember which bootloader I used

Try avrdude -c urclock -P COM7 -b 125000 -xshowall and it might tell you

Sweet! Did not know about the -x command/argument.

> .\avrdude.exe -c urclock -P COM7 -b 125000 -xshowversion
avrdude: AVR device initialized and ready to accept instructions
u7.7 weu-hpr-c

(should I / you close this 'issue'?)

On another note (which probable should be on another section): With optiboot, I was using the last 16 bytes to store an Id. From what I understood, I saw that part of this section is used for pgm_write_page(sram, progmem).

Is it possible to change the location of this function? If not, is it possible to detect, from software, the presence of this bootloader? Lastly, ¿how is that function called from the application? Is there something special since it's on the bootloader?

stefanrueger commented 4 months ago

With optiboot, I was using the last 16 bytes to store an Id.

Well, doesn't optiboot store its version number in the last two bytes of flash?

From what I understood, I saw that part of this section is used for pgm_write_page(sram, progmem).

Urboot v7.7 bootloaders hold a 6-byte table at top of flash, see "implicit communication" in the protocol definition

Is it possible to change the location of this function?

No, applications need to know how to call the function: they call the address 4 bytes from top flash.

how is that function called from the application?

The section about PGMWRITEPAGE of the make options explains how an application can call this bootloader function.

Is there something special since it's on the bootloader?

On most MCUs only code in the bootloader can self-program flash, so this function must reside in the bootloader. Now, how would an application know where in the bootloader this function sits? Urboot solves this by placing an rjmp to the function at the fixed, defined address FLASHEND-4+1.

is it possible to detect, from software, the presence of this bootloader?

Sure, you can look at the last 6 bytes in flash and see whether they conform to a pattern that would be expected for an urboot or optiboot bootoader. This is what the external program hexls in this repository does with an intel hex file that is a bootloader. You can write code in the MCU application that examines the top bytes in flash in a similar fashion.

I wouldn't compile an ID into the bootloader flash. Though you could, if you placed the ID into a separate section before the section version that contains the 6-byte table.

stefanrueger commented 4 months ago

Seeing that the problem was a blown cap, I close the issue at hand

stefanrueger commented 4 months ago

Ahh, one more thing. Please confirm whether the urboot bootloader actually works on an ATmega128RFA1 so I can move that MCU into the supported and tested list. Would be neat if you tried a vector bootloader (j in the version capabilities, different fuse setting) and the larger hardware-supported one (h) https://github.com/stefanrueger/urboot/blob/d8557f12db257d5b0b32aef64179a1caec122865/src/urboot.c#L32-L76

tglaria commented 4 months ago

OK, Testing:

bootloader: urboot_m128rfa1_1s_x16m0_125k0_uart0_rxe0_txe1_no-led.hex FUSE_BOOTRST: disabled FUSE_BOOTZ: 512words (it's the minimum size)

 .\avrdude.exe -c urclock -p m128rfa1 -P COM7 -b 115200 -xshowall
avrdude: AVR device initialized and ready to accept instructions
0 0000-00-00 00.00  application 0 store 0 meta 1 boot 256 u7.7 w-u-jPr-- vector 40 (SPM_READY) ATmega128RFA1

Flashing: Sometimes it works, sometimes it doesn't. I'm getting spammed with messages avrdude error: bootloader does not implement bytewise write to flash

> .\avrdude.exe -c urclock -p m128rfa1 -P COM7 -b 115200 -U flash:w:"test.hex"
avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1ea701 (probably m128rfa1)
avrdude: Note: flash memory has been specified, an erase cycle will be performed.
         To disable this feature, specify the -D option.
avrdude: erasing chip
         delaying chip erase until first -U upload to flash

avrdude: processing -U flash:w:test.hex:i
avrdude: reading input file test.hex for flash
         with 15712 bytes in 1 section within [0, 0x3d5f]
         using 62 pages and 160 pad bytes
avrdude: preparing flash input for device bootloader
avrdude: writing 15712 bytes flash ...
Writing | #############------------------------------------- | 26% 6.51 s
avrdude error: protocol expects OK byte 0x58 but got 0x61 in urclock_paged_write()
avrdude error: bootloader does not implement bytewise write to flash
 ***failed;
[...]
avrdude error: bootloader does not implement bytewise write to flash
 ***failed;

When it works, it works.

> .\avrdude.exe -c urclock -p m128rfa1 -P COM7 -b 115200 -U flash:w:"test.hex"
avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1ea701 (probably m128rfa1)
avrdude: Note: flash memory has been specified, an erase cycle will be performed.
         To disable this feature, specify the -D option.
avrdude: erasing chip
         delaying chip erase until first -U upload to flash

avrdude: processing -U flash:w:test.hex:i
avrdude: reading input file test.hex for flash
         with 15712 bytes in 1 section within [0, 0x3d5f]
         using 62 pages and 160 pad bytes
avrdude: preparing flash input for device bootloader
avrdude: writing 15712 bytes flash ...
Writing | ################################################## | 100% 24.50 s
avrdude: 15712 bytes of flash written
avrdude: verifying flash memory against test.hex
Reading | ################################################## | 100% 19.50 s
avrdude: 15712 bytes of flash verified

avrdude done.  Thank you.

bootloader: urboot_m128rfa1_1s_x16m0_125k0_uart0_rxe0_txe1_no-led_ee_ce_hw.hex FUSE_BOOTRST: enabled FUSE_BOOTZ: 1024 words

> .\avrdude.exe -c urclock -p m128rfa1 -P COM7 -b 115200 -xshowall
avrdude: AVR device initialized and ready to accept instructions
0000ffffffff 0000-00-00 00.00  application 0 store 0 meta 1 boot 1024 u7.7 weu-hpr-c vector 0 (RESET) ATmega128RFA1

Flashing works correctly. The application loads and runs (haven't extensively tested it though).

But, so does using "FUSE_BOOTZ: 512 words". What should the expected behaviour be (knowing that the application does not fill the whole flash)? When should I start start getting problems for selecting a smaller "bootloader size" than the real size? EDIT: The size in the table, listed as 1024, is in bytes? I thought it was in words. This would mean 512 words is the correct size for the bootloader. Am I wrong?

tglaria commented 4 months ago

With optiboot, I was using the last 16 bytes to store an Id. Well, doesn't optiboot store its version number in the last two bytes of flash? Yes, but I wasn't using those. Missing the version did not seem like a big problem.

From what I understood, I saw that part of this section is used for pgm_write_page(sram, progmem). Urboot v7.7 bootloaders hold a 6-byte table at top of flash, see "implicit communication" in the protocol definition I'm reading. BTW, I beleive the bytes for "number of pages" and "vector number" are swaped in the description vs the implementation.

I wouldn't compile an ID into the bootloader flash. Though you could, if you placed the ID into a separate section before the section version that contains the 6-byte table. Would be using "pgm_write_page" a better idea for storing ID?

On another thing: I was reading about about 'dual boot', wouldn't that be a good Idea to have implemented as a 'pre-compiled bootloader' for wireless microcontrollers (I'm thinking atmega128RFA1 and atmega256RFR2) leaving the selection of the CS pin the same way as the "LED NOP" pin?

stefanrueger commented 4 months ago

Thanks for testing!

The bootloader name suggests it is compiled for a fixed baudrate of 125000 baud, but the command line shows you test with -b 115200. I am surprised it works at all. Giving the hefty discrepancy (8%) am not surprised by comms error leading to protocol errors leading to paged access failing leading to trying bytewise access, which isn't supported... I suggest you

Yes, with the hardware-supported bootloader of 1024 bytes you need a bootsize of 512 words. The choice of 1024 words works by chance as long as the lower 1024 bytes are not overwritten by the application. A code sequence of four 0xff effectively is a NOP.

leaving the selection of the CS pin the same way as the "LED NOP" pin

Could do, but there are already a lot of pre-compiled bootloaders. Users who run applications with dual booting are probably OK with compiling their own bootloader.

leaving the selection of the CS pin the same way as the "LED NOP" pin

Well, the user would still need a way to change the CS NOPs in the bootloader hex with the op code to set/clear the CS. I haven't yet published a tool for doing so...

the bytes for "number of pages" and "vector number" are swaped in the description

Thanks, well spotted!

Would be using "pgm_write_page" a better idea for storing ID?

You can, but the bootloader pgm_write_page() function won't overwrite the bootloader area itself. There is a neat trick to store IDs just after the vector table just so in every application code that you upload

uint8_t __attribute__((used)) __attribute__((section(".vectors")))
  my_flash_ID[16] = {0x01, 0x02, 0x03, /* ... */ };
tglaria commented 4 months ago

Thanks for testing!

The bootloader name suggests it is compiled for a fixed baudrate of 125000 baud, but the command line shows you test with -b 115200. I am surprised it works at all. Giving the hefty discrepancy (8%) am not surprised by comms error leading to protocol errors leading to paged access failing leading to trying bytewise access, which isn't supported... I suggest you

  • Use -b 125000 if your OS/driver supports that baud rate
  • Use a bootloader compiled for 115200 baud (should have 115k2 in the name) with -b 115200
  • Use an autobaud bootloader; this adapts to the speed the host sends (within reason)

The difference in baudrate is because of the different clock source I was using. During testing, I was using a 14.7xxx MHz external crystal. Since the bootloader for 125kbps@16MHz is the same as 115.2kbps@14.7xxxMHz, I just used the same. (I did later test the connection with the 16MHz clock source and it correctly flashes using > .\avrdude.exe -c urclock -p m128rfa1 -P COM7 -b 125000 -U flash:w:"test.hex")

Yes, with the hardware-supported bootloader of 1024 bytes you need a bootsize of 512 words. The choice of 1024 words works by chance as long as the lower 1024 bytes are not overwritten by the application. A code sequence of four 0xff effectively is a NOP.

So it's the urboot bootloader who would could overwrite those last 512words when flashing the application, ¿right? I'm guessing the application couldn't write on the bootloader section because of the configured fuses. Am I right?

leaving the selection of the CS pin the same way as the "LED NOP" pin

Could do, but there are already a lot of pre-compiled bootloaders. Users who run applications with dual booting are probably OK with compiling their own bootloader.

Fair enough. I guess I'll try to configure a computer to compile it.

leaving the selection of the CS pin the same way as the "LED NOP" pin

Well, the user would still need a way to change the CS NOPs in the bootloader hex with the op code to set/clear the CS. I haven't yet published a tool for doing so...

I haven't read how it is done for "LED NOP" so I'm asking from ignorance, is that too complicated? Wouldn't it be like duplicate what's been done for the "LED NOP"?

Would be using "pgm_write_page" a better idea for storing ID?

You can, but the bootloader pgm_write_page() function won't overwrite the bootloader area itself. There is a neat trick to store IDs just after the vector table just so in every application code that you upload

uint8_t __attribute__((used)) __attribute__((section(".vectors")))
  my_flash_ID[16] = {0x01, 0x02, 0x03, /* ... */ };

I'll need to check this out. But from what I read, this is an ID per application, right? Each application will have to have it's ID in the code and will be overwritten when changing the application.

My idea is to have a 'per board ID', like a serial number. That's the whole idea to keep it in the bootloader, it's not writable. Am I correct or wrong?

Using this same bootloader, I see there's metadata (which I don't care about), could I use this space to store information to be read by the application? If so, how could this be read? Another question, is all the information on the 6bytes table at the top of the bootloader required? I know if I modify the rjmp for the pgm_write_page function, it won't work, but what about the number of pages the bootloader uses or the vector number, are those used or they are there only for when asking for those using -xshowall?

stefanrueger commented 4 months ago

My idea is to have a 'per board ID', like a serial number. That's the whole idea to keep it in the bootloader, it's not writable.

Understand. In this case the bootloader needs to actually have 16 free bytes (check out Usage-Size in the bootloader tables). Then you need a way to overwrite the unused bootloader bytes with your board serial number. If you use a v7.7 urboot bootloader on an ATmega128RFA1 with 16 or more free bytes, the natural place for your serial number would be flash address interval [0x1ffea, 0x1fff9], ie, just below the six-byte table needed by urboot. No guarantees that the next urboot version won't increase the table size at the end of flash, though.

You could create a board-serial.hex file with your serial number in that range (srec_cat is a great tool for this) and burn together with the urboot bootloader like so

$ avrdude -c your_ISP_programmer -p m128rfa1 ... -U urboot_..._.hex -U board-serial.hex

Voila

I see there's metadata (which I don't care about)

In which case you'd use -c urclock -x nometadata whenever you upload/download programs

Another question, is all the information on the 6bytes table at the top of the bootloader required?

Yes, avrdude needs to know all this to keep the bootloader small.

stefanrueger commented 4 months ago

I see there's metadata (which I don't care about), could I use this space to store information to be read by the application?

Well, actually the metadata hold information about where the application ends, the date and filename of the last uploaded sketch. Most crucially, the metadata identify the exact unused space between the application and the metadata. This unused space, called store can be used by the application to read and write data.

https://github.com/stefanrueger/urboot/blob/6a7bec8ae38512c8534d7e52e70b9a6fd8bd566f/urboot-utils/urboot-utils.cpp#L15-L44

Note that flash wears out, though, (the manufacturer guarantees some 100,000 writes) so one shouldn't write flash gratuitously. Also note that flash can only physically be written a page at a time, so if you use above functions to write a single byte to flash, the underlying functions need to read the page, modify it and write it back.

tglaria commented 4 months ago

My idea is to have a 'per board ID', like a serial number. That's the whole idea to keep it in the bootloader, it's not writable.

Understand. In this case the bootloader needs to actually have 16 free bytes (check out Usage-Size in the bootloader tables). Then you need a way to overwrite the unused bootloader bytes with your board serial number.

If you use a v7.7 urboot bootloader on an ATmega128RFA1 with 16 or more free bytes, the natural place for your serial number would be flash address interval [0x1ffea, 0x1fff9], ie, just below the six-byte table needed by urboot. No guarantees that the next urboot version won't increase the table size at the end of flash, though.

You could create a board-serial.hex file with your serial number in that range (srec_cat is a great tool for this) and burn together with the urboot bootloader like so

$ avrdude -c your_ISP_programmer -p m128rfa1 ... -U urboot_..._.hex -U board-serial.hex

Voila

Currently, I think that's what I'm doing. I'm writing an unique identifier on the end (or beginnig, FLASHEND) of the bootloader (optiboot in this example) by modifying the hex file before flashing the board. Then, since I'm using the bootloader to update the application, I don't lose that identifier.

I guess I could write this serial to EEPROM, but I'd rather have this info in a place that's not writable by the application.

Another question, is all the information on the 6bytes table at the top of the bootloader required?

Yes, avrdude needs to know all this to keep the bootloader small.

I see there's metadata (which I don't care about), could I use this space to store information to be read by the application?

Well, actually the metadata hold information about where the application ends, the date and filename of the last uploaded sketch. Most crucially, the metadata identify the exact unused space between the application and the metadata. This unused space, called store can be used by the application to read and write data.

https://github.com/stefanrueger/urboot/blob/6a7bec8ae38512c8534d7e52e70b9a6fd8bd566f/urboot-utils/urboot-utils.cpp#L15-L44

Note that flash wears out, though, (the manufacturer guarantees some 100,000 writes) so one shouldn't write flash gratuitously. Also note that flash can only physically be written a page at a time, so if you use above functions to write a single byte to flash, the underlying functions need to read the page, modify it and write it back.

I think this could work. I'll check it out. The number of writes shouldn't be a problem, since I want to use it as a read only section. Flash once and persist when updating the application without losing the data (it's a unique identifier, it should be unmutable).

Should it be compatible on future versions of the bootloader?

stefanrueger commented 4 months ago

I'm writing an unique identifier on the end (or beginnig, FLASHEND) of the bootloader (optiboot in this example) by modifying the hex file before flashing the board.

OK, you can still do that with urboot bootloaders except

Fun fact: avrdude -c urclock can display a Hex ID of up to 8 bytes as a hex number (low byte first). You specify the location with -xid=... like so

$ avrdude -qq -curclock -xid=F.-14.8 -xshowid -Pch340
ffffffffffffffff
$ avrdude -qq -curclock -xid=F.-22.8 -xshowid -Pch340
ffff95082411cffd

This shows that my urboot bootloader only has 10 free bytes 0xff below the table.

Of course, you can also use a terminal command such as

$ avrdude -qq -curclock -Pch340 -T "read flash -22 16"
7fea  fd cf 11 24 08 95 ff ff  ff ff ff ff ff ff ff ff  |...$............|

Should it be compatible on future versions of the bootloader?

Well, depends what you do with your ID. If applications never ever read it and it's only for you to inspect with the bootloader as above, then not. But if your application wants to read the board id, it needs to know its location (22 bytes below FLASHEND+1 for urboot v7.7), but a future urboot bootloader might have 8 bytes table and necessitate you mobe the board id 2 bytes lower.

stefanrueger commented 4 months ago

When it works, it works.

During testing, I was using a 14.7xxx MHz external crystal. Since the bootloader for 125kbps@16MHz is the same as 115.2kbps@14.7xxxMHz, I just used the same. (I did later test the connection with the 16MHz clock source and it correctly flashes using > .\avrdude.exe -c urclock -p m128rfa1 -P COM7 -b 125000 -U flash:w:"test.hex")

Seeing that the urboot bootloader can be made to work, I am guessing it's the crystal caps and crystal that sometimes don't play and cause comms error; I concluded that urboot tests OK for ATmega128RFA1