Jump to content
Emeryth

USB mass storage bootloader

Recommended Posts

Hi,

 

I wanted to share a bootloader I wrote for the Stellaris Launchpad (and other boards/chips if you change it up a bit).

The bootloader acts as a mass storage device, and allows for software update by simply moving a file to the device. No software or drivers needed!

It's inspired by the bootloader found on some NXP LPC microcontrollers.

 

The project was surprisingly easy thanks to the awesome Stellaris USB Library.

 

Grab the source here: https://github.com/Emeryth/Stellaris-mass-storage-bootloader

 

Pleas report any issues you encounter.

 

Share this post


Link to post
Share on other sites

Thanks Emeryth and welcome to Stellarisit!

 

 

 

Hi,

 

I wanted to share a bootloader I wrote for the Stellaris Launchpad (and other boards/chips if you change it up a bit).

The bootloader acts as a mass storage device, and allows for software update by simply moving a file to the device. No software or drivers needed!

It's inspired by the bootloader found on some NXP LPC microcontrollers.

 

The project was surprisingly easy thanks to the awesome Stellaris USB Library.

 

Grab the source here: https://github.com/Emeryth/Stellaris-mass-storage-bootloader

 

Pleas report any issues you encounter.

Share this post


Link to post
Share on other sites

Please report any issues you encounter.

 

Thanks for sharing this. Nice stuff!

 

So it seems to work on Windows. I got errors in Linux when I tried to safely eject. When I reset theboard a second time the file size was smaller than it should have been.

 

Is there something in the code that needs codesourcery? I tried with the Energia toolchain and that didn't seem to work properly, it didn't work on windows or linux.

[ edit] Actually it was some issues with my personal setup. I was able to compile it fine with the Energia toolchain ( at this point Yagarto 4.7.1 version )[ /edit]

 

[ edit2]

A follow up to my early problem.

 

As long as I avoid using the X based file manager, I can use this successfully on linux.  I made the required modifications to my local Energia lm4fcpp.ld linker ldscript so the energia code gets loaded at 0x4000 instead of 0x0000. A quick cp from the build directory /tmp/buildxxx/Blink.cpp.bin to  /media/foo/firmware.bin, a couple of sync; sync; commands, followed by an eject from the desktop UI, press reset and bingo bango it is running.  Nice!

[ /edit2]

 

Thanks,

 

 

-rick

Share this post


Link to post
Share on other sites

So it seems to work on Windows. I got errors in Linux when I tried to safely eject. When I reset theboard a second time the file size was smaller than it should have been.

 

[ edit2]

A follow up to my early problem.

 

As long as I avoid using the X based file manager, I can use this successfully on linux.  I made the required modifications to my local Energia lm4fcpp.ld linker ldscript so the energia code gets loaded at 0x4000 instead of 0x0000. A quick cp from the build directory /tmp/buildxxx/Blink.cpp.bin to  /media/foo/firmware.bin, a couple of sync; sync; commands, followed by an eject from the desktop UI, press reset and bingo bango it is running.  Nice!

[ /edit2]

 

 

The error when ejecting on Linux is harmless, I have no idea how to fix it.

 

Check the latest version, I think I have fixed problems with uploading firmware via a file manager on Linux.

The problem was that when using a file manager, copying a file to the drive interacts with the filesystem differently than just using cp from the command line!

 

Edit: In the latest version, you don't have to name your file "firmware.bin" anymore!

Share this post


Link to post
Share on other sites

Can someone please explain how this is done? 


 
INSTALLATION:
*Put the source in a dirctory inside stellarisware/boards/ek-lm4f120xl/
*Run make
*Flash gcc/boot_usb_msc.bin onto your Launchpad or other Stellaris board
 

Share this post


Link to post
Share on other sites

@Emeryth: How about also adding boot_usb_msc.bin to Github.

 

Would make it easier to start using the bootloader for beginners (and lazy bums like me :)).

 

Edit: Or for people that use CCS instead of a gcc tool chain (again like me :))

Share this post


Link to post
Share on other sites

Neat.  I was looking over the code have a few questions and suggestions.
It would be nice to document the disk data structures a bit more (make it easier to understand and modify).
 
For instance, something like the following makes the boot sector in ramdisk.c easier to understand.
 

unsigned char bootSector[] = {
	0xeb, 0x3c, 0x90, 					// Assembler (JMP to offset 62, NOP)
	0x6d, 0x6b, 0x64, 0x6f, 0x73, 0x66, 0x73, 0x00, 	// OEM name (8 chars) - "mkdosfs " 
	0x00, 0x02, 						// Bytes per sector (0x200 = 512)
	0x04, 							// Sectors / cluster (4)
	0x01, 0x00, 						// Reserved sectors (1 boot sector)
	0x02, 							// Number of FATs (2)
	0x00, 0x02, 						// Maximum number entries root directory (2)
	0x00, 0x04, 						// Total number sectors in filesystem (0x400 = 1024x 0.5k = 512k)
	0xf8, 							// Media type (f8 = fixed disk, f0 for removable)
	0x01, 0x00,						// Sectors/fat (1)
	0x20, 0x00, 						// Sectors/track (16)
	0x40, 0x00, 						// Heads (32)
	0x00, 0x00, 0x00, 0x00, 				// Sectors before start partition
	0x00, 0x00, 0x00, 0x00,					// Sectors in file system
	0x00, 							// BIOS Int13 drive #
	0x00, 							// Unused
	0x29, 							// Extended boot signature
	0x69, 0x17, 0xad, 0x53, 				// Volume serial #
	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, // Volume label in ASCII 
	0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, // File system type (FAT12)

// 62 - 509	Boot Code
	0x0e, 0x1f, 0xbe, 0x5b, 0x7c, 0xac, 0x22, 0xc0, 0x74, 0x0b,
	0x56, 0xb4, 0x0e, 0xbb, 0x07, 0x00, 0xcd, 0x10, 0x5e, 0xeb, 0xf0, 0x32,
	0xe4, 0xcd, 0x16, 0xcd, 0x19, 0xeb, 0xfe, 
/*  Disassembly of boot code - Initial numbers are just incidental addresses
0162 0E            PUSH    CS
0163 1F            POP     DS
0164 BE5B7C        MOV     SI,7C5B
0167 AC            LODSB
0168 22C0          AND     AL,AL
016A 740B          JZ      0177
016C 56            PUSH    SI
016D B40E          MOV     AH,0E
016F BB0700        MOV     BX,0007
0172 CD10          INT     10
0174 5E            POP     SI
0175 EBF0          JMP     0167
0177 32E4          XOR     AH,AH
0179 CD16          INT     16
017B CD19          INT     19
017D EBFE          JMP     017D
*/

// "This is not a bootable disk.  Please insert a bootable floppy and\r\npress any key to try again ### \r\n"
	0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 
	0x61, 0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x64, 
	0x69, 0x73, 0x6b, 0x2e, 0x20, 0x20, 
	0x50, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, 0x69, 0x6e, 0x73, 0x65,
	0x72, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c,
	0x65, 0x20, 0x66, 0x6c, 0x6f, 0x70, 0x70, 0x79, 0x20, 0x61, 0x6e, 0x64,
	0x0d, 0x0a, 0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6e, 0x79, 0x20,
	0x6b, 0x65, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x79, 0x20, 0x61,
	0x67, 0x61, 0x69, 0x6e, 0x20, 0x2e, 0x2e, 0x2e, 0x20, 0x0d, 0x0a, 0x00
};
// 510 - 511	Signature for File System.		Filled in by code

#define BOOT_FS_SIG_1	0x55
#define BOOT_FS_SIG_2	0xaa

(Not shown here, but used BOOT_FS_SIG_1 and 2 in place of the magic numbers down in massStorageRead)

 

Few questions/suggestions 

Why is this reported as a fixed disk?  (media type f8, rather than f0) - is that just one of those peculiarities/legacy things with

DOS/Windows?  

 

Would there be any benefit (or harm) to adding a non-blank volume label? (Just cosmetic)

 

The error message in the boot code seems verbose.  Might trim it to something like.

Microcontroller is not bootable, please unplug and press any key to reboot.

 

(Would save a few bytes of flash and RAM.  Might make it clearer what device it is trying to boot from.

The business about floppies is an anachronism.)

 

[Edit: Added comment with disassembly of the boot code ]

Share this post


Link to post
Share on other sites

Or at least how I might flash: boot_usb_msc.bin onto the board. New to this so appreciate some advice! Have the lm4f120H board, CCS with stellarisware package installed. 

Fiddled with some of the tutorials but they are not informative yet to tell me how to do something that should be simple.

Share this post


Link to post
Share on other sites

A few other questions on code details in ramdisk.c:

 

What is the number 27?  (Seems like it should be a #defined constant, with a little documentation on where comes from).

 

example uses:

 

#define FIRMWARE_START_SECTOR (27+firmware_start_cluster*4)

 

firmware_start_cluster=(blockNumber-27)/4;

 

Similarly, what is 239?  (Again, constant and comment might help.)

 

for (counter=0;counter<239;counter++)

 

Just at a guess these might be related to size of boot loader and/or size of flash?

 

In the following code snippet - why is the firmware_start_cluster updated when the FAT is written, rather than when
the directory is written?

	else if (blockNumber==1||blockNumber==2){
		memcpy(fat,data,FAT_LEN);
		firmware_start_cluster=directory[58];//sometimes the system will move the firmware to a different cluster
// Starting sector in second directory entry
	}
	else if (blockNumber==3){
		memcpy(directory,data,DIRECTORY_LEN);
		}

 

Also, is it possible for an operating system to mess this up by writing the directory entries in the other order (or just using a short file name)?  (i.e. this code assumes we always guaranteed of having a long file name followed by a short one.)

 

Does the boot sector get written to under normal operation (i.e., can one get away with using a constant copy of the boot record, saving a bunch of RAM, or does that break things)?

 

Thanks

Share this post


Link to post
Share on other sites

@jbp0801: LMFlashProgrammer is a tool that allows you to flash the Stellaris launchpad.

http://www.ti.com/tool/lmflashprogrammer&DCMP=STELLARIS®ARM®CORTEX+Other&HQS=Other+OT+lmflashprogrammer

 

 

But if you're not interested in learning the low level details of microcontrollers (i.e. C and fiddling with registers), you should check out the Energia project.

Share this post


Link to post
Share on other sites

Thanks chicken! I probably should have started with the arduino but this board seems to have much more integration advantages.. whenever the community of people fiddling   work out all the ways to do so in a simple format. 

 

Btw anyone know of info for PWM servo control for this board? I've seen some examples but I'm looking to drive 4 or so servos with a playstation 2 gamepad.

Share this post


Link to post
Share on other sites

@chicken: I've added precompiled bootloader images to the github repo.

 

@igor: Thanks for the helpful suggestions.

I agree that the code isn't very polished, will try to fix it up, get rid of magic numbers.

 

To be honest, I didn't put much thought into that filesystem image. I've created it by making a 512kB file, formatting it to FAT12 with 512b sectors using mkfs.msdos, mounting it and adding a firmware.bin file of the right size.

 

 

Why is this reported as a fixed disk?  (media type f8, rather than f0) - is that just one of those peculiarities/legacy things with

DOS/Windows?


According to FAT documentation, f0 means a 1.44MB/2.88MB floppy.

 

 

Would there be any benefit (or harm) to adding a non-blank volume label? (Just cosmetic)

 

Like you said, it's just cosmetic, I didn't bother with it :P

 

 

The error message in the boot code seems verbose.  Might trim it to something like.

Microcontroller is not bootable, please unplug and press any key to reboot.

 

(Would save a few bytes of flash and RAM.  Might make it clearer what device it is trying to boot from.

The business about floppies is an anachronism.)

 

Yeah, might as well get rid of the whole thing.

 

 

What is the number 27?  (Seems like it should be a #defined constant, with a little documentation on where comes from).

 

That's the sector where the data starts.

 

 

Similarly, what is 239?

 

That's the number of blocks for user firmware, should be 240 of course,  or calculated from USER_PROGRAM_LENGTH.

 

 

In the following code snippet - why is the firmware_start_cluster updated when the FAT is written, rather than when
the directory is written?

 

Oops, that's a bug. But that line is not needed anymore.

 

In the latest version, the program assumes the first cluster in the data region the host tries to write to is the beginning of a new firmware, so it doesn't look at the directory entries at all.

I had to do this, because on Ubuntu, the file manager first starts with writing data to disk (and not in the same place as the previous firmware.bin), and modifies the directory entry afterwards (Windows, for example, modifies the directory entry first).

Also thanks to this, you don't have to rename your binary to firmware.bin anymore.

 

 

 

Does the boot sector get written to under normal operation (i.e., can one get away with using a constant copy of the boot record, saving a bunch of RAM, or does that break things)?

 

I don't think it gets written to, but we have a lot of RAM, why not use it? ;)

Share this post


Link to post
Share on other sites

This is a nice way to send code to to Stellarpad! Unfortunately, I can't seem to get this working. I've flashed the code (prebuilt and my own) successfully. The process ends without error. The board blinks after sw2/reset (the prebuilt version blinks much faster though). In either case, no new usb device is found and I can't see the device on any linux machine I have. I'm using linux mint 13 and ubuntu 12.04.

 

Any suggestions?

Share this post


Link to post
Share on other sites

Wethaguy

 

Have you tried lsusb or similar on the port involved after hooking the device (not debug) connector to your linux system?

(i.e., do you get some sort of unrecognized USB descriptor, or does it just not show up at all)

 

If you have a windows system available, might try it on that just to see if it is recognized.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×