📄 bootloader877a10.c
字号:
/////////////////////////////////////////////////////////////////////////////
//
// =================================================
//
// This code is released under the GPL license. Read the attached license
// for full information but here's the basic points:
// - Use it freely
// - Let others use your new/modified code freely too
// - So, please release the source
//
// =================================================
//
// PIC Boot Loader for the 16F877A MCU
// V. 1.0 Nov 22, 2006
// By Arnan (Roger) Sipitakiat
// http://www.gogoboard.org
//
// This code is designed for the GoGo board
// but it should work with any 877A 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 <16F877A.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[i] = read8() + ((int16)read8() << 8);
}
// if data is in the EEPROM area
if ((writeAddr >= 0x2100) && (writeAddr <= 0x21FF)) {
write_eeprom((int) writeAddr, (int) Buffer[i]);
}
// 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<recLen ;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[i]);
else
write_program_eeprom(writeAddr + i, Buffer[i]);
}
}
// 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -