From 66d091317a4f8e48a8c2e42be48786e0da6141c1 Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Sun, 30 Dec 2012 23:29:24 -0300 Subject: [PATCH] lpc111x-isp/lpc111x.c: if file argument is given, flash that file --- lpc111x-isp/lpc111x.c | 187 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 181 insertions(+), 6 deletions(-) diff --git a/lpc111x-isp/lpc111x.c b/lpc111x-isp/lpc111x.c index 4d35f3b..867dd9e 100644 --- a/lpc111x-isp/lpc111x.c +++ b/lpc111x-isp/lpc111x.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include @@ -31,11 +33,26 @@ #define HOST_RX TGT_TX #define HOST_TX TGT_RX +#define BPS 115200 + #define MAX_BUF 10000 /* receive buffer */ -#define MAX_RECORD 45 /* data bytes per uuencoded record */ + #define AUTOBAUD_TRIES 10 #define SYNC "Synchronized" +#define MAX_RECORD 45 /* data bytes per uuencoded record */ + +/* + * UM 26.4.8 pg 416 says 0x1000017C to 0x1000025B and the last 256+32 bytes + * of the RAM are taken. + * + * UM 26.5.4 pg 418 hints 0x10000300 is a good place. + */ + +#define RAM_BUFFER 0x10000300 +#define SECTOR 4096 +#define PAGE 256 + static int verbose = 0; static int quiet = 0; @@ -170,7 +187,9 @@ static const char *dialog_rc(int idle, const char *cmd, ...) va_end(ap); p = strchr(res, '\n'); - if (!p || sscanf(res, "%u", &rc) != 1) { + if (!p) + p = strchr(res, 0); + if (sscanf(res, "%u", &rc) != 1) { fprintf(stderr, "invalid status\n"); exit(1); } @@ -257,10 +276,151 @@ static void identify(void) } +/* ----- Flash programming ------------------------------------------------- */ + + +static int ms_to_bits(int ms) +{ + return (BPS*ms+999)/1000; +} + + +static char uuechar(uint8_t b) +{ + b &= 0x3f; + return b ? b+32 : 0x60; +} + + +static const char *uuencode(const uint8_t *p, int len) +{ + static char buf[80]; + char *t = buf; + const uint8_t *end = p+len; + unsigned tmp = 0; /* initialize to prevent compiler complaints */ + int i; + + *t++ = len+32; + while (p != end) { + for (i = 0; i != 3; i++) + if (p == end) + tmp <<= 8; + else + tmp = tmp << 8 | *p++; + *t++ = uuechar(tmp >> 18); + *t++ = uuechar(tmp >> 12); + *t++ = uuechar(tmp >> 6); + *t++ = uuechar(tmp); + } + *t = 0; + return buf; +} + + +static void flash_erase_sectors(unsigned addr, unsigned len) +{ + unsigned from = addr/SECTOR; + unsigned to = (addr+len-1)/SECTOR; + + assert(!(addr & (SECTOR-1))); + assert(!(len & (SECTOR-1))); + + dialog_rc(100, "P %d %d", from, to); + + /* DS 10.2 pg 77: t_er(max) = 105 ms */ + dialog_rc(ms_to_bits(200), "E %d %d", from, to); +} + + +static void flash_write_page(unsigned addr, const uint8_t *buf) +{ + unsigned sector = addr/SECTOR; + unsigned sum; + int chunk, i; + const char *res; + + assert(!(addr & (PAGE-1))); + + dialog_rc(100, "W %u %u", RAM_BUFFER, PAGE); + for (i = 0; i != PAGE; i += chunk) { + chunk = PAGE-i > MAX_RECORD ? MAX_RECORD : PAGE-i; + dialog(100, "%s", uuencode(buf+i, chunk)); + } + + sum = 0; + for (i = 0; i != PAGE; i++) + sum += buf[i]; + + res = dialog(100, "%u", sum); + if (strcmp(res, "OK")) { + fprintf(stderr, "non-OK response: \"%s\"\n", res); + exit(1); + } + + dialog_rc(100, "P %d %d", sector, sector); + + /* DS 10.2 pg 77: t_prog(max) = 1.05 ms */ + dialog_rc(ms_to_bits(2), "C %d %u %d", addr, RAM_BUFFER, PAGE); +} + + +static void flash_write(unsigned addr, const uint8_t *p, int len, + int erase_all) +{ + uint8_t page[PAGE]; + + assert(!(addr & (PAGE-1))); + + dialog_rc(100, "U 23130"); + if (erase_all) + flash_erase_sectors(0, device->flash_kb << 10); + else + flash_erase_sectors(addr & ~(SECTOR-1), + (addr+len+SECTOR-1) & ~(SECTOR-1)); + while (len > 0) { + if (len < PAGE) { + memcpy(page, p, len); + memset(page+len, 0xff, PAGE-len); + } else { + memcpy(page, p, PAGE); + p += PAGE; + } + flash_write_page(addr, page); + addr += PAGE; + len -= PAGE; + } +} + + +static void flash_file(FILE *file) +{ + uint8_t buf[(device->flash_kb << 10)+1]; + size_t got; + + got = fread(buf, 1, sizeof(buf), file); + if (!got) { + if (ferror(file)) + perror("fread"); + else + fprintf(stderr, "file is empty\n"); + exit(1); + } + if (got > device->flash_kb << 10) { + fprintf(stderr, "file is larger than flash (%d kB)\n", + device->flash_kb); + exit(1); + } + flash_write(0, buf, got, 1); +} + + /* ----- Flash dump -------------------------------------------------------- */ -/* AN11229 */ +/* + * The uuencoding algorithm is described in AN11229. + * It's the same as used by uuencode. + */ static uint8_t uudchar(char c) @@ -388,7 +548,7 @@ static void start_isp(int power) CLR(TGT_nISP); OUT(TGT_nISP); - swuart_open(HOST_TX, HOST_RX, 115200); + swuart_open(HOST_TX, HOST_RX, BPS); if (!autobaud()) { fprintf(stderr, "target is not responding\n"); @@ -409,7 +569,7 @@ static void start_isp(int power) static void usage(const char *name) { fprintf(stderr, -"usage: %s [-n] [-q] [-v ...]\n\n" +"usage: %s [-n] [-q] [-v ...] [file.bin]\n\n" " -n don't power the device\n" " -q suppress basic progress messages\n" " -v increase verbosity level\n" @@ -420,6 +580,7 @@ static void usage(const char *name) int main(int argc, char **argv) { + FILE *file = NULL; int power = 1; int c; @@ -441,6 +602,17 @@ int main(int argc, char **argv) switch (argc-optind) { case 0: break; + case 1: + if (!strcmp(argv[optind], "-")) + file = stdin; + else { + file = fopen(argv[optind], "r"); + if (!file) { + perror(argv[optind]); + exit(1); + } + } + break; default: usage(*argv); } @@ -449,7 +621,10 @@ int main(int argc, char **argv) identify(); - dump(); + if (file) + flash_file(file); + else + dump(); return 0; }