289 lines
11 KiB
C
289 lines
11 KiB
C
/*
|
|
Turbo BDM Light ColdFire
|
|
Copyright (C) 2006 Daniel Malik
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "tblcf_hwdesc.h"
|
|
#include "tblcf_usb.h"
|
|
#include "version.h"
|
|
#include "tblcf_bt.h"
|
|
#include "log_cmdline.h"
|
|
#include "srec.h"
|
|
#include "commands.h"
|
|
|
|
/*
|
|
Changes:
|
|
1.0 Initial coding
|
|
|
|
*/
|
|
|
|
function_descriptor_t function_descriptor; /* this structure describes what the program should do */
|
|
|
|
/* returns number of parameters or a negative number in case of error */
|
|
char handleoptions(int argc,char *argv[]) {
|
|
int i,notoption=0;
|
|
for (i=1; i< argc;i++) {
|
|
if (argv[i][0] == '/' || argv[i][0] == '-') {
|
|
switch (argv[i][1]) {
|
|
case 'b':
|
|
case 'B':
|
|
/* replace boot sector */
|
|
function_descriptor.replace_boot=1;
|
|
break;
|
|
case 'd':
|
|
case 'D':
|
|
/* USB device number */
|
|
{
|
|
strcpy (function_descriptor.device_name, argv[i]+2);
|
|
print_screen("Device #: %s\n",function_descriptor.device_name);
|
|
break;
|
|
}
|
|
case 'U':
|
|
case 'u':
|
|
/* request firmware upgrade */
|
|
function_descriptor.request_upgrade=1;
|
|
break;
|
|
case 'l':
|
|
case 'L':
|
|
/* -l<log file> */
|
|
open_log(argv[i]+2);
|
|
break;
|
|
default:
|
|
print_screen("Unknown option %s\n",argv[i]);
|
|
return(-1);
|
|
}
|
|
} else {
|
|
if (notoption==0) { /* the first parameter which is not an option is the S-record file */
|
|
strncpy(function_descriptor.s_rec_filename,argv[i],MAX_PATH);
|
|
}
|
|
if (notoption>=1) {
|
|
print_screen("Too many parameters!\n");
|
|
}
|
|
notoption++;
|
|
}
|
|
}
|
|
return(notoption);
|
|
}
|
|
|
|
void usage(void) {
|
|
print_screen("\nUsage:\n\nTBLCF_BT <S-record file> [<options>]\n\n");
|
|
print_screen("Options:\n\n");
|
|
print_screen("-B\t\tReplace BOOT sector\n");
|
|
print_screen("-D<n>\t\tSpecify which USB device to work with\n");
|
|
print_screen("-L<log file>\tWrite messages into a log file\n");
|
|
print_screen("-U\t\tRequest Firmware upgrade\n");
|
|
print_screen("\n");
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
int i;
|
|
unsigned int start,end; /* indexes into the array delimiting block of data to be programmed into flash */
|
|
print_screen("Turbo BDM Light ColdFire Bootloader ver %01X.%01X. Compiled on %s, %s.\n",TBLCF_BOOTLOADER_VERSION>>4,TBLCF_BOOTLOADER_VERSION&0x0f,__DATE__,__TIME__);
|
|
/* initialise function_descriptor */
|
|
function_descriptor.replace_boot=0;
|
|
function_descriptor.device_no=0;
|
|
function_descriptor.request_upgrade=0;
|
|
for (i=0;i<sizeof(function_descriptor.boot_sector_data);i++) function_descriptor.boot_sector_data[i]=0xff;
|
|
for (i=0;i<sizeof(function_descriptor.flash_data);i++) function_descriptor.flash_data[i]=0xff;
|
|
/* now handle user supplied options */
|
|
i=handleoptions(argc,argv);
|
|
if ((i != 1)&&(function_descriptor.request_upgrade==0)) { /* number of parameters is incorrect */
|
|
print_screen("Number of parameters incorrect or other error\n");
|
|
usage();
|
|
return(1);
|
|
}
|
|
tblcf_usb_init();
|
|
/* request firmware upgrade on next power up (if required by the user) */
|
|
if (function_descriptor.request_upgrade) {
|
|
unsigned char data[6];
|
|
tblcf_usb_find_devices(TBLCF_PID);
|
|
print_screen("found %d Turbo BDM Light ColdFire device(s)\n",i=tblcf_usb_cnt());
|
|
if (function_descriptor.device_no>=i) {
|
|
print_screen("Not enough devices connected to work with device #%d\n",
|
|
function_descriptor.device_no);
|
|
return(1);
|
|
}
|
|
function_descriptor.device_no = tblcf_usb_open(function_descriptor.device_name);
|
|
/* request bootloader action op next power-up */
|
|
data[0]=1; /* return 1 byte */
|
|
data[1]=CMD_SET_BOOT;
|
|
data[2]='B';
|
|
data[3]='O';
|
|
data[4]='O';
|
|
data[5]='T';
|
|
i=tblcf_usb_recv_ep0(function_descriptor.device_no, data);
|
|
tblcf_usb_close(function_descriptor.device_no);
|
|
if ((i)||(data[0]!=CMD_SET_BOOT)) {
|
|
print_screen("USB communication problem or CMD_SET_BOOT command failure\n");
|
|
return(1);
|
|
}
|
|
print_screen("HC08JB16 ICP will execute on next power-up. Disconnect and reconnect the device.\n");
|
|
return(0);
|
|
}
|
|
if (s_rec_process()) return(1); /* process the S-record file, exit in case of error */
|
|
/* now open communication with the device */
|
|
tblcf_usb_find_devices(JB16ICP_PID);
|
|
print_screen("found %d HC08JB16 ICP device(s)\n",i=tblcf_usb_cnt());
|
|
if (function_descriptor.device_no>=i) {
|
|
print_screen("Not enough devices connected to work with device #%d\n",
|
|
function_descriptor.device_no);
|
|
return(1);
|
|
}
|
|
function_descriptor.device_no = tblcf_usb_open(function_descriptor.device_name);
|
|
/* boot sector reprogramming (if requested by user) */
|
|
i=icp_verify(function_descriptor.device_no,
|
|
function_descriptor.boot_sector_data,
|
|
TBLCF_FLASH_BOOT_START, TBLCF_FLASH_BOOT_END-TBLCF_FLASH_BOOT_START+1);
|
|
if (i<0) {
|
|
print_screen("USB communication problem\n");
|
|
tblcf_usb_close(function_descriptor.device_no);
|
|
return(1);
|
|
}
|
|
if (function_descriptor.replace_boot) {
|
|
/* user wants to overwrite the boot sector, first check, whether it is really needed */
|
|
if (i) {
|
|
print_screen("Boot sector contents different, performing mass erase\n");
|
|
/* erase flash of the device */
|
|
i=icp_mass_erase(function_descriptor.device_no);
|
|
if (i) {
|
|
print_screen("USB communication problem or mass erase failure\n");
|
|
tblcf_usb_close(function_descriptor.device_no);
|
|
return(1);
|
|
}
|
|
print_screen("Mass erase done, programming boot sector\n");
|
|
/* program the boot sector contents */
|
|
i=icp_program(function_descriptor.device_no,
|
|
function_descriptor.boot_sector_data,
|
|
TBLCF_FLASH_BOOT_START, TBLCF_FLASH_BOOT_END-TBLCF_FLASH_BOOT_START+1);
|
|
if (i) {
|
|
print_screen("USB communication problem or programming failure\n");
|
|
tblcf_usb_close(function_descriptor.device_no);
|
|
return(1);
|
|
}
|
|
print_screen("Programming done, verifying boot sector\n");
|
|
/* verify that the contents is now correct */
|
|
i=icp_verify(function_descriptor.device_no,
|
|
function_descriptor.boot_sector_data,
|
|
TBLCF_FLASH_BOOT_START, TBLCF_FLASH_BOOT_END-TBLCF_FLASH_BOOT_START+1);
|
|
if (i) {
|
|
print_screen("USB communication problem or verification failure\n");
|
|
tblcf_usb_close(function_descriptor.device_no);
|
|
return(1);
|
|
}
|
|
print_screen("Verification done, boot sector OK. You can start breathing again.\n");
|
|
} else {
|
|
print_screen("Boot sector contents identical, -B option ignored\n");
|
|
}
|
|
} else {
|
|
/* user does not want to reprogram the boot sector */
|
|
if (i) {
|
|
print_screen("Boot sector contents differs from S-record, update required\n");
|
|
tblcf_usb_close(function_descriptor.device_no);
|
|
return(1);
|
|
}
|
|
}
|
|
/* flash programming */
|
|
for (i=TBLCF_FLASH_START;i<TBLCF_FLASH_END;i+=ICP_FLASH_BLOCK_SIZE) {
|
|
/* erase all flash blocks one by one */
|
|
print_screen("Erasing block at address: 0x%04X\r",i);
|
|
if (icp_block_erase(function_descriptor.device_no, i)) {
|
|
print_screen("\nUSB communication problem or block erase failure\n");
|
|
tblcf_usb_close(function_descriptor.device_no);
|
|
return(1);
|
|
}
|
|
}
|
|
print_screen("\n");
|
|
/* set the boot_state variable to erased state (0xFF 0xFF) before programming */
|
|
function_descriptor.flash_data[TBLCF_BOOT_STATE-TBLCF_FLASH_START]=TBLCF_BOOT_STATE_BLANK>>8;
|
|
function_descriptor.flash_data[TBLCF_BOOT_STATE-TBLCF_FLASH_START+1]=TBLCF_BOOT_STATE_BLANK&&0xff;
|
|
/* now do the actual programming */
|
|
/* the algorithm below will split the flash into several sections if there is at least 8 unprogrammed bytes beetwen two sections */
|
|
/* for TBLCF firmware there will typically be only 2 sections: code of the application at the beginning of flash and secondary vectors at the end */
|
|
end=TBLCF_FLASH_START;
|
|
while (1) {
|
|
/* look for first byte in non-erased state */
|
|
start=end;
|
|
while ((function_descriptor.flash_data[start-TBLCF_FLASH_START]==0xff) &&
|
|
(start<=TBLCF_FLASH_END)) start++; /* find first byte != 0xff */
|
|
if (start>TBLCF_FLASH_END) break; /* end of array */
|
|
/* now look for block of 8 bytes in erased state */
|
|
end=start;
|
|
do {
|
|
while ((function_descriptor.flash_data[end-TBLCF_FLASH_START]!=0xff) &&
|
|
(end<TBLCF_FLASH_END)) end++; /* find first byte == 0xff */
|
|
if (end<TBLCF_FLASH_END) {
|
|
i=1;
|
|
while ((function_descriptor.flash_data[end+i-TBLCF_FLASH_START]==0xff) &&
|
|
((end+i)<TBLCF_FLASH_END)&&(i<8)) i++; /* keep going for 7 more bytes (max) */
|
|
if (i<8) end+=i;
|
|
}
|
|
} while ((i<8)&&(end<TBLCF_FLASH_END));
|
|
if (end<TBLCF_FLASH_END) end--; /* go back 1 byte (it is blank anyway) */
|
|
/* program the block */
|
|
print_screen("Programming block from 0x%04X to 0x%04X\n",start,end);
|
|
i=icp_program(function_descriptor.device_no,
|
|
function_descriptor.flash_data+(start-TBLCF_FLASH_START),
|
|
start, end-start+1);
|
|
if (i) {
|
|
print_screen("USB communication problem or programming failure\n");
|
|
tblcf_usb_close(function_descriptor.device_no);
|
|
return(1);
|
|
}
|
|
/* verify the block */
|
|
print_screen("Verifying block from 0x%04X to 0x%04X ",start,end);
|
|
i=icp_verify(function_descriptor.device_no,
|
|
function_descriptor.flash_data+(start-TBLCF_FLASH_START),
|
|
start, end-start+1);
|
|
if (i) {
|
|
print_screen("\nUSB communication problem or verification failure\n");
|
|
tblcf_usb_close(function_descriptor.device_no);
|
|
return(1);
|
|
}
|
|
print_screen("- OK\n",start,end);
|
|
end++; /* increment end again */
|
|
}
|
|
/* all flash programmed and verified, program the boot_state to 0xFF 0x01 to enable the application */
|
|
print_screen("All flash programmed and verified, enabling the application\n");
|
|
function_descriptor.flash_data[TBLCF_BOOT_STATE-TBLCF_FLASH_START]=TBLCF_BOOT_STATE_APPLOK>>8;
|
|
function_descriptor.flash_data[TBLCF_BOOT_STATE-TBLCF_FLASH_START+1]=TBLCF_BOOT_STATE_APPLOK&&0xff;
|
|
i=icp_program(function_descriptor.device_no,
|
|
function_descriptor.flash_data+(TBLCF_BOOT_STATE-TBLCF_FLASH_START),
|
|
TBLCF_BOOT_STATE, 2); /* bootloader_state is 2 bytes long */
|
|
if (i) {
|
|
print_screen("USB communication problem or programming failure\n");
|
|
tblcf_usb_close(function_descriptor.device_no);
|
|
return(1);
|
|
}
|
|
/* now verify that the bootloader state is programmed correctly */
|
|
i=icp_verify(function_descriptor.device_no,
|
|
function_descriptor.flash_data+(TBLCF_BOOT_STATE-TBLCF_FLASH_START),
|
|
TBLCF_BOOT_STATE, 2);
|
|
if (i) {
|
|
print_screen("USB communication problem or bootloader state verification failure\n");
|
|
tblcf_usb_close(function_descriptor.device_no);
|
|
return(1);
|
|
}
|
|
print_screen("Flash programming complete, disconnect & reconnect the device\n");
|
|
tblcf_usb_close(function_descriptor.device_no);
|
|
return(0);
|
|
}
|
|
|
|
|