LUFA Bootloader and application programming

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

Hello to all!

 

I am working with the “USB to Serial Converter” project from LUFA. Code is working fine. Now I would like to use bootloader (so I don’t need a programmer). That’s when I saw the “CDC Bootloader” example project (also from LUFA). Is this the correct bootloader for this case?

 

So, I flashed the bootloader with a programmer to the atmega32u4. This step is fine (led is blinking). Now I would like to flash my application to the uC. I am using a USB cable connected to the D+/D- pins. When I try to program the device from Atmel Studio, there is no option there… only the “simulator” tool… Probably that’s not the correct hardware connection I need…

 

I read the “Bootloader FAQ” pdf and there it’s written:

“… you will need an external programmer to write the bootloader to the MCU…”  -> Done!

“…Then simply use the bootloader's normal communication mechanism to transfer and program the application…” -> That’s the part I am lost…

 

How is this done? What am I missing here?

Should I use maybe another software (and not Atmel Studio) just to flash to *.hex?

And what would be the hardware connection?

 

Thank you very much for your support! Any tip will be appreciated!

This topic has a solution.
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is this the correct bootloader for this case?

Who can say? It completely depends on how you want the end users to upload code to the AVR from the PC end. That's basically what the choice of bootloader comes down to: what mechanism do you think the end user will find easiest and most obvious to pass a code.bin file from their PC to the AVR. Personally I like the idea of an MSD based bootloader do the AVR looks like a "drive" in bootloading mode. The end user on the PC then just drags and drops code.bin to drive F: (or whatever) and it gets programmed. If you use CDC I guess it's going to involve a terminal program and transmitting code.bin to the AVR using some protocol like Z/Y/Zmodem?

When I try to program the device from Atmel Studio, there is no option there…

Why did you think there would be? The only programmable devices that Studio supports are Atmel's own programmers and debuggers like AVRISPmkII, JTAGICE3, Dragon, Atmel-ICE and so on. For your AVR+bootloader to appear as such a device it's going to have to "fake" the identity of one of those by telling Studio the Atmel VID/PID and enumerating as the kind of device Atmel's own devices do.

 

As i say I rather like the idea of a mass storage bootloader. The command (at the command line rather than using GUI drag/drop) to program a file is then something like "copy /b code.bin F:\". So in Studio you would set up a menu entry or toolbar button so that when invoked it executes this command (don't hard code "code.bin" in the command - AS6 has a method to do parameter substitution in such commands).

“…Then simply use the bootloader's normal communication mechanism to transfer and program the application…” -> That’s the part I am lost…

As I say you simply have to arrange for what you do on the PC end to match the mechanism the bootloader in the AVR is programmed to receive. Often you pick that mechanism to make the operation at the PC end as simple as possible for the user. Of course you could implement a DFU or HID bootloader too. But in this case the end user will require "special software" that can read code.bin and send it via DFU or HID to the AVR. I suppose that is a possibility if you make a DFU bootloader that Atmel's own "Flip" will recognise. then you can tell the user to get a copy of Atmel's Java Flip program and run that (well until it crashes!).

Should I use maybe another software (and not Atmel Studio) just to flash to *.hex?

This is common. But like I say it could be as simple as a Command prompt copy command.

And what would be the hardware connection?

Well that one is easy and is, presumably, the whole reason for using USB in the first place - it's nothing more than a USB A-B cable. Note however that there may be a hardware requirement at the AVR end. When you think about it your 32U4 is normally operating as a CDC to do the USB-RS232 trick. But say you put an MSD or DFU or HID or any other class of bootloader into it. On the occasion you want to reprogram the 32U4 code you need a way to say "when you power on I don't want you to go into the usual CDC mode but, instead, I want you to go into DFU/MSD/HID/... mode and wait for a code file". The mechanism used for this on an USB enabled AVR is called "HWB". So unless you are going to enumerate always as a dual class device (like HID+CDC or MSD+CD or whatever) then you need to read about HWB in the 32U4 data and perhaps arrange for a button to "tickle" the HWB pin on the occasion the user wants to bootload some new code.

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

Hello Clawson!! Thank you very much for the fast reply! It was very clarifying!

 

So, I chose the cdc bootloader because I thought it was the right one… But the MSD based bootloader looks much easier to work with. As you said: ”… The end user on the PC then just drags and drops code.bin to drive F: (or whatever) and it gets programmed …”.That’s exactly what I need! Thankfully, there is MSD based bootloader available in the LUFA (I think that’s why you have mentioned it). I have already flashed to the uC and it works. There are two *.bin files inside now: EEPROM and FLASH.

Now I would like to put my application into it. I don’t think I should delete those two mentioned above, right?

 

I am having a problem now to get the .bin code…

I saw this for example: “Type: avr-objcopy -O binary myfile.elf myfile.bin for converting elf file to a binary file”, but I don’t know where to type this stuff…

I also saw another post (from 2006) that you have answered it actually: “Use avr-objcopy to get a .bin image from the .elf”. It looks like it is the same thing as I mentioned above. But how do I do this?

 

Again, thank for the tips!!

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

(I think that’s why you have mentioned it).

You may think so - I couldn't possibly say.

 

(but "yes"!)

 

As to how you make the files. The fact is that when you build in Studio (or pretty much any GCC based build system) the ultimate output file is an ELF file. It's probably called project.elf or something. Once it's cerated you will see two further steps involving avr-objcopy. One takes the flash bits from project.elf and makes project.hex (an Intel Hex file) and the other takes the EEPROM bits and creates a project.eep (also an Intel hex file but given a .eep extension simply to differentiate it). For the time being I wouldn't worry about anything to do with EEPROM. For starters just write simple C programs that don't use EEPROM and ignore any project.eep that might be created (in fact if you aren't using EEPROM it probably isn't created anyway).

 

So either project.elf or project.hex contain what you want to go into the flash of the AVR but the bootloader is (probably!) not interested in trying to decode ELF (VERY complex) or even HEX (moderately complex) so it wants you to convert one or the other to .BIN which is just the pure binary bytes to go into each byte location of the AVR's flash memory. While you can run a rule on the ELF file that is very similar to the one that created project.hex but tell it to write "binary" rather than "ihex" I think it's actually easier to ust take project.hex and output it as a third file called project.bin simply converting Intel Hex to binary. avr--bjcopy can do this for you and as you have found it's a command similar to what you showed:

avr-objcopy -O binary project.hex project.bin

That says "read in project.hex then write it out in "binary" as project.bin". It should detect that the input is Intel hex but you can help it by using:

avr-objcopy -I ihex -O binary project.hex project.bin

where the "-I ihex" specifically says "the input is in Intel hex format".

 

Now AS6 has a  nice feature it inherits from the Visual Studio it is based on. It has "pre-build" and "post-build" steps you can define. These are additional commands to be run either before or after the main project is compiled. You would want to add the avr-objcopy I just suggested a s a post build step so it waits until project.elf, project.hex (and project.eep) have been created then it takes the project.hex as input and outputs a project.bin

 

The only thing is you don't really want to hard code the names "project.hex" and "project.bin" in there in case you ever changed the project name to "project2" (for example). So another clever feature of AS6 is it "knows" the current project name and can supply this as a variable so you would actually enter:

avr-objcopy -I ihex -O binary $(MSBuildProjectDirectory)\$(Configuration)\$(Output File Name).hex $(MSBuildProjectDirectory)\$(Configuration)\$(Output File Name).bin

as the post build step and Studio will replace MSBuildProjectDirectory with something like C:\users\cliff\my documents\Atmel\studio62\test and Configuration will be "Debug" or "Release" and Output File Name will be "project" or whatever it is called. When you later look into C:\users\cliff\my documents\Atmel\studio62\test\Debug\ (or whatever the build directory is called) you should now find both a project.hex and a project.bin

 

PS I just reminded myself looking at LUFA/Bootloaders/MassStorage/Lib/VirtualFAT.c that the "fake disk" it presents has this:

		/* MSDOS file entry for the virtual Firmware image. */
		[DISK_FILE_ENTRY_FLASH_MSDOS] =
		{
			.MSDOS_File =
				{
					.Filename        = "FLASH   ",
					.Extension       = "BIN",
					.Attributes      = 0,
					.Reserved        = {0},
					.CreationTime    = FAT_TIME(1, 1, 0),
					.CreationDate    = FAT_DATE(14, 2, 1989),
					.StartingCluster = 2,
					.FileSizeBytes   = FLASH_FILE_SIZE_BYTES,
				}
		},

So the file you copy to the "drive" that appears will ultimately want to be renamed FLASH.BIN so you might want to have avr-objcopy use that name for the output file in the first place.

 

Equally the file it uses for EEPROM is called EEPROM.BIN

 

PPS Every time I look at code written by Dean Camera I feel just a little bit jealous. His code is always more elegant than anything I ever manage to produce - a true artist of the trade! (Atmel are idiots to have let him go).

Last Edited: Mon. Feb 9, 2015 - 05:00 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello! Thank you very much again for the reply and WOW… such a detailed reply!

It worked perfectly! I added the

 avr-objcopy -I ihex -O binary project.hex project.bin

to the build events and done! Changed the name to “FLASH.BIN” and copied to the uC.

 

But I am still unsure about something else:

The application is not starting. I suppose I have to tell the bootloader to do that… in the code, there is a function called “void Application_Jump_Check(void)” which seems what I need. But it looks like it checks for the state (high or low) of a pin… I would like to do it just by software, which I think it is like this:

((void (*)(void))0x0000)();

according to the code. But where should I put this? I mean… When I want to update my application, does the bootloader has to be running? So should I “create” a timer that after a few seconds of running the bootloader, it jumps to the application? So this way I would have time to copy the new application to the uC? How this process work?

 

Thank you very much again!!

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

Remember when I said?...

then you need to read about HWB in the 32U4 data

I think now may be that moment!

 

The fact is that bootloading in a USB device (that uses USB as the delivery channel) is not quite like bootloading in a "normal" AVR.

 

In mega's you have the chip set with BOOTRST so each and every time power is applied it starts executing in the bootloader code. That then makes some decision about whether it is time to do some bootloading or not. If not it does something like:

((void (*)(void))0x0000)();

and even if it does choose to bootload and SPM it ends by doing the same thing. That line codes to a "CALL 0" and that's what happens so the app code starts.

 

Now as I tried to explain above a USB-AVR is not like this. If it were the case that it always starts into the bootloader then the first thing the bootloader would do each time would be to have a conversation with the PC over the USB wires and say "here I am, I am an MSD class device and I'm ready to do some bootloading". But at most power-ons this is not what you actually want. If the code always started into the bootloader and announced it was an MSD you would then need a mechanism, after it had decided not to bootload for it to say "oh, wait a minute, I lied, I'm not really an MSD - forget I ever told you that - no, today I have decided to be a CDC instead".

 

This is why HWB exists. It's a pin on the USB-AVR and when held one way it says "start into the bootloader" and when held the other way it says "start into the application". For one the AVr will look like an MSD, for the other it will look like a CDC (or whatever you choose in the app code). The _HWB pin will only act in this way when the HWBE fuse has been activated.

 

The USB-AVR also has BOOTRST and if enabled it will always force a start in the bootloader but you would generally not set BOOTRST but would set HWBE then have a button or something on the HWB pin that you might hold on the odd occasion when you turn on and do want to use the bootloader. The following is a digram from the 16U4/32U4 datasheet (the one I happened to have) that shows the process...

 

If you want to skip the pin check in the current coed (though it only seems to be for LEONARDO and XPLAIN boards anyway) then at the top of:

void Application_Jump_Check(void)
{
        bool JumpToApplication = false;

change that false to true.

 

But really, HWBE/HWB is the way to handle this "properly".

 

EDIT: actually when I look at it I see the Application_Jump_Check is a .init3 routine which means it's going to run every time at the very start of the bootloader (it is not CALLd from anywhere) so changing that false to true could be unwise as I think this would then prevent the bootloader from ever operating in fact!

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

Hello again! Thank you very much for the reply.

 

To be honest, I didn’t understand what you meant when you mentioned HWB… Now I got the idea.

 

I searched and this is what I found: whenever there is a reset (reset button released), if the HBW pin is low, then it goes to bootloader mode. If the HBW pin is high, then application mode. And when the state of this pin changes, the modes application or bootloader will also change automatically. Is that correct? For example: I am running the application. Now I would like to update it. So I have to change to bootloader mode (changing the state of the HWB pin to low), so I can see the virtual MSD. I replace the flash.bin and return to application mode (changing back to high the state of the HWB pin). Did I get it right?

Ps: the HBW fuse is set. What about the BOOTRST? And BOOTSZ (2048W-3800)?

 

My question now is: the board I am using, the HWB pin is connected to ground through a resistor. I could change that, but then I would have an extra push-button flying around, unsoldered resistor, etc… This doesn’t look nice…

I could still develop my own board, but I would like to know how I could manage to do this without the usage of the extra push-button.

I searched and saw two ways:

1- use a timer interruption that after a few seconds, jump to application

2- watchdog

 

I tried the first one (easiest way I would say), but no success… Maybe did something wrong or fuses wrong, etc…

Am I in the correct direction? What would be the easiest way to avoid the extra push-button?

 

Thanks again for your time!!

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

And when the state of this pin changes, the modes application or bootloader will also change automatically. Is that correct?

No, you are wrong about the last bit. This is purely at power on - see that flow-diagram above. Once the HWB decision is made and either the app or the bootloader has started then that is it. If you want to switch back from the app to the bootloader you need to include some code in it to call back to the bootloader. Usually to bootload you would simply power off. Hold the "HWB button" then power on. As it starts up (with HWBE fuse enabled) it will sense the state of the HWB pin and enter the bootloader.

 

If you use HWBE/HWB then forget about BOOTRST. It's there as an alternative only if you ALWAYS want to start into the bootloader. You could, of course, do this and the startup code of the that bootloader could look for the "trigger" that says "this time I want to bootload" which might be a pin held of some value previously written to EEPROM or something. If the trigger is seen it goes on to enumerate as MSD but if not it just goes off into the app code and enumerates as something else.

 

If your hardware is fixed perhaps you do want to explore BOOTRST and some other trigger. I guess ultimately the question is "what do you want your users to have to do to get into a reprogramming?"

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

Yes, of course… it’s just at power on! Yes, yes… It was a stupid question… After I worked a little bit I saw, I saw how wrong I was…

 

So, everything is working now!

Thank you very much for the tips. I learned a lot this week :)

 

The MS bootloader was the most important tip! I was working with the wrong one before…

The FAQ pdf is also very… very helpful!

 

I want to congratulate everybody that keeps avr freaks alive!!

 

Thanks again!