📄 bootldr-cn.c.bak
字号:
#pragma psect text=bootldr
#include <pic18.h>
#include "bootldr.h"
/*
#if defined(MPLAB_ICD)
__CONFIG(4,DEBUGEN & LVPDIS); // 必须 ICD2 设置
__CONFIG(6,UNPROTECT); // 允许对FLASH写入
#else
__CONFIG(6,WPB & UNPROTECT); // BOOTLOADER自保护
#endif
*/
__CONFIG(1,IESODIS&FCMDIS&HS);
//__CONFIG(1,0x32FF); // 0011,0010,1111,1111
//振荡器为HS(20M),系统振荡器时钟转换选择禁止,故障保护时钟监视器禁止
//CONFIG1H(IESO,FCMEN,-,-,FOSC3,FOSC2,FOSC1,FOSC0)
//IESO: Internal/External Oscillator Switchover bit, 0=Oscillator Switchover mode disabled
//FCMEN:Fail-Safe Clock Monitor Enable bit,0=Fail-Safe Clock Monitor disabled
//FOSC=0010=HS oscillator
//低8位保留
__CONFIG(2,WDTDIS&WDTPS32K&BORV28&BOREN&PWRTEN);
//__CONFIG(2,0xFEF6); // 1110,1110, 1111,0110
//监视定时器WDT禁止,掉电锁定复位硬件使能,复位电压为2.8V,上电定时器使能
//CONFIG2H(-,-,-,WDTPS3,WDTPS2,WDTPS1,WDTPS0,WDTEN),看门狗定标和允许位)
//WDTEN=0,狗定标禁止
//CONFIG2L(-,-,-,BORV1,BOVR0,BOREN1,BOREN0,/PWRTEN)
//BORV1:BOVR0=10=2.8V
//BOREN1:BOREN0=11=Brown-out Reset enabled in hardware only(SBOREN is disabled)
///BORTEN=0=Power-up Timer Enable
__CONFIG(3,MCLREN&LPT1DIS&PBADDIS);
//__CONFIG(3,0xF9FF); // 1111,1001,1111,1111
//选定B口为数字通道,低电压定时器1振荡禁止高功率,MCLR使能
//CONFIG3H(MCLRE,-,-,-,-,LPT1OSC,PBADEN,-)
//MCLRE:MCLR Pin Enable bit=1=MCLR pin enabled;RE3 input pin disabled
//LPT1OSC:高功率振荡器1,1=低功率,0=高功率
//PBADEN:PB口AD允许位=0,禁止AD
//低8位保留
__CONFIG(4,DEBUGEN&XINSTDIS&BBSIZ1K&LVPDIS&STVREN);
//__CONFIG(4,0xFF2B); //调试使能(1111,1111,0010,1011)
//使能RB6、RB7为专用调试器接口,堆栈溢出复位使能,低压编程禁止
//CONFIG4L(/DEBUG,XINST,-,BBSIZ,-,LVP,-,STVREN)
///DEBUG:0=调试,RB6/RB7用于ICD,
//XINST:Extended Instruction Set Enable bit=Legacy mode
//BBSIZ:0=1K words (2 Kbytes) boot block
//LVP:0=单电源 ICSP 禁止
//STVREN:1=Stack full/underflow will cause Reset
//高8位保留
#if defined(ERRATA_4000_BOUNDARY)
#error Command line option -NOERRATA must be specified when compiling this code for this device.
#endif
/* 原型函数 */
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 字节发热缓冲,用于写入程序存储器 */
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
/*************************************************************
* 采用汇编将比C的代码更加紧缩
*************************************************************/
/*
#asm
psect intcode // 重定向高级中断到新的程序地址
goto PROG_START+8
psect intcodelo // 重定向低级中断到新的程序地址
goto PROG_START+0x18
#endasm
#ifndef VERBOSE
global _checksum
_checksum:
call _g2x // 读校验和字节
movf _cksum,w,c
btfss status,2,c // 如果校验失败.
reset // 复位
return
#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
#ifndef VERBOSE
/*******************************************************************
* 输出1字节到串口
*******************************************************************/
void
putch(unsigned char byte)
{
while(!TRMT); // 当发送寄存器空时,TRMT=1
TXREG = byte; //输出1字节
}
/*******************************************************************
* 输出1串字节到串口
*******************************************************************/
void
puts(const char *s)
{
while(s && *s)
putch(*s++);
}
/*********************************************************************
* 检查校验和字节
* 如果不用冗长方式, 可使用像上面给出的checksum()函数,将紧缩代码
**********************************************************************/
void
checksum(void){
g2x();
if(cksum) // 如果校验和不等于0,错误校验,重启
RESET();
putch('\r'); // 用换行来应答接收每个HEX字节
}
#endif
/*********************************************************************
* 从串口得到4 bit的 HEX数字
**********************************************************************/
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');
}
/*********************************************************************
* 将接收到的16进制数字并计算校验
**********************************************************************/
unsigned char g2x(void)
{
unsigned char temp = (gx()<<4);
temp += gx();
cksum+=temp;
return temp;
}
/* 初始化写内存 */
void
zap(void){
WREN=1;
EECON2=0x55;
EECON2=0xAA;
WR=1;
NOP();
while(WR);
WREN=0;
}
/* 从RAM传递字节到 flash 寄存器 */
void
table_write(void){
if(DO_NOT_INCREMENT) // 地址已经载入 TBLPTR, 不需要预先增加
asm("tblwt*");
else
asm("tblwt+*"); // 否则 TBLPTR 需要预先增加
DO_NOT_INCREMENT=0;
}
/* 写 8 字节缓冲区到 FLASH */
void
flash8(void){
if(DO_NOT_INCREMENT)
TBLPTRL&=0xF8; // 指向 8 字节块
for(index=0;index<8;)
{
TABLAT = buff[index++];
table_write();
}
zap();
}
void
clear_buffer(void){
buff[0] = buff[1] = buff[2] = FILL_BYTE; // 填充清除字节
buff[3] = buff[4] = buff[5] = FILL_BYTE;
buff[6] = buff[7] = FILL_BYTE;
}
void
main(void){
#if defined(_18F242) || defined(_18F252) || defined(_18F442) || defined(_18F452)
PIE1=0; // 这些型号需要的错误校正
#endif
init_comms(); // 初始化串口
/*******************************************************************************
* 如果串口没有响应,Bootloader 将等待一个设定的时间后,运行原来的固有的程序
*******************************************************************************/
#ifdef VERBOSE
puts(START_MSG);
#else
TXREG='\n';
#endif
// 某些型号的问题,需要清除这些寄存器
INTCON3=0; // Also serves to disable interrupts
PIE2=0;
INTCON=0;
T0CON = 0x94; // 使用这个值产生1秒延时
for(delay_time=BOOT_TIMEOUT; delay_time ; --delay_time)
{
if (RCIF)
break;
//========================================================
#ifdef VERBOSE // 冗长方案
puts(DOWNLOAD_MSG); // 给用户一个倒数计秒
putch('0'+delay_time);
//------------------------------------------------------
#else // 压缩方案
TXREG=('0'+delay_time);
while(!TRMT);
TXREG='\r';
#endif
//========================================================
while(!TMR0IF); // 等待定时器0超时
TMR0IF=0;
}
T0CON=0xFF; // 再次停止定时器
if (!RCIF) // 如果没有下载到HEX文件, 恢复运行原来程序 /
{
(*((void(*)(void))PROG_START))();
}
TXREG=':'; // 立即请求你下载一个新的程序
TBLPTRU=0;
erase=PROG_START;
while(1) //清除原来的程序,准备下载的程序使用
{
TBLPTRL=(unsigned char)erase;
TBLPTRH=(unsigned char)(erase>>8);
EECON1=0x90; // 准备FLASH删除
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
/**********************************************************
* 通过串口接收HEX文件,然后写到程序空间
**********************************************************/
for(;;) // l循环
{
while (RCREG!=':'); // 等待 HEX 文件开始
#ifdef VERBOSE
putch(':');
#endif
cksum = bcount = g2x(); // 取数据长度
#if EEPROM_SIZE > 256
EEADRH = TBLPTRH = g2x(); // 取地址
#else
TBLPTRH = g2x();
#endif
TBLPTRL = EEADR = g2x();
DO_NOT_INCREMENT = 1;
rectype = g2x(); // 取数据类型
switch(rectype)
{
case DATA: // 数据记录
#if (PROG_START > 0x200) || defined(__PIC18FX520) // 保护bootloader避免被改写
if( (FLASH) && (TBLPTRU==0) && (TBLPTRH < (unsigned char)(PROG_START>>8)) ) // 保护bootloader避免被改写
break;
#endif
clear_buffer();
while(bcount--)
{
TABLAT = EEDATA = buff[(EEADR&7)] = g2x(); // 取数据
if((CONFIG)||(EEPROM))
{
if(CONFIG) // EEPROM和配置字节 每次写1个字节
table_write();
zap();
}
else
if((EEADR&7)==7) // IDLOCs和程序每次写8个字节
{
flash8();
clear_buffer();
}
EEADR++;
}
if(((EEADR&7)!=0)&&(FLASH))
flash8();
checksum();
break;
case END: // 文件结束
checksum();
TXREG=')'; //提示升级成功
(*((void(*)(void))PROG_START))(); // 运行新程序
break;
case EXTEND_ADDRESS: // 扩展地址记录
while(bcount--)
{
EEADR=g2x(); // 是 EE, Config 或 ID 数据
}
EEPGD=1;
if(EEADR==0xF0)
EEPGD=0; // 选择EEPROM
CFGS=0;
if((EEADR&0xF0)==0x30)
CFGS=1; // 写配置寄存器
TBLPTRU=EEADR;
checksum();
break;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -