Better implementation of FET command protocol.

This commit is contained in:
Daniel Beer 2010-01-03 16:00:05 +13:00
parent ce5b4c7940
commit ec5c61e9c9
1 changed files with 174 additions and 177 deletions

351
fet.c
View File

@ -25,6 +25,51 @@
static const struct fet_transport *fet_transport; static const struct fet_transport *fet_transport;
static int fet_is_rf2500; static int fet_is_rf2500;
static int fet_breakpoint_enable;
/**********************************************************************
* FET command codes.
*
* These come from fet430uif by Robert Kavaler (kavaler@diva.com).
* www.relavak.com
*/
#define C_INITIALIZE 1
#define C_CLOSE 2
#define C_IDENTIFY 3
#define C_DEVICE 4
#define C_CONFIGURE 5
#define C_VCC 6
#define C_RESET 7
#define C_READREGISTERS 8
#define C_WRITEREGISTERS 9
#define C_READREGISTER 10
#define C_WRITEREGISTER 11
#define C_ERASE 12
#define C_READMEMORY 13
#define C_WRITEMEMORY 14
#define C_FASTFLASHER 15
#define C_BREAKPOINT 16
#define C_RUN 17
#define C_STATE 18
#define C_SECURE 19
#define C_VERIFYMEMORY 20
#define C_FASTVERIFYMEMORY 21
#define C_ERASECHECK 22
#define C_EEMOPEN 23
#define C_EEMREADREGISTER 24
#define C_EEMREADREGISTERTEST 25
#define C_EEMWRITEREGISTER 26
#define C_EEMCLOSE 27
#define C_ERRORNUMBER 28
#define C_GETCURVCCT 29
#define C_GETEXTVOLTAGE 30
#define C_FETSELFTEST 31
#define C_FETSETSIGNALS 32
#define C_FETRESET 33
#define C_READI2C 34
#define C_WRITEI2C 35
#define C_ENTERBOOTLOADER 36
/********************************************************************* /*********************************************************************
* Checksum calculation * Checksum calculation
@ -164,7 +209,8 @@ static const char *recv_packet(int *pktlen)
return NULL; return NULL;
} }
static int send_command(const char *data, int datalen, static int send_command(int command_code,
const u_int32_t *params, int nparams,
const char *extra, int exlen) const char *extra, int exlen)
{ {
char datapkt[256]; char datapkt[256];
@ -178,15 +224,35 @@ static int send_command(const char *data, int datalen,
assert (len + exlen + 2 <= sizeof(datapkt)); assert (len + exlen + 2 <= sizeof(datapkt));
assert (fet_transport != NULL); assert (fet_transport != NULL);
/* Assemble the unescaped undelimeted packet into datapkt. */ /* Command code and packet type */
memcpy(datapkt, data, datalen); datapkt[len++] = command_code;
len += datalen; datapkt[len++] = ((nparams > 0) ? 1 : 0) + ((exlen > 0) ? 2 : 0) + 1;
/* Optional parameters */
if (nparams > 0) {
datapkt[len++] = nparams & 0xff;
datapkt[len++] = nparams >> 8;
for (j = 0; j < nparams; j++) {
u_int32_t p = params[j];
datapkt[len++] = p & 0xff;
p >>= 8;
datapkt[len++] = p & 0xff;
p >>= 8;
datapkt[len++] = p & 0xff;
p >>= 8;
datapkt[len++] = p & 0xff;
}
}
/* Extra data */
if (extra) { if (extra) {
memcpy(datapkt + len, extra, exlen); memcpy(datapkt + len, extra, exlen);
len += exlen; len += exlen;
} }
/* Checksum */
cksum = calc_checksum(datapkt, len); cksum = calc_checksum(datapkt, len);
datapkt[len++] = cksum & 0xff; datapkt[len++] = cksum & 0xff;
datapkt[len++] = cksum >> 8; datapkt[len++] = cksum >> 8;
@ -212,7 +278,8 @@ static int send_command(const char *data, int datalen,
return fet_transport->send(buf, i); return fet_transport->send(buf, i);
} }
static const char *xfer(const char *command, int len, static const char *xfer(int command_code,
const u_int32_t *params, int nparams,
const char *data, int datalen, const char *data, int datalen,
int *recvlen) int *recvlen)
{ {
@ -221,16 +288,17 @@ static const char *xfer(const char *command, int len,
if (data && fet_is_rf2500) { if (data && fet_is_rf2500) {
if (send_rf2500_data(data, datalen) < 0) if (send_rf2500_data(data, datalen) < 0)
return NULL; return NULL;
if (send_command(command, len, NULL, 0) < 0) if (send_command(command_code, params, nparams, NULL, 0) < 0)
return NULL; return NULL;
} else if (send_command(command, len, data, datalen) < 0) } else if (send_command(command_code, params, nparams,
data, datalen) < 0)
return NULL; return NULL;
buf = recv_packet(recvlen); buf = recv_packet(recvlen);
if (!buf) if (!buf)
return NULL; return NULL;
if (command[0] != buf[0]) { if (command_code != buf[0]) {
fprintf(stderr, "xfer: reply type mismatch\n"); fprintf(stderr, "xfer: reply type mismatch\n");
return NULL; return NULL;
} }
@ -244,57 +312,41 @@ static const char *xfer(const char *command, int len,
int fet_open(const struct fet_transport *tr, int proto_flags, int vcc_mv) int fet_open(const struct fet_transport *tr, int proto_flags, int vcc_mv)
{ {
static char config[12] = { static u_int32_t parm[4];
0x05, 0x02, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
static char vcc[8] = {
0x06, 0x02, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00
};
fet_transport = tr; fet_transport = tr;
fet_is_rf2500 = proto_flags & FET_PROTO_RF2500; fet_is_rf2500 = proto_flags & FET_PROTO_RF2500;
init_codes(); init_codes();
/* open */ if (!xfer(C_INITIALIZE, NULL, 0, NULL, 0, NULL)) {
if (!xfer("\x01\x01", 2, NULL, 0, NULL)) {
fprintf(stderr, "fet_open: open failed\n"); fprintf(stderr, "fet_open: open failed\n");
return -1; return -1;
} }
/* init */ parm[0] = 4;
if (!xfer("\x27\x02\x01\x00\x04\x00\x00\x00\x00", 8, NULL, 0, NULL)) { if (!xfer(39, parm, 1, NULL, 0, NULL)) {
fprintf(stderr, "fet_open: init failed\n"); fprintf(stderr, "fet_open: init failed\n");
return -1; return -1;
} }
/* configure: Spy-Bi-Wire or JTAG */ /* configure: Spy-Bi-Wire or JTAG */
config[8] = (proto_flags & FET_PROTO_SPYBIWIRE) ? 1 : 0; parm[0] = 8;
if (!xfer(config, 12, NULL, 0, NULL)) { parm[1] = (proto_flags & FET_PROTO_SPYBIWIRE) ? 1 : 0;
if (!xfer(C_CONFIGURE, parm, 2, NULL, 0, NULL)) {
fprintf(stderr, "fet_open: configure failed\n"); fprintf(stderr, "fet_open: configure failed\n");
return -1; return -1;
} }
/* I don't know what this is. It's RF2500-specific. It may have parm[0] = 0x50;
* something to do with flash -- 0x1d is sent before an erase. parm[1] = 0;
*/ if (!fet_is_rf2500 && !xfer(C_IDENTIFY, parm, 2, NULL, 0, NULL)) {
if (fet_is_rf2500 && !xfer("\x1e\x01", 2, NULL, 0, NULL)) {
fprintf(stderr, "fet_open: command 0x1e failed\n");
return -1;
}
if (!fet_is_rf2500 &&
!xfer("\x03\x02\x02\x00\x50\x00\x00\x00\x00\x00\x00\x00", 12,
NULL, 0, NULL)) {
fprintf(stderr, "fet_open: identify failed\n"); fprintf(stderr, "fet_open: identify failed\n");
return -1; return -1;
} }
/* set VCC */ /* set VCC */
vcc[4] = vcc_mv & 0xff; parm[0] = vcc_mv;
vcc[5] = vcc_mv >> 8; if (!xfer(C_VCC, parm, 2, NULL, 0, NULL)) {
if (!xfer(vcc, 8, NULL, 0, NULL)) {
fprintf(stderr, "fet_open: set VCC failed\n"); fprintf(stderr, "fet_open: set VCC failed\n");
return -1; return -1;
} }
@ -302,9 +354,9 @@ int fet_open(const struct fet_transport *tr, int proto_flags, int vcc_mv)
/* I don't know what this is, but it appears to halt the MSP. Without /* I don't know what this is, but it appears to halt the MSP. Without
* it, memory reads return garbage. This is RF2500-specific. * it, memory reads return garbage. This is RF2500-specific.
*/ */
if (fet_is_rf2500 && parm[0] = 0;
!xfer("\x28\x02\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00", parm[1] = 0;
12, NULL, 0, NULL)) { if (fet_is_rf2500 && !xfer(0x28, parm, 2, NULL, 0, NULL)) {
fprintf(stderr, "fet_open: command 0x28 failed\n"); fprintf(stderr, "fet_open: command 0x28 failed\n");
return -1; return -1;
} }
@ -323,12 +375,15 @@ int fet_open(const struct fet_transport *tr, int proto_flags, int vcc_mv)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x33, 0x0f, 0x1f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x33, 0x0f, 0x1f, 0x0f,
0xff, 0xff, 0xff, 0xff
}; };
if (!xfer("\x29\x02\x04\x00\x00\x00\x00\x00" parm[0] = 0;
"\x39\x00\x00\x00\x31\x00\x00\x00" parm[1] = 0x39;
"\x4a\x00\x00\x00", 20, data, sizeof(data), NULL)) { parm[2] = 0x31;
parm[3] = sizeof(data);
if (!xfer(0x29, parm, 4, data, sizeof(data), NULL)) {
fprintf(stderr, "fet_open: command 0x29 failed\n"); fprintf(stderr, "fet_open: command 0x29 failed\n");
return -1; return -1;
} }
@ -342,21 +397,13 @@ int fet_open(const struct fet_transport *tr, int proto_flags, int vcc_mv)
int fet_reset(int flags) int fet_reset(int flags)
{ {
static char reset[] = { u_int32_t parm[3] = {
0x07, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, flags & FET_RESET_ALL,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 flags & FET_RESET_HALT ? 1 : 0,
flags & FET_RESET_HALT ? 1 : 0
}; };
reset[4] = flags & FET_RESET_ALL; if (!xfer(C_RESET, parm, 3, NULL, 0, NULL)) {
if (flags & FET_RESET_HALT) {
reset[8] = 0;
reset[12] = 0;
} else {
reset[8] = 1;
reset[12] = 1;
}
if (!xfer(reset, 16, NULL, 0, NULL)) {
fprintf(stderr, "fet_reset: reset failed\n"); fprintf(stderr, "fet_reset: reset failed\n");
return -1; return -1;
} }
@ -366,7 +413,9 @@ int fet_reset(int flags)
int fet_close(void) int fet_close(void)
{ {
if (!xfer("\x02\x02\x01\x00", 4, NULL, 0, NULL)) { u_int32_t parm = 0;
if (!xfer(C_CLOSE, &parm, 1, NULL, 0, NULL)) {
fprintf(stderr, "fet_shutdown: close command failed\n"); fprintf(stderr, "fet_shutdown: close command failed\n");
return -1; return -1;
} }
@ -383,7 +432,7 @@ int fet_get_context(u_int16_t *regs)
int i; int i;
const char *buf; const char *buf;
buf = xfer("\x08\x01", 2, NULL, 0, &len); buf = xfer(C_READREGISTERS, NULL, 0, NULL, 0, &len);
if (len < 72) { if (len < 72) {
fprintf(stderr, "fet_get_context: short reply (%d bytes)\n", fprintf(stderr, "fet_get_context: short reply (%d bytes)\n",
len); len);
@ -399,6 +448,10 @@ int fet_get_context(u_int16_t *regs)
int fet_set_context(u_int16_t *regs) int fet_set_context(u_int16_t *regs)
{ {
char buf[FET_NUM_REGS * 4]; char buf[FET_NUM_REGS * 4];
u_int32_t parm[4] = {
0xffff,
sizeof(buf)
};
int i; int i;
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
@ -408,21 +461,8 @@ int fet_set_context(u_int16_t *regs)
buf[i * 4 + 1] = regs[i] >> 8; buf[i * 4 + 1] = regs[i] >> 8;
} }
static char cmd[] = { if (!xfer(C_WRITEREGISTERS, parm, fet_is_rf2500 ? 2 : 1,
0x09, 0x00, 0x00, 0x00, buf, sizeof(buf), NULL)) {
0xff, 0xff, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00
};
if (fet_is_rf2500) {
cmd[1] = 0x02;
cmd[2] = 0x02;
} else {
cmd[1] = 0x04;
cmd[2] = 0x01;
}
if (!xfer(cmd, 12, buf, sizeof(buf), NULL)) {
fprintf(stderr, "fet_set_context: context set failed\n"); fprintf(stderr, "fet_set_context: context set failed\n");
return -1; return -1;
} }
@ -432,21 +472,16 @@ int fet_set_context(u_int16_t *regs)
int fet_read_mem(u_int16_t addr, char *buffer, int count) int fet_read_mem(u_int16_t addr, char *buffer, int count)
{ {
u_int32_t parm[2];
while (count) { while (count) {
int plen = count > 128 ? 128 : count; int plen = count > 128 ? 128 : count;
const char *buf; const char *buf;
int len; int len;
static char readmem[] = { parm[0] = addr;
0x0d, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, parm[1] = plen;
0x00, 0x00, 0x00, 0x00 buf = xfer(C_READMEMORY, parm, 2, NULL, 0, &len);
};
readmem[4] = addr & 0xff;
readmem[5] = addr >> 8;
readmem[8] = plen;
buf = xfer(readmem, 12, NULL, 0, &len);
if (!buf) { if (!buf) {
fprintf(stderr, "fet_read_mem: failed to read " fprintf(stderr, "fet_read_mem: failed to read "
"from 0x%04x\n", addr); "from 0x%04x\n", addr);
@ -470,27 +505,15 @@ int fet_read_mem(u_int16_t addr, char *buffer, int count)
int fet_write_mem(u_int16_t addr, char *buffer, int count) int fet_write_mem(u_int16_t addr, char *buffer, int count)
{ {
u_int32_t parm[2];
while (count) { while (count) {
int plen = count > 128 ? 128 : count; int plen = count > 128 ? 128 : count;
static char writemem[] = { parm[0] = addr;
0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, parm[1] = plen;
0x00, 0x00, 0x00, 0x00 if (!xfer(C_WRITEMEMORY, parm, fet_is_rf2500 ? 2 : 1,
}; buffer, plen, NULL)) {
if (fet_is_rf2500) {
writemem[1] = 0x02;
writemem[2] = 0x02;
} else {
writemem[1] = 0x04;
writemem[2] = 0x01;
}
writemem[4] = addr & 0xff;
writemem[5] = addr >> 8;
writemem[8] = plen;
if (!xfer(writemem, 12, buffer, plen, NULL)) {
fprintf(stderr, "fet_write_mem: failed to write " fprintf(stderr, "fet_write_mem: failed to write "
"to 0x%04x\n", addr); "to 0x%04x\n", addr);
return -1; return -1;
@ -506,56 +529,47 @@ int fet_write_mem(u_int16_t addr, char *buffer, int count)
int fet_erase(int type, u_int16_t addr) int fet_erase(int type, u_int16_t addr)
{ {
static char erase[] = { u_int32_t parm[3];
0x0c, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
switch (type) { parm[0] = 2;
case FET_ERASE_MAIN: parm[1] = 0x26;
erase[4] = 1; if (!xfer(C_CONFIGURE, parm, 2, NULL, 0, NULL)) {
erase[8] = 0xe0;
erase[9] = 0xff;
erase[12] = 2;
break;
case FET_ERASE_ADDR:
erase[8] = addr & 0xff;
erase[9] = addr >> 8;
erase[12] = 2;
break;
case FET_ERASE_INFO:
erase[9] = 0x10;
erase[13] = 1;
break;
case FET_ERASE_ALL:
default:
erase[4] = 2;
erase[9] = 0x10;
erase[13] = 0x01;
break;
}
if (!xfer("\x1d\x01", 2, NULL, 0, NULL)) {
fprintf(stderr, "fet_erase: command 1d failed\n");
return -1;
}
if (!xfer("\x05\x02\x02\x00\x02\x00\x00\x00\x26\x00\x00\x00",
12, NULL, 0, NULL)) {
fprintf(stderr, "fet_erase: config (1) failed\n"); fprintf(stderr, "fet_erase: config (1) failed\n");
return -1; return -1;
} }
if (!xfer("\x05\x02\x02\x00\x05\x00\x00\x00\x00\x00\x00\x00", parm[0] = 5;
12, NULL, 0, NULL)) { parm[1] = 0;
if (!xfer(C_CONFIGURE, parm, 2, NULL, 0, NULL)) {
fprintf(stderr, "fet_erase: config (2) failed\n"); fprintf(stderr, "fet_erase: config (2) failed\n");
return -1; return -1;
} }
if (!xfer(erase, 16, NULL, 0, NULL)) { switch (type) {
case FET_ERASE_MAIN:
parm[0] = 1;
parm[2] = 2;
break;
case FET_ERASE_ADDR:
parm[0] = 0;
parm[2] = 2;
break;
case FET_ERASE_INFO:
parm[0] = 0;
parm[2] = 1;
break;
case FET_ERASE_ALL:
default:
parm[0] = 2;
parm[2] = 0x100;
break;
}
parm[1] = addr;
if (!xfer(C_ERASE, parm, 2, NULL, 0, NULL)) {
fprintf(stderr, "fet_erase: erase command failed\n"); fprintf(stderr, "fet_erase: erase command failed\n");
return -1; return -1;
} }
@ -567,12 +581,13 @@ int fet_poll(void)
{ {
const char *reply; const char *reply;
int len; int len;
u_int32_t parm = 0;
/* Without this delay, breakpoints can get lost. */ /* Without this delay, breakpoints can get lost. */
if (usleep(500000) < 0) if (usleep(500000) < 0)
return -1; return -1;
reply = xfer("\x12\x02\x01\x00\x00\x00\x00\x00", 8, NULL, 0, &len); reply = xfer(C_STATE, &parm, 1, NULL, 0, &len);
if (!reply) { if (!reply) {
fprintf(stderr, "fet_poll: polling failed\n"); fprintf(stderr, "fet_poll: polling failed\n");
return -1; return -1;
@ -583,8 +598,11 @@ int fet_poll(void)
int fet_step(void) int fet_step(void)
{ {
if (!xfer("\x11\x02\x02\x00\x02\x00\x00\x00\x00\x00\x00\x00", static const u_int32_t parm[2] = {
12, NULL, 0, NULL)) { 2, 0
};
if (!xfer(C_RUN, parm, 2, NULL, 0, NULL)) {
fprintf(stderr, "fet_step: failed to single-step\n"); fprintf(stderr, "fet_step: failed to single-step\n");
return -1; return -1;
} }
@ -594,8 +612,11 @@ int fet_step(void)
int fet_run(void) int fet_run(void)
{ {
if (!xfer("\x11\x02\x02\x00\x03\x00\x00\x00\x00\x00\x00\x00", u_int32_t parm[2] = {
12, NULL, 0, NULL)) { fet_breakpoint_enable ? 3 : 1, 0
};
if (!xfer(C_RUN, parm, 2, NULL, 0, NULL)) {
fprintf(stderr, "fet_run: run failed\n"); fprintf(stderr, "fet_run: run failed\n");
return -1; return -1;
} }
@ -605,7 +626,9 @@ int fet_run(void)
int fet_stop(void) int fet_stop(void)
{ {
if (!xfer("\x12\x02\x01\x00\x01\x00\x00\x00", 8, NULL, 0, NULL)) { u_int32_t parm = 1;
if (!xfer(C_STATE, &parm, 1, NULL, 0, NULL)) {
fprintf(stderr, "fet_stop: stop failed\n"); fprintf(stderr, "fet_stop: stop failed\n");
return -1; return -1;
} }
@ -615,36 +638,10 @@ int fet_stop(void)
int fet_break(int enable, u_int16_t addr) int fet_break(int enable, u_int16_t addr)
{ {
static char buf[] = { u_int32_t parm[2] = { 0, addr };
0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x0e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x98, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
};
if (enable) { fet_breakpoint_enable = enable;
buf[12] = addr & 0xff; if (!xfer(C_BREAKPOINT, parm, 2, NULL, 0, NULL)) {
buf[13] = addr >> 8;
buf[30] = 0xff;
buf[31] = 0xff;
buf[36] = 2;
buf[52] = 3;
} else {
buf[12] = 0;
buf[13] = 0;
buf[30] = 0;
buf[31] = 0;
buf[36] = 0;
buf[52] = 1;
}
if (!xfer("\x2a\x02\x04\x00\x08\x00\x00\x00\xb0\x00\x00\x00"
"\x00\x00\x00\x00\x40\x00\x00\x00", 20,
buf, sizeof(buf), NULL)) {
fprintf(stderr, "fet_break: set breakpoint failed\n"); fprintf(stderr, "fet_break: set breakpoint failed\n");
return -1; return -1;
} }