Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
kubark42
PostPosted: Dec 10, 2008 - 02:21 PM
Hangaround


Joined: Jun 04, 2008
Posts: 256


(This tutorial is based on modified code from http://www.mikrocontroller.net/articles ... 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

Code:
/*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.

Code:
/*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).

Code:
/*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.

Code:
/*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.

Code:
/*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.

Code:
/* 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.

Code:
/*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
Code:

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().

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


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.

Code:
/*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:

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.

(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.]


Last edited by kubark42 on Dec 11, 2008 - 08:51 AM; edited 2 times in total
 
 View user's profile Send private message  
Reply with quote Back to top
ozra
PostPosted: Dec 10, 2008 - 10:40 PM
Newbie


Joined: Nov 05, 2006
Posts: 4
Location: Australia/Sydney

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 Smile

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
 
 View user's profile Send private message  
Reply with quote Back to top
kubark42
PostPosted: Dec 11, 2008 - 08:48 AM
Hangaround


Joined: Jun 04, 2008
Posts: 256


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
Code:
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.
 
 View user's profile Send private message  
Reply with quote Back to top
jofre
PostPosted: Apr 17, 2009 - 12:30 AM
Newbie


Joined: Jul 23, 2008
Posts: 18
Location: Houston, TX , USA

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
 
 View user's profile Send private message  
Reply with quote Back to top
robotdude
PostPosted: Oct 23, 2010 - 09:40 PM
Rookie


Joined: Mar 10, 2008
Posts: 24
Location: somewhere

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.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
clawson
PostPosted: Oct 24, 2010 - 12:50 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 71119
Location: (using avr-gcc in) Finchingfield, Essex, England

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?

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
average_male
PostPosted: Jul 06, 2012 - 09:43 PM
Hangaround


Joined: Nov 22, 2008
Posts: 192


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
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jul 07, 2012 - 12:27 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 71119
Location: (using avr-gcc in) Finchingfield, Essex, England

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.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
sswift
PostPosted: Jan 16, 2013 - 01:10 PM
Hangaround


Joined: Oct 09, 2012
Posts: 185


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:

Code:

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.
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jan 16, 2013 - 01:21 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 71119
Location: (using avr-gcc in) Finchingfield, Essex, England

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/

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
sswift
PostPosted: Jan 17, 2013 - 11:01 AM
Hangaround


Joined: Oct 09, 2012
Posts: 185


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.
 
 View user's profile Send private message  
Reply with quote Back to top
sswift
PostPosted: Jan 17, 2013 - 11:54 AM
Hangaround


Joined: Oct 09, 2012
Posts: 185


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?
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jan 17, 2013 - 12:20 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 71119
Location: (using avr-gcc in) Finchingfield, Essex, England

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.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
sswift
PostPosted: Jan 17, 2013 - 01:28 PM
Hangaround


Joined: Oct 09, 2012
Posts: 185


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?
 
 View user's profile Send private message  
Reply with quote Back to top
sswift
PostPosted: Jan 17, 2013 - 01:37 PM
Hangaround


Joined: Oct 09, 2012
Posts: 185


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.
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jan 17, 2013 - 03:06 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 71119
Location: (using avr-gcc in) Finchingfield, Essex, England

The message you quoted:
Code:
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.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
sswift
PostPosted: Jan 19, 2013 - 11:48 AM
Hangaround


Joined: Oct 09, 2012
Posts: 185


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 ... p;t=128789
 
 View user's profile Send private message  
Reply with quote Back to top
sswift
PostPosted: Feb 03, 2013 - 04:33 AM
Hangaround


Joined: Oct 09, 2012
Posts: 185


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.
 
 View user's profile Send private message  
Reply with quote Back to top
sswift
PostPosted: Feb 03, 2013 - 05:19 AM
Hangaround


Joined: Oct 09, 2012
Posts: 185


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.
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Feb 03, 2013 - 04:56 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 71119
Location: (using avr-gcc in) Finchingfield, Essex, England

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

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits