📄 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 defined(ERRATA_4000_BOUNDARY)
#error Command line option -NOERRATA 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[8]; /* 8 byte 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 VERBOSE
persistent near unsigned char START_MSG[] = "HI-TECH Software (C)2002\n";
persistent near unsigned char DOWNLOAD_MSG[] = "\rDownload-";
#endif
#asm
psect 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,c
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 VERBOSE
void
putch(unsigned char byte){
while(!TRMT); /* set when register is empty */
TXREG = byte; /* output one byte */
}
/* Output a string via the serial port */
void
puts(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.
*/
void
checksum(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 char
gx(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 */
void
zap(void){
WREN=1;
EECON2=0x55;
EECON2=0xAA;
WR=1;
NOP();
while(WR);
WREN=0;
}
/* transfer a byte from RAM to internal flash register(s) */
void
table_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;
}
/* write the 8 byte buffer to flash */
void
flash8(void){
if(DO_NOT_INCREMENT)
TBLPTRL&=0xF8; // point to start of 8 byte panel
for(index=0;index<8;)
{
TABLAT = buff[index++];
table_write();
}
zap();
}
void
clear_buffer(void){
buff[0] = buff[1] = buff[2] = FILL_BYTE; // 8 byte buffer initialised with
buff[3] = buff[4] = buff[5] = FILL_BYTE; // known data
buff[6] = buff[7] = FILL_BYTE;
}
void
main(void){
#if defined(_18F242) || defined(_18F252) || defined(_18F442) || defined(_18F452)
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+=64;
#ifdef UPPER_ADDRESS_BYTE
if(CARRY)
TBLPTRU++;
if(TBLPTRU==UPPER_ADDRESS_BYTE)
#endif
if(erase==MEM_TOP)
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 EEPROM_SIZE > 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&7)] = 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&7)==7) // program/IDLOCs are flashed 8 bytes at a time
{
flash8();
clear_buffer();
}
EEADR++;
}
if(((EEADR&7)!=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 + -