Difference between revisions of "USB bootloading"

From Mech
Jump to navigationJump to search
Line 47: Line 47:
=== PIC software ===
=== PIC software ===


You can download the PIC hex file here.
You can download the PIC hex file here: [[Media:HID_Bootloader_PIC18_Non_J.hex]].

You can download the full MPLAB project for the PIC program here.
You can download the full MPLAB project for the PIC program here: [[Media:Mplab-usb-bootloader.zip]].


=== PC software ===
=== PC software ===
Line 77: Line 78:




With MPLAB/C18 the required code is a bit longer:
With MPLAB/C18 the required code is a bit longer. So as not to clutter up this page, it's on a separate one: see [[Compiling for a bootloader in MPLAB]].


'''HID bootloader with MPLAB:'''
'''HID bootloader with MPLAB:'''

Revision as of 07:46, 11 June 2009

This article assumes you are using Windows. The provided code is intended to be run on a PIC18F4550 or 4553 with a 20Mhz oscillator.

Bootloading allows you to reprogram your PIC without the need for an expensive hardware programmer like an ICD.

Bootloading works like this:

  • You compile your program on the computer, which generates a file with a .hex extension. This is the compiled code for your program, which you want to get onto the PIC.
  • You connect the PIC to the computer, in this case with a simple USB cable.
  • You fire up a PC program that takes your hex file and sends it to the PIC.
  • Sitting on the PIC there is a small program called a bootloader. It takes the hex file that is coming from the computer and writes it into memory.
  • You reset the PIC, and your program starts running!


USB bootloading is bootloading over a USB cable. To do this you need to be working with a PIC that talks USB, like a PIC 18f4550. Then you need to have a bootloader on the PIC. The only way to put a bootloader in place is with a hardware programmer like an ICD, but you only need to do this once: afterwards, all you'll need is a regular USB cable. See here for how to connect a USB cable to a PIC.

Note: if you're going to load programs onto a PIC with a bootloader, you need to put some special instructions in the PIC code to make it work. See the "Compiling for a bootloader" section.

CDC Bootloader

Loading the bootloader

Here is a USB bootloader hex file that works for the 18f4553 with a 20Mhz oscillator: File:FW B 20.hex. It comes from http://www.schmalzhaus.com/UBW , where you can find the source it was built from, if you're interested. The bootloader is a slightly modified version of one supplied by Microchip; the changes allow the compiled hex file to fit within the first 0x800 bytes program memory. To load this precompiled hex file onto the PIC using the CCS ICD, use the icd.exe program in the C:\Program Files\PICC directory. Now the bootloader is itself loaded.

The PC software

There needs to be a program on the PC that sends your hex files to bootloader on the PIC. This bootloader uses a program from the Microchip USB Framework. You can download the framework installer here. It will create some folders in the C:\ directory. The loader program is at C:\MCHPFSUSB\Pc\Pdfsusb\PDFSUSB.exe.

Required circuitry

You need some sort of button or switch hooked up to pin RC2 so that it is normally high. If you reset the PIC and pin RC2 is high, the bootloader will run whatever program you've loaded onto it. But if RC2 is low, because you're pressing the button, the bootloader will run, allowing you to load a new program onto the PIC. You don't need to keep holding the button down, C2 just has to be low at the time the PIC resets. So whenever you want to put the PIC into bootloader mode, press and hold the reset button, then press your bootloading button, then release the reset button, then release the bootloading button. You can attach an LED to pin RC1 and the bootloader will flash it when it runs. These pins can be easily changed in the bootloader source code.

Installing Drivers

When you first connect the PIC to the PC and make the bootloader run, Windows will need to install a driver. Point it to "C:\MCHPFSUSB\Pc\MCHPUSB Driver\Release" and it will install the right driver. Now you're all set up.

Bootloading

Now that everything's set up, here are the steps to load your program onto your PIC:

  • Compile your program with the two lines mentioned above.
  • Fire up PDFSUSB.exe.
  • Put your PIC into bootloading mode. You should now be able to select "PICDEM FS USB 0" from the PDFSUSB.exe drop-down list.
  • Click "Load Hex File" and go find the hex file that you created when you compiled your program.
  • Click "Program Device" to load your program.
  • Reset your PIC and your program should run.


HID Bootloader

A HID (Human Interface Device) bootloader has the advantage that it doesn't require any driver installation on the programming computer. Once the bootloader is programmed onto the PIC and the PIC is plugged into the PC, your computer should be able to handle the rest of the setup automatically. A HID bootloader is supplied with the Microchip USB Framework. This is a slightly modified version of the original HID bootloader project from Microchip. The original project is designed to fit within the first 0x1000 bytes of program memory, but due to changes in the compiler will no longer compile into that space; the modified version goes int he first 0x1100 bytes.

PIC software

You can download the PIC hex file here: Media:HID_Bootloader_PIC18_Non_J.hex.

You can download the full MPLAB project for the PIC program here: Media:Mplab-usb-bootloader.zip.

PC software

You can download the PC program here (it comes as part of the Microchip USB Framework): Media:HIDBootLoader.zip. Unzip the downloaded .zip file to get the HIDBootLoader.exe executable. Running this requires a sufficiently recent version of the .NET Framework, which you may not have if you are running XP or earlier versions of Windows. You can download a sufficiently recent version here (the install takes a while): .NET Framework download.

When the program is running it should automatically detect when you attach the PIC (if the PIC has been properly programmed). To program the PIC click "Open Hex File," and browse your compiled hex file. Then click "Program/Verify" and the bootloader should, after a few seconds, report that it has successfully erase, programmed, and verified the PIC. After that you can reset the PIC and it should run your program.

Required circuitry

Like the CDC bootloader, you must have a button wired up to indicate when the PIC should start up in bootloader mode. This bootloader looks at pin RC4; if RC4 is low on reset, the bootloader starts, otherwise the user program starts. The bootloader will use pins D0 and D1 to indicate connection state: leds hooked up to these pins will flash alternately when the connection has been established with the PC. Again, these pins can easily be changed in the bootloader source code.

Note that the first time you plug the PIC into the PC and start it up in bootloader mode, it will take a few seconds for the PC to initialize everything before the lights start flashing, but after that the process should be pretty fast.


Compiling for a bootloader

A bootloader takes up part of the available program memory, and you need to take this into account when you write your program. Generally, the bootloader takes up a small chunk of memory at the beginning of space available for program memory. You need to tell the compiler to place your code just after the bootloader (rather than overwriting it). The CDC bootloader takes up the memory from 0x000 to 0x7FF (the first two kilobytes of program memory), while the HID bootloader goes from 0x0000 to 0x10FF (these are hexadecimal numbers). Your program therefore needs to start at address 0x800 or 0x1100, depending on which bootloader you're using, and not touch the memory from 0x000 to 0x7FF.

With CCS you can accomplish this by adding the following two lines at the top of your code:

CDC bootloader with CCS:

#build (reset=0x800, interrupt=0x808)  //code starts right after the bootloader
#org 0, 0x7FF {}                       //don't overwrite the bootloader


HID bootloader with CCS:

#build (reset=0x1100, interrupt=0x1108)  //code starts right after the bootloader
#org 0, 0x10FF {}                       //don't overwrite the bootloader


With MPLAB/C18 the required code is a bit longer. So as not to clutter up this page, it's on a separate one: see Compiling for a bootloader in MPLAB.

HID bootloader with MPLAB:

//The following lengthy and involved incantation sets things up so that resets and interrupt
//handling operate as they should, given the presence of the bootloader. 
//Omitting this incantation will make the code stop working.
//If you are generating absolutely no interrupts, you can probably leave out just the stuff 
//referring to interrupts.
//Comments are by Microchip.


//On PIC18 devices, addresses 0x00, 0x08, and 0x18 are used for
//the reset, high priority interrupt, and low priority interrupt
//vectors.  However, the current Microchip USB bootloader 
//examples are intended to occupy addresses 0x00-0x7FF or
//0x00-0xFFF depending on which bootloader is used.  Therefore,
//the bootloader code remaps these vectors to new locations
//as indicated below.  This remapping is only necessary if you
//wish to program the hex file generated from this project with
//the USB bootloader.
#define REMAPPED_RESET_VECTOR_ADDRESS			0x1100
#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS	0x1108
#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS	0x1118

void YourHighPriorityISRCode();
void YourLowPriorityISRCode();

extern void _startup (void);        // See c018i.c in your C18 compiler dir
#pragma code REMAPPED_RESET_VECTOR = REMAPPED_RESET_VECTOR_ADDRESS
void _reset (void)
{
    _asm goto _startup _endasm
}

#pragma code REMAPPED_HIGH_INTERRUPT_VECTOR = REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS
void Remapped_High_ISR (void)
{
     _asm goto YourHighPriorityISRCode _endasm
}
#pragma code REMAPPED_LOW_INTERRUPT_VECTOR = REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS
void Remapped_Low_ISR (void)
{
     _asm goto YourLowPriorityISRCode _endasm
}

//If the output hex file is not programmed with
//the bootloader, addresses 0x08 and 0x18 would end up programmed with 0xFFFF.
//As a result, if an actual interrupt was enabled and occured, the PC would jump
//to 0x08 (or 0x18) and would begin executing "0xFFFF" (unprogrammed space).  This
//executes as nop instructions, but the PC would eventually reach the REMAPPED_RESET_VECTOR_ADDRESS
//(0x1000 or 0x800, depending upon bootloader), and would execute the "goto _startup".  This
//would effective reset the application.

//To fix this situation, we should always deliberately place a 
//"goto REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS" at address 0x08, and a
//"goto REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS" at address 0x18.  When the output
//hex file of this project is programmed with the bootloader, these sections do not
//get bootloaded (as they overlap the bootloader space).  If the output hex file is not
//programmed using the bootloader, then the below goto instructions do get programmed,
//and the hex file still works like normal.  The below section is only required to fix this
//scenario.	
#pragma code HIGH_INTERRUPT_VECTOR = 0x08
void High_ISR (void)
{
     _asm goto REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS _endasm
}
#pragma code LOW_INTERRUPT_VECTOR = 0x18
void Low_ISR (void)
{
     _asm goto REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS _endasm
}

#pragma code

#pragma interrupt YourHighPriorityISRCode
void YourHighPriorityISRCode()
{
		//Check which interrupt flag caused the interrupt.
		//Service the interrupt
		//Clear the interrupt flag
		//Etc.
}	//This return will be a "retfie fast", since this is in a #pragma interrupt section 

#pragma interruptlow YourLowPriorityISRCode
void YourLowPriorityISRCode()
{
		//Check which interrupt flag caused the interrupt.
		//Service the interrupt
		//Clear the interrupt flag
		//Etc.	
}	//This return will be a "retfie", since this is in a #pragma interruptlow section 

//End incantation

Here's a shorter version of the same thing, stripped of most explanatory comments:

#define REMAPPED_RESET_VECTOR_ADDRESS			0x1100
#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS	0x1108
#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS	0x1118

void YourHighPriorityISRCode();
void YourLowPriorityISRCode();

extern void _startup (void);        // See c018i.c in your C18 compiler dir
#pragma code REMAPPED_RESET_VECTOR = REMAPPED_RESET_VECTOR_ADDRESS
void _reset (void) { _asm goto _startup _endasm }

#pragma code REMAPPED_HIGH_INTERRUPT_VECTOR = REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS
void Remapped_High_ISR (void) { _asm goto YourHighPriorityISRCode _endasm }

#pragma code REMAPPED_LOW_INTERRUPT_VECTOR = REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS
void Remapped_Low_ISR (void) { _asm goto YourLowPriorityISRCode _endasm }

#pragma code HIGH_INTERRUPT_VECTOR = 0x08
void High_ISR (void) { _asm goto REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS _endasm }
#pragma code LOW_INTERRUPT_VECTOR = 0x18
void Low_ISR (void) { _asm goto REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS _endasm }

#pragma code

#pragma interrupt YourHighPriorityISRCode
void YourHighPriorityISRCode() {
    //high priority interrupt code
}

#pragma interruptlow YourLowPriorityISRCode
void YourLowPriorityISRCode() {
    //low priority interrupt code
}


If you wish to use the CDC bootloader with MPLAB source code, you only need to change three lines of the above, where the REMAPPED_VECTOR_ADDRESS constants are defined:

#define REMAPPED_RESET_VECTOR_ADDRESS			0x800
#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS	0x808
#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS	0x818

See also

USB communication with PC

Wireless PIC bootloading