#include #include #include #include #include #include "tool78_defs.h" #include "tool78_hw.h" #include "tool78_cmds.h" static uint8_t databuf[255]; // variable name | /fRH=/8MHz us us // 78k RL78 | 78k0 78k0r rl78 // -----------------+---------------------------------------------------------- // tCOM tSDNx/tMB | 106 13.2 62 (good enough) // tSF | 215 X X // tWT0 tCS1 | 172 0 255 // tWT1 (tSD8) |857883+128*44160 (1420100+128*281100) 212 // tWT2 tCS3 |214714*512+128*44160 (3300+271600+128*275000) (248862+299307) // tWT3 tCS5 | 1506 0 1432 // tWT4 tDS5 |893355/2 149900 (309870+488315) // tWT5 tSS5 |100407 1187500 (1732+58+(17403+29293)*128+(184+44)) // tWT6 tCS2 | 686 0 351 // tWT7 tDS2 | 12827 0 11981 // tWT8 tCS4 | 55044 18000 (3805+168+(5035+1110)*128+(5827+318)) // tWT9 (tCS8) | 1238 X 154 // tWT10 tCS6 | X 379.2 4735 // tWT11 tCS11 | 1233 0 111 // tWT12 (tCS9) | 252 0 (146110+534723+(5035+1110)*128+(203+57)) // tWT13 tCS7 | 975 0 168 // tWT14 tDS7 |66005812/2 70.2 (277095+1075967) // tWT15 |66018156/2 1152.3 X // tWT16 tCS10 | 583 0 219 // tFD1 tSD10 | 54368 0 (72+128*30720) // tFD2 tSD11 | 321 11.4 512 // tFD3 tSD2 | 163 416.4 41 // tFD3 tSD5 | 163 416.4 41 // tFD4 tSD7 | 163 985.8 32 // ~tCS8~ | // ~tSD8~ | // ~tCS9~ | struct delayvalues { int none; int k0; int k0r; int rl78; }; #define D(a,b,c) ((struct delayvalues){.none=1000, .k0=(a), .k0r=(b), .rl78=(c)}) static const struct delayvalues delays[23] = { D(106, 14, 62), // tCOM D(215, -1, -1), // tSF (78k0 SPI only) D(172, 0, 255), // tWT0 D(857883+128*44160, (1420100+128*281100), 212), // tWT1 D(214714*512+128*44160, (3300+271600+128*275000),(248862+299307)), // tWT2 D(1506,0,1432), // tWT3 D(893355/2, 149900, (309870+488315)), // tWT4 D(100407 , 1187500, (1732+58+(17403+29293)*128+(184+44))), // tWT5 D(686,0,351), // tWT6 D(12827, 0, 11981), // tWT7 D(55044, 1800, (3805+168+(5035+1110)*128+(5827+318))), // tWT8 D(1238, -1, 154), // tWT9, D(-1, 380, 4735), // tWT10, D(1233, 0, 111), // tWT11, D(252, 0, (146110+534723+(5035+1110)*128+(203+57))), // tWT12 D(975, 0, 168), // tWT13 D(66005812/2 ,71, (277095+1075967)), // tWT14 D(66018156/2 ,1153, -1), // tWT15 D(583, 0, 219), // tWT16 D(54368, 0, (72+128*30720)), // tFD1 D(321, 12, 512), // tFD2 D(163, 417, 41), // tFD3 D(163, 986, 32), // tFD4 }; // SD5 SS5 SD2 CS4 SD7 CS8 SD8 CS9 #define tCOM (((&delays[ 0].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tSF (((&delays[ 1].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tWT0 (((&delays[ 2].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tWT1 (((&delays[ 3].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tWT2 (((&delays[ 4].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tWT3 (((&delays[ 5].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tWT4 (((&delays[ 6].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tWT5 (((&delays[ 7].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tWT6 (((&delays[ 8].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tWT7 (((&delays[ 9].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tWT8 (((&delays[10].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tWT9 (((&delays[11].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tWT10 (((&delays[12].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tWT11 (((&delays[13].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tWT12 (((&delays[14].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tWT13 (((&delays[15].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tWT14 (((&delays[16].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tWT15 (((&delays[17].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tWT16 (((&delays[18].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tFD1 (((&delays[19].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tFD2 (((&delays[20].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tFD3 (((&delays[21].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tFD4 (((&delays[22].none)[(hw->target & tool78_mcu_mask) >> 4])) #define tSD5 tFD3 #define tSS5 tWT5 #define tSD2 tFD3 #define tCS4 tWT8 #define tSD7 tFD4 #define tCS8 tWT9 #define tSD8 tWT1 #define tCS9 tWT12 #define tG23 (1000*1000) /* RL78/G23 datasheet just says "everything 1ms lol" */ // G10 proto #define tDTR (3*1000) #define tDRT 20 #define tCRC 1000 #define tPRO 1000 #define tVER 20000 #define tERA (350*1000) #define tDT 1 /*#define tDR 1*/ static enum tool78_stat tool78_data_send(struct tool78_hw* hw, int len, const uint8_t* data, bool final_block) { //printf("datasend: len=%d data=%02x %02x %02x ...\n", len, data[0], data[1], data[2]); if (len == 0) return tool78_stat_ack; if (len > 0x100) return tool78_stat_internal_error; uint8_t lenfield = len & 0xff; uint8_t pre[2], // stx, len post[2]; // cksum, etx/etb pre[0] = tool78_frame_stx; pre[1] = lenfield; post[0] = 0; // checksum post[1] = final_block ? tool78_frame_etx : tool78_frame_etb; uint8_t r = 0; r = tool78_digest_checksum8(r, 1, &pre[1]); // len if (len) r = tool78_digest_checksum8(r, len, data); post[0] = r; //printf("data cksum=%02x\n", r); int rr = hw->send(2, pre, -1); if (rr != 2) return tool78_stat_internal_error; if (len) { rr = hw->send(len, data, -1); if (rr != len) { //printf("data not sent properly: %d\n", r); return tool78_stat_internal_error; } } rr = hw->send(2, post, -1); if (rr != 2) return tool78_stat_internal_error; return tool78_stat_ack; } static enum tool78_stat tool78_cmd_send(struct tool78_hw* hw, uint8_t cmd, int len, const uint8_t* data) { if (len >= 0x100) return tool78_stat_internal_error; uint8_t lenfield = len &= 0xff; busy_wait_us_32(tCOM); // aka tSN6(/tDN6?) (reset?) or tMB (others?) uint8_t pre[3], // soh, len, cmd post[2]; // cksum, etx pre[0] = tool78_frame_soh; pre[1] = lenfield + 1; pre[2] = cmd; post[0] = 0; // checksum post[1] = tool78_frame_etx; uint8_t r = 0; r = tool78_digest_checksum8(r, 2, &pre[1]); // len and cmd if (len) r = tool78_digest_checksum8(r, len, data); post[0] = r; int rr = hw->send(3, pre, -1); if (rr != 3) return tool78_stat_internal_error; if (len) { rr = hw->send(len, data, -1); if (rr != len) return tool78_stat_internal_error; } rr = hw->send(2, post, -1); if (rr != 2) return tool78_stat_internal_error; return tool78_stat_ack; } static enum tool78_stat tool78_data_recv(struct tool78_hw* hw, uint8_t* buf, int expected_len, int timeout_us_first) { uint8_t pre[10]; // stx, len uint8_t post[2]; // cksum, etx/etb //printf("recv to=%d\n", timeout_us_first); int rr = hw->recv(1, &pre[0], timeout_us_first); //printf("data recv rr=%d\n", rr); if (rr == 0) return tool78_stat_busy; if (rr != 1) return tool78_stat_internal_error; //printf("pre[0]=0x%02x\n", pre[0]); if (hw->target == tool78k0_spi && pre[0] == tool78_stat_busy) return tool78_stat_busy; if (pre[0] != tool78_frame_stx) return (hw->flags & tool78_hw_flag_done_reset) ? tool78_stat_busy : tool78_stat_protocol_error; rr = hw->recv(1, &pre[1], 100*100); //printf("rr=%d (0x%08lx) pre[1]=0x%02x\n", rr, (uint32_t)rr, pre[1]); if (rr != 1) { /*for (int i = 0; i < rr && rr < 256; ++i) printf("pre[%d]=0x%02x\n", i+1, pre[i+1]); printf("interr\n");*/ return tool78_stat_internal_error; } int len = pre[1]; if (!len) len = 256; if (hw->target == tool78k0_spi && pre[1] == tool78_stat_busy) return tool78_stat_busy; if (expected_len >= 0 && len != expected_len) { return tool78_stat_protocol_error; } rr = hw->recv(len, buf, 1000*len*100); if (rr != len) return tool78_stat_internal_error; rr = hw->recv(2, post, 200*100); if (rr != 2) return tool78_stat_internal_error; if (post[1] != tool78_frame_etx && post[1] != tool78_frame_etb) { return tool78_stat_protocol_error; } uint8_t ck = tool78_calc_checksum8(len, buf); ck = tool78_digest_checksum8(ck, 1, &pre[1]); if (ck != post[0]) { return tool78_stat_protocol_error; } return tool78_stat_ack; } /*#define tool78_wait_status(hw, l, timeout_us, ...) \ tool78_wait_status__impl(hw, l, timeout_us, __VA_OPT__(1 ? __VA_ARGS__ : ) -1) \ */ static enum tool78_stat tool78_wait_status/*__impl*/(struct tool78_hw* hw, int l, int timeout_us/*, int minl*/) { /*if (hw->target == tool78k0_spi && timeout_us >= 0) { busy_wait_us_32(timeout_us); timeout_us *= 2; }*/ enum tool78_stat st; bool blockinf = timeout_us < 0; absolute_time_t at = make_timeout_time_us(timeout_us); timeout_state_t ts = {0}; check_timeout_fn ct = NULL; if (!blockinf) ct = init_single_timeout_until(&ts, at); for (int i = 0; (blockinf && i < 64) || !ct(&ts); ++i) { if (hw->target == tool78k0_spi) { // with SPI, a status request must be sent manually enum tool78_stat st = tool78_cmd_send(hw, tool78_cmd_status, 0, NULL); if (st != tool78_stat_ack) return st; busy_wait_us_32(tSF); } st = tool78_data_recv(hw, databuf, l, timeout_us); //printf("recv: 0x%02x\n", st); if (st == tool78_stat_busy) goto cont; if (st != tool78_stat_ack) return st; st = databuf[0]; //printf("recvdat: 0x%02x\n", st); if (st == tool78_stat_busy) goto cont; return st; cont: busy_wait_us_32(timeout_us/64); } printf("wait t/o\n"); return tool78_stat_timeout_error; } // ---- enum tool78_stat tool78_do_reset(struct tool78_hw* hw) { enum tool78_stat st = tool78_cmd_send(hw, tool78_cmd_reset, 0, NULL); //printf("send st=%02x\n", st); if (st != tool78_stat_ack) return st; st = tool78_wait_status(hw, 1, tWT0); // aka tCS1 //printf("wait st=%02x\n", st); if (st != tool78_stat_ack) return st; //printf("reset cmd sent\n"); return st; } enum tool78_stat tool78_do_baud_rate_set(struct tool78_hw* hw) { uint8_t d0x[5]; enum tool78_stat st; switch (hw->target & tool78_mcu_mask) { case tool78_mcu_78k0r: // on the 78K0R/Kx3-L, baudrate set also switches to a fixed 115200 baud // line, much like the 78K0/Kx2 interface d0x[0] = 0x00; // uC correction mode d0x[1] = 0x00; // fixed value d0x[2] = 0x0a; // 115.2k d0x[3] = 0x00; // noise filter off (0x01: noise filter on) d0x[4] = 0x00; // we're most likely in full-speed mode (Vdd in 2.7V..5.5V // range, needs to be 0x01 to also support down to 1.8V) st = tool78_cmd_send(hw, tool78_cmd_baud_rate_set, 5, d0x); if (st != tool78_stat_ack) return st; busy_wait_us_32(tWT10); // now at 115.2kbaud, so let the physical layer switch to it hw->set_baudrate(115200); st = tool78_do_reset(hw); break; case tool78_mcu_rl78: // TODO: don't hardcode baudrate? idk d0x[0] = 0x00; // 0=115.2k 1=250k 2=500k 3=1M d0x[1] = 33; // 3.3V, will switch to full-speed mode st = tool78_cmd_send(hw, tool78_cmd_baud_rate_set, 2, d0x); //printf("brs send=0x%02x\n", st); if (st != tool78_stat_ack) return st; st = tool78_wait_status(hw, -1, tWT10); // aka tCS6 // -1 because can be 1 (OCD mode, denied) or 3 //printf("brs stat=0x%02x\n", st); if (st != tool78_stat_ack) return st; // let's ignore the two data bytes for now // now at 115.2kbaud, so let the physical layer switch to it hw->set_baudrate(115200); hw->flags |= tool78_hw_flag_done_reset; if (hw->flags & tool78_hw_flag_do_ocd) { //printf("brs ok, wait for ocd...\n"); // wait for ack 0x00 byte uint8_t byte = 0xff; int rr = hw->recv(1, &byte, 10000); //printf("ocd rr=%d, v=%02x\n", rr, byte); if (rr != 1) st = tool78_stat_timeout_error; else if (byte != 0x00) st = tool78_stat_protocol_error; else st = tool78_stat_ack; } else { st = tool78_do_reset(hw); } break; case tool78_mcu_78k0: default: return tool78_stat_bad_mcu_for_cmd; } return st; } enum tool78_stat tool78_do_osc_freq_set(struct tool78_hw* hw) { if ((hw->target & tool78_mcu_mask) != tool78_mcu_78k0) return tool78_stat_bad_mcu_for_cmd; // OFS specifies the frequency of the EXTCLK signal (see 78k0_uart2_extclk) // otherwise kinda irrelevant, EXCEPT THAT IS ALSO SWITCHES THE BAUDRATE TO // A FIXED VALUE OF 115200 BAUD! // so for now we kinda hardcode it to the value for the EXTCLK frequency to // the one also used in 78k0_uart2_extclk.c, aka 8 MHz uint8_t d0x[4]; // one-digit BCD, last element is an exponent // i.e. value is (d00*100 + d01*10 + d02) * 10^d03 in Hz d0x[0] = 8; d0x[1] = 0; d0x[2] = 0; d0x[3] = 4; enum tool78_stat st = tool78_cmd_send(hw, tool78_cmd_osc_freq_set, 4, d0x); if (st != tool78_stat_ack) return st; // now at 115.2kbaud, so let the physical layer switch to it if (hw->target != tool78k0_spi) hw->set_baudrate(115200); st = tool78_wait_status(hw, 1, tWT9); if (st != tool78_stat_ack) return st; return st; } // - enum tool78_stat tool78_do_chip_erase(struct tool78_hw* hw) { if ((hw->target & tool78_mcu_mask) == tool78_mcu_rl78) return tool78_stat_bad_mcu_for_cmd; enum tool78_stat st = tool78_cmd_send(hw, tool78_cmd_chip_erase, 0, NULL); if (st != tool78_stat_ack) return st; return tool78_wait_status(hw, 1, tWT1); } enum tool78_stat tool78_do_block_erase(struct tool78_hw* hw, uint32_t start, uint32_t end) { bool isrl78 = (hw->target & tool78_mcu_mask) == tool78_mcu_rl78; if (isrl78) end = 0xffffff; if (start >= end) return 0; uint8_t data[6]; // on the rl78, the end address is ignored/unused and it's little-endian if (isrl78) { data[0] = (start >> 0) & 0xff; data[1] = (start >> 8) & 0xff; data[2] = (start >> 16) & 0xff; } else { data[0] = (start >> 16) & 0xff; data[1] = (start >> 8) & 0xff; data[2] = (start >> 0) & 0xff; data[3] = (end >> 16) & 0xff; data[4] = (end >> 8) & 0xff; data[5] = (end >> 0) & 0xff; } enum tool78_stat st = tool78_cmd_send(hw, tool78_cmd_block_erase, isrl78 ? 3 : 6, data); if (st != tool78_stat_ack) return st; st = tool78_wait_status(hw, 1, tWT2); // aka tCS3 if (st != tool78_stat_ack) return st; //st = tool78_wait_status(hw, 1, tWTx); // TODO: ? return st; } enum tool78_stat tool78_do_programming(struct tool78_hw* hw, uint32_t start, uint32_t end, const uint8_t* src) { if (start >= end) return 0; bool isrl78 = (hw->target & tool78_mcu_mask) == tool78_mcu_rl78; uint8_t data[6]; if (isrl78) { data[0] = (start >> 0) & 0xff; data[1] = (start >> 8) & 0xff; data[2] = (start >> 16) & 0xff; data[3] = (end >> 0) & 0xff; data[4] = (end >> 8) & 0xff; data[5] = (end >> 16) & 0xff; } else { data[0] = (start >> 16) & 0xff; data[1] = (start >> 8) & 0xff; data[2] = (start >> 0) & 0xff; data[3] = (end >> 16) & 0xff; data[4] = (end >> 8) & 0xff; data[5] = (end >> 0) & 0xff; } enum tool78_stat st = tool78_cmd_send(hw, tool78_cmd_programming, 6, data); if (st != tool78_stat_ack) return st; st = tool78_wait_status(hw, 1, tWT3); // aka tCS5 if (st != tool78_stat_ack) return st; size_t nbytes = end - start + 1; int nblocks = ((nbytes + 255) / 256); for (size_t off = 0; off < nbytes; off += 256) { busy_wait_us_32(tSD5); // aka tFD3 size_t todo = nbytes - off; if (todo > 256) todo = 256; bool finalblk = off + 256 >= nbytes; //printf("prgmdata@%zu = %02x %02x %02x ...\n", off, src[off], src[off+1], src[off+2]); st = tool78_data_send(hw, todo, &src[off], finalblk); if (st != tool78_stat_ack) return st; st = tool78_wait_status(hw, 2, tWT4*10); // aka tDS5 printf("prgm %zu st=%02x %02x fin=%c\n", off, st, databuf[1], finalblk?'t':'f'); if (st != tool78_stat_ack) return st; st = databuf[1]; if (st != tool78_stat_ack) return st; } st = tool78_wait_status(hw, 1, isrl78 ? (tSS5*10) : (tWT5 * nblocks)); if (st != tool78_stat_ack) return st; return st; } enum tool78_stat tool78_do_verify(struct tool78_hw* hw, uint32_t start, uint32_t end, const uint8_t* src) { if (start >= end) return 0; bool isrl78 = (hw->target & tool78_mcu_mask) == tool78_mcu_rl78; uint8_t data[6]; if (isrl78) { data[0] = (start >> 0) & 0xff; data[1] = (start >> 8) & 0xff; data[2] = (start >> 16) & 0xff; data[3] = (end >> 0) & 0xff; data[4] = (end >> 8) & 0xff; data[5] = (end >> 16) & 0xff; } else { data[0] = (start >> 16) & 0xff; data[1] = (start >> 8) & 0xff; data[2] = (start >> 0) & 0xff; data[3] = (end >> 16) & 0xff; data[4] = (end >> 8) & 0xff; data[5] = (end >> 0) & 0xff; } enum tool78_stat st = tool78_cmd_send(hw, tool78_cmd_verify, 6, data); if (st != tool78_stat_ack) return st; st = tool78_wait_status(hw, 1, tWT6); // aka tCS2 if (st != tool78_stat_ack) return st; size_t nbytes = end - start + 1; //int nblocks = ((nbytes + 255) / 256); for (size_t off = 0; off < end - start; off += 256) { busy_wait_us_32(tSD2); // aka tFD3 size_t todo = nbytes - off; if (todo > 256) todo = 256; bool finalblk = off + 256 >= nbytes; st = tool78_data_send(hw, todo, &src[off], finalblk); if (st != tool78_stat_ack) return st; st = tool78_wait_status(hw, 2, tWT7); // aka tDS2 if (st != tool78_stat_ack) return st; st = databuf[1]; if (st != tool78_stat_ack) return st; } return st; } enum tool78_stat tool78_do_block_blank_check(struct tool78_hw* hw, uint32_t start, uint32_t end, bool check_flash_opt /* RL78 only */) { if (start >= end) return 0; bool isrl78 = (hw->target & tool78_mcu_mask) == tool78_mcu_rl78; uint8_t data[7]; if (isrl78) { data[0] = (start >> 0) & 0xff; data[1] = (start >> 8) & 0xff; data[2] = (start >> 16) & 0xff; data[3] = (end >> 0) & 0xff; data[4] = (end >> 8) & 0xff; data[5] = (end >> 16) & 0xff; data[6] = check_flash_opt ? 1 : 0; // RL78 only } else { data[0] = (start >> 16) & 0xff; data[1] = (start >> 8) & 0xff; data[2] = (start >> 0) & 0xff; data[3] = (end >> 16) & 0xff; data[4] = (end >> 8) & 0xff; data[5] = (end >> 0) & 0xff; } size_t nbytes = end - start + 1; int nblocks = ((nbytes + 255) / 256); enum tool78_stat st = tool78_cmd_send(hw, tool78_cmd_block_blank_check, isrl78 ? 7 : 6, data); if (st != tool78_stat_ack) return st; st = tool78_wait_status(hw, 1, isrl78 ? tCS4 : (tWT8 * nblocks)); if (st != tool78_stat_ack) return st; return st; } static bool check_parity(uint8_t v) { uint8_t parity = (v >> 7) & 1; uint8_t calc = 1; // odd parity for (size_t i = 0; i < 7; ++i) calc ^= (v >> i) & 1; return calc == parity; } enum tool78_stat tool78_do_silicon_signature(struct tool78_hw* hw, tool78_silicon_sig_t* sig_dest) { int nbyte = 0; switch (hw->target & tool78_mcu_mask) { case tool78_mcu_78k0: nbyte = 19; break; case tool78_mcu_78k0r: nbyte = 27; break; case tool78_mcu_rl78: nbyte = 22; break; default: // oops return tool78_stat_bad_mcu_for_cmd; } /*gpio_set_function(18, GPIO_FUNC_SIO); gpio_set_dir(18, true); gpio_put(18, true);*/ memset(sig_dest, 0, 27); enum tool78_stat st = tool78_cmd_send(hw, tool78_cmd_silicon_signature, 0, NULL); if (st != tool78_stat_ack) return st; //gpio_put(18, false); st = tool78_wait_status(hw, 1, tWT11); // aka tCS11 //gpio_put(18, true); //printf("silisig: status 0x%02x\n", st); if (st != tool78_stat_ack) return st; //gpio_put(18, false); st = tool78_data_recv(hw, (uint8_t*)sig_dest, nbyte, tFD2); // aka tSD11 //gpio_put(18, true); //printf("silisig: data 0x%02x\n", st); if (st != tool78_stat_ack) return st; switch (hw->target & tool78_mcu_mask) { case tool78_mcu_78k0: nbyte = 18; break; case tool78_mcu_78k0r: nbyte = 6; break; case tool78_mcu_rl78: nbyte = 0; break; } for (int i = 0; i < nbyte; ++i) { if (!check_parity(((const uint8_t*)sig_dest)[i])) return tool78_stat_parity_error; } return st; } enum tool78_stat tool78_do_version_get(struct tool78_hw* hw, tool78_version_t* vout) { if ((hw->target & tool78_mcu_mask) == tool78_mcu_rl78) return tool78_stat_bad_mcu_for_cmd; enum tool78_stat st = tool78_cmd_send(hw, tool78_cmd_version_get, 0, NULL); if (st != tool78_stat_ack) return st; st = tool78_wait_status(hw, 1, tWT12); if (st != tool78_stat_ack) return st; memset(vout, 0, 6); st = tool78_data_recv(hw, (uint8_t*)vout, 6, tFD2); if (st != tool78_stat_ack) return st; return st; } enum tool78_stat tool78_do_checksum(struct tool78_hw* hw, uint32_t start, uint32_t end, uint16_t* ckout) { if (end <= start) return 0; bool isrl78 = (hw->target & tool78_mcu_mask) == tool78_mcu_rl78; uint8_t data[6]; if (isrl78) { data[0] = (start >> 0) & 0xff; data[1] = (start >> 8) & 0xff; data[2] = (start >> 16) & 0xff; data[3] = (end >> 0) & 0xff; data[4] = (end >> 8) & 0xff; data[5] = (end >> 16) & 0xff; } else { data[0] = (start >> 16) & 0xff; data[1] = (start >> 8) & 0xff; data[2] = (start >> 0) & 0xff; data[3] = (end >> 16) & 0xff; data[4] = (end >> 8) & 0xff; data[5] = (end >> 0) & 0xff; } enum tool78_stat st = tool78_cmd_send(hw, tool78_cmd_checksum, 6, data); if (st != tool78_stat_ack) return st; st = tool78_wait_status(hw, 1, tWT16); // aka tCS10 if (st != tool78_stat_ack) return st; *ckout = 0; st = tool78_data_recv(hw, (uint8_t*)ckout, 2, tFD1); // aka tSD10 if (st != tool78_stat_ack) return st; return st; } enum tool78_stat tool78_do_security_set(struct tool78_hw* hw, const struct tool78_security* sec) { uint8_t data[8]; // 78k0/78k0r data[1] = data[0] = 0; bool isrl78 = (hw->target & tool78_mcu_mask) == tool78_mcu_rl78; enum tool78_stat st = tool78_cmd_send(hw, tool78_cmd_security_set, isrl78 ? 0 : 2, data); if (st != tool78_stat_ack) return st; st = tool78_wait_status(hw, 1, tWT13); // aka tCS7 if (st != tool78_stat_ack) return st; busy_wait_us_32(tSD7); // aka tFD3 switch (hw->target & tool78_mcu_mask) { case tool78_mcu_78k0: data[0] = sec->flg; data[1] = 0x03; // 78k0: fixed value st = tool78_data_send(hw, 2, data, true); break; case tool78_mcu_78k0r: case tool78_mcu_rl78: data[0] = sec->flg; data[1] = isrl78 ? sec->bot : 0x03; // 78k0r: fixed value // yes they switched around the endianness. sigh. if (isrl78) { data[2] = (sec->fsws >> 0) & 0xff; data[3] = (sec->fsws >> 8) & 0xff; data[4] = (sec->fswe >> 0) & 0xff; data[5] = (sec->fswe >> 8) & 0xff; } else { data[2] = (sec->fsws >> 8) & 0xff; data[3] = (sec->fsws >> 0) & 0xff; data[4] = (sec->fswe >> 8) & 0xff; data[5] = (sec->fswe >> 0) & 0xff; } data[7] = data[6] = 0xff; // fixed/reserved st = tool78_data_send(hw, 8, data, true); break; default: st = tool78_stat_bad_mcu_for_cmd; } if (st != tool78_stat_ack) return st; st = tool78_wait_status(hw, 1, tWT14); // aka tDS7 if (st != tool78_stat_ack) return st; if (!isrl78) { // yeah... st = tool78_wait_status(hw, 1, tWT15); if (st != tool78_stat_ack) return st; } return st; } enum tool78_stat tool78_do_security_get(struct tool78_hw* hw, struct tool78_security* sec) { if ((hw->target & tool78_mcu_mask) != tool78_mcu_rl78) return tool78_stat_bad_mcu_for_cmd; uint8_t data[8]; enum tool78_stat st = tool78_cmd_send(hw, tool78_cmd_security_get, 0, NULL); if (st != tool78_stat_ack) return st; st = tool78_wait_status(hw, 1, tCS8); if (st != tool78_stat_ack) return st; st = tool78_data_recv(hw, data, 8, tSD8); if (st != tool78_stat_ack) return st; sec->flg = data[0]; sec->bot = data[1]; sec->fsws = data[2] | ((uint16_t)data[3]<<8); sec->fswe = data[4] | ((uint16_t)data[5]<<8); return st; } enum tool78_stat tool78_do_security_release(struct tool78_hw* hw) { // basically does the same as chip erase... oh well if ((hw->target & tool78_mcu_mask) != tool78_mcu_rl78) return tool78_stat_bad_mcu_for_cmd; enum tool78_stat st = tool78_cmd_send(hw, tool78_cmd_security_release, 0, NULL); if (st != tool78_stat_ack) return st; st = tool78_wait_status(hw, 1, tCS9); if (st != tool78_stat_ack) return st; // TODO: needs a modeset/re-entry sequence now? return st; } // new RL78/G23 stuff enum tool78_stat tool78_do_g23_security_set(struct tool78_hw* hw, const struct tool78_security* sec) { bool isrl78 = (hw->target & tool78_mcu_mask) == tool78_mcu_rl78; if (!isrl78) return tool78_stat_bad_mcu_for_cmd; uint8_t data[2]; data[0] = sec->flg | 0xe9; data[1] = sec->flg2 | 0xfa; enum tool78_stat st = tool78_cmd_send(hw, tool78_cmd_security_set, 2, data); if (st != tool78_stat_ack) return st; st = tool78_wait_status(hw, 1, tWT13 + tWT14); if (st != tool78_stat_ack) return st; return st; } enum tool78_stat tool78_do_g23_security_get(struct tool78_hw* hw, struct tool78_security* sec) { bool isrl78 = (hw->target & tool78_mcu_mask) == tool78_mcu_rl78; if (!isrl78) return tool78_stat_bad_mcu_for_cmd; uint8_t data[2]; enum tool78_stat st = tool78_cmd_send(hw, tool78_cmd_security_get, 0, NULL); if (st != tool78_stat_ack) return st; st = tool78_wait_status(hw, 1, tCS8); if (st != tool78_stat_ack) return st; st = tool78_data_recv(hw, data, 2, tSD8); if (st != tool78_stat_ack) return st; sec->flg = data[0]; sec->flg2 = data[1]; return st; } enum tool78_stat tool78_do_security_idauth(struct tool78_hw* hw, const uint8_t passwd[static 10]) { if ((hw->target & tool78_mcu_mask) != tool78_mcu_rl78) return tool78_stat_bad_mcu_for_cmd; enum tool78_stat st = tool78_cmd_send(hw, tool78_cmd_security_idauth, 10, passwd); if (st != tool78_stat_ack) return st; st = tool78_wait_status(hw, 1, tG23); if (st != tool78_stat_ack) return st; return st; } enum tool78_stat tool78_do_exopt_set(struct tool78_hw* hw, const uint8_t exopt[static 14]) { if ((hw->target & tool78_mcu_mask) != tool78_mcu_rl78) return tool78_stat_bad_mcu_for_cmd; enum tool78_stat st = tool78_cmd_send(hw, tool78_cmd_exopts_set, 14, exopt); if (st != tool78_stat_ack) return st; st = tool78_wait_status(hw, 1, tG23); if (st != tool78_stat_ack) return st; return st; } enum tool78_stat tool78_do_flash_rdp_set(struct tool78_hw* hw, uint16_t block_start, uint16_t block_end, bool rdp_rw_allow) { if ((hw->target & tool78_mcu_mask) != tool78_mcu_rl78) return tool78_stat_bad_mcu_for_cmd; uint8_t data[4]; data[0] = block_start & 0xff; data[1] = (block_start >> 8) | 0xfe; data[2] = block_end & 0xff; data[3] = ((block_end >> 8) & 1) | 0x7e | (rdp_rw_allow ? 0x80 : 0); enum tool78_stat st = tool78_cmd_send(hw, tool78_cmd_flash_rdp_set, 4, data); if (st != tool78_stat_ack) return st; st = tool78_wait_status(hw, 1, tG23); if (st != tool78_stat_ack) return st; return st; } enum tool78_stat tool78_do_fsw_set(struct tool78_hw* hw, const struct tool78_fsw_settings* fswopt) { if ((hw->target & tool78_mcu_mask) != tool78_mcu_rl78) return tool78_stat_bad_mcu_for_cmd; uint8_t data[4]; data[0] = fswopt->block_start & 0xff; data[1] = ((fswopt->block_start >> 8) & 1) | 0x7e | (fswopt->fswopt_rw_allow ? 0x80 : 0); data[2] = fswopt->block_end & 0xff; data[3] = ((fswopt->block_end >> 8) & 1) | 0x7e | (fswopt->fsw_area_invert ? 0x80 : 0); enum tool78_stat st = tool78_cmd_send(hw, tool78_cmd_fsw_set, 4, data); if (st != tool78_stat_ack) return st; st = tool78_wait_status(hw, 1, tG23); if (st != tool78_stat_ack) return st; return st; } enum tool78_stat tool78_do_fsw_get(struct tool78_hw* hw, struct tool78_fsw_settings* fswopt) { bool isrl78 = (hw->target & tool78_mcu_mask) == tool78_mcu_rl78; if (!isrl78) return tool78_stat_bad_mcu_for_cmd; uint8_t data[4]; enum tool78_stat st = tool78_cmd_send(hw, tool78_cmd_fsw_get, 0, NULL); if (st != tool78_stat_ack) return st; st = tool78_wait_status(hw, 1, tG23); if (st != tool78_stat_ack) return st; st = tool78_data_recv(hw, data, 4, tG23); if (st != tool78_stat_ack) return st; fswopt->block_start = data[0] | ((data[1] & 1) << 8); fswopt->block_end = data[2] | ((data[3] & 1) << 8); fswopt->fswopt_rw_allow = data[1] & 0x80; fswopt->fsw_area_invert = data[3] & 0x80; return st; } // ---- enum tool78_stat tool78_do_g10_get_flash_size(struct tool78_hw* hw, enum tool78_g10_flash_size* fsz) { busy_wait_us_32(tDTR); // start crc calc cmd uint8_t data[3]; data[0] = tool78_cmd_crc_check; int rr = hw->send(1, data, -1); if (rr != 1) return tool78_stat_internal_error; data[1] = data[2] = 0; rr = hw->recv(3, data, (tDT+tDRT)*100); // cmd is echoed back //printf("gfsz rr=%d data=%02x %02x %02x\n", rr, data[0], data[1], data[2]); if (rr != 3) return tool78_stat_timeout_error; if (data[1] != tool78_stat_ack) return data[1]; *fsz = data[2]; busy_wait_us_32(tDTR); data[0] = tool78_stat_nak; // should send ack here, but send nak to stop crc calc rr = hw->send(1, data, -1); //printf("send nak: rr=%d data=%02x\n", rr, data[0]); if (rr != 1) return tool78_stat_internal_error; rr = hw->recv(3, data, tCRC); //printf("recv rr=%d data=%02x %02x %02x\n", rr, data[0], data[1], data[2]); // should answer with 0x04 but let's not care here return tool78_stat_ack; } enum tool78_stat tool78_do_g10_check_crc(struct tool78_hw* hw, enum tool78_g10_flash_size fsz, uint16_t* crc) { busy_wait_us_32(tDTR); uint8_t data[3]; data[0] = tool78_cmd_crc_check; int rr = hw->send(1, data, -1); if (rr != 1) return tool78_stat_internal_error; rr = hw->recv(3, data, (tDT+tDRT)*100); if (rr != 3) return tool78_stat_timeout_error; if (data[1] != tool78_stat_ack) return data[1]; busy_wait_us_32(tDTR); if (data[2] != fsz) { data[0] = tool78_stat_nak; // should send ack here, but send nak to stop crc calc rr = hw->send(1, data, -1); if (rr != 1) return tool78_stat_internal_error; rr = hw->recv(3, data, tCRC); // should answer with 0x04 but let's not care here return tool78_stat_bad_flash_size; } else { data[0] = tool78_stat_ack; rr = hw->send(1, data, -1); if (rr != 1) return tool78_stat_internal_error; rr = hw->recv(2, data, tCRC*2); if (rr != 2) return tool78_stat_timeout_error; if (data[0] == 0xff) { // framing error bullshit data[0] = data[1]; rr = hw->recv(1, &data[1], tCRC); if (rr != 1) return tool78_stat_timeout_error; } //printf("recv1 rr=%d data=%02x %02x\n", rr, data[0], data[1]); enum tool78_stat st = data[1]; if (st != tool78_stat_ack) return st; rr = hw->recv(2, data, tDT*1000); //printf("recv2 rr=%d data=%02x %02x %02x\n", rr, data[0], data[1], data[2]); if (rr != 2) return tool78_stat_timeout_error; if (data[0] == 0xff) { data[0] = data[1]; rr = hw->recv(1, &data[1], tDT*500); if (rr != 1) return tool78_stat_timeout_error; } //printf("recv2 rr=%d data=%02x %02x %02x\n", rr, data[0], data[1], data[2]); *crc = data[0] | ((uint16_t)data[1] << 8); return tool78_stat_ack; } } enum tool78_stat tool78_do_g10_erase_then_write(struct tool78_hw* hw, enum tool78_g10_flash_size fsz, const uint8_t* data_to_wr, size_t datalen) { busy_wait_us_32(tDTR); uint8_t data[5]; data[0] = tool78_cmd_write_after_erase; int rr = hw->send(1, data, -1); if (rr != 1) return tool78_stat_internal_error; rr = hw->recv(3, data, (tDT+tDRT)*100); printf("recv1 rr=%d data=%02x %02x %02x\n", rr, data[0], data[1], data[2]); if (rr != 3) return tool78_stat_timeout_error; if (data[1] != tool78_stat_ack) return data[1]; busy_wait_us_32(tDTR); if (data[2] != fsz) { data[0] = tool78_stat_nak; // should send ack here, but send nak to stop crc calc rr = hw->send(1, data, -1); if (rr != 1) return tool78_stat_internal_error; rr = hw->recv(3, data, tERA); // should answer with 0x04 but let's not care here return tool78_stat_bad_flash_size; } else { data[0] = tool78_stat_ack; rr = hw->send(1, data, -1); if (rr != 1) return tool78_stat_internal_error; rr = hw->recv(2, data, tERA); if (rr != 2) return tool78_stat_timeout_error; if (data[0] == 0xff) { // framing error bullshit data[0] = data[1]; rr = hw->recv(1, &data[1], tERA); if (rr != 1) return tool78_stat_timeout_error; } printf("recv2 rr=%d data=%02x %02x\n", rr, data[0], data[1]); enum tool78_stat st = data[1]; if (st != tool78_stat_ack) return st; size_t flash_sz = (fsz + 1) * 256; for (size_t i = 0; i < flash_sz; i += 4) { data[0] = ((i+0) < datalen) ? data_to_wr[i+0] : 0xff; data[1] = ((i+1) < datalen) ? data_to_wr[i+1] : 0xff; data[2] = ((i+2) < datalen) ? data_to_wr[i+2] : 0xff; data[3] = ((i+3) < datalen) ? data_to_wr[i+3] : 0xff; busy_wait_us_32(tDTR); rr = hw->send(1, &data[0], -1); if (rr != 1) return tool78_stat_internal_error; busy_wait_us_32(tDRT*20); rr = hw->send(1, &data[1], -1); if (rr != 1) return tool78_stat_internal_error; busy_wait_us_32(tDRT*20); rr = hw->send(1, &data[2], -1); if (rr != 1) return tool78_stat_internal_error; busy_wait_us_32(tDRT*20); rr = hw->send(1, &data[3], -1); if (rr != 1) return tool78_stat_internal_error; rr = hw->recv(5, data, tPRO); printf("recv3 i=%04zx rr=%d data=%02x %02x %02x %02x %02x\n", i, rr, data[0], data[1], data[2], data[3], data[4]); if (rr != 5) return tool78_stat_timeout_error; st = data[4]; if (st != tool78_stat_ack) return st; } rr = hw->recv(2, data, tVER*100); printf("recv4 rr=%d data=%02x %02x\n", rr, data[0], data[1]); if (rr != 2) return tool78_stat_timeout_error; st = data[1]; return st; } } // ---- int tool78_ocd_version(struct tool78_hw* hw, uint16_t* ver) { bool is_g10 = (hw->target & tool78_mcu_mask) == tool78_mcu_rl78g10; if (is_g10) return -5; busy_wait_ms(1); uint8_t bytes[3]; bytes[0] = tool78ocd_cmd_version; int rr = hw->send(1, &bytes[0], -1); // bytes[0] is tool78ocd_cmd_version echoed back rr = hw->recv(3, bytes, 1000); if (rr != 3) { /*printf("OCDver rr: %d\n", rr); for (int iii = 0; iii < rr; ++iii) { printf("0x%02x%c", bytes[iii], (iii==rr-1)?'\n':' '); }*/ return -1; } if (rr == 3) { *ver = bytes[1] | ((uint16_t)bytes[2] << 8); } /*else { *ver = bytes[0] | ((uint16_t)bytes[1] << 8); }*/ //printf("ver=%04x\n", *ver); return 0; } int tool78_ocd_connect(struct tool78_hw* hw, const uint8_t passwd[10]) { busy_wait_ms(1); uint8_t stuff[11]; uint8_t connst; bool is_g10 = (hw->target & tool78_mcu_mask) == tool78_mcu_rl78g10; stuff[0] = is_g10 ? tool78ocd_cmdg10_connect : tool78ocd_cmd_connect; int rr = hw->send(1, &stuff[0], -1); // stuff[1] is tool78ocd_cmd_connect echoed back rr = hw->recv(2, &stuff[1], 1000); if (rr != 2) { /*printf("OCDconn rr: %d\n", rr); for (int iii = 0; iii < rr; ++iii) { printf("0x%02x%c", stuff[1+iii], (iii==rr-1)?'\n':' '); }*/ return -1; } connst=stuff[2]; //printf("connst 1=%02x\n", connst); if (connst == 0xff) { rr = hw->recv(1, &connst, 1000); if (rr != 1) return -1; } //printf("connst 2=%02x\n", connst); if (connst == 0xf0 || connst == 0xf4) return connst; // connst==0xf1 memcpy(stuff, passwd, 10); if (!is_g10) { stuff[10] = tool78_calc_ocd_checksum8(10, passwd); } busy_wait_us_32(100); rr = hw->send(is_g10 ? 10 : 11, stuff, -1); // stuff[9] is the checksum byte echoed back rr = hw->recv(2, &stuff[9], 100000); //printf("ocdpw 2 = %02x %02x\n", stuff[9], stuff[10]); if (rr != 2) { /*printf("OCDconn2 rr: %d\n", rr); for (int iii = 0; iii < rr; ++iii) { printf("0x%02x%c", stuff[9+iii], (iii==rr-1)?'\n':' '); }*/ return -2; } if (stuff[9] == 0xff && is_g10) { // framing error bullshit stuff[9] = stuff[10]; rr = hw->recv(1, &stuff[10], 100000); if (rr != 1) return -2; } //printf("ocdpw 3 = %02x %02x\n", stuff[9], stuff[10]); while (stuff[10] == 0) { rr = hw->recv(1, &stuff[10], 100000); if (rr != 1) return -2; } //printf("ocdpw 4 = %02x %02x\n", stuff[9], stuff[10]); /*printf("cksum=0x%02x conn=%02x pw=%02x\n", cksum, connst, stuff[10]);*/ //printf("connst=%u stuff=%u\n", connst, stuff[10]); return stuff[10];//(uint32_t)connst | ((uint32_t)stuff[10] << 8); } int tool78_ocd_read(struct tool78_hw* hw, uint16_t off, uint8_t len, uint8_t* data) { busy_wait_ms(1); bool is_g10 = (hw->target & tool78_mcu_mask) == tool78_mcu_rl78g10; uint8_t hdr[4]; int rr; if (is_g10) { if (len == 2) { hdr[0] = tool78ocd_cmdg10_setptr; hdr[1] = off & 0xff; // l hdr[2] = off >> 8; // h hdr[3] = 1; // b rr = hw->send(sizeof hdr, hdr, -1); if (rr != sizeof hdr) return -1; // command echoed back rr = hw->recv(4, hdr, 1000); if (rr != 4) return -2; if (hdr[0] == 0xff) { // frame error bullshit hdr[0] = hdr[1]; hdr[1] = hdr[2]; hdr[2] = hdr[3]; rr = hw->recv(1, &hdr[3], 1000); if (rr != 1) return -2; } // status rr = hw->recv(1, hdr, 1000); if (rr != 1) return -1; if (hdr[0] != 0x00) return -3; busy_wait_us_32(100); hdr[0] = tool78ocd_cmdg10_read_word; rr = hw->send(1, hdr, -1); if (rr != 1) return -1; rr = hw->recv(1, hdr, 1000); // command echoed back if (rr != 1) return -1; rr = hw->recv(2, data, 1000*len); if (rr != 2) return -2; return 0; } else { hdr[0] = tool78ocd_cmdg10_setptr; hdr[1] = off & 0xff; // l hdr[2] = off >> 8; // h hdr[3] = len; // b rr = hw->send(sizeof hdr, hdr, -1); if (rr != sizeof hdr) return -1; //printf("sent hdr\n"); rr = hw->recv(4, hdr, 1000); //printf("stat rr=%d hdr=%02x %02x %02x %02x\n", rr, hdr[0], hdr[1], hdr[2], hdr[3]); if (rr != 4) return -2; if (hdr[0] == 0xff) { // frame error bullshit hdr[0] = hdr[1]; hdr[1] = hdr[2]; hdr[2] = hdr[3]; rr = hw->recv(1, &hdr[3], 1000); if (rr != 1) return -2; } rr = hw->recv(1, hdr, 1000); //printf("stat rr=%d hdr=%02x\n", rr, hdr[0]); if (rr != 1) return -1; if (hdr[0] != 0x00) return -3; busy_wait_us_32(100); hdr[0] = tool78ocd_cmdg10_read_raw; rr = hw->send(1, hdr, -1); if (rr != 1) return -1; //printf("sent rdcmd\n"); rr = hw->recv(1, hdr, 1000); // command echoed back //printf("recv dd=%d hdr=%02x\n", rr, hdr[0]); if (rr != 1) return -1; rr = hw->recv(len, data, 1000*len); //printf("got data rr=%d data=%02x\n", rr, data[0]); if (rr != len) return -2; return 0; } } else { hdr[0] = tool78ocd_cmd_read; hdr[2] = off >> 8; hdr[1] = off & 0xff; hdr[3] = len; //printf("rd len=%u\n", len); int rr = hw->send(sizeof hdr, hdr, -1); if (rr != sizeof hdr) return -1; rr = hw->recv(1, &hdr[2], 1000); // last byte of header sent echoed back if (rr != 1 || hdr[2] != hdr[3]) { //printf("rd recv=%02x\n", hdr[2]); return -2; } rr = hw->recv(len, data, 1000*len); //printf("ocd read %d\n", rr); return (rr == len) ? 0 : -1; } } int tool78_ocd_write(struct tool78_hw* hw, uint16_t addr, uint8_t len, const uint8_t* data) { if (len == 0) return -1; busy_wait_ms(1); bool is_g10 = (hw->target & tool78_mcu_mask) == tool78_mcu_rl78g10; uint8_t hdr[4]; int rr; if (is_g10) { if (len == 2) { hdr[0] = tool78ocd_cmdg10_setptr; hdr[1] = addr & 0xff; // l hdr[2] = addr >> 8; // h hdr[3] = data[1]; // b rr = hw->send(sizeof hdr, hdr, -1); if (rr != sizeof hdr) return -1; // command echoed back rr = hw->recv(4, hdr, 1000); if (rr != 4) return -2; if (hdr[0] == 0xff) { // frame error bullshit hdr[0] = hdr[1]; hdr[1] = hdr[2]; hdr[2] = hdr[3]; rr = hw->recv(1, &hdr[3], 1000); if (rr != 1) return -2; } // status rr = hw->recv(1, hdr, 1000); if (rr != 1) return -1; if (hdr[0] != 0x00) return -3; hdr[0] = tool78ocd_cmdg10_write_word; hdr[1] = data[0]; // a busy_wait_us_32(100); rr = hw->send(2, hdr, -1); if (rr != 2) return -1; rr = hw->recv(3, hdr, 1000); // command echoed back + ack if (rr != 3) return -1; return (hdr[2] == 0) ? 0 : -2; } else { hdr[0] = tool78ocd_cmdg10_setptr; hdr[1] = addr & 0xff; // l hdr[2] = addr >> 8; // h hdr[3] = len; // b rr = hw->send(sizeof hdr, hdr, -1); if (rr != sizeof hdr) return -1; // command echoed back rr = hw->recv(4, hdr, 1000); printf("wr p1: rr=%d %02x %02x %02x %02x\n", rr, hdr[0], hdr[1], hdr[2], hdr[3]); if (rr != 4) return -2; if (hdr[0] == 0xff) { // frame error bullshit hdr[0] = hdr[1]; hdr[1] = hdr[2]; hdr[2] = hdr[3]; rr = hw->recv(1, &hdr[3], 1000); if (rr != 1) return -2; } printf("wr p1: rr=%d %02x %02x %02x %02x\n", rr, hdr[0], hdr[1], hdr[2], hdr[3]); // status rr = hw->recv(1, hdr, 1000); printf("wr p2: rr=%d %02x %02x %02x %02x\n", rr, hdr[0], hdr[1], hdr[2], hdr[3]); if (rr != 1) return -1; if (hdr[0] == len) { rr = hw->recv(1, hdr, 1000); printf("wr p2: rr=%d %02x %02x %02x %02x\n", rr, hdr[0], hdr[1], hdr[2], hdr[3]); if (rr != 1) return -1; } if (hdr[0] != 0x00) return -3; hdr[0] = tool78ocd_cmdg10_write_raw; busy_wait_us_32(100); rr = hw->send(1, hdr, -1); if (rr != 1) return -1; rr = hw->recv(1, hdr, 1000); // sigh printf("wr p3: rr=%d %02x %02x %02x %02x\n", rr, hdr[0], hdr[1], hdr[2], hdr[3]); if (rr != 1) return -1; for (int i = 0; i < len; i += 8) { int todo = len - i; if (todo > 8) todo = 8; busy_wait_us_32(100); rr = hw->send(todo, &data[i], -1); if (rr != todo) return -1; rr = hw->recv(todo, NULL, 1000*todo); // sigh printf("wr p4: rr=%d %02x %02x %02x %02x\n", rr, hdr[0], hdr[1], hdr[2], hdr[3]); if (rr != todo) return -1; } rr = hw->recv(1, hdr, 1000); printf("wr p5: rr=%d %02x %02x %02x %02x\n", rr, hdr[0], hdr[1], hdr[2], hdr[3]); printf("recv %d: %02x %02x\n", rr, hdr[0], hdr[1]); if (rr != 1) return -1; return (hdr[0] == 0) ? 0 : -2; } } else { hdr[0] = tool78ocd_cmd_write; hdr[1] = addr & 0xff; hdr[2] = addr >> 8; hdr[3] = len; int rr = hw->send(sizeof hdr, hdr, -1); if (rr != sizeof hdr) return -1; rr = hw->send(len, data, -1); if (rr != len) return -1; // last data byte echoed back rr = hw->recv(2, hdr, 1000*len); if (rr != 2) return -1; ///printf("ocd write 0x%02x\n", hdr[1]); return (hdr[1] == tool78ocd_cmd_write) ? 0 : -2; } } int tool78_ocd_exec(struct tool78_hw* hw) { busy_wait_ms(1); bool is_g10 = (hw->target & tool78_mcu_mask) == tool78_mcu_rl78g10; uint8_t hdr[2], cmd; cmd = hdr[0] = is_g10 ? tool78ocd_cmdg10_exec : tool78ocd_cmd_exec; int rr = hw->send(1, hdr, -1); // G13 sends status before exec, G10 sends it after rr = hw->recv(is_g10 ? 1 : 2, hdr, 1000); if (rr != 1 && rr != 2) return -1; printf("exec r=%d: h[0]=0x%02x, h[1]=0x%02x\n", rr, hdr[0], hdr[1]); return 0;//(hdr[0] == cmd) ? 0 : -2; } int tool78_ocd_leave(struct tool78_hw* hw, bool exit_to_ram) { busy_wait_ms(1); bool is_g10 = (hw->target & tool78_mcu_mask) == tool78_mcu_rl78g10; uint8_t hdr[2]; if (is_g10) { hdr[0] = tool78ocd_cmdg10_exit_reti; } else { hdr[0] = exit_to_ram ? tool78ocd_cmd_exit_ram : tool78ocd_cmd_exit_reti; } int rr = hw->send(1, hdr, -1); if (is_g10) { rr = hw->recv(2, &hdr[0], 1000); if (rr != 2) return -1; return 0; } else { rr = hw->recv(1, &hdr[1], 1000); if (rr != 1) return -1; return (hdr[0] == hdr[1]) ? 0 : -2; } } // ---- static enum tool78_stat tool78_init_common(struct tool78_hw* hw) { if (!hw) return tool78_stat_internal_error; if ((hw->target & tool78_mcu_mask) != tool78_mcu_rl78g10) { hw->flags &= ~tool78_hw_flag_done_reset; } else { hw->flags |= tool78_hw_flag_done_reset; } enum tool78_stat st = tool78_stat_ack; for (size_t i = 0; i < 16; ++i) { if (!hw->init()) return tool78_stat_fatal_hw_error; //printf("init %zu ok\n", i); if ((hw->target & tool78_mcu_mask) != tool78_mcu_rl78 && (hw->target & tool78_mcu_mask) != tool78_mcu_rl78g10) { st = tool78_do_reset(hw); //printf("done reset st=0x%02x\n", st); } if (st == tool78_stat_timeout_error) { hw->deinit(); continue; } break; } if (st != tool78_stat_ack) return st; //printf("hw inited\n"); if ((hw->target & tool78_mcu_mask) != tool78_mcu_rl78g10) { st = tool78_do_generic_baudrate(hw); //printf("baudrate result=0x%02x\n", st); if (st != tool78_stat_ack) return st; } else { // 0x3a/0xc5 is echoed back as well uint8_t data[5]; int rr = hw->recv(2, data, 1000); st = data[1]; //printf("init rr:%d st=%02x\n", rr, st); if (rr != 2) return tool78_stat_timeout_error; if (st == 0x06) { // should be 5 zero bytes, but let's not check rr = hw->recv(5, data, 5*1000); if (rr != 5) return tool78_stat_no_ocd_status; } } return st; } enum tool78_stat tool78_init_sfp(struct tool78_hw* hw, tool78_silicon_sig_t* sig) { hw->flags &= ~tool78_hw_flag_do_ocd; enum tool78_stat st = tool78_init_common(hw); if (st != tool78_stat_ack) return st; if ((hw->target & tool78_mcu_mask) != tool78_mcu_rl78g10) { st = tool78_do_silicon_signature(hw, sig); //printf("sig result=0x%02x\n", st); if (st != tool78_stat_ack) return st; } return st; } enum tool78_stat tool78_init_ocd(struct tool78_hw* hw, uint16_t* ver, const uint8_t passwd[10]) { hw->flags |= tool78_hw_flag_do_ocd; int st = tool78_init_common(hw); //printf("common st=%d\n", st); if (st != tool78_stat_ack) return st; if ((hw->target & tool78_mcu_mask) != tool78_mcu_rl78g10) { st = tool78_ocd_version(hw, ver); //printf("ocdver st=%d\n", st); if (st) return st; } st = tool78_ocd_connect(hw, passwd); //printf("conn st=%d\n", st); /*uint8_t i = 0; do { st = tool78_ocd_connect(hw, passwd, i); ++i; if (i == 0) break; } while ((st & 0xff00) == 0xf300 && (st & 0xff) == 0xf1);*/ return st; }