Bootloaders and avr-libc

Go To Last Post
30 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Freaks,

It's time for me to write my first bootloader. I understand the process - write the bootloader code, relocate it into the bootloader section. However, it seems that for me to write one with WinAVR, I must relocate all my functions, variables, etc. via the BOOTLOADER_SECTION macro in .

I'm trying to create a FLIP-compatible bootloader based on MyUSB, in less than the maximum 4KB of bootloader space. However, MyUSB isn't designed to be relocated into the bootloader section - the BOOTLOADER_SECTION macro isn't used on any of the library functions and variables.

Is it possible to relocate the entire binary to the new section easily? I'd rather write the application like a normal program, and use the makefile to relocate the binary into the bootloader space for the chosen AT90USBXXX model.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Something like this does the trick (for me)-
LDFLAGS += -Wl,-section-start=.text=0x1e00

(that BOOTLOADER_SECTION macro is pretty much useless unless you are creating an app that wants functions placed in the bootloader section)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dean,

As Curt says you have fallen into the same trap as I see repeatedly on here.

Folks thinking that "BOOTLOADER_SECTION" is the magic for writing a bootloader. It is NOT. What that is intended for is when you write some app code (i.e. with reset and vectors at 0) but you need to do some SPM work to write flash or whatever maybe using the code flash as dynamic data space or something. So you just use that macro in the function definition of all the functions that must remain visible when the app space "disappears" to 0xFF during SPM. (before the call to boot_rww_enable() to make it visible again)

All BOOTLOADER_SECTION does is place some functions into .bootloader then your LDFLAGS would have an added --section-start=.bootloader=0xNNNNN where NNNNN is the bootloader address

When it comes to writing a "real" bootloader that is normally done as a completely standalone program (even if the intention is that the final output .hex will be SREC glued onto the end of an application .hex for a single image programming) then like Curt says you can just uproot .text using --section-start but there's actually a shortcut to this and that is -Ttext=0xNNNN which is an exact synonym for --section-start=.text=0xNNNN

(and just to be pedantic: but Curt missed one of the hyphens from his --section-start above! ;) )

If you do go for the completely separate boot and app (the only sensible way to do it really) then hte next issue you'll face is, for example, when you don't want to duplicate all your UART_Rx() and UART_Tx() routines so there are copies in both places - insstea dyou want the app to be able to "borrow" those in the boot and this is where the perennial subject of having a table of function pointers (or whatever) is a boot location that is "known" to both sides some in. The __vectors can often be a good place for this link.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I only had a cursory look over the bootloader API, but I did see that it was my responsibility to relocate the new .bootloader section to the correct address. I was under the impression that .text couldn't be located due to the linker scripts, which was why the custom section was supplied.

Since I can indeed relocate the whole darn app it's much more simple than I feared, which makes my life much easier. Thanks both of you.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yup once you move .text with -Ttext= then everything else (in code space) just moves automagically along with it (so reset/vectors start at 0xNNNNN followed by the pre-amble, the progmem data, the .text, .data initialisers and so on)

(BTW remember that NNNNN in GCC is the BYTE address which is double the WORD addresses the Atmel datasheet uses when talking about BLS positions)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is there any possibility to remove the vector table at the beginning of the bootloader? If no interrupts are used, the table is not neccessary and is only a waste of valuable program space.

Regards
Sebastian

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

-nostartfiles and -nostdlib are worth a look. Be warned that you may need to provide your own preamble and/or handle .data/.bss variables differently. You also have to set the stack and make sure R1 contains 0 etc.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
(and just to be pedantic: but Curt missed one of the hyphens from his --section-start above! Wink )

avr-ld user manual
Quote:
For options whose names are multiple letters, either one dash or two can precede the option name

which is why it works, I guess. AVR Studio produced the makefile option via the memory options.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Cliff!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Strange. While the code works in the normal section, relocating .text causes the thing to break (it's definitely running as per the status LEDs, just the USB system isn't working). I've turned off --gc-sections and --relax, and other gotchas I should be looking for?

EDIT: What about .data, .bss and the like?

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There's something wrong with my interrupts. The listing file shows the vector table at the correct bootloader address, and my JTAG shows that IVSEL is being set correctly, but the vector handler is never reached.

EDIT: Program shows in the listing as starting at 0xF000, but my JTAG shows it at starting at 0x7800. What gives?

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have you checked the BOOTRST fuse and the IVSEL bit in MCUCR?

Regards
Sebastian

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Have you checked the BOOTRST fuse and the IVSEL bit in MCUCR?

Regards
Sebastian

IVSEL is being set correctly. The problem I've discovered is that my listing shows the entire program correctly being relocated to 0xF000. However, AVRStudio shows it starting at 0x7800. That's preventing the app from correctly finding the boot vector table.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think you got confused by the word addresses in AVR Studio and the byte address in GCC. The same happend to me.

Regards
Sebastian

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

0x7800 <-> 0xF000 / 2

sounds like you're mixing word and byte adresses. GCC deals in byte adresses, whereas all Atmel datasheets give the bootloader adresses in word adresses.

Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ah, so it's correct then? Still doesn't explain why the vector isn't firing.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ah, I see. I've doubled the start address to 0x1E000 and it's now seeing the device, but not enumerating correctly anymore. Still more things to figure out.

EDIT: Got it - pgm_read_byte doesn't work on addresses over 64KB. Added compile time option to the library to use RAM located descriptors instead as a workaround.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
(BTW remember that NNNNN in GCC is the BYTE address which is double the WORD addresses the Atmel datasheet uses when talking about BLS positions)

Wonder who said that above? ;-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> pgm_read_byte doesn't work on addresses over 64KB.

There's a pgm_read_byte_far as well.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

There's a pgm_read_byte_far as well.

Saw that, couldn't figure out what it wanted for the address. No matter - RAM usage in the bootloader doesn't matter, and the option to use RAM descriptors will be more useful to end-users than far descriptors.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
when you don't want to duplicate all your UART_Rx() and UART_Tx() routines so there are copies in both places - insstea dyou want the app to be able to "borrow" those in the boot and this is where the perennial subject of having a table of function pointers (or whatever) is a boot location that is "known" to both sides some in. The __vectors can often be a good place for this link.

Dean this could be a very cool feature of combining MyUSB + your bootloader. In email you and I talked about the likely difficulty of making a USB bootloader fit in 2k or less. But instead of thinking about bootloader smallness, how about giving apps more space by jamming as much of the core USB logic into the bootloader as possible. Then using if from both apps and the bootloader as Cliff suggests. If you had say... 1 or 2K of USB logic in the bootloader that didn't need to be in an app, that would be a significant gain on smaller devices. On a 16k AT90USB162 it would be a huge gain! Heck you might even single handedly make the 8K AT90USB82 a usable USB device ;)

Of course there are a few difficulties. 1) The USB code in the bootloader should be stable since it will be harder to upgrade. 2) You'd want to be able to build MyUSB with and without the booloader dependency so that it worked with standard Atmel bootloaders.

Anyway, something to think about down the road.

-Brad

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Aha, so you're Daniel then.

The bootloader's progressing very well - it works with FLIP now and I can read the signature, erase the flash, start the user app and get the bootloader details. I'll work on the flash/eeprom read/write on Monday, and it'll be pretty much done.

Good idea for the linking. I'll work on that once the bootloader's done. I think it'll require a jump table system like Cliff is so fond of, with the only real cavet being that the descriptors will have to live in RAM rather than progmem.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

Last Edited: Sun. Feb 10, 2008 - 07:18 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

abcminiuser wrote:
Aha, you you're Daniel then.

No, I'm Brad.

abcminiuser wrote:
with the only real cavet being that the descriptors will have to live in RAM rather than progmem.

That won't work for the AT90USB162 and AT90USB82 with on 512 bytes of RAM. Those descriptions are pretty verbose.

-Brad

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

abcminiuser wrote:
Aha, you you're Daniel then.

No, I'm Brad.

Whoops, sorry. I've got two similar conversations going on at the same time, and I got confused.

Quote:

That won't work for the AT90USB162 and AT90USB82 with on 512 bytes of RAM. Those descriptions are pretty verbose.

True. I'll have to solve a few problems before it will be viable to use the bootloader functions - like the event handling. Still, I'm sure I'll get it all figured out in the end.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

schickb wrote:
.... Then using if from both apps and the bootloader as Cliff suggests. If you had say... 1 or 2K of USB logic in the bootloader that didn't need to be in an app, that would be a significant gain on smaller devices. On a 16k AT90USB162 it would be a huge gain! Heck you might even single handedly make the 8K AT90USB82 a usable USB device ;)

I use usbtiny in a bootloader that fits into 2k and re-use the usb interface from the application. It's currently working on mega88 and tiny44.

I extract an assembler file that declares the usb interface functions with their address from the bootloader. And then link the application statically against that.

Not sure if that solution works for you but it has minimal overhead.

Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

schickb wrote:
abcminiuser wrote:
with the only real cavet being that the descriptors will have to live in RAM rather than progmem.

That won't work for the AT90USB162 and AT90USB82 with on 512 bytes of RAM. Those descriptions are pretty verbose.
Stepping in where angels fear to tread... Could the descriptors live in EEPROM? Seems to make sense, as they don't change often. You still have only 512 bytes of EEPROM in the USB devices Brad quoted, but at least your RAM is freed up.

Stu

PS: Dean, I stand in awe of what you've accomplished at your age. You rock!

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Stepping in where angels fear to tread... Could the descriptors live in EEPROM? Seems to make sense, as they don't change often. You still have only 512 bytes of EEPROM in the USB devices Brad quoted, but at least your RAM is freed up.

Stu

Hey, I like recieving ideas! Saves me head from hurting and I love to think about the different ways to implement the best ones.

EEPROM descriptors would be scary for the bootloader because the user could wipe them out, killing the bootloader in the process. I will however add in a compile option to use EEPROM located descriptors, should the end-user want them in their own applications.

Only have the write flash/EEPROM left to implement.

Quote:
PS: Dean, I stand in awe of what you've accomplished at your age. You rock!

Cheers! But I'll be old and wrinkly (19) in a few days on the 14th. Yes, my mother likes to joke every year that I've cheated her out of her romantic Valentine's day dinners...

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

DAMNIT TO HELL.

Sometime I think I'm too stupid to be doing this for a hobby. I just spent the afternoon chasing down a memory corruption bug, only to find that I forgot to put in a busy-wait after sending the endpoint's contents to the host to wait until the host was ready for more data.

If that wasn't enough, it then took me a whole hour to figure out why every 1024'th byte was corrupted - the 16-bit address was wrapping around back to zero.

Anyone have a brain upgrade for sale?

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

abcminiuser wrote:
DAMNIT TO HELL.

Sometime I think I'm too stupid to be doing this for a hobby. I just spent the afternoon chasing down a memory corruption bug, only to find that I forgot to put in a busy-wait after sending the endpoint's contents to the host to wait until the host was ready for more data.

If that wasn't enough, it then took me a whole hour to figure out why every 1024'th byte was corrupted - the 16-bit address was wrapping around back to zero.

Anyone have a brain upgrade for sale?

- Dean :twisted:

In these far too common situations I tell myself that a person has to be very smart and study for a long time to know enough to make a mistake this stupid. Ordinary mortals never make the kind of incredibly stupid mistakes we embedded systems guys make. So, get used to it. It is part of the job, and while you may refer to it as a hobby, I'd bet a lot that you'll end up feeding your family with these activities so best to learn coping skills early to protect yourself from the mindnumbingly dumb things you and everyone else in the field do on a regular basis.

Welcome to the club.

Smiley

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh, I do cope, but it helps to vent a bit after finding such stupid mistakes. The worst of it is, it still doesn't quite work -- I've emailed Atmel with the hope that they'll share their read/programming algorithm.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!