Root/lpc111x-isp/lpc111x.c

1/*
2 * lpc111x-isp/lpc111x.c - LPC111x/LPC11Cxx ISP programmer
3 *
4 * Written 2012 by Werner Almesberger
5 * Copyright 2012 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#define _GNU_SOURCE /* for vasprintf */
15#include <stdarg.h>
16#include <stdlib.h>
17#include <stdio.h>
18#include <unistd.h>
19#include <string.h>
20#include <strings.h> /* for strcasecmp, strncasecmp */
21#include <alloca.h>
22#include <assert.h>
23#include <sys/types.h>
24
25#include <ubb/ubb.h>
26#include <ubb/swuart.h>
27
28
29#define BPS 115200
30
31#define MAX_BUF 10000 /* receive buffer */
32
33#define AUTOBAUD_TRIES 10
34#define SYNC "Synchronized"
35
36#define MAX_RECORD 45 /* data bytes per uuencoded record */
37
38/*
39 * UM 26.4.8 pg 416 says 0x1000017C to 0x1000025B and the last 256+32 bytes
40 * of the RAM are taken.
41 *
42 * UM 26.5.4 pg 418 hints 0x10000300 is a good place.
43 */
44
45#define RAM_BUFFER 0x10000300
46#define SECTOR 4096
47#define PAGE 256
48
49
50enum {
51    pin_rxd, /* RXD pin on the device (PIO1_6) */
52    pin_txd, /* TXD pin on the device (PIO1_7) */
53    pin_nisp, /* nISP: ISP mode selection (PIO0_1) */
54    pin_nreset, /* nRESET pin (PIO0_0) */
55    pin_end /* last value */
56};
57
58static struct pin {
59    const char *name;
60    const char *alt_name;
61    uint32_t pin;
62} pins[] = {
63    [pin_rxd] = { "RXD", "P1_6", UBB_DAT2 },
64    [pin_txd] = { "TXD", "P1_7", UBB_DAT3 },
65    [pin_nisp] = { "nISP", "P0_1", UBB_DAT1 },
66    [pin_nreset] = { "nRESET", "P0_0", UBB_CMD },
67    [pin_end] = { NULL }
68};
69
70static const struct signal {
71    const char *name;
72    uint32_t pin;
73} signals[] = {
74    { "CMD", UBB_CMD },
75    { "CLK", UBB_CLK },
76    { "DAT0", UBB_DAT0 },
77    { "DAT1", UBB_DAT1 },
78    { "DAT2", UBB_DAT2 },
79    { "DAT3", UBB_DAT3 },
80    { NULL }
81};
82
83static int verbose = 0;
84static int quiet = 0;
85
86
87/* ----- Debugging and tracing --------------------------------------------- */
88
89
90static void trace(const char *label, const uint8_t *s, int len)
91{
92    const uint8_t *end = s+len;
93
94    if (label)
95        fprintf(stderr, "%s ", label);
96    for (end = s+len; s != end; s++) {
97        if (*s >= ' ' && *s <= '~')
98            fprintf(stderr, "%c", *s);
99        else if (*s == 10)
100            fprintf(stderr, "\\n");
101        else if (*s == 13)
102            fprintf(stderr, "\\r");
103        else
104            fprintf(stderr, "\\%02o", *s);
105    }
106    fprintf(stderr, "\n");
107}
108
109
110static void trace_out(const void *s, int len)
111{
112    trace(">>>", s, len);
113}
114
115
116static void trace_in(const void *s, int len)
117{
118    trace("<<<", s, len);
119}
120
121
122/* ----- Dialog functions -------------------------------------------------- */
123
124
125static const char *dialog_fixed(int idle, const char *msg)
126{
127    static char *res = NULL;
128    int msg_len = strlen(msg);
129    char *tx_buf = alloca(msg_len+3);
130    char *rx_buf = alloca(MAX_BUF);
131    char *s, *t;
132    int got;
133
134    memcpy(tx_buf, msg, msg_len);
135    memcpy(tx_buf+msg_len, "\r\n", 2);
136
137    if (verbose)
138        trace_out(tx_buf, msg_len+2);
139    got = swuart_trx(tx_buf, msg_len+2, rx_buf, MAX_BUF, idle, idle);
140    if (verbose)
141        trace_in(rx_buf, got);
142
143    if (got < msg_len+2) {
144        fprintf(stderr, "response too short for echo\n");
145        exit(1);
146    }
147    if (memcmp(rx_buf, msg, msg_len) ||
148        rx_buf[msg_len] != '\r' || rx_buf[msg_len+1] != '\n') {
149        fprintf(stderr, "echo mismatch\n");
150        exit(1);
151    }
152
153    if (memchr(rx_buf, 0, got)) {
154        fprintf(stderr, "NUL in response\n");
155        exit(1);
156    }
157
158    rx_buf += msg_len+2;
159    got -= msg_len+2;
160
161    res = realloc(res, got+1);
162    if (!res) {
163        perror("realloc");
164        exit(1);
165    }
166
167    t = res;
168    for (s = rx_buf; s != rx_buf+got; s++) {
169        if (*s == '\r') {
170            if (s+1 != rx_buf+got && s[1] == '\n')
171                continue;
172            fprintf(stderr, "\\r without \\n\n");
173            exit(1);
174        }
175        if (*s == '\n' && s+1 == rx_buf+got)
176            break;
177        *t++ = *s;
178    }
179    *t = 0;
180
181    return res;
182}
183
184
185static const char *vdialog(int idle, const char *cmd, va_list ap)
186{
187    char *msg;
188
189    vasprintf(&msg, cmd, ap);
190    return dialog_fixed(idle, msg);
191}
192
193
194static const char *dialog(int idle, const char *cmd, ...)
195{
196    va_list ap;
197    const char *res;
198
199    va_start(ap, cmd);
200    res = vdialog(idle, cmd, ap);
201    va_end(ap);
202    return res;
203}
204
205
206static const char *dialog_rc(int idle, const char *cmd, ...)
207{
208    va_list ap;
209    const char *res, *p;
210    unsigned rc;
211
212    va_start(ap, cmd);
213    res = vdialog(idle, cmd, ap);
214    va_end(ap);
215
216    p = strchr(res, '\n');
217    if (!p)
218        p = strchr(res, 0);
219    if (sscanf(res, "%u", &rc) != 1) {
220        fprintf(stderr, "invalid status\n");
221        exit(1);
222    }
223
224    if (rc != 0) {
225        fprintf(stderr, "rc %d\n", rc);
226        exit(1);
227    }
228
229    return p+1;
230}
231
232
233static int autobaud(void)
234{
235    uint8_t reply[100];
236    int i, got;
237    const char *res;
238
239    for (i = 0; i != AUTOBAUD_TRIES; i++) {
240        CLR(pins[pin_nreset].pin);
241        usleep(10); /* DS Table 9 pg 29 says min 50 ns */
242        SET(pins[pin_nreset].pin);
243
244        usleep(5*1000); /* UM 26.3.1 pg 408 says max 3 ms */
245
246        got = swuart_trx("?", 1, reply, sizeof(reply), 1000, 100);
247        if (got != strlen(SYNC)+2 || memcmp(reply, SYNC "\r\n", got))
248            continue;
249
250        res = dialog(100, SYNC);
251
252        if (!strcmp(res, "OK"))
253            return 1;
254    }
255    return 0;
256}
257
258
259/* ----- Devices database -------------------------------------------------- */
260
261
262static const struct device {
263    const char *name;
264    unsigned id;
265    int flash_kb;
266} devices[] = {
267    { "LPC1112FHxxx/202", 0x2524902b, 16 },
268    { NULL, }
269}, *device = NULL;
270
271
272static void identify(void)
273{
274    const char *res;
275    unsigned id, serial[4];
276
277    res = dialog_rc(100, "J");
278    if (sscanf(res, "%u", &id) != 1) {
279        fprintf(stderr, "J: cannot parse ID \"%s\"\n", res);
280        exit(1);
281    }
282
283    res = dialog_rc(100, "N");
284    if (sscanf(res, "%u %u %u %u",
285        serial, serial+1, serial+2, serial+3) != 4) {
286        fprintf(stderr, "N: cannot parse serial number\"%s\"\n", res);
287        exit(1);
288    }
289
290    for (device = devices; device->name; device++)
291        if (device->id == id) {
292            if (!quiet)
293                fprintf(stderr, "%s (0x%04x %04x) %d kB "
294                    "serial %08x.%08x.%08x.%08x\n",
295                    device->name, id >> 16, id & 0xffff,
296                    device->flash_kb,
297                    serial[0], serial[1], serial[2], serial[3]);
298            return;
299        }
300
301    fprintf(stderr, "unknown device 0x%04x %04x\n", id >> 16, id & 0xffff);
302    exit(1);
303}
304
305
306/* ----- Flash programming ------------------------------------------------- */
307
308
309static int ms_to_bits(int ms)
310{
311    return (BPS*ms+999)/1000;
312}
313
314
315static char uuechar(uint8_t b)
316{
317    b &= 0x3f;
318    return b ? b+32 : 0x60;
319}
320
321
322static const char *uuencode(const uint8_t *p, int len)
323{
324    static char buf[80];
325    char *t = buf;
326    const uint8_t *end = p+len;
327    unsigned tmp = 0; /* initialize to prevent compiler complaints */
328    int i;
329
330    *t++ = len+32;
331    while (p != end) {
332        for (i = 0; i != 3; i++)
333            if (p == end)
334                tmp <<= 8;
335            else
336                tmp = tmp << 8 | *p++;
337        *t++ = uuechar(tmp >> 18);
338        *t++ = uuechar(tmp >> 12);
339        *t++ = uuechar(tmp >> 6);
340        *t++ = uuechar(tmp);
341    }
342    *t = 0;
343    return buf;
344}
345
346
347static void flash_erase_sectors(unsigned addr, unsigned len)
348{
349    unsigned from = addr/SECTOR;
350    unsigned to = (addr+len-1)/SECTOR;
351
352    assert(!(addr & (SECTOR-1)));
353    assert(!(len & (SECTOR-1)));
354
355    dialog_rc(100, "P %d %d", from, to);
356
357    /* DS 10.2 pg 77: t_er(max) = 105 ms */
358    dialog_rc(ms_to_bits(200), "E %d %d", from, to);
359}
360
361
362static void flash_write_page(unsigned addr, const uint8_t *buf)
363{
364    unsigned sector = addr/SECTOR;
365    unsigned sum;
366    int chunk, i;
367    const char *res;
368
369    assert(!(addr & (PAGE-1)));
370
371    dialog_rc(100, "W %u %u", RAM_BUFFER, PAGE);
372    for (i = 0; i != PAGE; i += chunk) {
373        chunk = PAGE-i > MAX_RECORD ? MAX_RECORD : PAGE-i;
374        dialog(100, "%s", uuencode(buf+i, chunk));
375    }
376
377    sum = 0;
378    for (i = 0; i != PAGE; i++)
379        sum += buf[i];
380
381    res = dialog(100, "%u", sum);
382    if (strcmp(res, "OK")) {
383        fprintf(stderr, "non-OK response: \"%s\"\n", res);
384        exit(1);
385    }
386
387    dialog_rc(100, "P %d %d", sector, sector);
388
389    /* DS 10.2 pg 77: t_prog(max) = 1.05 ms */
390    dialog_rc(ms_to_bits(2), "C %d %u %d", addr, RAM_BUFFER, PAGE);
391}
392
393
394static void flash_write(unsigned addr, const uint8_t *p, int len,
395    int erase_all)
396{
397    uint8_t page[PAGE];
398
399    assert(!(addr & (PAGE-1)));
400
401    dialog_rc(100, "U 23130");
402    if (erase_all)
403        flash_erase_sectors(0, device->flash_kb << 10);
404    else
405        flash_erase_sectors(addr & ~(SECTOR-1),
406            (addr+len+SECTOR-1) & ~(SECTOR-1));
407    while (len > 0) {
408        if (len < PAGE) {
409            memcpy(page, p, len);
410            memset(page+len, 0xff, PAGE-len);
411        } else {
412            memcpy(page, p, PAGE);
413            p += PAGE;
414        }
415        flash_write_page(addr, page);
416        addr += PAGE;
417        len -= PAGE;
418    }
419}
420
421
422static void flash_file(FILE *file)
423{
424    uint8_t buf[(device->flash_kb << 10)+1];
425    size_t got;
426
427    got = fread(buf, 1, sizeof(buf), file);
428    if (!got) {
429        if (ferror(file))
430            perror("fread");
431        else
432            fprintf(stderr, "file is empty\n");
433        exit(1);
434    }
435    if (got > device->flash_kb << 10) {
436        fprintf(stderr, "file is larger than flash (%d kB)\n",
437            device->flash_kb);
438        exit(1);
439    }
440    flash_write(0, buf, got, 1);
441}
442
443
444/* ----- Flash dump -------------------------------------------------------- */
445
446
447/*
448 * The uuencoding algorithm is described in AN11229.
449 * It's the same as used by uuencode.
450 */
451
452
453static uint8_t uudchar(char c)
454{
455    if (c <= 0x20 && c > 0x60) {
456        fprintf(stderr, "invalid UU character '%c'\n", c);
457        exit(1);
458    }
459    return c == 0x60 ? 0 : c-32;
460}
461
462
463static int uudecode(const char *s, uint8_t *buf)
464{
465    int len, uu_len;
466    const char *nl;
467    const uint8_t *end;
468
469    len = *s-32;
470    if (len < 0 || len > MAX_RECORD) {
471        fprintf(stderr, "invalid UU length (%d)\n", len);
472        exit(1);
473    }
474    nl = strchr(++s, '\n');
475    if (!nl) {
476        fprintf(stderr, "no \\n at end of UU record\n");
477        exit(1);
478    }
479    uu_len = nl-s;
480    if (uu_len & 3) {
481        fprintf(stderr, "UU length %d not a multiple of 4\n", uu_len);
482        exit(1);
483    }
484    if ((len+2)/3 != uu_len/4) {
485        fprintf(stderr, "UU length %d vs. %d bytes (\"%.*s\")\n",
486            uu_len, len, nl-s+1, s-1);
487        exit(1);
488    }
489
490    end = buf+len;
491    while (buf != end) {
492        unsigned tmp = uudchar(s[0]) << 18 | uudchar(s[1]) << 12 |
493            uudchar(s[2]) << 6 | uudchar(s[3]);
494
495        *buf++ = tmp >> 16;
496        if (buf != end)
497            *buf++ = tmp >> 8;
498        if (buf != end)
499            *buf++ = tmp;
500        s += 4;
501    }
502    return len;
503}
504
505
506static void dump(void)
507{
508    int addr = 0, end;
509    unsigned sum = 0, check;
510    const char *res, *nl;
511    int got, wrote, i;
512
513    end = device->flash_kb << 10;
514    res = dialog_rc(100, "R 0 %u", end);
515    while (addr != end) {
516        while (1) {
517            uint8_t buf[MAX_RECORD];
518
519            nl = strchr(res, '\n');
520            if (!nl)
521                break;
522            got = uudecode(res, buf);
523            for (i = 0; i != got; i++)
524                sum += buf[i];
525            wrote = fwrite(buf, 1, got, stdout);
526            if (wrote != got) {
527                perror("fwrite");
528                exit(1);
529            }
530            addr += got;
531            res = nl+1;
532        }
533        if (sscanf(res, "%u", &check) != 1) {
534            fprintf(stderr, "can't parse checksum \"%s\"\n", res);
535            exit(1);
536        }
537        if (check != sum) {
538            fprintf(stderr, "checksum error: got %u received %u\n",
539                sum, check);
540            exit(1);
541        }
542        res = dialog(100, "OK");
543        sum = 0;
544    }
545}
546
547
548/* ----- ISP session ------------------------------------------------------- */
549
550
551static void at_exit(void)
552{
553    ubb_close(0);
554}
555
556
557static void start_isp(int power)
558{
559    const char *res;
560
561    if (ubb_open(0) < 0) {
562        perror("ubb_open");
563        exit(1);
564    }
565    atexit(at_exit);
566
567    if (power)
568        ubb_power(1);
569
570    usleep(100*1000);
571
572    SET(pins[pin_nreset].pin);
573    OUT(pins[pin_nreset].pin);
574
575    CLR(pins[pin_nisp].pin);
576    OUT(pins[pin_nisp].pin);
577
578    if (swuart_open(pins[pin_rxd].pin, pins[pin_txd].pin, BPS) < 0) {
579        perror("swuart_open");
580        exit(1);
581    }
582
583    if (!autobaud()) {
584        fprintf(stderr, "target is not responding\n");
585        exit(1);
586    }
587
588    res = dialog(100, "12000");
589    if (strcmp(res, "OK")) {
590        fprintf(stderr, "cannot set clock rate\n");
591        exit(1);
592    }
593}
594
595
596/* ----- Reset and run target ---------------------------------------------- */
597
598
599static void run_target(int power)
600{
601    if (ubb_open(0) < 0) {
602        perror("ubb_open");
603        exit(1);
604    }
605
606    if (power)
607        ubb_power(1);
608
609    SET(pins[pin_nreset].pin);
610    OUT(pins[pin_nreset].pin);
611
612    IN(pins[pin_nisp].pin);
613
614    CLR(pins[pin_nreset].pin);
615    usleep(10); /* DS Table 9 pg 29 says min 50 ns */
616    SET(pins[pin_nreset].pin);
617
618    ubb_close(UBB_nPWR | pins[pin_nreset].pin | pins[pin_nisp].pin);
619}
620
621
622/* ----- Command-line processing ------------------------------------------- */
623
624
625static void usage(const char *name)
626{
627    const struct signal *signal;
628    int i;
629
630    fprintf(stderr,
631"usage: %s [-P function=signal ...] [-n] [-q] [-v ...] [file.bin]\n"
632" %s [-P function=signal ...] [-n] -r\n\n"
633" -n don't power the device\n"
634" -q suppress basic progress messages\n"
635" -P function=signal assign a 8:10 interface signal to a function "
636  "(see below)\n"
637" -r reset the target and let it run\n"
638" -v increase verbosity level\n\n"
639"Functions: RXD (P1_6), TXD (P1_7), nISP (P0_1), nRESET (P0_0)\n"
640"Signals: CMD, CLK, DAT0, DAT1, DAT2, DAT3\n"
641    , name, name);
642
643    fprintf(stderr, "Default mapping:");
644    for (i = 0; i != pin_end; i++) {
645        for (signal = signals; signal->pin != pins[i].pin; signal++);
646        fprintf(stderr, " -P %s=%s", pins[i].name, signal->name);
647    }
648    fprintf(stderr, "\n");
649    exit(1);
650}
651
652
653static void assign_pin(const char *name, const char *s)
654{
655    const char *eq;
656    struct pin *pin;
657    const struct signal *signal;
658
659    eq = strchr(s, '=');
660    if (!eq)
661        usage(name);
662
663    for (pin = pins; pin->name; pin++) {
664        if (strlen(pin->name) == eq-s &&
665            !strncasecmp(pin->name, s, eq-s))
666            break;
667        if (strlen(pin->alt_name) == eq-s &&
668            !strncasecmp(pin->alt_name, s, eq-s))
669            break;
670    }
671    if (!pin->name) {
672        fprintf(stderr, "unknown function \"%.*s\"\n", eq-s, s);
673        exit(1);
674    }
675
676    for (signal = signals; signal->name; signal++)
677        if (!strcasecmp(signal->name, eq+1))
678            break;
679    if (!signal->name) {
680        fprintf(stderr, "unknown signal \"%s\"\n", eq+1);
681        exit(1);
682    }
683
684    pin->pin = signal->pin;
685}
686
687
688int main(int argc, char **argv)
689{
690    FILE *file = NULL;
691    int power = 1;
692    int run = 0;
693    int c;
694
695    while ((c = getopt(argc, argv, "nP:qrv")) != EOF)
696        switch (c) {
697        case 'n':
698            power = 0;
699            break;
700        case 'P':
701            assign_pin(*argv, optarg);
702            break;
703        case 'q':
704            quiet = 1;
705            break;
706        case 'r':
707            run = 1;
708            break;
709        case 'v':
710            verbose++;
711            break;
712        default:
713            usage(*argv);
714        }
715
716    if (run) {
717        if (quiet || verbose || argc != optind)
718            usage(*argv);
719        run_target(power);
720        return 0;
721    }
722
723    switch (argc-optind) {
724    case 0:
725        break;
726    case 1:
727        if (!strcmp(argv[optind], "-"))
728            file = stdin;
729        else {
730            file = fopen(argv[optind], "r");
731            if (!file) {
732                perror(argv[optind]);
733                exit(1);
734            }
735        }
736        break;
737    default:
738        usage(*argv);
739    }
740
741    start_isp(power);
742
743    identify();
744
745    if (file)
746        flash_file(file);
747    else
748        dump();
749
750    return 0;
751}
752

Archive Download this file

Branches:
master



interactive