关于PIC16 BootLoader 编译代码到末端FLASH地址问题?
附件是PICC软件的例子,有个疑问,编译器没有任何设置,编译完代码自动偏移到末端FLASH地址,
明显是在代码实现的,那代码上是怎么实现编译偏移到FLASH 尾部?
/*
* BOOT LOADER v3.04 Copyright (C) 2008 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.
*
* The boot loader is suitable for use with the following
* PICmicro controllers:
*
* 16F870, 16F871, 16F873, 16F873A, 16F874,
* 16F874A, 16F876, 16F876A, 16F877, 16F877A
*
* Refer to the accompanying bootldr.txt file for details.
*
* BOOTLDR.C
*/
#include <htc.h>
#include "bootldr.h"
/* Unprotect memory and disable the watchdog timer */
#ifdef MPLAB_ICD
__CONFIG(UNPROTECT & WDTDIS & DEBUGEN & LVPDIS);
#else
__CONFIG(UNPROTECT & WDTDIS);
#endif
// cksum - a variable used for calculating checksums. By declaring the
// variable "persistent" it will tell the compiler not to bother initializing
// it on startup and therefore code size will be smaller.
persistent unsigned char cksum;
// if "VERBOSE" is defined, additional feedback is given by the
// below routines.
#ifdef VERBOSE
const unsigned char START_MSG[]="HI-TECH Software (C)2008\n";
const unsigned char DOWNLOAD_MSG[]="\rDownload-";
/* PUTCH() - outputs a byte to the serial port */
void
putch(unsigned char byte)
{
while(!TXIF); /* 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++);
}
#endif
/* Get a 4 bit HEX number from the serial port */
unsigned char
gx(void)
{
#if VERBOSE == 2
char tmp;
while(!RCIF);
tmp = RCREG;
putch(XOFF);
putch(tmp); // echo input nibbles to output
tmp -= '0';
if (tmp>9)
tmp -= ('A' - '0');
putch(XON);
return tmp;
#else
while(!RCIF);
if(RCREG>='A') //translate the ASCII to hex
return ((RCREG - (unsigned char)'A')+10);
return (RCREG - '0');
#endif
}
/* Get an 8 bit HEX number from the serial port */
unsigned char
g2x(void)
{
unsigned char input_byte;
input_byte=(gx()<<4); //get first nibble
input_byte|=gx(); //get second nibble
cksum+=input_byte; //compute checksum
return (input_byte);
}
/* check the checksum */
void
checksum(void)
{
g2x();
if(cksum!=0) // if checksum does not add to zero, bad check, reset
RESET();
#if VERBOSE == 2
putch('\r'); // echo each hex record on a new line
putch('\n'); // echo each hex record on a new line
#endif
}
/* Initiate a write to memory */
void
writemem(void)
{
char tmpadrh;
#ifdef IRREG_START
char tmpadr;
#endif
while(!TXIF);
TXREG = XOFF;
#ifdef IRREG_START
tmpadr = EEADR;
if (((tmpadrh=EEADRH)==0) && (tmpadr < 4)) // is the address < 4?
{
EEADRH = BOOT_START >> 8; //yes - then move it
EEADR += (BOOT_START & 0xFF);
}
#else
if (((tmpadrh = EEADRH)==0) && (EEADR < 4))
{
EEADRH = BOOT_START >> 8; //yes - then move it
}
#endif
while(WR); //configure for the write to memory
WREN=1;
EECON2=0x55;
EECON2=0xAA;
WR=1; //initiate the write
NOP();
NOP();
WREN=0;
EEADRH = tmpadrh; //swap back the address in case it was one we moved
#ifdef IRREG_START
EEADR = tmpadr; //swap back the address in case it was one we moved
#endif
while(!TXIF);
TXREG = XON;
}
void
main(void)
{
unsigned char LOW_ADDRESS,rectype,count;
INIT_COMMS(); // sets up the serial port for communication
LOW_ADDRESS = RCREG;//flush receive register
/* 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); // print a welcome message
#endif
for(count=BOOT_TIMEOUT; count; --count)
{
if (RCIF) //have we recieved anything?
break;
#ifdef VERBOSE // display a countdown for user response
puts(DOWNLOAD_MSG);
putch('0'+count);
#else
TXREG=('0'+count); //display a countdown
while(!TXIF);
TXREG='\r';
#endif
INTCON=0; // disables interrupts.
T1CON=0x35; // pause during countdown
while(!TMR1IF); //wait...
TMR1IF=0; //clear the flag
T1CON=0x00; // disable the timer again
}
if (!RCIF) //did it timeout without recieving anything?
{ // no hex file to download, resume normal program
#asm
ljmp BOOT_START
#endasm
}
TXREG=':'; // prompt to indicate bootloader is ready to recieve hex file
/* 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 record
#if VERBOSE == 2
putch(':');
#elif defined(VERBOSE)
putch('.');
#endif
cksum = count = g2x(); // get the byte count and reset the checksum
count>>=1; // byte count >> word count
EEDATA = g2x(); // get the high address byte
LOW_ADDRESS = g2x(); // get the low byte of the address
LOW_ADDRESS >>=1; // convert the hex file's byte address to a PIC word address
if((EEDATA&1)==1) // does the high byte need to roll a bit into the low address?
LOW_ADDRESS |= 0x80;
EEADRH = EEDATA >> 1; // byte to word conversion on high address byte
EEADR = LOW_ADDRESS & 0xFC; // point to start of 4 word block
EEPGD = 1; // destination is flash memory
if(EEDATA == 0x42) // unless this case,
EEPGD = 0; // when EEPROM should be selected
else
if(EEDATA >= 0x40){ // ignore any other special types such as CONFIG/IDLOC
#if VERBOSE == 2
putch('\r');
#endif
continue;
}
rectype = g2x(); // get the record type
if(rectype==1){ // END OF FILE record: prepare to run new program
checksum();
#ifdef VERBOSE
puts("Ok");
#else
TXREG=')';
#endif
#asm
ljmp _redirect
#endasm
}
else{ // this record is a data record
while((count != 0)||(EEADR&2)||(EEADR&1)){ // keep writing until all bytes done and 4 word block complete...
RD=1; // read data from destination address (may need to re-write this word)
NOP();
NOP();
if(EEADR == LOW_ADDRESS) // has the address reached the valid range yet?
rectype |= OK_BIT; // if so set a bit to indicate we are Ok to source from USART
// Test to see whether this address is to be written with new data.
if(count!=0){ // if there is still incoming data for this hex record
if((rectype & OK_BIT) == OK_BIT){ // has the address reached the valid range yet?
if(LOADER_SAFE){
EEDATA = g2x(); // get the data low byte
EEDATH = g2x(); // get the data high byte
}
count--; // decrement word count
}
}
writemem(); // write this to memory
if(++EEADR == 0) // select next address
EEADRH++;
} // end of this record and 4 word block
checksum();
}
}
}
void redirect(void) @ BOOT_START{
#asm
PCLATH equ 0Ah
PCL equ 02h
; this must be 4 word in length (including return)
movlw 0
movwf PCLATH
movwf PCL
#endasm
}
#ifndef _BOOTLDR_H_
#define _BOOTLDR_H_
/*
* BOOT LOADER v3.01A Copyright (C) 2008 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.
*
* The boot loader is suitable for use with the following
* PICmicro controllers:
*
* 16F870, 16F871, 16F873, 16F873A, 16F874,
* 16F874A, 16F876, 16F876A, 16F877, 16F877A
*
* BOOTLDR.H
*/
/* Time (seconds) to wait for user input. Must be <= 9 */
#define BOOT_TIMEOUT 9
/* Baud rate to use for data transfer/communication */
#ifndef BAUD
#define BAUD 2400
#endif
// System frequency
#ifndef FOSC
#define FOSC 4000000L
#endif
// Find out the program memry size of this chip
#ifndef _ROMSIZE
#error Bootloader does not support the selected processor
#else
#define FLASH_SIZE _ROMSIZE // _ROMSIZE is defined by the compiler
#endif
// Address where boot loader will start
#if VERBOSE == 2
#define BOOTLOADER_SIZE 0x180
#elif defined(VERBOSE)
#define BOOTLOADER_SIZE 0x180
#else
#define BOOTLOADER_SIZE 0x100
#endif
// If this bootloader is being compiled to run on a system that may one day
// be debugged with the ICD2, we need to allow space for that.
#if defined(MPLAB_ICD)
#define BOOT_START (FLASH_SIZE - BOOTLOADER_SIZE - 0x100)
#else
#define BOOT_START (FLASH_SIZE - BOOTLOADER_SIZE)
#endif
// Check whether the bootloader supports this processor
#if defined(_16F877) || defined(_16F877A) || defined(_16F876) || defined(_16F876A) || \
defined(_16F874) || defined(_16F874A) || defined(_16F873) || defined(_16F873A) || \
defined(_16F871) || defined(_16F870)
// processor is supported
#else
#error This bootloader does not support the selected processor
#endif
#if ((BOOT_START & 0xFF) != 0)
#define IRREG_START
#endif
#if (BAUD > 2400)
#warning File transfer not recommended to exceed 2400 baud
#endif
#define NINE 0 /* Use 9bit communication? FALSE=8bit */
#define DIVIDER ((int)(FOSC/(16UL * BAUD) -1))
#define HIGH_SPEED 1
#if NINE == 1
#define NINE_BITS 0x40
#else
#define NINE_BITS 0
#endif
#if HIGH_SPEED == 1
#define SPEED 0x4
#else
#define SPEED 0
#endif
#define RX_PIN TRISC7
#define TX_PIN TRISC6
/* Serial initialization */
#define INIT_COMMS()\
RX_PIN = 1; \
TX_PIN = 1; \
SPBRG = DIVIDER; \
RCSTA = (NINE_BITS|0x90); \
TXSTA = (SPEED|NINE_BITS|0x20)
#ifndef NOP()
#define NOP() asm("nop")
#endif
#ifndef RESET()
#define RESET() asm("ljmp 0")
#endif
/* expressions used in the code */
#define FLASH EEPGD==1
#define EEPROM EEPGD==0
#ifdef IRREG_START
#define LOADER_SAFE ((EEPROM) || (EEADRH < (BOOT_START >> 8)) || ((EEADRH == (BOOT_START >> 8)) && (EEADR < (BOOT_START & 0xFF))) )
#else
#define LOADER_SAFE ((EEPROM)||(EEADRH < (BOOT_START >> 8)))
#endif
#define OK_BIT 0x80
/* stop & start controls for HyperTerminal */
#define XON 17
#define XOFF 19
#endif
页:
[1]