///////////////////////////////////////////////////////////////////////////// // // 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[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