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.
1589 lines
35 KiB
1589 lines
35 KiB
6 years ago
|
/*
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|