Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question on Dual Templates #42

Open
elogh opened this issue Dec 13, 2024 · 19 comments
Open

Question on Dual Templates #42

elogh opened this issue Dec 13, 2024 · 19 comments
Labels
documentation Improvements or additions to documentation

Comments

@elogh
Copy link

elogh commented Dec 13, 2024

Hi Stefan,

I'm going to set up a Pro Mini board with dual boot from SPI flash that has its CS pin on A0.
Reading your documentation I found that I either have to build an appropriate version of urboot myself or will need to use the urloader sketch to install a templated prebuilt urboot.hex.
Unfortunately I couldn't find any additional information about an urloader sketch.
I've also been looking on the minicore site, but couldn't find information on how to select (and install) a templated bootloader although there is a page (cores/minicore/atmega328p/watchdog_1_s/autobaud/uart0_rxd0_txd1/template_dual) offering a suitable version. (At least I think so, because there is no "dual" in the path/file name.)
So could you please guide me to additional documentation on how to use a templated bootloader?
Regarding the option to build my own version of urboot: I read that I should use an older tool chain, but I'm on Windows only and don't have it at hand.
So, can I use the tool chain installed with the Arduino IDE (2.3) to build urboot? (It wouldn't be a problem for me that some more bytes are consumed then.)

Thanks,
Erwin

@stefanrueger
Copy link
Owner

urloader

I meant to offer an urloader sketch that would patch template bootloaders on the fly with the desired ports/pins but faced difficulties porting that from a bespoke IDE to plain vanilla avr-gcc; over time, this fell off my todo list. Apologies for raising expectations.

documentation on how to use a templated bootloader

The source code is currently the only additional source I can offer

urboot/src/urboot.c

Lines 610 to 620 in 5e9d508

#define NOP_SFM_SBIPORT() asm volatile("mov r5, r5\n")
#define NOP_SFM_CBIPORT() asm volatile("mov r6, r6\n")
#define NOP_SFM_SBIDDR() asm volatile("mov r7, r7\n")
#define NOP_SFM_CLRPORT() asm volatile("mov r8, r8\n")
#define NOP_SFM_CLRDDR() asm volatile("mov r9, r9\n")
#define sfm_release() NOP_SFM_SBIPORT()
#define sfm_assert() NOP_SFM_CBIPORT()
#define sfm_setupcs() NOP_SFM_SBIDDR()
#define sfm_resetddr() NOP_SFM_CLRDDR()
#define sfm_resetport() NOP_SFM_CLRPORT()

In your case this translates to the following replacement table for opcodes in the template hex file assuming the CS pin is PC0 (I guess your reference to A0 is the Arduino numbering of pins, but the datasheet pin name would be PC0)

Template opcode Replacement Comment
mov r5, r5 sbi <port-C>, 0 Set bit 0 of PORT C (release CS)
mov r6, r6 cbi <port-C>, 0 Clear bit 0 of PORT C (assert CS)
mov r7, r7 sbi <ddr-C>, 0 Set bit 0 of DDR C (make CS output)
mov r8, r8 out <port-C>, r1 Reset all PORT C bits: register R1 contains 0
mov r9, r9 out <ddr-C>, r1 Reset all DDR C bits

For the ATmega328P the address of PORT C is 8 and that of DDR C is 7:

$ avrdude -qq -pm328p -cdryrun -T "regfile -a" | grep portc
I/O 0x06: portc.pinc
I/O 0x07: portc.ddrc
I/O 0x08: portc.portc

Once these replacements are done in the template bootloader, it will be ready for use.

build my own version of urboot

Yes, you could do that, too. Newer toolchain versions should work but they are untested: some of the tricks to keep urboot small rely on properties of those specific toolchains. Best to use the provided docker file to compile on Windows, eg,

 $ docker run --platform linux/amd64 -v "$(pwd)/src":/src --rm -it $(docker build -q .) \
   MCU=atmega328p AUTOBAUD=1 VBL=1 AUTOFRILLS=5..10 NAME=atmega328p_a

You will need to add dual boot options...

@elogh
Copy link
Author

elogh commented Dec 13, 2024

I guess your reference to A0 is the Arduino numbering of pins, but the datasheet pin name would be PC0

Right, I'm still a beginner (with MCUs) and follow what is printed on the boards.

Once these replacements are done in the template bootloader, it will be ready for use.

So I have to search for the “move rx,rx” opcodes across the entire hex file and also need to adjust the checksums, right?

@stefanrueger
Copy link
Owner

need to adjust the checksums

Not if you use the :I format for uploading the bootloader to the board with a physical programmer as in

$ avrdude -c ... -p 328p -U flash:w:mydualurboot.hex:I

The format :I is forgiving re checksum errors

@elogh
Copy link
Author

elogh commented Dec 14, 2024

Great, that makes life easier. Thanks!

@stefanrueger
Copy link
Owner

pro tip: you can use the disasm terminal command in connection with -t -c dryrun to identify the mov nops and verify that they have been replaced correctly.

@elogh
Copy link
Author

elogh commented Dec 14, 2024

Hmm, it's looking more and more like AVRDUDE is a much more powerful tool than I originally thought.

@elogh
Copy link
Author

elogh commented Dec 17, 2024

Before patching a template bootloader, I tried to verify my OTA-enabled sketch on a test board with urboot_m328p_1s_autobaud_uart0_rxd0_txd1_led+d5_csb0_dual_pr_ee_ce.hex installed (and CS on PB0).
Thereby I faced a problem, however. Although the OTA upload of the testsketch.ino.hex, the transfer to the SPI flash, and the transfer from SPI flash to MCU by urboot (including subsequent erasure of the SPI flash) seemed to work, there was no response from the test board thereafter.
To figure out what went wrong, I let avrdude dump the MCU flash of the board and compared this dump with the hex file, the SPI flash after upload and a dump of the sketch uploaded via UART.
I found two differences between the regularly uploaded sketch and the other codes (which were all identical):
First, one byte, a part of a jump address, has changed: 0x0064: 0C94FC08 --> 0C94D408.
The other difference occurs at the end of the programm (at 0x6CAA): the UART-uploaded code (or data) continues for 100 extra Bytes, which are not present in the uploaded hex file.

Next, I patched this single byte at 0x0066 in the SPI flash from FC to D4 just before resetting the board and - viola - the OTA uploaded sketch runs fine.
So if I didn't miss something essential, this looks like avrdude (or the bootloader?) modifies the code before writing it to the MCU flash. Is that correct?

@stefanrueger
Copy link
Owner

stefanrueger commented Dec 17, 2024

I take it this bootloader comes directly or indirectly from this repo directory.

urboot_m328p_1s_autobaud_uart0_rxd0_txd1_led+d5_csb0_dual_pr_ee_ce.hex is a vector bootloader that (by its very nature) needs uploaded sketches be patched. AVRDUDE knows about this and patches the to-be-uploaded sketches automagically. When it's the dual bootloader itself that uploads the sketch from the SPI flash memory it expects the sketch be already patched. The reason for this is that the patching code costs valuable space in the bootloader for something that an external PC can do.

However, in this case the MCU has hardware-protected bootloading and the 512 byte size of the bootloader is exactly one of the sizes that the MCU offers. So this situation does not require vector bootloading, and it is better to select the hw-supported bootloader urboot_m328p_1s_autobaud_uart0_rxd0_txd1_led+d5_csb0_dual_ee_ce_hw.hex. Note that the fuse setting needs to match the hardware-supported bootloader and will be different to vector bootloaders.

The uploaded code always needs to be presented in terms of full pages (128 bytes for the m328p). So either way, each sketch needs to be rounded up in size either by AVRDUDE or by the very fact that it's taken page-wise from the SPI flash memory.

@stefanrueger
Copy link
Owner

And in case my previous answer wasn't clear: hw-supported bootloaders don't need patching of the sketch.

@elogh
Copy link
Author

elogh commented Dec 17, 2024

It was, thank you very much. Nice to see that my observations have a natural explanation.
I chose the vector bootloader from my MiniCore installation, because MiniCore selected a vector bootloader for my board. In fact I first tried using the hw bootloader you suggest, but with this I could not upload via UART anymore (probably due to the not matched fuse setting). So I switched to the vector type.

Managing fuses seems feasible as far as I can see (I think I need to switch the BOOTRST one, right?). I will check it out.
However, I'm planning to publish my application when its ready and then burning fuses might be too daunting. So my question: How dangerous do you think it is to trust that the byte to be patched will always be in the same place and will need the same change in the future so that I can patch it during the OTA upload?

@stefanrueger
Copy link
Owner

Very: the bytes in that place code where the application starts and that depends on the sketch and the compiler.

Really, it is best to use a hw-supported bootloader here. With a reasonably recent AVRDUDE it is easy to set the fuses correctly using a physical programmer whilst you flash your bootloader, eg, as in

avrdude -qq -p m328p -c ... -e -U my_hw_bootloader.hex -T "config bootrst=boot_section; config bootsz=bs_256w"

Note that the boot section size 256w is given in words, ie, means 512 bytes. If you feel like it you can sprinkle in a config blb1=spm_disabled_in_boot though hardware write protection for the boot section is not necessary as urboot bootloaders don't overwrite themselves. You can add -T config at the end of the line to verify all fuse settings.

@elogh
Copy link
Author

elogh commented Dec 18, 2024

Ok, I did it. And it looks good.
(I copied the commands applied by MiniCore from the Arduino IDE and toggled the BOOTRST bit in hfuse. Will check the avrdude config commands for future activities.)
Now I'm going to patch urboot_m328p_1s_autobaud_uart0_rxd0_txd1_template_dual_ee_ce_hw.hex

@stefanrueger
Copy link
Owner

I copied the commands applied by MiniCore from the Arduino IDE and toggled the BOOTRST bit in hfuse.

If it's the case that the MiniCore IDE issues the wrong fuse settings for hw-supported bootloaders I'd encourage to raise an issue over that. I am sure Hans will be happy to engage with that.

going to patch ...

Good luck. If you'd like, please share your experience with that and let me know how the documentation for urboot could be improved with that respect.

@stefanrueger
Copy link
Owner

Will check the avrdude config commands

Highly recommended to at least check the fuse settings. It's important that the bootloader size is correctly set. When the bootloader size setting in the fuses is too big, you might not notice trouble initially (b/c the MCU sails over the initial 0xff section of the too big bootloader section until it rexches urboot in the top 512 bytes) but as soon as the sketches get bigger reset will jump to the top end of your sketches with unknown results.

@elogh
Copy link
Author

elogh commented Dec 18, 2024

If it's the case that the MiniCore IDE issues the wrong fuse settings for hw-supported bootloaders I'd encourage to raise an issue over that.

The MiniCore/Arduino IDE issues the fuse settings for vector bootloaders because it installs a vector bootloader for (8 MHz) 328p MCUs (.../urboot/atmega328p/watchdog_1_s/autobaud/uart0_rxd0_txd1/led+b5/urboot_atmega328p_pr_ee_ce.hex).
That's the reason why I tried a vector bootloader at all, because I could not change that.

From this installation I also copied the fuse settings for the bootloader size which I think is ok.

If you'd like, please share your experience with that ..

Yes, I will do so.

@elogh
Copy link
Author

elogh commented Dec 19, 2024

Done. I wasted some time looking for an AVR disassemler to verify the replacement opcodes, but even without it everything worked out fine.

@elogh
Copy link
Author

elogh commented Dec 20, 2024

Regarding the documentation for urboot I'd suggest to include your post from Dec 13, this helped me a lot.
For my own documentation and for people who want to replicate my project, I will add the following:


Without suitable tools, you have to put together the opcodes yourself. They are always 2-byte codes, with the first byte in the binary program in second place.
The second identifies the operands (port register, bit-, port- or register-index):

sbi: 0x9A + 5 bits for one of the port registers + 3 bits for the bit;
cbi: 0x98 + 5 bits for one of the port registers + 3 bits for the bit;
out: 0xB8 + 4 bits for the source register + 4 bits for one of the I/O ports.

Since hex files are plain text files, a text editor is a good choice for finding and replacing the opcodes.
These are the replacements I had to apply to the dual_template in order to define A0 (= PC0) as chip select:

assembler opcode hex --> Replaced by:
instruction
mov r5,r5 0x2C55 552C --> sbi 8,0 0x9A40 409A
mov r6,r6 0x2C66 662C --> cbi 8,0 0x9840 4098
mov r7,r7 0x2C77 772C --> sbi 7,0 0x9A38 389A
mov r8,r8 0x2C88 882C --> out 8,r1 0xB818 18B8
mov r9,r9 0x2C99 992C --> out 7,r1 0xB817 17B8

The 'hex' column indicates how the opcodes appear in a text editor. After replacement I saved the bootloader as

urboot_m328p_1s_autobaud_uart0_rxd0_txd1_no-led_csc0_patched_dual_ee_ce_hw.hex

Each line of a hex file ends with a checksum byte, which is now invalid for all the patched lines.
To avoid avrdude reporting errors and aborting, ":I" must be appended to the name of the hex file instead of ":i" as a format specifier.


Since the people I'm addressing often don't have much experience with micro controllers, this is a bit more detailed as might be appropriate for the urboot site, I think. But maybe you can still use some of it.

@stefanrueger
Copy link
Owner

@elogh Thanks for your suggestions to update the documentation. I have now pushed two commits doing so

  • Remove all references to the urloader sketch
  • Add explicit tables for how to change a template bootloader before burning it

Please could you review these two commits, in particular the latter?

Once you are happy, we can close the issue.

@stefanrueger stefanrueger added the documentation Improvements or additions to documentation label Dec 23, 2024
@elogh
Copy link
Author

elogh commented Dec 23, 2024

I think now it is clearly documented how to modify a template and quite easy to do.
If you want to make the access still easier you could add links from the template keywords on the urboot and the urboot/blob/main/docs/howtoselect.md pages to urboot/blob/main/docs/makeoptions.md.

Thanks again for your valuable help and your excellent software!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

2 participants