You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1588 lines
35 KiB
1588 lines
35 KiB
/* |
|
|
|
hex2lpc.c |
|
|
|
Upload Intel Hex File to LPC8xx devices |
|
|
|
Features: |
|
- Calculates the checksum at 0x001c in the vector table |
|
- Part ID detection (if no hex file is specified on the commandline) |
|
|
|
*/ |
|
|
|
#include <stdio.h> |
|
#include <stdarg.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <assert.h> |
|
|
|
#include <sys/types.h> |
|
#include <sys/stat.h> |
|
#include <fcntl.h> |
|
#include <termios.h> |
|
#include <unistd.h> |
|
|
|
#include <time.h> |
|
|
|
/* this defines the number of bytes, which should be sent before any further read happens */ |
|
/* it seems that there is a echo with the LPC devices, so that all data sent to the LPC */ |
|
/* is always sent back. This means, while writing, the same number of bytes are sent back */ |
|
/* so in general, we could write one byte and read one byte, but this is slow */ |
|
/* setting UART_BLOCKSIZE to 4 will write 4 bytes and then read 4 bytes, which is much faster */ |
|
#define UART_BLOCKSIZE 4 |
|
|
|
/* forward declarations */ |
|
int fmem_store_data(unsigned long adr, unsigned long cnt, unsigned char *data); |
|
|
|
|
|
/*================================================*/ |
|
/* error procedure */ |
|
void err(char *fmt, ...) |
|
{ |
|
va_list va; |
|
va_start(va, fmt); |
|
vprintf(fmt, va); |
|
printf("\n"); |
|
va_end(va); |
|
} |
|
|
|
/* user msg */ |
|
void msg(char *fmt, ...) |
|
{ |
|
va_list va; |
|
va_start(va, fmt); |
|
vprintf(fmt, va); |
|
printf("\n"); |
|
va_end(va); |
|
} |
|
|
|
|
|
/*================================================*/ |
|
/* flash memory management */ |
|
|
|
/* mb = memory block */ |
|
struct _mb_struct |
|
{ |
|
unsigned long adr; /* adr for "data" inside the target controller */ |
|
unsigned long cnt; /* number of bytes in "data" */ |
|
unsigned char *data; /* pointer to some data */ |
|
}; |
|
typedef struct _mb_struct mb_struct; |
|
|
|
mb_struct *mb_open(void) |
|
{ |
|
mb_struct *mb = (mb_struct *)malloc(sizeof(mb_struct)); |
|
if ( mb != NULL ) |
|
{ |
|
mb->adr = 0UL; |
|
mb->cnt = 0UL; |
|
mb->data = NULL; |
|
return mb; |
|
} |
|
return err("fmem: mem block init error"), NULL; |
|
} |
|
|
|
void mb_close(mb_struct *mb) |
|
{ |
|
if ( mb == NULL ) |
|
return; |
|
mb->cnt = 0UL; |
|
if ( mb->data != NULL ) |
|
free(mb->data); |
|
free(mb->data); |
|
} |
|
|
|
/* set size of the memory block, existing data will be preserved, returns 0 for error */ |
|
int mb_set_data_size(mb_struct *mb, unsigned long cnt) |
|
{ |
|
if ( mb->data == NULL ) |
|
{ |
|
mb->data = (unsigned char *)malloc(cnt); |
|
if ( mb->data == NULL ) |
|
return err("fmem: mem data alloc error"), 0; |
|
} |
|
else |
|
{ |
|
void *ptr; |
|
ptr = realloc(mb->data , cnt); |
|
if ( ptr == NULL ) |
|
return err("fmem: mem data realloc error"), 0; |
|
mb->data = (unsigned char *)ptr; |
|
} |
|
|
|
mb->cnt = cnt; |
|
return 1; |
|
} |
|
|
|
mb_struct **fmem_mb_list = NULL; |
|
unsigned long fmem_mb_list_cnt = 0UL; |
|
unsigned long fmem_mb_list_max = 0UL; |
|
#define FMEM_EXPAND 32 |
|
|
|
int fmem_init(void) |
|
{ |
|
fmem_mb_list = (mb_struct **)malloc(sizeof(mb_struct *)*FMEM_EXPAND); |
|
if ( fmem_mb_list == NULL ) |
|
return err("fmem: mem block init error"), 0; |
|
fmem_mb_list_cnt = 0UL; |
|
fmem_mb_list_max = 0UL; |
|
return 1; |
|
} |
|
|
|
/* (internal function, only called by fmem_add_data) */ |
|
int fmem_expand(void) |
|
{ |
|
void *ptr; |
|
ptr = realloc(fmem_mb_list, (fmem_mb_list_max+FMEM_EXPAND)*sizeof(mb_struct *)); |
|
if ( ptr == NULL ) |
|
return err("fmem: mem block list expand error"), 0; |
|
fmem_mb_list = (mb_struct **)ptr; |
|
fmem_mb_list_max+= FMEM_EXPAND; |
|
return 1; |
|
} |
|
|
|
/* add a new data block to the flash memory manager */ |
|
/* (internal function, only called by fmem_store_data) */ |
|
int fmem_add_data(unsigned long adr, unsigned long cnt, unsigned char *data) |
|
{ |
|
mb_struct *mb = mb_open(); |
|
if ( mb != NULL ) |
|
{ |
|
if ( mb_set_data_size(mb, cnt) != 0 ) |
|
{ |
|
memcpy(mb->data, data, cnt); |
|
while( fmem_mb_list_cnt >= fmem_mb_list_max ) |
|
if ( fmem_expand() == 0 ) |
|
{ |
|
mb_close(mb); |
|
return 0; |
|
} |
|
|
|
fmem_mb_list[fmem_mb_list_cnt] = mb; |
|
fmem_mb_list_cnt++; |
|
return 1; |
|
} |
|
} |
|
return 0; |
|
} |
|
|
|
/* same as fmem_add_data, but it tries to expand the last data block of possible */ |
|
/* idea is to reduce the number of independent data blocks */ |
|
int fmem_store_data(unsigned long adr, unsigned long cnt, unsigned char *data) |
|
{ |
|
if ( fmem_mb_list_cnt > 0 ) |
|
{ |
|
mb_struct *mb = fmem_mb_list[fmem_mb_list_cnt-1]; |
|
if ( mb->adr + mb->cnt == adr ) |
|
{ |
|
unsigned long old_cnt = mb->cnt; |
|
if ( mb_set_data_size(mb, mb->cnt + cnt) == 0 ) |
|
return 0; |
|
memcpy(mb->data + old_cnt, data, cnt); |
|
return 1; |
|
} |
|
} |
|
return fmem_add_data(adr, cnt, data); |
|
} |
|
|
|
void fmem_show(void) |
|
{ |
|
unsigned long i; |
|
mb_struct *mb; |
|
for( i = 0; i < fmem_mb_list_cnt; i++ ) |
|
{ |
|
mb = fmem_mb_list[i]; |
|
printf("%lu/%lu: adr=0x%08lx cnt=%lu\n", i+1, fmem_mb_list_cnt, mb->adr, mb->cnt); |
|
} |
|
} |
|
|
|
/* |
|
copy memory from fmem to a target buffer |
|
any data, which is NOT in the fmem will be set to 0xff |
|
return 1 if data has been copied to buf (intersection with the ihex data) |
|
*/ |
|
int fmem_copy(unsigned long adr, unsigned long size, unsigned char *buf) |
|
{ |
|
unsigned long i, j; |
|
mb_struct *mb; |
|
int r = 0; |
|
|
|
memset(buf, 0xff, size); |
|
|
|
j = 0; |
|
while( j < size ) |
|
{ |
|
for( i = 0; i < fmem_mb_list_cnt; i++ ) |
|
{ |
|
mb = fmem_mb_list[i]; |
|
if ( adr >= mb->adr && adr < mb->adr+mb->cnt ) |
|
{ |
|
/* |
|
assert(j < size); |
|
assert(adr >= mb->adr); |
|
assert(adr - mb->adr < mb->cnt ); |
|
*/ |
|
buf[j] = mb->data[adr - mb->adr]; |
|
r = 1; |
|
} |
|
} |
|
adr++; |
|
j++; |
|
} |
|
return r; |
|
} |
|
|
|
unsigned char fmem_get_byte(unsigned long adr) |
|
{ |
|
unsigned long i; |
|
mb_struct *mb; |
|
for( i = 0; i < fmem_mb_list_cnt; i++ ) |
|
{ |
|
mb = fmem_mb_list[i]; |
|
if ( adr >= mb->adr && adr < mb->adr+mb->cnt ) |
|
{ |
|
//printf("adr: %08lx data: %x\n",adr, mb->data[adr - mb->adr]); |
|
return mb->data[adr - mb->adr]; |
|
} |
|
} |
|
return 0xff; |
|
} |
|
|
|
void fmem_set_byte(unsigned long adr, unsigned char val) |
|
{ |
|
unsigned long i; |
|
mb_struct *mb; |
|
for( i = 0; i < fmem_mb_list_cnt; i++ ) |
|
{ |
|
mb = fmem_mb_list[i]; |
|
if ( adr >= mb->adr && adr < mb->adr+mb->cnt ) |
|
{ |
|
//printf("adr: %08lx data: %x\n",adr, mb->data[adr - mb->adr]); |
|
mb->data[adr - mb->adr] = val; |
|
} |
|
} |
|
} |
|
|
|
/*================================================*/ |
|
/* intel hex parser */ |
|
|
|
#define IHEX_LINE_LEN 1024 |
|
#define IHEX_DATA_LEN 300 |
|
FILE *ihex_fp; |
|
char ihex_line[IHEX_LINE_LEN]; |
|
int ihex_pos = 0; |
|
int ihex_curr_line = 0; |
|
|
|
unsigned long ihex_line_bytes; |
|
unsigned long ihex_line_extsegadr = 0UL; /* from typ 02 */ |
|
unsigned long ihex_line_extlinadr = 0UL; /* from typ 04 */ |
|
unsigned long ihex_line_adr; |
|
unsigned long ihex_line_type; |
|
unsigned char ihex_line_data[IHEX_DATA_LEN]; |
|
|
|
/* calculate the current address */ |
|
unsigned long ihex_get_curr_adr(void) |
|
{ |
|
unsigned long adr; |
|
adr = 0UL; |
|
adr += ihex_line_extlinadr<<16; |
|
adr += ihex_line_extsegadr<<16; |
|
adr += ihex_line_adr; |
|
return adr; |
|
} |
|
|
|
/* read one line from the stream (global variable), return 0 for error or EOF */ |
|
int ihex_read_line(void) |
|
{ |
|
if ( ihex_fp == NULL ) |
|
return err("ihex line %lu: internal error (file ptr)", ihex_curr_line), 0; |
|
if ( fgets(ihex_line, IHEX_LINE_LEN, ihex_fp) == NULL ) |
|
return 0; |
|
ihex_line[IHEX_LINE_LEN-1] = '\0'; |
|
ihex_pos = 0; |
|
ihex_curr_line++; |
|
return 1; |
|
} |
|
|
|
/* get a char from the internal line buffer and goto to next char */ |
|
unsigned int ihex_getc(void) |
|
{ |
|
unsigned int c; |
|
c = ihex_line[ihex_pos]; |
|
if ( c != '\0' ) |
|
ihex_pos++; |
|
return c; |
|
} |
|
|
|
unsigned int ihex_getchex(void) |
|
{ |
|
unsigned int c = ihex_getc(); |
|
if ( c < '0' ) |
|
return 0; |
|
if ( c <= '9' ) |
|
return c - '0'; |
|
if ( c < 'A' ) |
|
return 0; |
|
if ( c <= 'F' ) |
|
return c - 'A' + 10U; |
|
if ( c < 'a' ) |
|
return 0; |
|
if ( c <= 'f' ) |
|
return c - 'a' + 10U; |
|
return 0; |
|
|
|
} |
|
|
|
unsigned long ihex_gethex(int size) |
|
{ |
|
unsigned long v = 0; |
|
|
|
while( size > 0 ) |
|
{ |
|
v *= 16; |
|
v += ihex_getchex(); |
|
size--; |
|
} |
|
return v; |
|
} |
|
|
|
/* parse line in global buffer ihex_line, return 0 on error, return 1 for eof, otherwise 2 */ |
|
int ihex_parse_line(void) |
|
{ |
|
unsigned long i; |
|
unsigned long sum = 0; |
|
if ( ihex_getc() != ':' ) |
|
return 0; |
|
|
|
ihex_line_bytes = ihex_gethex(2); |
|
sum += ihex_line_bytes; |
|
ihex_line_adr = ihex_gethex(4); |
|
sum += ihex_line_adr & 0x0ff; |
|
sum += (ihex_line_adr>>8) & 0x0ff; |
|
ihex_line_type = ihex_gethex(2); |
|
sum += ihex_line_type & 0x0ff; |
|
switch(ihex_line_type) |
|
{ |
|
case 0: /* data record */ |
|
|
|
for( i = 0; i <= ihex_line_bytes /* includes checksum */; i++ ) |
|
{ |
|
ihex_line_data[i] = ihex_gethex(2); |
|
sum += ihex_line_data[i]; |
|
// printf("%02lx: %02x/%02lx\n", i, ihex_line_data[i], sum); |
|
} |
|
if ( (sum & 0x0ff) != 0 ) |
|
return err("ihex line %lu: checksum error", ihex_curr_line), 0; /* checksum error */ |
|
/* call flash memory management */ |
|
if ( fmem_store_data( ihex_get_curr_adr(), ihex_line_bytes, ihex_line_data) == 0 ) |
|
return err("ihex line %lu: store memory error", ihex_curr_line), 0; |
|
break; |
|
case 1: /* end of file */ |
|
return 1; |
|
case 2: /* extended segment adr */ |
|
ihex_line_extsegadr = ihex_gethex(4); |
|
break; |
|
case 3: /* start extended segment adr */ |
|
/* ignored */ |
|
break; |
|
case 4: /* linear adr */ |
|
ihex_line_extlinadr = ihex_gethex(4); |
|
break; |
|
case 5: /* start linear adr */ |
|
/* ignored */ |
|
break; |
|
default: |
|
return err("ihex line %lu: unknown type %lu", ihex_curr_line, ihex_line_type), 0; /* unknown type */ |
|
} |
|
return 2; |
|
} |
|
|
|
int ihex_read_fp(void) |
|
{ |
|
if ( fmem_init() == 0 ) |
|
return 0; |
|
for(;;) |
|
{ |
|
if ( ihex_read_line() == 0 ) |
|
break; |
|
if ( ihex_parse_line() == 0 ) |
|
return 0; |
|
} |
|
return 1; |
|
} |
|
|
|
/* |
|
read intel hex file into the flash memory manager. |
|
after this, use the following functions: |
|
|
|
int fmem_copy(unsigned long adr, unsigned long size, unsigned char *buf) |
|
unsigned char fmem_get_byte(unsigned long adr) |
|
void fmem_set_byte(unsigned long adr, unsigned char val) |
|
|
|
*/ |
|
int ihex_read_file(const char *filename) |
|
{ |
|
ihex_fp = fopen(filename, "rb"); |
|
if ( ihex_fp == NULL ) |
|
return err("ihex: open error with file '%s'", filename), 0; |
|
msg("intel hex file %s", filename); |
|
if ( ihex_read_fp() == 0 ) |
|
{ |
|
fclose(ihex_fp); |
|
return 0; |
|
} |
|
fclose(ihex_fp); |
|
return 1; |
|
} |
|
|
|
/*================================================*/ |
|
const char *lpc_error_string[] = |
|
{ |
|
"CMD_SUCCESS", |
|
"INVALID_COMMAND", |
|
"SRC_ADDR_ERROR", |
|
"DST_ADDR_ERROR", |
|
"SRC_ADDR_NOT_MAPPED", |
|
"DST_ADDR_NOT_MAPPED", /* 5 */ |
|
"COUNT_ERROR", |
|
"iNVALID_SECTOR", |
|
"SECTOR_NOT_BLANK", |
|
"SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION", |
|
"COMPARE_ERROR", /* 10 */ |
|
"BUSY", |
|
"PARAM_ERROR", |
|
"ADDR_ERROR", |
|
"ADDR_NOT_MAPPED", |
|
"CMD_LOCKED", /* 15 */ |
|
"INVALID_CODE", |
|
"INVALID_BAUD_RATE", |
|
"INVALID_STOP_BIT", |
|
"CODE_READ_PROTECTION_ENABLED", |
|
"internal hex2lpc error" /* 20 */ |
|
}; |
|
|
|
/*================================================*/ |
|
/* uart connection */ |
|
|
|
int uart_fd = 0; |
|
struct termios uart_io; |
|
/* in_buf should be large enough to read a complete sector with some additional overhead */ |
|
#define UART_IN_BUF_LEN (1024*48) |
|
unsigned char uart_in_buf[UART_IN_BUF_LEN]; |
|
unsigned long uart_in_pos = 0; |
|
unsigned long wait_time_in_clk_ticks = CLOCKS_PER_SEC/4; |
|
unsigned long uart_in_first_0x0a_pos = 0x0ffffffff; |
|
|
|
int uart_is_synchronized = 0; |
|
|
|
void uart_add_in_buf(unsigned char c) |
|
{ |
|
if ( uart_in_pos < UART_IN_BUF_LEN ) |
|
{ |
|
if ( uart_in_first_0x0a_pos == 0x0ffffffff && c == 0x0a ) |
|
uart_in_first_0x0a_pos = uart_in_pos; |
|
uart_in_buf[uart_in_pos++] = c; |
|
} |
|
} |
|
|
|
void uart_reset_in_buf(void) |
|
{ |
|
uart_in_first_0x0a_pos = 0x0ffffffff; |
|
uart_in_pos = 0; |
|
} |
|
|
|
void uart_show_in_buf(void) |
|
{ |
|
unsigned long i,j; |
|
i = 0; |
|
while( i < uart_in_pos ) |
|
{ |
|
for( j = 0; j < 16; j++ ) |
|
{ |
|
if ( i + j < uart_in_pos ) |
|
printf("%02x ", uart_in_buf[i+j]); |
|
else |
|
printf(" "); |
|
} |
|
|
|
for( j = 0; j < 16; j++ ) |
|
{ |
|
if ( i + j < uart_in_pos && uart_in_buf[i+j] >= 32 && uart_in_buf[i+j] <= 127 ) |
|
printf("%c", uart_in_buf[i+j]); |
|
else |
|
printf("."); |
|
} |
|
printf("\n"); |
|
i += j; |
|
} |
|
} |
|
|
|
int uart_get_result_code_after_first_0x0a(void) |
|
{ |
|
if ( uart_in_first_0x0a_pos == 0x0ffffffff ) |
|
return 20; |
|
return atoi((const char *)uart_in_buf+uart_in_first_0x0a_pos+1); |
|
} |
|
|
|
/* get the LPC error/result code from the end of the buffer */ |
|
int uart_get_result_code_from_buf_end(void) |
|
{ |
|
int code = 0; |
|
unsigned long i = uart_in_pos; |
|
if ( i == 0 ) |
|
return -1; |
|
i--; |
|
if ( uart_in_buf[i] == '\n' || uart_in_buf[i] == '\r' ) |
|
{ |
|
if ( i == 0 ) |
|
return -1; |
|
i--; |
|
} |
|
if ( uart_in_buf[i] == '\n' || uart_in_buf[i] == '\r' ) |
|
{ |
|
if ( i == 0 ) |
|
return -1; |
|
i--; |
|
} |
|
if ( uart_in_buf[i] >= '0' && uart_in_buf[i] <= '9' ) |
|
{ |
|
code = uart_in_buf[i] - '0'; |
|
if ( i == 0 ) |
|
return code; |
|
i--; |
|
if ( uart_in_buf[i] >= '0' && uart_in_buf[i] <= '9' ) |
|
{ |
|
code = (uart_in_buf[i] - '0')*10 + code; |
|
} |
|
return code; |
|
} |
|
return -1; |
|
|
|
} |
|
|
|
/* |
|
values for baud are: |
|
B1200 |
|
B1800 |
|
B2400 |
|
B4800 |
|
B9600 |
|
B19200 |
|
B38400 |
|
B57600 |
|
B115200 |
|
B230400 |
|
*/ |
|
int uart_open(const char *device, int baud) |
|
{ |
|
uart_is_synchronized = 0; |
|
uart_reset_in_buf(); |
|
|
|
switch(baud) |
|
{ |
|
case B57600: |
|
case B115200: |
|
case B230400: |
|
wait_time_in_clk_ticks = CLOCKS_PER_SEC/8; |
|
break; |
|
} |
|
|
|
|
|
uart_fd=open(device, O_RDWR|O_NONBLOCK|O_NDELAY); |
|
if ( uart_fd < 0 ) |
|
return perror(device), err("uart: %s error", device), 0; |
|
if ( tcgetattr(uart_fd, &uart_io) < 0 ) |
|
return close(uart_fd), err("uart: tcgetattr error"), 0; |
|
|
|
uart_io.c_iflag = IGNBRK | IGNPAR; |
|
uart_io.c_oflag = 0; |
|
uart_io.c_cflag = CS8|CREAD|CLOCAL; |
|
uart_io.c_lflag = 0; /* none canonical mode */ |
|
uart_io.c_cc[VMIN] = 0; /* make chars available immeadiatly in none canonical mode */ |
|
uart_io.c_cc[VTIME] = 0; |
|
|
|
|
|
if ( cfsetispeed(&uart_io, baud) < 0 ) |
|
return close(uart_fd), err("uart: cfsetispeed error"), 0; |
|
if ( cfsetospeed(&uart_io, baud) < 0 ) |
|
return close(uart_fd), err("uart: cfsetospeed error"), 0; |
|
if ( cfsetspeed(&uart_io, baud) < 0 ) |
|
return close(uart_fd), err("uart: cfsetspeed error"), 0; |
|
|
|
if ( tcsetattr(uart_fd, TCSANOW, &uart_io) < 0 ) |
|
return close(uart_fd), err("uart: tcsetattr error"), 0; |
|
|
|
|
|
return 1; |
|
} |
|
|
|
int uart_read_byte(void) |
|
{ |
|
ssize_t cnt; |
|
unsigned char buf[2]; |
|
if ( uart_fd < 0 ) |
|
return -1; |
|
cnt = read(uart_fd, buf, 1); |
|
if ( cnt == 0 ) |
|
return -1; |
|
uart_add_in_buf(buf[0]); |
|
return buf[0]; |
|
} |
|
|
|
void uart_read_bytes(void) |
|
{ |
|
ssize_t i, cnt; |
|
unsigned char buf[UART_BLOCKSIZE+2]; |
|
if ( uart_fd < 0 ) |
|
return; |
|
cnt = read(uart_fd, buf, UART_BLOCKSIZE); |
|
for( i = 0; i < cnt; i++) |
|
uart_add_in_buf(buf[i]); |
|
} |
|
|
|
int uart_send_byte(int c) |
|
{ |
|
unsigned char buf[1]; |
|
buf[0] = c; |
|
if ( uart_fd >= 0 ) |
|
{ |
|
write(uart_fd, buf, 1); |
|
uart_read_byte(); |
|
} |
|
return 1; |
|
} |
|
|
|
int uart_send_bytes(int cnt, const unsigned char *buf) |
|
{ |
|
int i = 0; |
|
if ( uart_fd >= 0 ) |
|
{ |
|
while( i < cnt ) |
|
{ |
|
if ( i + UART_BLOCKSIZE <= cnt ) |
|
{ |
|
write(uart_fd, buf+i, UART_BLOCKSIZE); |
|
uart_read_bytes(); |
|
/* |
|
for( j = 0; j < UART_BLOCKSIZE; j++ ) |
|
uart_read_byte(); |
|
*/ |
|
i+=UART_BLOCKSIZE; |
|
} |
|
else |
|
{ |
|
write(uart_fd, buf+i, 1); |
|
uart_read_byte(); |
|
i++; |
|
} |
|
} |
|
} |
|
return 1; |
|
} |
|
|
|
int uart_send_cnt_bytes(int cnt, unsigned char data) |
|
{ |
|
unsigned char buf[UART_BLOCKSIZE]; |
|
int i = 0; |
|
int j; |
|
for( j = 0; j < UART_BLOCKSIZE; j++ ) |
|
buf[j] = data; |
|
|
|
if ( uart_fd >= 0 ) |
|
{ |
|
while( i < cnt ) |
|
{ |
|
if ( i + UART_BLOCKSIZE <= cnt ) |
|
{ |
|
write(uart_fd, buf, UART_BLOCKSIZE); |
|
for( j = 0; j < UART_BLOCKSIZE; j++ ) |
|
uart_read_byte(); |
|
i+=UART_BLOCKSIZE; |
|
} |
|
else |
|
{ |
|
write(uart_fd, buf, 1); |
|
uart_read_byte(); |
|
i++; |
|
} |
|
} |
|
} |
|
return 1; |
|
} |
|
|
|
|
|
int uart_send_str(const char *str) |
|
{ |
|
return uart_send_bytes(strlen(str), (const unsigned char *)str); |
|
|
|
/* |
|
int i, len = strlen(str); |
|
for( i = 0; i < len; i++ ) |
|
if ( uart_send_byte(str[i]) == 0 ) |
|
return 0; |
|
return 1; |
|
*/ |
|
} |
|
|
|
#ifdef USE_TIME |
|
void uart_read_more(void) |
|
{ |
|
time_t start; |
|
time_t curr; |
|
int c; |
|
unsigned long received_chars; |
|
|
|
time(&start); |
|
received_chars = 0; |
|
for(;;) |
|
{ |
|
time(&curr); |
|
if ( start + 2 <= curr ) |
|
break; |
|
c =uart_read_byte(); |
|
if ( c >= 0 ) |
|
{ |
|
// printf("[%lu %d %c]\n", received_chars, c, c < ' ' ? ' ' : c); |
|
time(&start); |
|
received_chars++; |
|
} |
|
} |
|
// printf("received_chars=%lu\n", received_chars); |
|
} |
|
#else |
|
void uart_read_more(void) |
|
{ |
|
clock_t start; |
|
clock_t curr; |
|
//clock_t wait = wait_time_in_clk_ticks; |
|
int c; |
|
unsigned long received_chars; |
|
|
|
start = clock(); |
|
received_chars = 0; |
|
for(;;) |
|
{ |
|
curr = clock(); |
|
if ( start + wait_time_in_clk_ticks <= curr ) |
|
break; |
|
c =uart_read_byte(); |
|
if ( c >= 0 ) |
|
{ |
|
// printf("[%lu %d %c]\n", received_chars, c, c < ' ' ? ' ' : c); |
|
start = clock(); /* reset clock */ |
|
//wait = wait_time_in_clk_ticks/4; /* wait lesser once another byte was read */ |
|
received_chars++; |
|
} |
|
} |
|
// printf("received_chars=%lu\n", received_chars); |
|
} |
|
#endif |
|
|
|
/*================================================*/ |
|
/* LPC communication */ |
|
|
|
|
|
/* |
|
set the uart_is_synchronized flag |
|
return the flag value. |
|
*/ |
|
#define UART_STR_SYNCHRONIZED "Synchronized" |
|
#define UART_STR_12000 "12000" |
|
|
|
/* return 0 if not in sync */ |
|
int uart_send_startup(void) |
|
{ |
|
uart_reset_in_buf(); |
|
uart_send_str(UART_STR_SYNCHRONIZED "\r\n"); |
|
uart_read_more(); |
|
if ( strncmp((const char *)uart_in_buf, UART_STR_SYNCHRONIZED, strlen(UART_STR_SYNCHRONIZED)) == 0 ) |
|
{ |
|
/* yes, synchronized, send clock speed */ |
|
uart_reset_in_buf(); |
|
uart_send_str(UART_STR_12000 "\r\n"); |
|
uart_read_more(); |
|
if ( strncmp((const char *)uart_in_buf, UART_STR_12000, strlen(UART_STR_12000)) == 0 ) |
|
{ |
|
/* yes, synchronized */ |
|
return 1; |
|
} |
|
} |
|
return 0; |
|
} |
|
|
|
|
|
int uart_synchronize(int is_retry_quiet) |
|
{ |
|
if ( is_retry_quiet == 0 ) |
|
msg("send '?'"); |
|
uart_reset_in_buf(); |
|
uart_send_str("?"); |
|
uart_read_more(); |
|
|
|
if ( uart_in_pos == 0 ) |
|
{ |
|
if ( is_retry_quiet == 0 ) |
|
msg("no response"); |
|
uart_is_synchronized = 0; |
|
|
|
} |
|
else |
|
{ |
|
/* echo received, this could mean, that the device is already syncronized */ |
|
if ( uart_in_buf[0] == '?' ) |
|
{ |
|
if ( is_retry_quiet == 0 ) |
|
msg("echo received, try startup sequence"); |
|
/* the input was echoed, looks like it is synchronized */ |
|
/* to ensure proper operation, the startup sequence is repeated */ |
|
|
|
uart_is_synchronized = uart_send_startup(); |
|
} |
|
else |
|
{ |
|
/* check if the controller did response with the synchronized command */ |
|
if ( strncmp((const char *)uart_in_buf, UART_STR_SYNCHRONIZED, strlen(UART_STR_SYNCHRONIZED)) == 0 ) |
|
{ |
|
/* "Synchronized" recevied, send startup */ |
|
msg("controller synchronize request"); |
|
uart_is_synchronized = uart_send_startup(); |
|
} |
|
else |
|
{ |
|
if ( is_retry_quiet == 0 ) |
|
msg("incorrect response from controller"); |
|
uart_is_synchronized = 0; |
|
} |
|
} |
|
} |
|
if ( uart_is_synchronized != 0 ) |
|
msg("controller is in sync"); |
|
if ( is_retry_quiet == 0 ) |
|
{ |
|
if ( uart_is_synchronized == 0 ) |
|
msg("controller is NOT in sync"); |
|
} |
|
return uart_is_synchronized; |
|
} |
|
|
|
/* |
|
Read from controller memory. Result will be placed in uart_in_buf |
|
Return value contains the start index in uart_in_buf or is -1 if the read has failed |
|
*/ |
|
long uart_read_from_adr(unsigned long adr, unsigned long cnt) |
|
{ |
|
char s[32]; |
|
if ( cnt > UART_IN_BUF_LEN-64 ) |
|
return err("wrong args for read memory"), -1; |
|
sprintf(s, "R %lu %lu\r\n", adr, cnt); |
|
uart_reset_in_buf(); |
|
uart_send_str(s); |
|
uart_read_more(); |
|
if ( uart_in_pos < 3+cnt ) |
|
return err("read memory failed (too less data)"), -1; |
|
|
|
/* check for success code */ |
|
if ( uart_in_buf[uart_in_pos-cnt-3] != '0' ) |
|
return err("read memory failed (illegal return code)"), -1; |
|
|
|
//printf("read operation, uart_in_pos = %lu, result stats at %ld\n", uart_in_pos, uart_in_pos-cnt); |
|
return uart_in_pos-cnt; |
|
} |
|
|
|
/* |
|
read part number, also returned as result |
|
*/ |
|
unsigned long uart_read_part_numer(void) |
|
{ |
|
unsigned long id, i; |
|
uart_reset_in_buf(); |
|
uart_send_str("J\r\n"); |
|
uart_read_more(); |
|
if ( uart_in_pos < 5 ) |
|
return err("read part number failed (too less data)"), 0; |
|
|
|
uart_in_buf[uart_in_pos] = '\0'; |
|
|
|
/* check for success code */ |
|
i = 0; |
|
while( i < uart_in_pos ) |
|
{ |
|
if ( uart_in_buf[i] == '0' ) |
|
{ |
|
i++; |
|
while( uart_in_buf[i] == '\r' || uart_in_buf[i] == '\n') |
|
{ |
|
i++; |
|
} |
|
id = strtoul((const char *)uart_in_buf+i, NULL, 10); |
|
return id; |
|
} |
|
i++; |
|
} |
|
return err("read part number failed (illegal return code)"), 0; |
|
|
|
} |
|
|
|
|
|
/*================================================*/ |
|
/* LPC type identification */ |
|
|
|
struct _lpc_struct |
|
{ |
|
char *name; |
|
unsigned long part_id; |
|
unsigned long flash_adr; /* start address of the internal flash memory */ |
|
unsigned long flash_size; /* total size of the flash memory */ |
|
unsigned long sector_size; /* size of a sector flash_size/sector_size gives the number of sectors, sector_size must be power of 2 */ |
|
unsigned long ram_buf_adr; /* start address of the RAM buffer for writing, check manual for a suitable place */ |
|
unsigned long ram_buf_size; /* must be power of 2 and must be smaller than or equal to sector_size and bigger than one flash page */ |
|
}; |
|
typedef struct _lpc_struct lpc_struct; |
|
|
|
/* |
|
for LPC81x and LPC82x, the stack is located at 0x1000 0270 and grows downwards. |
|
LPC81x: sector size=1024 bytes, page size=64 bytes |
|
*/ |
|
|
|
lpc_struct lpc_list[] = { |
|
/* name, part_id, flash_adr, flash_size, sec_size, ram_adr, ram_size */ |
|
|
|
{"LPC824M201JHI33", 0x00008241, 0x00000000, 0x8000, 0x0400, 0x10000300, 0x0400 }, |
|
{"LPC822M201JHI33", 0x00008221, 0x00000000, 0x8000, 0x0400, 0x10000300, 0x0400 }, |
|
{"LPC824M201JDH20", 0x00008242, 0x00000000, 0x8000, 0x0400, 0x10000300, 0x0400 }, |
|
{"LPC822M201JDH20", 0x00008222, 0x00000000, 0x4000, 0x0400, 0x10000300, 0x0400 }, |
|
|
|
{"LPC810M021FN8", 0x00008100, 0x00000000, 0x1000, 0x0400, 0x10000300, 0x0100 }, |
|
{"LPC811M001JDH16", 0x00008110, 0x00000000, 0x2000, 0x0400, 0x10000300, 0x0100 }, |
|
{"LPC812M101JDH16", 0x00008120, 0x00000000, 0x4000, 0x0400, 0x10000300, 0x0100 }, |
|
{"LPC812M101JD20", 0x00008121, 0x00000000, 0x4000, 0x0400, 0x10000300, 0x0100 }, |
|
{"LPC812M101JDH20", 0x00008122, 0x00000000, 0x4000, 0x0400, 0x10000300, 0x0100 }, |
|
{"LPC812M101JTB16", 0x00008122, 0x00000000, 0x4000, 0x0400, 0x10000300, 0x0100 } |
|
|
|
|
|
|
|
}; |
|
|
|
unsigned long lpc_part_id = 0; |
|
lpc_struct *lpc_part = NULL; |
|
|
|
lpc_struct *lpc_find_by_part_id(unsigned long part_id) |
|
{ |
|
int i; |
|
for( i = 0; i < sizeof(lpc_list)/sizeof(*lpc_list); i++ ) |
|
{ |
|
if ( part_id == lpc_list[i].part_id ) |
|
return lpc_list+i; |
|
} |
|
return NULL; |
|
} |
|
|
|
/* |
|
unlock |
|
*/ |
|
int lpc_unlock(void) |
|
{ |
|
int result_code; |
|
|
|
if ( lpc_part == NULL ) |
|
return 0; |
|
|
|
uart_reset_in_buf(); |
|
uart_send_str("U 23130\r\n"); |
|
uart_read_more(); |
|
//uart_show_in_buf(); |
|
result_code = uart_get_result_code_from_buf_end(); |
|
if ( result_code != 0 ) |
|
return err("unlock failed (%d)", result_code), 0; |
|
return 1; |
|
|
|
} |
|
|
|
|
|
/* |
|
requires, that lpc_part has been set correctly |
|
*/ |
|
int lpc_prepare_sectors(unsigned long start_sector, unsigned long end_sector) |
|
{ |
|
int i; |
|
char s[32]; |
|
int result_code; |
|
|
|
if ( lpc_part == NULL ) |
|
return 0; |
|
|
|
msg("flash prepare for sector %lu-%lu (0x%08lx-0x%08lx)", |
|
start_sector, |
|
end_sector, |
|
lpc_part->flash_adr+start_sector*lpc_part->sector_size, |
|
lpc_part->flash_adr+end_sector*lpc_part->sector_size+lpc_part->sector_size-1); |
|
|
|
sprintf(s, "P %lu %lu\r\n", start_sector, end_sector); |
|
uart_reset_in_buf(); |
|
uart_send_str(s); |
|
|
|
for( i = 0; i < 4*5; i++) |
|
{ |
|
uart_read_more(); |
|
|
|
result_code = uart_get_result_code_from_buf_end(); |
|
if ( result_code > 0 ) |
|
return err("flash prepare failed (%d)", result_code), 0; |
|
else if ( result_code == 0 ) |
|
return 1; |
|
msg("flash prepare in progress (%d)", i); |
|
} |
|
return err("flash prepare timeout"), 0; |
|
|
|
//uart_show_in_buf(); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
/* |
|
requires, that lpc_part has been set correctly |
|
Also prepares sectors |
|
*/ |
|
int lpc_erase_all(void) |
|
{ |
|
int i; |
|
char s[32]; |
|
unsigned long sector_cnt; |
|
int result_code; |
|
|
|
if ( lpc_part == NULL ) |
|
return 0; |
|
|
|
sector_cnt = lpc_part->flash_size / lpc_part->sector_size; |
|
sector_cnt--; |
|
sprintf(s, "E 0 %lu\r\n", sector_cnt); |
|
|
|
lpc_prepare_sectors(0, sector_cnt); |
|
|
|
msg("flash erase"); |
|
|
|
uart_reset_in_buf(); |
|
uart_send_str(s); |
|
|
|
for( i = 0; i < 4*5; i++) |
|
{ |
|
uart_read_more(); |
|
|
|
result_code = uart_get_result_code_from_buf_end(); |
|
if ( result_code > 0 ) |
|
return err("flash erase failed (%d)", result_code), 0; |
|
else if ( result_code == 0 ) |
|
return 1; |
|
msg("flash erase in progress (%d)", i); |
|
} |
|
return err("flash erase timeout"), 0; |
|
|
|
} |
|
|
|
|
|
/* |
|
sub-proc of the download/flash/verify procedure: download data to ram |
|
the global variable lpc_part must be set for this procedure |
|
the size of the page is available in lpc_part->ram_buf_size |
|
if 'size' is smaller than lpc_part->ram_buf_size, remaining bytes are filled with "0x0ff" |
|
*/ |
|
int lpc_page_download_to_ram(unsigned long size, unsigned char *buf) |
|
{ |
|
char s[32]; |
|
int result_code; |
|
|
|
if ( lpc_part == NULL ) |
|
return 0; |
|
|
|
msg("page download to RAM"); |
|
|
|
sprintf(s, "W %lu %lu\r\n", lpc_part->ram_buf_adr, lpc_part->ram_buf_size); |
|
uart_reset_in_buf(); |
|
uart_send_str(s); |
|
uart_read_more(); |
|
result_code = uart_get_result_code_from_buf_end(); |
|
if ( result_code > 0 ) |
|
return err("page download failure (%d)", result_code), 0; |
|
|
|
uart_reset_in_buf(); |
|
|
|
if ( size < lpc_part->ram_buf_size) |
|
{ |
|
uart_send_bytes(size, buf); |
|
uart_send_cnt_bytes(lpc_part->ram_buf_size-size, 0x0ff); |
|
} |
|
else |
|
{ |
|
uart_send_bytes(lpc_part->ram_buf_size, buf); |
|
} |
|
|
|
uart_read_more(); |
|
//uart_show_in_buf(); |
|
|
|
if ( memcmp(buf, uart_in_buf,size) != 0 ) |
|
return err("page data download error"), 0; |
|
|
|
|
|
return 1; |
|
} |
|
|
|
/* |
|
compare the content at adr with the content at the ram buffer |
|
This will always compare the complete ram buffer. This is ok, because |
|
during download of the data, RAM buffer is filled with 0x0ff. |
|
Also flash procedure will always flash the complete buffer. |
|
|
|
Problem: this seems to succeed always...??? |
|
*/ |
|
int lpc_page_quick_compare(unsigned long adr) |
|
{ |
|
char s[48]; |
|
int result_code; |
|
msg("compare %lu bytes at 0x%08x", lpc_part->ram_buf_size, adr); |
|
sprintf(s, "M %lu %lu %lu\r\n", lpc_part->ram_buf_adr, adr, lpc_part->ram_buf_size); |
|
uart_reset_in_buf(); |
|
uart_send_str(s); |
|
uart_read_more(); |
|
//uart_show_in_buf(); |
|
result_code = uart_get_result_code_after_first_0x0a(); |
|
if ( result_code > 0 ) |
|
return err("compare failure (%d)", result_code), 0; |
|
return 1; |
|
} |
|
|
|
/* |
|
compare the page data (size & buf) with the data in the controller at "adr" |
|
adr can be lpc_part->ram_buf_adr or the flash rom adr. |
|
data is loaded from the controller and compared with the data at "buf". |
|
only "size" bytes are compared. |
|
|
|
0: failed or page not equal |
|
*/ |
|
int lpc_page_compare(unsigned long adr, unsigned long size, unsigned char *buf) |
|
{ |
|
char s[32]; |
|
|
|
if ( lpc_part == NULL ) |
|
return 0; |
|
|
|
msg("verify with data at 0x%08x", adr); |
|
|
|
sprintf(s, "R %lu %lu\r\n", adr, lpc_part->ram_buf_size); |
|
uart_reset_in_buf(); |
|
uart_send_str(s); |
|
uart_read_more(); |
|
|
|
if ( uart_in_pos < lpc_part->ram_buf_size ) |
|
return err("page verify failure (too less data)"), 0; |
|
|
|
if ( memcmp(buf, uart_in_buf+uart_in_pos-lpc_part->ram_buf_size,size) != 0 ) |
|
return err("page verify failed (not equal)"), 0; |
|
|
|
return 1; |
|
} |
|
|
|
/* |
|
flash the data from the controller ram into flash memory |
|
the RAM address is defined by lpc_part->ram_buf_adr |
|
the size of the RAM block is always lpc_part->ram_buf_size |
|
|
|
*/ |
|
int lpc_page_flash(unsigned long dest_adr) |
|
{ |
|
int i; |
|
char s[48]; |
|
int result_code; |
|
|
|
if ( lpc_part == NULL ) |
|
return 0; |
|
|
|
msg("flash RAM page to adr 0x%08x", dest_adr); |
|
|
|
sprintf(s, "C %lu %lu %lu\r\n", dest_adr, lpc_part->ram_buf_adr, lpc_part->ram_buf_size); |
|
uart_reset_in_buf(); |
|
uart_send_str(s); |
|
|
|
for( i = 0; i < 4*5; i++) |
|
{ |
|
uart_read_more(); |
|
|
|
result_code = uart_get_result_code_from_buf_end(); |
|
if ( result_code > 0 ) |
|
return err("page flash failed (%d)", result_code), 0; |
|
else if ( result_code == 0 ) |
|
return 1; |
|
msg("page flash in progress (%d)", i); |
|
} |
|
return err("page flash timeout"), 0; |
|
|
|
|
|
} |
|
|
|
|
|
/* |
|
write a single page (a part of a sector) |
|
page size is defined by lpc_part->ram_buf_size |
|
'size' must be smaller or equal to lpc_part->ram_buf_size |
|
if 'size' is smaller than lpc_part->ram_buf_size, remaining bytes are filled with "0x0ff" |
|
|
|
precondition: erase flash before executing this procedure |
|
*/ |
|
int lpc_page_write_flash_verify(unsigned long size, unsigned char *buf, unsigned long dest_adr) |
|
{ |
|
unsigned long sector; |
|
|
|
|
|
if ( lpc_part == NULL ) |
|
return 0; |
|
|
|
/* calculate the number of the sector, later used for the prepare command */ |
|
sector = dest_adr / lpc_part->sector_size; |
|
|
|
/* download the page (a fraction of the sector) to RAM */ |
|
if ( lpc_page_download_to_ram(size, buf) == 0 ) |
|
return 0; |
|
|
|
/* prepare the sector */ |
|
if ( lpc_prepare_sectors(sector, sector) == 0 ) |
|
return 0; |
|
|
|
/* flash the page into the prepared sector */ |
|
if ( lpc_page_flash(dest_adr) == 0 ) |
|
return 0; |
|
|
|
/* check the content of the controller RAM with the newly flashed area */ |
|
if ( lpc_page_quick_compare(dest_adr) == 0 ) |
|
return 0; |
|
|
|
/* check, whether the page has been written correctly, by reading the data back to the PC */ |
|
/* this is not required any more */ |
|
if ( lpc_page_compare(dest_adr, size, buf) == 0 ) |
|
return 0; |
|
|
|
return 1; |
|
} |
|
|
|
/* |
|
flash an ihex file |
|
*/ |
|
int lpc_flash_ihex(void) |
|
{ |
|
unsigned long page_cnt; |
|
unsigned char *buf; |
|
|
|
if ( lpc_part == NULL ) |
|
return 0; |
|
|
|
if ( lpc_erase_all() == 0 ) |
|
return 0; |
|
|
|
buf = (unsigned char *)malloc(lpc_part->ram_buf_size); |
|
if ( buf == NULL ) |
|
return err("page alloc failure"), 0; |
|
|
|
page_cnt = lpc_part->flash_size / lpc_part->ram_buf_size; |
|
|
|
while( page_cnt > 0 ) |
|
{ |
|
page_cnt--; |
|
if ( fmem_copy(lpc_part->flash_adr + page_cnt * lpc_part->ram_buf_size, lpc_part->ram_buf_size, buf) != 0 ) |
|
{ |
|
msg("flash page %03d at address 0x%08x", page_cnt, lpc_part->flash_adr + page_cnt * lpc_part->ram_buf_size); |
|
if ( lpc_page_write_flash_verify(lpc_part->ram_buf_size, buf, lpc_part->flash_adr + page_cnt * lpc_part->ram_buf_size) == 0 ) |
|
{ |
|
return free(buf), 0; |
|
} |
|
} |
|
else |
|
{ |
|
//msg("flash page %03d at address 0x%08x is skipped (no data in ihex file)", page_cnt, lpc_part->flash_adr + page_cnt * lpc_part->ram_buf_size); |
|
} |
|
} |
|
|
|
msg("success"); |
|
return 1; |
|
} |
|
|
|
void arm_calculate_vector_table_crc(void) |
|
{ |
|
int i; |
|
unsigned long crc; |
|
unsigned long vector; |
|
unsigned long adr; |
|
|
|
/* calculate the crc */ |
|
crc = 0UL; |
|
adr = 0UL; |
|
for( i = 0; i < 7; i++ ) |
|
{ |
|
vector = (unsigned long)fmem_get_byte(adr++); |
|
vector |= ((unsigned long)fmem_get_byte(adr++)) << 8; |
|
vector |= ((unsigned long)fmem_get_byte(adr++)) << 16; |
|
vector |= ((unsigned long)fmem_get_byte(adr++)) << 24; |
|
crc += vector; |
|
} |
|
crc = 0-crc; |
|
|
|
/* put found crc in vector */ |
|
vector = (unsigned long)fmem_get_byte(adr++); |
|
vector |= ((unsigned long)fmem_get_byte(adr++)) << 8; |
|
vector |= ((unsigned long)fmem_get_byte(adr++)) << 16; |
|
vector |= ((unsigned long)fmem_get_byte(adr++)) << 24; |
|
|
|
msg("LPC crc calculated = 0x%08lx, crc found = 0x%08lx", crc, vector); |
|
|
|
/* overwrite crc in the ihex file */ |
|
adr = 7*4; |
|
fmem_set_byte(adr++, (crc>>0) & 255); |
|
fmem_set_byte(adr++, (crc>>8) & 255); |
|
fmem_set_byte(adr++, (crc>>16) & 255); |
|
fmem_set_byte(adr++, (crc>>24) & 255); |
|
} |
|
|
|
unsigned long arm_get_reset_vector(void) |
|
{ |
|
unsigned long vector; |
|
unsigned long adr = 0x04; |
|
|
|
vector = (unsigned long)fmem_get_byte(adr++); |
|
vector |= ((unsigned long)fmem_get_byte(adr++)) << 8; |
|
vector |= ((unsigned long)fmem_get_byte(adr++)) << 16; |
|
vector |= ((unsigned long)fmem_get_byte(adr++)) << 24; |
|
|
|
vector &= 0x0fffffffe; |
|
|
|
return vector; |
|
} |
|
|
|
/* |
|
execute reset handler |
|
*/ |
|
int lpc_exec_reset(void) |
|
{ |
|
int result_code; |
|
unsigned long reset_vector; |
|
char s[32]; |
|
|
|
if ( lpc_part == NULL ) |
|
return 0; |
|
|
|
reset_vector = arm_get_reset_vector(); |
|
msg("execute reset handler at 0x%08x", reset_vector); |
|
sprintf(s, "G %lu T\r\n", reset_vector); |
|
uart_reset_in_buf(); |
|
uart_send_str(s); |
|
uart_read_more(); |
|
//uart_show_in_buf(); |
|
result_code = uart_get_result_code_from_buf_end(); |
|
if ( result_code > 0 ) |
|
return err("exec reset handler failed (%d)", result_code), 0; |
|
return 1; |
|
|
|
} |
|
|
|
|
|
int lpc_load_and_flash_ihex(const char *ihex_name) |
|
{ |
|
if ( ihex_name == NULL ) |
|
{ |
|
return err("no ihex file"), 0; |
|
} |
|
|
|
if ( ihex_name[0] == '\0' ) |
|
{ |
|
return err("no ihex file"), 0; |
|
} |
|
|
|
|
|
if ( ihex_read_file(ihex_name) == 0 ) |
|
{ |
|
return err("ihex file read error"), 0; |
|
} |
|
|
|
arm_calculate_vector_table_crc(); |
|
|
|
lpc_unlock(); |
|
|
|
return lpc_flash_ihex(); |
|
} |
|
|
|
|
|
/*================================================*/ |
|
/* commandline parser and main procedure */ |
|
|
|
int get_str_arg(char ***argv, int c, char **result) |
|
{ |
|
if ( (**argv)[0] == '-' ) |
|
{ |
|
if ( (**argv)[1] == c ) |
|
{ |
|
if ( (**argv)[2] == '\0' ) |
|
{ |
|
(*argv)++; |
|
*result = **argv; |
|
} |
|
else |
|
{ |
|
*result = (**argv)+2; |
|
} |
|
(*argv)++; |
|
return 1; |
|
} |
|
} |
|
return 0; |
|
} |
|
|
|
|
|
int get_num_arg(char ***argv, int c, unsigned long *result) |
|
{ |
|
if ( (**argv)[0] == '-' ) |
|
{ |
|
if ( (**argv)[1] == c ) |
|
{ |
|
if ( (**argv)[2] == '\0' ) |
|
{ |
|
(*argv)++; |
|
*result = strtoul((**argv), NULL, 10); |
|
} |
|
else |
|
{ |
|
*result = strtoul((**argv)+2, NULL, 10); |
|
} |
|
(*argv)++; |
|
return 1; |
|
} |
|
} |
|
return 0; |
|
} |
|
|
|
int is_arg(char ***argv, int c) |
|
{ |
|
if ( (**argv)[0] == '-' ) |
|
{ |
|
if ( (**argv)[1] == c ) |
|
{ |
|
(*argv)++; |
|
return 1; |
|
} |
|
} |
|
return 0; |
|
} |
|
|
|
/*================================================*/ |
|
void help(void) |
|
{ |
|
printf("-h Display this help\n"); |
|
printf("-f <file> Load data from intel hex <file>\n"); |
|
printf("-x Execute ARM reset handler after upload\n"); |
|
printf(" Note: Reset handler must set the stack pointer and restore SYSMEMREMAP\n"); |
|
printf("-p <port> Use UART at <port> (default: '/dev/ttyUSB0')\n"); |
|
printf("-s <n> Set UART transfer speed, 0=9600 (default), 1=19200, 2=57600\n"); |
|
} |
|
|
|
/*================================================*/ |
|
/* main */ |
|
|
|
int main(int argc, char **argv) |
|
{ |
|
unsigned long speed = 0; |
|
int baud = B9600; |
|
int is_execute = 0; |
|
|
|
char *file = ""; |
|
char *port = "/dev/ttyUSB0"; |
|
|
|
argv++; |
|
/* |
|
if ( *argv == NULL ) |
|
{ |
|
help(); |
|
exit(1); |
|
} |
|
*/ |
|
for(;;) |
|
{ |
|
if ( *argv == NULL ) |
|
break; |
|
if ( is_arg(&argv, 'h') != 0 ) |
|
{ |
|
help(); |
|
exit(1); |
|
} |
|
else if ( is_arg(&argv, 'x') != 0 ) |
|
{ |
|
is_execute = 1; |
|
} |
|
else if ( get_num_arg(&argv, 's', &speed) != 0 ) |
|
{ |
|
} |
|
else if ( get_str_arg(&argv, 'f', &file) != 0 ) |
|
{ |
|
} |
|
else if ( get_str_arg(&argv, 'p', &port) != 0 ) |
|
{ |
|
} |
|
else |
|
{ |
|
help(); |
|
exit(1); |
|
} |
|
} |
|
|
|
|
|
switch(speed) |
|
{ |
|
default: |
|
case 0: baud = B9600; break; |
|
case 1: baud = B19200; break; |
|
case 2: baud = B57600; break; |
|
} |
|
|
|
//fmem_show(); |
|
if ( uart_open(port, baud) == 0 ) |
|
{ |
|
for(;;) |
|
{ |
|
msg("please connect controller to USB port, retry..."); |
|
sleep(2); |
|
if ( uart_open(port, baud) != 0 ) |
|
break; |
|
} |
|
} |
|
|
|
if ( uart_synchronize(0) == 0 ) |
|
{ |
|
for(;;) |
|
{ |
|
msg("please put controller into UART ISP mode, retry..."); |
|
if ( uart_synchronize(1) != 0 ) |
|
break; |
|
} |
|
} |
|
|
|
/* read part number */ |
|
lpc_part_id = uart_read_part_numer(); |
|
msg("received part id 0x%08x", lpc_part_id); |
|
|
|
/* check if the part number is known */ |
|
lpc_part = lpc_find_by_part_id(lpc_part_id); |
|
if ( lpc_part == NULL ) |
|
{ |
|
err("unknown controller"); |
|
return 0; |
|
} |
|
|
|
msg("controller %s with %lu bytes flash memory", lpc_part->name, lpc_part->flash_size); |
|
|
|
if ( lpc_load_and_flash_ihex(file) == 0 ) /* unlock, erase and flash procedure */ |
|
return 0; |
|
|
|
if ( is_execute != 0 ) |
|
lpc_exec_reset(); |
|
|
|
return 0; |
|
} |
|
|
|
|
|
|
|
|
|
|