[TUT] [C] Bootloader using SD/MMC card

Last post
40 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

(This tutorial is based on modified code from http://www.mikrocontroller.net/articles/MMC/SD_Bootloader_für_AT_Mega. In addition, it uses modified sd/mmc reader code from E.Chan.)

Introduction

Bootloaders can be very confusing. Lots of posts make references to the possibility of using an SD card, but I couldn't find any that actually discussed how to do it. This tutorial is meant to allow beginners to quickly modify and use an memory-based bootloader, without having to go through all the stress and development I had to.

Bootloaders are actually quite simple, but when you're just starting out they can be a little overwhelming. The first thing to understand is that bootloaders are actually fully separate, independently flashed, programs. It might be surprising, but you actually need two main()s: one in the bootloader and one in the "real" program.

The crucial difference comes from the fact that the bootloader is located at the end of the program flash, instead of the beginning. This is why the MCU must be configured to send the reset vector to the beginning of the bootloader instead of the absolute beginning of the flash.

What this means is that with an ISP, JTAG, or other programmer you'll first flash the MCU with the bootloader and then use the bootloader to load the "real" program into the lower flash section. When the chip boots, it goes directly to the bootloader executable, and from there the bootloader instructs the chip to start the main application. This is easier than you think: all the bootloader does is tell the MCU to do whatever instruction is located at 0x0000, i.e. the beginning of the flash. Since this is precisely what happens when you don't have a bootloader, the program runs just as it would if it had been flashed on directly with a programmer.

Configuring the MCU

Since the bootloader is about 100 bytes over 2K (can anyone help me get it under 2K?), we have no other choice than to configure the MCU for a 4K bootloader. For this, two fuses need to be set: BOOTRST and BOOTSZ. BOOTRST simply needs to be turned on, but BOOTSZ needs to be properly configured. As we need a 4K boot sector, we have to choose the Boot Flash size = 2048 words. (Confusing, eh? 2 bytes equals 1 word. Not sure why Atmel counts in this way, I'm certain there's a good reason. Maybe one of our 10K+ posters can tell us?) If you're using AVRStudio, it will even nicely tell you the start address-- again in words, not in bytes; otherwise, you can find that information in the chip docs.

That's all there is to configuring the chip. Write the fuses, and henceforth the MCU will go to the start address instead of 0x0000 after a reset. Now comes the harder part.

Bootloader

The bootloader is completely independent from the main application. This has two consequences, one good, one bad. The good: you can debug the bootloader separately without worrying about what the main application needs to do. The bad: if you use a programmer to flash the bootloader, you erase the main program and vice-versa. (Of course this isn't strictly true, as you can choose not to erase the chip when you flash, but this probably makes life worse, not better.)

Settings

In order for the included code to work, several settings must be made. Almost all settings are in defines.h.

defines.h

/*Firmware version*/
#define DEVID 0x00000001 		//Arbitrary ID

The device ID (DEVID) is how the bootloader tells if the firmware is meant for that device. This is an arbitrary number and can be set as you like. If the device ID in the main program firmware does not correspond to that of the bootloader, the bootloader will ignore it.

/*MCU bootloader info*/
#define BOOTLDRSIZE  0x1000	//Size of bootloader in [bytes]. 0x1000 = 4096 bytes

This is the size of the bootloader section in [bytes]. It must be equal to the Boot Flash size (times two if the BFs is expressed in words).

/*FAT version*/
//#define USE_FAT12 				//Uncomment for FAT12 support. Requires additional flash

The bootloader can also read FAT12 partitions. Uncomment to activate this, but note it increases the program size.

/*Watchdog*/
//#define WATCHDOG 					//Uncomment if Watchdog is used in normal code

If the "real" application activates a watchdog, you'll need to make sure you deactivate it in the bootloader. Otherwise, this can (and will) lead to inexplicable behavior that drives you crazy. Enabling this section marginally increases bootloader size.

/*SPI configuration*/
#define DD_MOSI		DDB5
#define DD_SCK			DDB7
#define DDR_SPI		DDRB
#define DD_SS_PORT	PORTB
#define DD_SS			DDB4

These must be set to match your chip settings. These parameters are defined in the chip docs.

/* Port configuration for SD card SPI access */
#define SD_CS_BLOCK		DDRC
#define SD_CS_PORT		PORTC
#define SD_CS_PIN			7

Configure this for where you have connected the SD card's chip select line.

/*Visual feedback*/
#define USE_FLASH_LED 				//Uncomment if you want visual feedback

/* Port configuration for visual feedback*/
#ifdef USE_FLASH_LED
#define FLASH_LED_POLARITY 0 //1 if HI turns LED on. 0. If LO turns LED on.
#define FLASH_LED_DDR		DDRA
#define FLASH_LED_PORT		PORTA
#define FLASH_LED_PIN		0
#endif

If you have an LED, you can enable this module and configure it for where the LED is connected. Note that this increases the bootloader program size.

Flash location

The programmer must put the bootloader into the bootloader section. This is quite easy and just requires reassinging .text (default 0x0000) to the bootloader start address.

NB: The hex address for .text is in words, which exactly translates to half bytes. i.e. two bytes to a word. This means that for a bootloader location of 0x7000, the word address is 0x3800. This is the exact same address as the "start address" from the fuse setting dialog in AVRStudio.

Lastly, in Project-->Configuration Options-->Memory Settings, click Add, and configure

Memory type: flash
Name: .text
Address(Hex): 0x3800

This can be done with a the linker command -tText, too, although I forget the exact syntax. A quick search on the forum will find you plenty of examples.

Main program

Fortunately, the main program is to be written exactly as if there were no bootloader, with one tiny exception as detailed immediately below. What that means is that you can debug it without the bootloader and only add the bootloader when the final program is ready to go out the door.

In order for the bootloader to know what version a given firmware is, we need to include that data in the file. This bootloader looks for that information at the end of the binary hex file. To that end, we have to add it there ourselves. We do this with the following code, added outside main().

const bootldrinfo_t bootlodrinfo __attribute__ ((section (".bootldrinfo"))) = {DEVID, SWVERSIONMAJOR << 8 | SWVERSIONMINOR, 0x0000};

This defines a section in the flash with three elements. (The last one, 0x0000, is for the CRC word, which will come later in the tutorial.). We now have to place this element in the correct part of the flash. This section must be the last 8 bytes immediately before the bootloader. Since for me, the bootloader starts at 0x7000, this means 0x6FF8.

NB: The hex address for .bootldrinfo is in words, which exactly translates to half bytes. i.e. two bytes to a word. This means that for a bootloader location of 0x6FF8, the word address is 0x37FC.

Similar to above, in Project-->Configuration Options-->Memory Settings, click Add, and configure

Memory type: flash
Name: .bootldrinfo
Address(Hex): 0x37FC

You'll also need to actually define DEVID, SWVERSIONMAJOR, and SWVERSIONMINOR. You can do this immediately before the __attribute__ section, or as I do in a separate file. DEVID must be the same as in the bootloader, or else it will not work. The firmware version is split into major (SWVERSIONMAJOR) and minor (SWVERSIONMINOR) fields. Again, these are arbitrary and can be defined as you wish. Remember, though, that the bootloader only flashes the firmware if the new version number is greater than the existing one.

/*Firmware version*/
#define DEVID 0x00000001 		//Arbitrary ID
#define SWVERSIONMAJOR 0x01 	//Major version
#define SWVERSIONMINOR 0x00 	//Minor version

Lastly, you'll need to compile and add the CRC to the file. Unfortunately, compiling with AVRStudio is not completely straightforward, as AVRStudio unhelpfully does not give you the option of creating a binary hex file (why, oh, why Atmel???). So you'll have to do it in two steps. Compile it as you normally would from within AVRStudio (F7, for instance), and then find the project Makefile (most likely in the "default" directory in the project source). Here, toward the end you'll find a line similar to the folowing:

%.hex: $(TARGET)
	avr-objcopy -O ihex $(HEX_FLASH_FLAGS)  $< $@

Replace ihex with binary.

%.hex: $(TARGET)
	avr-objcopy -O binary $(HEX_FLASH_FLAGS)  $< $@

Then load a command window and run the command make clean and make all. This should create a hex file that is in binary instead of intel hex.

(If you don't use AVRStudio, and instead use makefiles, now's your chance to laugh.)

Still using the command window, finish up by running crcgen.exe on the hex file. This will automatically add the CRC to the very last two bytes of the hex file, an absolutely necessary step as otherwise the bootloader's internal CRC check will fail.

There you go, all done now! Just copy the hex file onto an SD card and you're ready to go.

Problems

There are several flaws in this firmware. First and foremost, there are no previsions for downgrading. This could be written in by reserving a special number that overrides flashing, no matter what. Still, this makes things difficult in the field. A better solution might be to press a button during the booting, but that could take extra hardware. If anyone has ideas or experience, please post them here.

Secondly, the firmware has no way of knowing if a file is valid firmware unless it's the exact right size. This is less than optimal, but saves coding space.

Lastly, if your MCU project has an SD card slot, there's a very good chance that the main application reads the slot, too. This means a duplication of a quite large (>1K?) chunk of code. That's really a shame, and can make a big difference amongst the smaller MCUs. I understand there are ways to reference the code in the bootloader from the main application, but those are beyond the scope of 1) this tutorial and 2) my abilities.

Included files
I have attached an AVRStudio project along with the necessary code for generating the CRC. If you don't use AVRStudio, but instead makefiles, you're advanced enough to build your own makefile for this project. Note that the project is configured for an ATMega324p, so make sure to change that for your processor.

Questions, comments, criticisms?

Good luck,
Kenn Sebesta

[Edited for clarity reasons.]

Attachment(s): 

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

Thank you very much for the tutorial.

I am using Bascom.

I have many questions as I like to learn but will try to limit them :-)

Not knowing enough C (yet!!) I am unable to fluently understand the program so my question is:

Can this be used to flash a compiled Bascom file from the SD to the MCU flash?

I can run crcgen.exe on the compiled file, but how do I add the version info etc to accomplish
In order for the bootloader to know what version a given firmware is

Is it easier to just strip out the version check functionality from the bootloader?

Thanks very much

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

ozra wrote:
Can this be used to flash a compiled Bascom file from the SD to the MCU flash?

I plead ignorance here, not really even understanding what a Bascom is. However, *most* of the program is processor independent. The logic for how to communicate with an SD card and a FAT partition are universal, although the individual commands you must write in order to use the SPI bus might vary. Looking at sdIO.c, only the sections labeled "platform dependent" would have to be changed.

Likewise for the bootloader instructions (although these are not marked with "platform dependent", it should be very easy to figure out which commands need to be changed).

ozra wrote:
I can run crcgen.exe on the compiled file, but how do I add the version info etc to accomplish
In order for the bootloader to know what version a given firmware is

You add the version info once in the defines.h file and once in the "real" application. When you add

const bootldrinfo_t bootlodrinfo __attribute__ ((section (".bootldrinfo"))) = {DEVID, SWVERSIONMAJOR << 8 | SWVERSIONMINOR, 0x0000};

to the "real" application, it will fail to compile if you haven't somewhere defined DEVID!

However, device ID is very different from checksum. The checksum ensures data integrity. In this implementation, it's two bytes added to the very end of the hex file (by the program crcgen.exe, not manually).

Quote:
Is it easier to just strip out the version check functionality from the bootloader?

Errr... Easier, yes, but if for some reason the code is corrupted or the flash fails, you won't know it until things crash.

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

Thanks the tutorial is short and nice , but I do not understand how to use it . I think it will be nice to have an example application with the ID and CKSM in order to show how it works.

Can you tell me if below statements are correct ?

1) The bootloader will always load an hex file with an exact size such that the last three bytes ends just before the bootloader code starts.

2) The bootloader will load if and only if the version is higher than the loaded info in the bootloader code

I would like, for instance, write a flashing LEDs program , then load it with the bootloader but no idea yet on how to do it.

The more similar thing I've found so far is here

http://yuki-lab.jp/hw/MMCboot/index.html

This is nice because allow you to browse on the files. of course the source code needs to be modified , we need to change the LED printing to UART messages for instance. But this bootloader has like two entry points like the start of the boot section plus another section. They overlayed when I tried to compile it. So I am still struggling to understand it. To complicate things the comments are in japanese, I've translated most of them.

If you have some links or know a book that may bring some info on this kind of bootloaders please let me know.

Thanks ,

Jose

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

Nice tutorial! The reason Atmel counts in words over bytes is that the AVR's program memory has a 16 bit data bus. It doesn't support high/low byte reading/writing so any operation has to go as 16 bits.

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

Quote:

It doesn't support high/low byte reading/writing so any operation has to go as 16 bits

Then you haven't heard of the LPM opcode then?

 

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

Great tutorial; Very well written and explained. Thank you for sharing the code with the rest of the community.

Quick question hoping someone could assist with:

If I were to use this bootloader with my Teensy++ 2.0, I take it that I could no longer use the Teensy's supplied USB programmer/program and I would need to flash my Teensy using this bootloader and will need to put the new firmware .HEX file on the SD card, correct? It seems so, just wanted to confirm.

Thanks,
Moe

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

The Teensy comes preloaded with a boot loader so, yes, it's going to be either/or and you are going to need an ISP to program one or the other.

 

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

I have installed Atmel Studio 6 (I assume AVR Studio was renamed?) but I don't seem to be able to load the .aws or .aps files, which I assume are the project files.

Can anyone explain how I should set this project up so I can compile it for a 1284P? I've never used Atmel Studio before, I usually just compile stuff from the Arduino IDE.

[edit]

Actually, I just found the "import" option on the file menu (Ugh. Why don't they just make things easy and show those files on the project loader and ask if you want to convert them there?) but I got some warnings when I imported the project. I'm not sure if they're important or not:

08:12:00: [WARNING] Skipped reading Build Dependency settings from source project. It is either invalid or not provided., ModuleName: ProjectImporter.Core
08:12:00: [WARNING] Skipped reading Pre/Post build event settings from source project. It is either invalid or not provided., ModuleName: ProjectImporter.Core
08:12:03: [WARNING] Include Path not found : include
08:12:03: [WARNING] Include Path not found : include-fixed
08:12:03: [WARNING] Include Path not found : C:\WinAVR-20080610\avr\include
08:12:03: [WARNING] Include Path not found : include
08:12:03: [WARNING] Include Path not found : include-fixed
08:12:03: [WARNING] Include Path not found : C:\WinAVR-20080610\avr\include
08:12:03: [WARNING] Include Path not found : include
08:12:03: [WARNING] Include Path not found : include-fixed
08:12:03: [WARNING] Include Path not found : C:\WinAVR-20080610\avr\include
08:12:03: [WARNING] Include Path not found : include
08:12:03: [WARNING] Include Path not found : include-fixed
08:12:03: [WARNING] Include Path not found : C:\WinAVR-20080610\avr\include
08:12:03: [WARNING] Include file not found : C:\WinAVR-20080610\avr\include\avr\iom324p.h
08:12:12: [WARNING] Include Path not found : include
08:12:12: [WARNING] Include Path not found : include-fixed
08:12:12: [WARNING] Include Path not found : C:\WinAVR-20080610\avr\include
08:12:12: [WARNING] Include Path not found : include
08:12:12: [WARNING] Include Path not found : include-fixed
08:12:12: [WARNING] Include Path not found : C:\WinAVR-20080610\avr\include
08:12:12: [WARNING] Include Path not found : include
08:12:12: [WARNING] Include Path not found : include-fixed
08:12:12: [WARNING] Include Path not found : C:\WinAVR-20080610\avr\include
08:12:12: [WARNING] Include Path not found : include
08:12:12: [WARNING] Include Path not found : include-fixed
08:12:12: [WARNING] Include Path not found : C:\WinAVR-20080610\avr\include
08:12:12: [WARNING] Include file not found : C:\WinAVR-20080610\avr\include\avr\iom324p.h

[edit]

That missing include at the end seems to be processor dependent and I know when I create a new project I can select the processor, but I can't seem to figure out how to change the processor this project is configured for or if I even need to.

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

Quote:

which I assume are the project files.

.aws and .aps were the name of project files in AS4 not AS6. In theory AS6 can "import" and AS4 project but there are many threads in the AS5/6 forum that seem to suggest this may not always work the best.

BTW not to hijack the thread but there is another SD/MMC bootloader option (and it's an AS6 project):

http://spaces.atmel.com/gf/project/sdbootloader/

 

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

I appreciate the suggestion, but I've already modified the other bootloader to suit my needs and it sounds like all the bugs haven't been worked out of that one yet. I also can't seem to find the link to actually download that one on the website.

I just need to know how to configure Atmel studio to compile the project for my chip.

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

Well I found out how to change the device (I noticed a button that seemed to have a processor name and clicked it and that opened a tab that I either hadn't noticed or hadn't existed before with some config options) but when I did so I got more of those warnings:

Quote:

06:52:58: [WARNING] Include file not found : C:\WinAVR-20080610\avr\include\avr\iom1284p.h

How do I correct this?

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

The 1284 did not exist in 2008 so it would have need a psychic compiler developer to have guessed its forthcoming existence. WinAVR20100110 has iom1284p.h and Atmel Toolchain 3.4.1.95 has both iom1284.h and iom1284p.h.

As you have to upgrade your compiler I'd go for the Atmel one that is more modern and has wider device support than WinAVR. But keep an installation of WinAVR handy as it has some command line tools that Atmel don't package in their distribution.

 

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

I don't even know what WinAVR is. And that directory doesn't exist on my machine. It seems to be some open source compiler according to Google? Why is Avr Studio using that? Doesn't it have it's own built in compiler?

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

I recalled hearing WinAVR spoken of before on the Aduino website so I checked the Arduino directory and there's a tools dir with WinAVR in there. And it does have that iom1284p.h file.

Also, the install says it's version 20081205, so the 1284P either came out in 2008 or the version number is wrong.

[edit]

Yeah the datasheet says at the bottom that the first revision was April 2008.

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

The message you quoted:

C:\WinAVR-20080610\avr\include\avr\iom1284p.h 

Most definitely says your system was attempting to interact with C:\WinAVR-20080610. That is why I was questioning why you were using such an old installation.

 

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

I've moved the discussion of my issues getting the bootloader compiled to here so as not to clutter up this thread:
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=128789

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

I've got another question about this bootloader.

The bootloader checks that the firmware is the right size. That seems to be FLASHEND - BOOTLOADERSIZE + 1.

But how do you get the main program to be that size? My Arduino IDE spits out hex files which are not the same size every time. It seems like this bootloader is expecting files with a bunch of nulls at the end if it ends up too small, but what step in the process produces that result?

And if I take out the file size check, which I may do because it's not really needed since I'm looking for a specific filename instead, then is that going to cause any problem loading the firmware? I assume it does not matter if there is garbage data after the firmware. And I also am guessing the flash is erased so it would be 0's anyway.

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

Hm, I think perhaps this might be what causes the firmware to be the right size:

Memory type: flash
Name: .bootldrinfo
Address(Hex): 0x37FC

I think what this does is put the bootloader info at the end of the flash memory which would cause the hex file that is output to be large enough to include that. Or maybe it's just some compiler setting in the config.

The important thing though is that I just realized there's no way to accomplish this in the Arduino IDE, and I really don't have the time to figure out how the heck to compile my Arduino programs within Atmel Studio. So I may need to modify how the bootloader works. Maybe make it check the file date/time to see if they're different.

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

You can always post process the .hex using srec_cat to pad/insert/etc. (see my own SD bootloader for an example).

 

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

Okay so I've modified the bootloader to look for a file with the HEX extension, so that I can name different hex files for different devices and add a version number in the filename if I wish.

I couldn't use the file size to determine if it's a proper firmware because I'm gonna be using the Arduino IDE to make them and I want to keep the process simple and not do any post processing.

To that end I also removed the CRC check. And I will be removing the .bootlodrinfo check because the Arduino IDE doesn't have a way to add that. I'm not really concerned about the file being corrupted, I mean how often does that happen? I can't recall the last time I encountered that. And this isn't some mission critical device, it's a prop, so no worries.

I also changed the check to see if the firmware is newer than the current version to a check to see if it is different, so that downgrades will be possible.

But, since I no longer will be including the firmware version in the firmware, I need another way to figure out if the current firmware has already been installed.

To accomplish that, I've decided to store the file date/time of the firmware somewhere after it's installed, so I can compare the file's date with that every time the device boots.

But I'm not sure how to best go about this. I have an idea though.

Quote:

Fortunately, the main program is to be written exactly as if there were no bootloader, with one tiny exception as detailed immediately below. What that means is that you can debug it without the bootloader and only add the bootloader when the final program is ready to go out the door.

In order for the bootloader to know what version a given firmware is, we need to include that data in the file. This bootloader looks for that information at the end of the binary hex file. To that end, we have to add it there ourselves. We do this with the following code, added outside main().

Code:
const bootldrinfo_t bootlodrinfo __attribute__ ((section (".bootldrinfo"))) = {DEVID, SWVERSIONMAJOR << 8 | SWVERSIONMINOR, 0x0000};

This defines a section in the flash with three elements. (The last one, 0x0000, is for the CRC word, which will come later in the tutorial.). We now have to place this element in the correct part of the flash. This section must be the last 8 bytes immediately before the bootloader. Since for me, the bootloader starts at 0x7000, this means 0x6FF8.

NB: The hex address for .bootldrinfo is in words, which exactly translates to half bytes. i.e. two bytes to a word. This means that for a bootloader location of 0x6FF8, the word address is 0x37FC.

Similar to above, in Project-->Configuration Options-->Memory Settings, click Add, and configure
Code:

Memory type: flash
Name: .bootldrinfo
Address(Hex): 0x37FC

Though I cannot do this in my main program in the Arduino IDE, I CAN do this in Atmel Studio 6 which I am using to compile the bootloader. So I'm thinking I could do that within the bootloader itself and have the bootloader write the file data to it's own flash region.

I'm just a little confused about the syntax.

0x37FC is 4 bytes less than 3800, so I assume that that code is sticking the 4 bytes of .bootldrinfo at the end of the flash on a 328 Atmega. The file date is also 4 bytes long, but I don't want to stick this in the main program memory since I have no control over that since the Arduino IDE generates it. Also my I'm using a 1284P, so I would need a diffferent address anyway.

I think the bootloader goes at the beginning of the flash. And it's 4K, so I think I would want to place the data at 0x0FFC? Would that be correct?

And the .bootldrinfo struct in the bootloader is this:

typedef struct
{
	unsigned long dev_id;
	unsigned short app_version;
	unsigned short crc;
} bootldrinfo_t;

So I'd just change that to:

typedef struct
{
uint32_t crttime; // File creation time - 32 bit
} bootldrinfo_t;

I think?

The thing that confuses me though is:

const bootldrinfo_t bootlodrinfo __attribute__ ((section (".bootldrinfo"))) = {DEVID, SWVERSIONMAJOR << 8 | SWVERSIONMINOR, 0x0000}; 

If the second parameter is a short, which is a byte, then why is the major software version being shifted left by 8?

But back on track, I guess in my own code I would do this?

const bootldrinfo_t bootlodrinfo __attribute__ ((section (".bootldrinfo"))) = {0};

I guess I may not need the struct anymore since I only have one value but I think I want to keep it around in case I decide to store anything else.

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

Quote:

I mean how often does that happen?

The usual use of CRCs is not to detect corrupted files but to detect corrupted images. Say you are programming 23K and it gets to 14K when the batteries die. How does the bootloader know that only 14K of the programming is present when it comes to start it next time?
Quote:

But I'm not sure how to best go about this.

See my sdbootloader (http://spaces.atmel.com/gf/project/sdbootloader/) I use EEPROM to hold "current version". I also use it as a flag to try and catch the "half programmed" scenario I just described. I wipe it to 0xFF when programming begins and program it to N when finished.
Quote:

write the file data to it's own flash region.

Believe me EEPROM is a WHOLE lot easier.
Quote:

If the second parameter is a short, which is a byte, then why is the major software version being shifted left by 8?
There is an OR (|) in the middle. It is:

SWVERSIONMAJOR << 8 | SWVERSIONMINOR

So if it's v4.7 and MAJOR=4 and MINOR=7 this creates a short (16bit) holding 0x0407.

Quote:

I guess I may not need the struct anymore since I only have one value

Indeed, you could use:

const uint32_t foo __attribute__((section(".name"))) = 12345;

or similar. Then obviously --section-start=.name=0x3FFC or whatever.

 

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

Quote:

The usual use of CRCs is not to detect corrupted files but to detect corrupted images. Say you are programming 23K and it gets to 14K when the batteries die. How does the bootloader know that only 14K of the programming is present when it comes to start it next time?

Because it won't have written the last four bytes of the firmware indicating the version number and device ID?

And in my version, I would write the file date to the bootloader section after the rest of the firmware is written.

I suppose the battery could die just as those last four bytes are being written, but that would not cause a problem except in some extreme outside case where the battery died as those last two bytes were being written and rather than boot the device with fresh batteries you loaded a new firmware whose version just happened to match the corrupted version. And I'm not gonna worry about that, since you can downgrade. :)

Quote:
Believe me EEPROM is a WHOLE lot easier.

The method the other boothloader uses doesn't look that complicated, and I'm pretty sure if I write to eeprom there is no way for the main application to know that that data is there and it could overwrite it.

Of course since I am writing the main app I will know the data is there but since I'm not doing anyhting with the eeprom now or in the near future it's possible I could forget that data is there... and someone else writing code for the board might not know it's thee. So it seems unsafe to me.

Quote:

So if it's v4.7 and MAJOR=4 and MINOR=7 this creates a short (16bit) holding 0x0407.

Hm. Okay. I thought short was a signed 8 bit value.

So wait... that struct is a long, and two shorts. So that's 8 bytes. But 0x37FC is only 4 less than 3800.

So is that mean the address is in words?

Memory type: flash
Name: .bootldrinfo
Address(Hex): 0x37FC 

Quote:

NB: The hex address for .bootldrinfo is in words, which exactly translates to half bytes. i.e. two bytes to a word. This means that for a bootloader location of 0x6FF8, the word address is 0x37FC.

Hm, I guess it is. But why? I get why it is in words when you specify the size of the bootloader in the fuses. Well I think I do. I think that's because there's not enough bits to specify the length in bytes. But maybe the avr is 16 bit internally? I thought it was 8 bit.

Anyway, I didn't expect an address specified in the compiler to be in words. I mean I don't use words to specify where pointers point.

Anyway the boot start address for my chip is $F800, so I guess the bootloader is at the end of flash, which the data sheet confirms, and my chip has 128K of ram, so the last address (in words) is 0xFFFF, and my 32 bit file date is 2 words, so I guess the start address for the file date would be 0xFFFE. That sound right?

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

Hm, it looks like you're right about eeprom being much easier to use after all. I assumed it would be easy to write individual bytes to the flash since it seemed easy enough to access them, but it seems that you have to write a whole page at a time.

I'm having a hard time finding this eeprom code of yours though. That website is very confusing. There's no apparent download link for the whole thing, though I did find some code after clicking SVN and then selecting a file and then clicking the "view" link in one of the notes.

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

I think I've got it all figured out now. Just need to test it out.

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

Quote:

Hm. Okay. I thought short was a signed 8 bit value.

E:\avr>avr-gcc -E -dM -mmcu=atmega16 test.c | grep SIZEOF
#define __SIZEOF_INT__ 2
#define __SIZEOF_POINTER__ 2
#define __SIZEOF_LONG__ 4
#define __SIZEOF_LONG_DOUBLE__ 4
#define __SIZEOF_SIZE_T__ 2
#define __SIZEOF_WINT_T__ 2
#define __SIZEOF_PTRDIFF_T__ 2
#define __SIZEOF_FLOAT__ 4
#define __SIZEOF_SHORT__ 2
#define __SIZEOF_WCHAR_T__ 2
#define __SIZEOF_DOUBLE__ 4
#define __SIZEOF_LONG_LONG__ 8

Quote:

So is that mean the address is in words?

Yes if you use the "Memories" section in Studio to define it then being Atmel they want word addresses. Meanwhile GCC uses byte addressing (so Atmel double what you enter when they pass the --section-start). If this is a 32K micro (top byte address 0x7FFF) and addresses around 0x3800 are being used then they have to be word addresses to be up near the end of 0x7FFF.
Quote:

But maybe the avr is 16 bit internally? I thought it was 8 bit.

It is 8bits.

To be honest I don't get what's going on here either. If we're talking about a 32K micro then 0x3800 is clearly a word address which is equivalent to byte address 0x7000 which is 4K from the end of the chip. So I guess this is a 4K bootloader? In that case if this "info" is positioned at (word) 0x37FC that is the 8bytes below the bootloader - ie the very last bytes of the application space from 0x6FF8 to 0x6FFF (byte addresses) - I suppose that makes sense. 8bytes is exactly enough to accommodate one long and two shorts.

This word thing is an Atmel only thing. It's true that in he flash of an AVR the minimum granularity is 16bits wide. The shortest AVR opcodes are 16bits and if you store data to be accessed using LPM then although LPM can pick out a byte at a time the data itself has to be padded to end on a 16 bit boundary (with the addition of a final 0x00 if there's an odd number of bytes). Meanwhile the GCC compiler (that Atmel seem to be trying to pretend is theirs in some way) works on 8/16/32/64 it wide CPUs. In order to cover all those everything internally in terms of addressing is done in 8bits. So to convert from Atmel "speak" to GCC "speak" you always end up with a <<1.

Quote:

Anyway the boot start address for my chip is $F800,

But that's only 2K. You aren't going to fit a 4K bootloader into 2K. Suggest you change BOOTSZ fuses from default to wind that back to 0xF000. The 8 bytes will then position at 0xEFF8. In Atmel (studio) speak this will put .text at 0x7800 and the bootloader info at 0x7FFC.
Quote:

and my chip has 128K of ram,

There isn't any AVr with 128K of RAM. Surely you mean flash? Can you actually say which model of AVR this is we're talking about? If it is a chip with 128K flash (not RAM) and you are saying the boot is at 0xF800 then THAT is a word address and it is 4K. So the bootloader info would go at 0xF7FC. In byte addressing that is .text at 0x1F000 and the info at 0x1EFF8.
Quote:

There's no apparent download link for the whole thing,

yes there is:

http://spaces.atmel.com/gf/project/sdbootloader/scmsvn/?action=AccessInfo

Just use:

svn checkout https://spaces.atmel.com/svn/sdbootloader

to pull a complete copy. The site is Atmel's not mine - it's where they are encouraging all AVR users to host their projects now.

 

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

Quote:
Anyway the boot start address for my chip is $F800

Quote:
But that's only 2K. You aren't going to fit a 4K bootloader into 2K.

That's 4K. The address is in words, and 0xFFFF - 0xF800 = 0x7FF = 2047 words

I used this fuse calculator:
http://www.engbedded.com/fusecalc

And I've got the fuses set to this: 0xC6 0xDA 0xFC

Anyway I decided to use the EEPROM after all cause it was easier.

Quote:

to pull a complete copy. The site is Atmel's not mine - it's where they are encouraging all AVR users to host their projects now.

I'm aware it's their site, but the site is confusing. I prefer SourceForge.

To add to my earlier confusion, I don't know if I need that SVN tool installed to pull code down, but I don't have it, I don't use it, and I shouldn't need to install a special tool for version control to look at code samples on a website.

I'm also getting this error when I try to download the code:

Quote:

Error loading stylesheet: An XSLT stylesheet does not have an XML mimetype:https://spaces.atmel.com/svnindex.xsl

I've tried to refresh the page, but I continue to get the same error and it hasn't popped up another password dialog.

Anyway I found eeprom documentation here, so I'm all set with that:
http://www.nongnu.org/avr-libc/user-manual/group__avr__eeprom.html

Quote:
There isn't any AVr with 128K of RAM. Surely you mean flash? Can you actually say which model of AVR this is we're talking about? If it is a chip with 128K flash (not RAM) and you are saying the boot is at 0xF800 then THAT is a word address and it is 4K. So the bootloader info would go at 0xF7FC.

Yes I meant flash. It's the 1284P.

Quote:

In byte addressing that is .text at 0x1F000

Oh now you've done it. Now I'm worried my compiler settings are wrong. There's a section called "flash segment" in the linker and it's set to .text=0xF800. I don't know how it got set that way. And I don't know if that's the right setting. Do I need to change that? I set the device to the 1284P I would think that was set automatically to the right value.

I think it's correct though... because it's in word addressing right? So 0x1F000 becomes 0xF800? Hm... Yes I'm fairly certain that's correct.

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

Quote:

I prefer SourceForge.

Why? (the fact is that IS sourceforge - it's running on identical software and offers the same facilities so it's just the layout/UI that might be a bit different). The way I have my project configured you would need a copy of SVN to use it. But if you wanted to keep abreast of any updates then you'd want to be using SVN anyway. I suppose I could package up a .zip of a "snapshot" and offer that under "Releases" but I sort of assumed that anyone doing this kind of stuff would either already be an SVN user or know how to use it. You can browse the code of course - almost everything is in the single main.c file:

http://spaces.atmel.com/gf/project/sdbootloader/scmsvn/?action=browse&path=%2Ftrunk%2Fmain.c&view=markup

Quote:

There's a section called "flash segment" in the linker and it's set to .text=0xF800. I don't know how it got set that way.

For a 128K micro with a 4K BLS that is correct. The bootloader begins at 124K, that is 0x1F000 (byte) or 0xF800 (word). What's more 8 bytes below that is 0x1EFF8 (byte) or 0xF7FC (word) which is where you want to position the section holding that 8 byte structure.

 

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

Getting ready to upload the bootloader to my board, and I was looking at avrdude parameters and I noticed that there appears to be an intel hex option under the -U parameter section:

http://www.nongnu.org/avrdude/user-manual/avrdude_4.html#Option-Descriptions

This may mean the step in the tutorial where the make file is modified to convert the file to binary hex is unnecessary. Just thought I'd mention that.

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

Another thing I wanted to point out for folks, is that there's a new version of avrdude apparently that burns bootloaders far faster. The old version would burn every byte up to and including the bootloader. On a 1284P this was taking over two minutes to burn 4K. But with the new version it's only a few seconds.

Someone has built an executable for the new version here:
http://arduino.cc/forum/index.php/topic,133005.msg1005465.html#msg1005465

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

I can't seem to get this bootloader to work. :/

Here's the code:

#include 
#include 
#include 
//#include 
//#include 
#include 
#include 

#include "defines.h"
#include "sdIO.h"
#include "readFAT1216.h"

/*
typedef struct
{
	unsigned long dev_id;
	unsigned short app_version;
	unsigned short crc;
} bootldrinfo_t;
*/

uint16_t startcluster;
uint16_t updatecluster; //is set when update is available

// bootldrinfo_t current_bootldrinfo;

// static inline void (*app_start)(void) = 0x0000;
void (*app_start)(void) = 0x0000;

typedef void (*f_ptr)(void);

/*****************************************************************/
/* shut down the watchdog timer and clear any pending interrupts */  
/*****************************************************************/
#ifdef WATCHDOG

void get_mcusr(void) \
	__attribute__((naked)) \
	__attribute__((section(".init3")));
	void get_mcusr(void)
{
	MCUSR = 0;
	wdt_disable();
}

#endif

/********************************************/
/* Check firmware size, device, and version */  
/********************************************/

static inline void check_file(void)
{

	char extension[3] = "HEX"; // In C, the trailing null will be dropped when placing a string in an array too small to contain the null. 
	
	//if (filesize != FLASHEND - BOOTLDRSIZE + 1) { return; } // Check that firmware is correct size. Since we allow firmware to be any size we don't check this. 
	
	// In the FAT file sytem, 8.3 filenames are stored with the first 8 chars being the main part of the filename, padded with spaces, and the last 3 being the extension.  
	// There is no period in the filename. It is implied.
		
    if (memcmp(&filename[8], &extension[0], 3) != 0) { return; } // Compare last three bytes in filename to desired extension.  If they do not match, return.
	
	// Check file date (should create variable in bootloader flash which is updated by bootloader)
/*	if (crttime == eeprom_read_dword((uint32_t *)0)) { 
		
		// If file date is the same, firmware does not need to be updated.  Skip checking remainder of files and start application.

		// Turn LED off
#ifdef USE_FLASH_LED
	#if FLASH_LED_POLARITY
		FLASH_LED_PORT &= ~(1<<FLASH_LED_PIN);
	#else
		FLASH_LED_PORT |= 1<<FLASH_LED_PIN;
	#endif
#endif	
		
		app_start(); 
		
	} 
*/
	
	//bootldrinfo_t *file_bootldrinfo;
	//fat1216_readfilesector(startcluster, (FLASHEND - BOOTLDRSIZE + 1) / 512 - 1);
	
	//file_bootldrinfo = (bootldrinfo_t*) (uint8_t*) (fat_buf + (FLASHEND - BOOTLDRSIZE - sizeof(bootldrinfo_t) + 1) % 512);
	
	//Check DEVID
	//if (file_bootldrinfo->dev_id != DEVID) { return; }
		
	//Check application version
	//if (file_bootldrinfo->app_version == current_bootldrinfo.app_version) { return; }
		
	//current_bootldrinfo.app_version = file_bootldrinfo->app_version;
	
	updatecluster = startcluster; // Setting this to something other than 0 triggers the firmware update.
	
}


/******/
/*MAIN*/
/******/

int main(void)
{
	//=====================================
	//Define and initialize local variables
	//=====================================

	uint16_t res=1;
	
	uint16_t filesector, j;
	uint16_t *lpword;
	uint16_t adr;


	//=====================
	//Initialize components
	//=====================

	//----------------------
	//Turn on LED
	//----------------------
#ifdef USE_FLASH_LED
	FLASH_LED_DDR = 1<<FLASH_LED_PIN;
	#if FLASH_LED_POLARITY
	FLASH_LED_PORT |= 1<<FLASH_LED_PIN;
	#endif
#endif

	//----------------------
	//Initialize memory card
	//----------------------
	for (int i=0; (i<10) && (res & STA_NOINIT); i++){
		res=disk_initialize(0); //Initialize SD card
	}

#ifdef USE_FLASH_LED
FLASH_LED_PORT ^= 1<<FLASH_LED_PIN; // Toggle LED
_delay_ms(1000);
#endif

	if (res & STA_NOINIT) { app_start(); } //SD Card not found. Start application.
			
	//----------------------
	//Check current firmware
	//----------------------
	
		// I think this is reading the flashed firmware version from the end of the firmware.  
	
		//memcpy_P(¤t_bootldrinfo, (uint8_t*) FLASHEND - BOOTLDRSIZE - sizeof(bootldrinfo_t) + 1, sizeof(bootldrinfo_t));
		//if (current_bootldrinfo.app_version == 0xFFFF) { current_bootldrinfo.app_version = 0; } //application not flashed yet

	//-----------------------
	//Search for new firmware
	//-----------------------
	if (fat1216_init() == 0) //Initialize file system
	{
		for (int i=0; i<512; i++) // Loop through each entry in the root directory.
		{
			startcluster = fat1216_readRootDirEntry(i);
			
			if (startcluster == 0xFFFF)
			{
				continue;
			}

#ifdef USE_FLASH_LED
FLASH_LED_PORT ^= 1<<FLASH_LED_PIN; // Toggle LED
_delay_ms(100); 
#endif
			
			check_file();
			
		}
	
		if (updatecluster) // If we found a valid firmware which is different from the current version...
		{
			
			
			//----------------------
			//Write new firmware
			//----------------------
			
			// This code loads the file one 512 byte block at a time and writes it to the flash one block at a time. 
			// On a 1284P the block size (SPM_PAGESIZE) is 256 bytes, so the inner loop runs twice.  
			
			// If file is not an even multiple of 512 bytes in size, last block written may contain some garbage data but that shouldn't matter since that code will never be executed.
			
			// for (filesector = 0; filesector < (FLASHEND - BOOTLDRSIZE + 1) / 512; filesector++) // This is the orginal code and assumes a fixed flash size.
			
			for (filesector = 0; filesector < (filesize-1)/512 + 1; filesector++) // This divides the size of the file by the size of the blocks and rounds up. (Math underflows for file size 0 but that doesn't matter.)
			{
				
#ifdef USE_FLASH_LED
				FLASH_LED_PORT ^= 1<<FLASH_LED_PIN; // Toggle LED
#endif
		
				lpword = (uint16_t*) fat_buf;
				fat1216_readfilesector(updatecluster, filesector);
	
				for (int i=0; i<(512 / SPM_PAGESIZE); i++) 
				{
					adr = (filesector * 512) + i * SPM_PAGESIZE;
					boot_page_erase(adr);
					while (boot_rww_busy())
						boot_rww_enable();
			
					for (j=0; j
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

The code above is designed to look for a file with a .HEX extension, check the file date against the one currently stored in eeprom (currently that check is disabled for testing), and if it is different, it writes the file to flash.

It seems to work, sort of... I see the LED blink slowly once, then it blinks a bit faster as it scans the files, then it blinks really fast as the data is copied...

And then it repeats. Over and over. It doesn't seem to want to actually run the application once it's been uploaded.

Any ideas?

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

That code is extremely difficult to follow as so many lines are commented. As far as I can determine the active part is just this:

#include 
#include 
#include 
#include 
#include 

#include "defines.h"
#include "sdIO.h"
#include "readFAT1216.h"

uint16_t startcluster;
uint16_t updatecluster; //is set when update is available

void (*app_start)(void) = 0x0000;

typedef void (*f_ptr)(void);

/*****************************************************************/
/* shut down the watchdog timer and clear any pending interrupts */ 
/*****************************************************************/
#ifdef WATCHDOG

void get_mcusr(void) \
   __attribute__((naked)) \
   __attribute__((section(".init3")));
   void get_mcusr(void)
{
   MCUSR = 0;
   wdt_disable();
}

#endif

/********************************************/
/* Check firmware size, device, and version */ 
/********************************************/

static inline void check_file(void)
{

   char extension[3] = "HEX"; // In C, the trailing null will be dropped when placing a string in an array too small to contain the null.
   
    if (memcmp(&filename[8], &extension[0], 3) != 0) { return; } // Compare last three bytes in filename to desired extension.  If they do not match, return.
   
   updatecluster = startcluster; // Setting this to something other than 0 triggers the firmware update.
   
}


/******/
/*MAIN*/
/******/

int main(void)
{
   //=====================================
   //Define and initialize local variables
   //=====================================

   uint16_t res=1;
   
   uint16_t filesector, j;
   uint16_t *lpword;
   uint16_t adr;


   //=====================
   //Initialize components
   //=====================

   //----------------------
   //Turn on LED
   //----------------------
#ifdef USE_FLASH_LED
   FLASH_LED_DDR = 1<<FLASH_LED_PIN;
   #if FLASH_LED_POLARITY
   FLASH_LED_PORT |= 1<<FLASH_LED_PIN;
   #endif
#endif

   //----------------------
   //Initialize memory card
   //----------------------
   for (int i=0; (i<10) && (res & STA_NOINIT); i++){
      res=disk_initialize(0); //Initialize SD card
   }

#ifdef USE_FLASH_LED
FLASH_LED_PORT ^= 1<<FLASH_LED_PIN; // Toggle LED
_delay_ms(1000);
#endif

   if (res & STA_NOINIT) { app_start(); } //SD Card not found. Start application.
         

   //-----------------------
   //Search for new firmware
   //-----------------------
   if (fat1216_init() == 0) //Initialize file system
   {
      for (int i=0; i<512; i++) // Loop through each entry in the root directory.
      {
         startcluster = fat1216_readRootDirEntry(i);
         
         if (startcluster == 0xFFFF)
         {
            continue;
         }

#ifdef USE_FLASH_LED
	FLASH_LED_PORT ^= 1<<FLASH_LED_PIN; // Toggle LED
	_delay_ms(100);
#endif
         
         check_file();
         
      }
   
      if (updatecluster) // If we found a valid firmware which is different from the current version...
      {
         
         
         //----------------------
         //Write new firmware
         //----------------------
         
         // This code loads the file one 512 byte block at a time and writes it to the flash one block at a time.
         // On a 1284P the block size (SPM_PAGESIZE) is 256 bytes, so the inner loop runs twice. 
         
         // If file is not an even multiple of 512 bytes in size, last block written may contain some garbage data but that shouldn't matter since that code will never be executed.
         
         for (filesector = 0; filesector < (filesize-1)/512 + 1; filesector++) // This divides the size of the file by the size of the blocks and rounds up. (Math underflows for file size 0 but that doesn't matter.)
         {
            
#ifdef USE_FLASH_LED
            FLASH_LED_PORT ^= 1<<FLASH_LED_PIN; // Toggle LED
#endif
      
            lpword = (uint16_t*) fat_buf;
            fat1216_readfilesector(updatecluster, filesector);
   
            for (int i=0; i<(512 / SPM_PAGESIZE); i++)
            {
               adr = (filesector * 512) + i * SPM_PAGESIZE;
               boot_page_erase(adr);
               while (boot_rww_busy())
                  boot_rww_enable();
         
               for (j=0; j

In which case don't you think there's something rather important missing?

It appears to use files of type .hex but does not include an Intel Hex file decoder. If you read Intel Hex (which is an ASCII format) and program that into flash it's not going to run is it? You need AVR binary code for that.

Either you have to convert the .hex files to .bin on the PC and have the bootloader read .bin format or you need to add an Intel Hex decoder to this. As the goal with bootloaders is always the smallest possible amount of well tried and tested code I'd leave the hex->bin conversion for a utility on your PC if I were you! (again see my sdbootloader - that's exactly what I do).

EDIT: I haven't read this entire thread but I think I've scanned enough of the original post to know that the authors intention was that you generate/program .bin files and he even shows how to update the normal app build rules to output .bin rather than .hex. Where did you get he idea that you could just use Intel hex "as is"?

 

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

Quote:
EDIT: I haven't read this entire thread but I think I've scanned enough of the original post to know that the authors intention was that you generate/program .bin files and he even shows how to update the normal app build rules to output .bin rather than .hex. Where did you get he idea that you could just use Intel hex "as is"?

Quote:

Unfortunately, compiling with AVRStudio is not completely straightforward, as AVRStudio unhelpfully does not give you the option of creating a binary hex file (why, oh, why Atmel???). So you'll have to do it in two steps. Compile it as you normally would from within AVRStudio (F7, for instance), and then find the project Makefile (most likely in the "default" directory in the project source). Here, toward the end you'll find a line similar to the folowing:

Code:
%.hex: $(TARGET)
avr-objcopy -O ihex $(HEX_FLASH_FLAGS) $< $@

Replace ihex with binary.

Code:
%.hex: $(TARGET)
avr-objcopy -O binary $(HEX_FLASH_FLAGS) $< $@

Then load a command window and run the command make clean and make all. This should create a hex file that is in binary instead of intel hex.

I was under the impression that the .hex files output by the Arduino IDE were in this binary hex format the author seems to indicate exists.

But perhaps there is no such thing as a binary .hex file, and the author should have indicated that the extension be changed to .bin?

Looking at the .hex file produced by the Arduino IDE that I'm trying to load it appears you are correct and it is ascii. I don't know if it's intel hex, but there's a colon before every line:

Quote:

:100000000C9408010C9433010C9433010C943301CB

I guess this means I have to find a way to convert the file to binary.

Still, this doesn't explain why the bootloader is behaving the way it does. If I jump to an address with garbage data, why would it start the bootloader again?

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

Woo, I got it working!

All I had to do was convert that file to binary like you said and now it runs. I am still curious why the bootloader ran over and over though when it was garbage data.

I saw you used srec_cat to convert your files, but I wasn't interested in adding a CRC and it looked complicated and when I went looking for the executable on sourceforge it helpfully suggested another project called hex2bin, which looked simpler to use:

http://sourceforge.net/projects/hex2bin/?source=dlp

So I ran that on my hex file and it spat out a binary file and it worked on the first go once I changed the extension to .hex. I'll change my bootloader to look for .bin instead like it should of course.

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

Quote:

But perhaps there is no such thing as a binary .hex file, and the author should have indicated that the extension be changed to .bin?

Correct. What he's done above results in files that still have .hex extension but contain binary (how very confusing!). So are you saying you are using that?
Quote:

Looking at the .hex file produced by the Arduino IDE that I'm trying to load it appears you are correct and it is ascii. I don't know if it's intel hex, but there's a colon before every line:

Ah sorry, should have read further. In which case do this:

c:\>avr-objcopy -I ihex -O binary foo.hex foo.bin

This will read in foo.hex created by Arduino and write out foo/bin suitable for bootloading.

Quote:

I guess this means I have to find a way to convert the file to binary.

I really should read your whole message before replying ;-) Err, yes, I think you just got it above!

Garbage can behave in very curious ways! AVR has 16 (and some 32) bit opcodes. So every 2 bytes in flash are a number between 0 and 65535 (0x0000..0xFFFF). I haven't analysed it but I think the AVR recognises about 40,000 of those as valid opcodes so even if you write "Hello world" into flash it wil likely make the CPU do SOMETHING. (What the 24,000 other values actually do is anyones guess). In fact you can see this:

E:\>echo "Hello world" > avr.bin
E:\>
E:\>avr-objdump -b binary -s avr.bin

avr.bin:     file format binary

Contents of section .data:
 0000 2248656c 6c6f2077 6f726c64 22200d0a  "Hello world" ..
E:\>
E:\>avr-objdump -b binary -D -m avr avr.bin

avr.bin:     file format binary


Disassembly of section .data:

00000000 <.data>:
   0:   22 48           sbci    r18, 0x82       ; 130
   2:   65 6c           ori     r22, 0xC5       ; 197
   4:   6c 6f           ori     r22, 0xFC       ; 252
   6:   20 77           andi    r18, 0x70       ; 112
   8:   6f 72           andi    r22, 0x2F       ; 47
   a:   6c 64           ori     r22, 0x4C       ; 76
   c:   22 20           and     r2, r2
   e:   0d 0a           sbc     r0, r29

So the whole of "Hello world\r\n" are valid AVr opcodes in fact!

 

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

I use Studio 6 to build a complete .bin file right from the IDE using the "Build Events" section of the IDE. This build event uses srec_cat to convert the resulting projects .hex file to a 128K binary file which also contains 0xFF fill characters to the very end of the binary image. This method allows the program file size to grow within the "fill" area as needed, and still fill the remaining space at the end with 0xFF's as needed. This file can later be modified to include CRC if needed by adding the necessary commands to the srec_cat program. I don't use CRC right now for my bootloader running on my Xmega128A1U processor. I do use the Petit-FS from Chan, and it flashes the full 128K image file in under 8 seconds when running at 32MHz clock rate. I use filename versioning in my bootloader.

The srec_cat command looks like this:
srec_cat YOM_XMEGA.hex -intel -fill 0xFF 0x0000 0x20000 -o YOM_117.bin -binary

Jerry

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

Well with the Sparkfun programmer it takes a full two minutes to burn the whole 128K.

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

sswift wrote:
Well with the Sparkfun programmer it takes a full two minutes to burn the whole 128K.

Yikes!!! Maybe you need to use a bootloader to program your parts. It must be painful making updates or bug fixes. Even a JTAGICE 3 is faster than that.

Jerry

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

That's the problem. The two minutes was for the bootloader. The program itself was loaded by it off the SD card. (That's why I'm posting in this particular thread.)

But that's not a problem or me now. The problem was avrdude. It was burning every byte before the bootloader. I installed the latest version that someone compiled for windows and it fixed that issue. But I still suspect that burning the whole 128K would take two minutes with that device even with the newer avrdude.

Anyway, I just purchased a MKII programmer, and that actually has config options to program at up to 8mhz, though with my board I could only use the 4mhz option since the programming speed can't be higher than 1/4 the chip's speed. I'm guessing even that would be pretty darn fast though if I needed to burn the whole chip.