📄 bootldr.c
字号:
/* * 18Fxxx BOOT LOADER Copyright (C) 2002 HI-TECH Software * This software is freely distributable and may be used * for any purpose. No warranty of any kind is provided * and all use is entirely at your own risk. * */#pragma psect text=bootldr #include <pic18.h>#include "bootldr.h"#if defined(MPLAB_ICD)__CONFIG(4,DEBUGEN & LVPDIS); // required ICD2 settings__CONFIG(6,UNPROTECT); // enable writing to flash#else__CONFIG(6,WPB & UNPROTECT); // bootloader self protection#endif#if _ERRATA_TYPES & ERRATA_4000 #error Command line option --errata=default,-4000 must be specified when compiling this code for this device.#endif/* Function prototypes */void checksum(void);void putch(unsigned char);void puts(const char *s);unsigned char gx(void);unsigned char g2x(void);void zap(void);void table_write(void);void flash8(void);void clear_buffer(void);persistent near unsigned char buff[_FLASH_WRITE_SIZE]; /* Internal buffer used for writing to program memory */persistent near unsigned char DO_NOT_INCREMENT;persistent near unsigned char cksum,rectype,bcount;persistent near unsigned char delay_time;persistent near unsigned char index;persistent near unsigned short erase;#ifdef VERBOSEpersistent near unsigned char START_MSG[] = "HI-TECH Software (C)2002\n";persistent near unsigned char DOWNLOAD_MSG[] = "\rDownload-";#endif#asmpsect intcode // redirect interrupts to new routine addresses goto PROG_START+8 #ifndef VERBOSE/* Sqeeze the checksum function in between the ISR redirection * instructions for even tighter code! * Will not fit if VERBOSE mode is enabled, in which case * the C version will be used. */global _checksum_checksum: call _g2x // read the checksum byte movf _cksum,w btfss status,2,c // if it doesn't add up... reset // reset return#endif psect intcodelo // redirect low priority interrupts to new routine addresses goto PROG_START+0x18#endasm/* putch() - outputs 1 byte to the serial port */#ifdef VERBOSEvoidputch(unsigned char byte){ while(!TRMT); /* set when register is empty */ TXREG = byte; /* output one byte */}/* Output a string via the serial port */voidputs(const char *s){ while(s && *s) putch(*s++); }/* check the checksum * NOTE: if not in verbose mode, the code will use the even more compact * assembler version of the checksum() function defined above. */voidchecksum(void){ g2x(); if(cksum) // if checksum does not add to zero, bad check, reset RESET(); putch('\r'); // echo each hex record on a new line} #endif/* Get a 4 bit HEX number from the serial port */unsigned chargx(void){ while(!RCIF); EEDATA=RCREG;#ifdef VERBOSE if(!TRMT) // Echo RX nibbles to output. If high speed RX, some TXREG=EEDATA; // nibbles mightn't be TXed but will still be programmed.#endif if(EEDATA>='A') return ((EEDATA - (unsigned char)'A')+10); return (EEDATA - '0');}/* recieve a hexadecimal byte, add it to the checksum */unsigned char g2x(void){ unsigned char temp = (gx()<<4); temp += gx(); cksum+=temp; return temp;}/* Initiate a write to memory */voidzap(void){ WREN=1; EECON2=0x55; EECON2=0xAA; WR=1; NOP(); while(WR); WREN=0;}/* transfer a byte from RAM to internal flash register(s) */voidtable_write(void){ if(DO_NOT_INCREMENT) // address is already loaded in TBLPTR, no pre-increment needed asm("tblwt*"); else asm("tblwt+*"); // otherwise TBLPTR must be pre-incremented DO_NOT_INCREMENT=0;}/* Commit the internal buffer to flash */voidflash8(void){ if(DO_NOT_INCREMENT) TBLPTRL&= ~(_FLASH_WRITE_SIZE-1); // point to start of flash panel for(index=0;index<_FLASH_WRITE_SIZE;) { TABLAT = buff[index++]; table_write(); } zap();}voidclear_buffer(void){ unsigned char x; for(x=sizeof(buff);x--;){ buff[x]=FILL_BYTE; // initialize buffer with known values }}voidmain(void){#if _ERRATA_TYPES & ERRATA_TBLWTINT PIE1=0; // as per the errata document for these parts#endif init_comms(); // sets up the serial port for communication/* Bootloader waits for a specified time. If the serial port gets no response in *//* this time, execution of existing program begins. */#ifdef VERBOSE puts(START_MSG);#else TXREG='\n';#endif // Some devices' errata require these registers to be cleared INTCON3=0; // Also serves to disable interrupts PIE2=0; INTCON=0; T0CON = 0x94; // use timer to give ~1 second delays for(delay_time=BOOT_TIMEOUT; delay_time ; --delay_time) { if (RCIF) break;#ifdef VERBOSE /* display a countdown for user response */ puts(DOWNLOAD_MSG); putch('0'+delay_time);#else TXREG=('0'+delay_time); while(!TRMT); TXREG='\r';#endif while(!TMR0IF); // pause for timer 0 timeout TMR0IF=0; } T0CON=0xFF; // disable timer again if (!RCIF) /* if no hex file to download, resume normal program */ { (*((void(*)(void))PROG_START))(); } TXREG=':'; // the prompt to invite you to download a new program TBLPTRU=0; erase=PROG_START; /* Clear program memory prior to program download */ while(1) { TBLPTRL=(unsigned char)erase; TBLPTRH=(unsigned char)(erase>>8); EECON1=0x90; // set up for flash erasure zap(); erase+=_FLASH_ERASE_SIZE;#if defined(UPPER_ADDRESS_BYTE) // cases where top of memory greater than 10000h if(erase==0) TBLPTRU++; if(TBLPTRU==UPPER_ADDRESS_BYTE) // continues to next "if" or "break"#endif#if !defined(UPPER_ADDRESS_BYTE) || (MEM_TOP!=0) if(erase==MEM_TOP) // for MEM_TOPs like 20000h, don't need to test lower 0000h#endif break; }#ifdef UPPER_ADDRESS_BYTE TBLPTRU=0;#endif/* receive a hex file via the serial port and write it to program memory */ for(;;) // loop until end of file { while (RCREG!=':'); // wait for start of hex file line #ifdef VERBOSE putch(':');#endif cksum = bcount = g2x(); // get the byte count #if _EEPROMSIZE > 256 EEADRH = TBLPTRH = g2x(); // get the address#else TBLPTRH = g2x();#endif TBLPTRL = EEADR = g2x(); DO_NOT_INCREMENT = 1; rectype = g2x(); // get the record type switch(rectype) { case DATA: // data record #if (PROG_START > 0x200) || defined(__PIC18FX520) // to protect bootloader from being overwritten if( (FLASH) && (TBLPTRU==0) && (TBLPTRH < (unsigned char)(PROG_START>>8)) ) // to protect bootloader from being overwritten break; // if bootloader address range is threatened, skip this record#endif clear_buffer(); while(bcount--) { TABLAT = EEDATA = buff[(EEADR&(_FLASH_WRITE_SIZE-1))] = g2x(); // get the data if((CONFIG)||(EEPROM)) { if(CONFIG) // EEPROM/config. bytes are written one byte at a time table_write(); zap(); } else if((EEADR & (_FLASH_WRITE_SIZE-1)) == (_FLASH_WRITE_SIZE-1)) // program/IDLOCs are flashed x bytes at a time { flash8(); clear_buffer(); } EEADR++; } if(((EEADR&(_FLASH_WRITE_SIZE-1))!=0)&&(FLASH)) flash8(); checksum(); break; case END: // end of hex file checksum(); TXREG=')'; (*((void(*)(void))PROG_START))(); // jump to new program break; case EXTEND_ADDRESS: // extended address record while(bcount--) { EEADR=g2x(); // this byte determines whether EE, Config or ID data } EEPGD=1; if(EEADR==0xF0) EEPGD=0; // select for EEPROM CFGS=0; if((EEADR&0xF0)==0x30) CFGS=1; // select for config write TBLPTRU=EEADR; checksum(); break; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -