PIC16F877 Bootloader (C语言版)

出处
http://learning.media.mit.edu/projects/gogo/bootloader/bootloader10.c


/////////////////////////////////////////////////////////////////////////////
//
// PIC Boot Loader for the 16F877 MCU
// V. 1.0 Nov 27, 2003
// By Arnan (Roger) Sipitakiat
// http://www.gogoboard.org
// =================================================
//
// This code is designed for the GoGo board
// but it should work with any 877 PIC device.
//
// The loader will start when pin B7 is set high during
// power-up.
//
// The loader occupies memory addresses between 0x1e50-0x1fff (0.4k)
// User code must not use this memory segment.
// in CCS, you can use the following command to reserve the memory space
// #ORG 0x1e50, 0x1fff {}
//
// Note that the configuration bits can't be changed. Whatever is used
// here is what the user's program is stuck with.
//
/////////////////////////////////////////////////////////////////////////////


#include <16F877.H>
#device ADC=10 *=16

#case

#fuses HS,NOWDT,NOPROTECT, BROWNOUT, NOLVP, PUT

#use DELAY(clock=20000000)

#use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7)

// define possible reply bytes
#define READY_FOR_NEXT 0x11
#define FINISH_FLAG 0x55
#define BOOTLOADER_OVERWRITE 0x80

#define LOADER_BEGIN 0x1E50
#define LOADER_END 0x1FFF

#define SerBufferSize 45 // serial input buffer size

#define RUN_BUTTON PIN_B7
#define RUN_LED PIN_B6
#define USER_LED PIN_D0

// #org tells the compiler where to put the procedures in memory
#ORG LOADER_BEGIN, LOADER_END auto=0 default

// a slim version of atoi().
// converts ascii text to integer
// i.e. '1' = 1, 'A' = 10
unsigned int a2i(unsigned char asciiByte) {

if (asciiByte >= 'A' && asciiByte <= 'F')
return((asciiByte) - 'A' + 10);
else if (asciiByte >= '0' && asciiByte <= '9')
return( asciiByte - '0');
}


// convert two ascii text to a 8 bit integer
unsigned int read8() {
return( (a2i(getc()) << 4) + (a2i(getc())) );
}



void main()
{
unsigned int16 Buffer[SerBufferSize]; // serial input buffer
int1 notDone = 1;

unsigned int recLen; // HEX file record length
unsigned int16 writeAddr; // HEX file write address
unsigned char recType; // HEX file record type

unsigned char i=0,j; // general counters
unsigned int16 UserBootVectorAddr; // holds the address of our new boot vector

if (input(RUN_BUTTON) ) {

UserBootVectorAddr=label_address(UserBootVector);

output_high(RUN_LED); output_high(USER_LED);

while (notDone) {

//////////////////////////////////////////
/// Wait for ':'

while (getc() != ':') ;

/////////////////////////////////////////
// Record length

recLen = read8();
recLen >>= 1; // we divided the Length by 2.
// Each memory location on the PIC (16 bit) is
// twice the unit size of the HEX file (8 bit).

/////////////////////////////////////////
// Write Address

writeAddr = ((int16)read8() << 8) + read8();

writeAddr >>= 1; // divide by 2
// The physical address on the PIC is half the
// address in the HEX file.


/////////////////////////////////////////
// Rec Type

getc(); // ignore the first digit, it is always '0'
recType = getc();

if (recType == '1') { // End of file record
notDone = 0;

} else if (recType == '0') {
// data record

// get the data
for (i=0; i < recLen ; i++) {
Buffer = read8() + ((int16)read8() << 8);
}

/*** if data is in the EEPROM area***/
if ((writeAddr >= 0x2100) && (writeAddr <= 0x21FF))
{
write_eeprom((int) writeAddr, (int) Buffer);
}



/* else if data is in the Configuration register area*/
else if ((writeAddr >= 0x2000) && (writeAddr <= 0x20FF))
{
// Can't write configuration registers -> just skip.
}

/* else if data overlaps the bootloader code -> halt*/
else if ((writeAddr >= LOADER_BEGIN) && (writeAddr <= LOADER_END))
{

putc(BOOTLOADER_OVERWRITE);
/* while (1) {
output_high(RUN_LED);
delay_ms(300);
output_low(RUN_LED);
delay_ms(300);
}
*/
}


// else -> data is in program area
else {
for (i=0; i
// (*) Modifing the Boot Vector

// The first four commands in memory are called the boot
// vector. It resets the board and points to the address of
// the main function.

// Each HEX file has their own version of these commands. But
// since we always want the boot loader to run before the
// user code, we must not overwrite the loader's boot vertor.
// Instead, we move the user's boot vector to another location
// within the boot loader's program area
// (see label "UserBootVector" below).

// This 'if' command detects user's boot vector and redirects it
// The boot vector is at address 0x0000 - 0x0003
if ((writeAddr < 0x004) && (i<4) )
write_program_eeprom(UserBootVectorAddr + i, Buffer);
else
write_program_eeprom(writeAddr + i, Buffer);
}

}
// Tells the PC to send the next line
putc(READY_FOR_NEXT);


}


}

// Tells the PC that we are finished
putc(FINISH_FLAG);
for (j=0;j<255;j++) {
for (i=0;i<255;i++) {}; // this loop gives the chip time to finish
// sending the serial byte before resetting it self.
// I did not use delay_ms() because I have had
// some strange problems with it.
}

}

// This is a reboot command written in Assembly.
// these four commands will be overwritten with the boot vector we obtain
// from the HEX file.
// See (*) above for more info.
UserBootVector:
#asm
MOVLW 0x00
MOVWF 0x0A
GOTO 0x00
NOP
NOP
#endasm

}


#ORG default

作者:anonymous   更新日期:2005-01-09
来源:internet   浏览次数:

相关文章

相关评论   发表评论