📄 bootload.c
字号:
//State-machine for S19 line data processing
switch (s19RecState) { //switch to each possible state
//State-0: wait for 1st leading 'S'
case 0:
if (dat!='S') return;
else
s19RecState = 1; //'S' detected, check for next byte
break;
//State-1: check for 2nd data right afte leading 'S'
case 1:
//check to the data content
switch (dat) {
case '0': //0 = begin of S19 file
s19RecState = 3; //switch to state-3 and wait for its completion
break;
case '3': //3 = valid S19 code line
s19RecCount = 0; //reset counter
s19RecState = 2; //switch to state-2 for getting rest of data
break;
case '7': //end of S19 file
reBootFlag = 1; //re-boot enabled
s19RecState = 3; //switch to state-3 and wait for its completion
break;
default: //invalid line
s19RecState = 3; //switch to state-3 and wait for its completion
break;
}
break;
//State-2: save for the rest of data in one S19 line
case 2:
if ((dat>='0' && dat<='9') || //valid ASCII 0-9
(dat>='A' && dat<='F')) { //valid ASCII A-F
if (s19RecCount>=MAX_S19_LINE) //make sure no buffer overflow
s19RecCount = 0;
s19RecBuff[s19RecCount++] = dat; //save valid data to line buffer
}
else if (dat==0x00) { //end of current S19 line detected
LED_COMM_IN = LED_OFF; //SCI data in-coming inactive
dat = S19LineFormat(); //re-format the line and get back the checksum
if (dat==0xff) { //correct checksum
tmpPtr = s19RecBuff; //get the pointer of pay-load data
num = *tmpPtr++; //number of data byte in this line
num--; //deduct the last byte which is the checksum
num >>= 2; //num/=4, number of 4-byte group
datPtr = (void*)(*(unsigned long*)tmpPtr); //get the Flash address intented to be programmed
if (datPtr >= (void*)FLASH_PRG_ADDR) { //address is in re-programable area
LED_PRG_BUSY = LED_ON; //turn LED on as start-of-programming
((unsigned long*)tmpPtr)++; //point to code data
num--; //deduct 1 group of address 4-bytes
for (i=0;i<num;i++) {
FSTAT = 0x30; //clear FPVIOL & FACCERR, if any
*(unsigned long*)datPtr = *(unsigned long*)tmpPtr; //latch 4 bytes of data into flash array
prg = ((byte (*)(byte))codeInRam)(0x20); //launch command for flash programming
((unsigned long*)tmpPtr)++; //next group of data
((unsigned long*)datPtr)++; //next flash address
}
LED_PRG_BUSY = LED_OFF;
}
}
__SciSendData('.'); //echo back to PC asking for more data
s19RecState = 0; //reset state machine for next new line
}
break;
//wait for completion of one S19 line
//Echo back '.' to acknowledge once end-of-line detected
case 3:
if (dat==0x00) {
LED_COMM_IN = LED_OFF; //SCI data in-coming inactive
__SciSendData('.'); //echo back to PC asking for more data
s19RecState = 0; //reset state machine for next new line
if (reBootFlag) { //re-boot with new code now !!!
asm(jmp 0xffffffff); //Jump to illegal address will result a RESET!!!
}
}
break;
//invalid state, reset the state-machine
default:
s19RecState = 0; //reset state for next new line
}
}
//=============================================================================
// - Launch Flash programing command and wait for its completion
// - This routine is implemented in Flash memory but must be copied into RAM
// and executed in RAM.
// - With the coding here the total length of this routine is less than 128 bytes
// - User must verify the length again if one makes any code additions for any
// specific purposes
//=============================================================================
byte FlashCmdExec(byte cmd)
{
//FSTAT_FACCERR = 1; //clear any pending Flash error flag
FCMD = cmd;
FSTAT_FCBEF = 1; //command launched and FCBEF cleared
if (FSTAT_FPVIOL || FSTAT_FACCERR) { //exit if encounter any error
return(0); //return with error flag
}
while(!FSTAT_FCCF) { //wait for FCCF=1
__RESET_WATCHDOG();
}
return(1); //return with success
}
//=============================================================================
// - Copy ROM data into RAM buffer 'codeInRam'
// - Input: romPtr - byte pointer of ROM data
// size - no. of bytes need to be copied
// - Return: no. of data bytes actually copied
//=============================================================================
word CopyRom2Ram(byte* romPtr, word size)
{
word i;
if (size==0 || size>RAM_CODE_SIZE)
return(0); //no data copied
//copy ROM data into RAM
for (i=0;i<size;i++) {
codeInRam[i] = *romPtr++;
}
return(i); //return with no. of bytes copied
}
//=============================================================================
// - Erase all flash memory sectors except base vector table & bootload section
// for new code download
// - FLASH_PRG_ADDR refers to the starting address to be erased
//=============================================================================
void FlashErase(void)
{
byte sect, i;
word w;
sect = FLASH_PRG_ADDR/FLASH_PAGE_SIZE; //get the starting sector number
while(sect<128) {
datPtr = (void*)(sect*FLASH_PAGE_SIZE);
for (w=0;w<FLASH_PAGE_SIZE;w++) { //verify if this sector is already blank
if (((byte*)datPtr)[w] != 0xff) break; //found at least one byte was not blank
}
if (w<FLASH_PAGE_SIZE) { //this sector needs to be erased
while (!FCDIV_FDIVLD) FCDIV = 39;
while (!FSTAT_FCBEF) {;}
FSTAT = 0x30; //clear FPVIOL & FACCERR, if any
*(unsigned long*)datPtr = 0L; //dummy write;
i = ((byte (*)(byte))codeInRam)(0x40); //command for sector erase
}
sect++;
}
}
//=============================================================================
// Check for TMP1 overflow and toggle LED
//=============================================================================
void TPM1OverflowChk(void)
{
if (TPM1SC&0x80) {
TPM1SC_TOF = 0;
LED_BOOTLOADER = !LED_BOOTLOADER;
}
}
//=============================================================================
// Boot-loader main routine
//=============================================================================
void BootLoader(void)
{
//setup A7 stack pointer
asm (lea _SP_INIT, a7);
//setup A6 dummy stackframe
asm (movea.l #0, a6);
asm (link a6, #0);
//setup A5
asm (lea _SDA_BASE, a5);
DisableInterrupts; //disable all interrupt, no interrupt is allowed
//Do all the initialization works
InitBootLoad();
//Copy flash-command execution code into RAM
CopyRom2Ram((byte*)FlashCmdExec, 128);
//Erase all pages in reprogramable area
FlashErase();
//Boot-loader main loop
for (;;) {
__RESET_WATCHDOG(); //clear watchdog
ReceiveS19Text(); //polling to process incoming data
TPM1OverflowChk(); //polling to check timer
}
}
//=============================================================================
// - Vector 1 - Reset vector
//
// - This portion of code will be executed right after reset.
// - The purpose is to check if it should go to normal code flow or get into
// Boot-loader by checking key-press on PortD pin3 and validity of vector area
//=============================================================================
void interrupt VectorNumber_INITPC FirstHandChk(void)
{
//setup A7 stack pointer
asm (lea _SP_INIT, a7);
//setup A6 dummy stackframe
asm (movea.l #0, a6);
asm (link a6, #0);
//setup A5
asm (lea _SDA_BASE, a5);
//setup PORTD3 for key-press detection
PTDDD_PTDDD3 = 0; //set PTD3 as input (key)
// check if boot-loader function is activated by pressing PortD pin3
// upon reset
if (!PTDD_PTDD3) { //pin is low - possible key-press detected
for (wTmp=0;wTmp<1024;wTmp++) {} //delay for key debouncing
if (!PTDD_PTDD3) { //double-check to confirm key-press
asm (jmp BootLoader); //Boot-loader activation confirmed, jump to Boot-loader routine
}
}
//Boot-loader is not activated by key upon reset,
//Need to further verify if normal code flow exists
//by checking 1st 16 bytes of data in remapped vector area
datPtr = (void*)StartupEntry; //get the starting address by referring to 1st entry in redirected vector map
for (bTmp=0;bTmp<16;bTmp++) { //check for consecutive 16 bytes
if (*(byte*)datPtr != 0xff) //break out if any one is not 0xff
break;
((byte*)datPtr)++;
}
if (bTmp==16) { //leading 16 bytes in vector map are all 0xff, vector map is invalid
asm (jmp BootLoader); //Jump to Boot-loader routine
}
//execute normal code follow
asm (jmp StartupEntry); //Jump to normal "startup" routine
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -