diff --git a/src/tool78/tool78_cmds.c b/src/tool78/tool78_cmds.c new file mode 100644 index 0000000..756524d --- /dev/null +++ b/src/tool78/tool78_cmds.c @@ -0,0 +1,636 @@ + +#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*TODO+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~ | + + +static enum tool78_stat tool78_data_send(struct tool78_hw* hw, + size_t len, const uint8_t* data, bool final_block) { + if (len == 0) return tool78_stat_ack; + if (len > 0x100) return tool78_stat_internal_error; + len &= 0xff; + + uint8_t pre[2], // soh, len + post[2]; // cksum, etx + pre[0] = tool78_frame_soh; + pre[1] = len; + 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; + + int rr = hw->send(2, 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_cmd_send(struct tool78_hw* hw, uint8_t cmd, + uint8_t len, const uint8_t* data) { + if (len == 0) return tool78_stat_ack; + if (len > 0x100) return tool78_stat_internal_error; + len &= 0xff; + + busy_wait_us_32(tCOM); // TODO // 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] = len + 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[2]; // stx, len + uint8_t post[2]; // cksum, etx/etb + + int rr = hw->recv(1, &pre[0], timeout_us_first); + if (rr != 1) return tool78_stat_internal_error; + if (hw->target == tool78k0_spi && pre[0] == tool78_stat_busy) + return tool78_stat_busy; + if (pre[0] != tool78_frame_soh) return tool78_stat_protocol_error; + + rr = hw->recv(1, &pre[1], 100); + if (rr != 1) return tool78_stat_internal_error; + + uint8_t 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, 100*len); + if (rr != len) return tool78_stat_internal_error; + + rr = hw->recv(2, post, 200); + 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_checksum(len, buf); + if (ck != post[0]) + return tool78_stat_protocol_error; + + return tool78_stat_ack; +} + +static enum tool78_stat tool78_wait_status(struct tool78_hw* hw, int l, int timeout_us) { + if (hw->target == tool78k0_spi && timeout_us >= 0) { + busy_wait_us_32(timeout_us); + timeout_us *= 2; + } + + 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); // TODO + } + + st = tool78_data_recv(hw, databuf, l, timeout_us); + if (st == tool78_status_busy) goto cont; + if (st != tool78_stat_ack) return st; + + st = databuf[0]; + if (st == tool78_status_busy) goto cont; + + return st; + + cont: + busy_wait_us_32(timeout_us/64); + } + + 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); + if (st != tool78_stat_ack) return st; + + st = tool78_wait_status(hw, 1, tWT0); // TODO // aka tCS1 + if (st != tool78_stat_ack) return st; + + return st; +} + +enum tool78_stat tool78_do_baud_rate_set(struct tool78_hw* hw) { + uint8_t d0x[5]; + int len = 0; + 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); // TODO + + // 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, 5, d0x); + if (st != tool78_stat_ack) return st; + + st = tool78_wait_status(hw, 3, tWT10); // TODO // aka tCS6 + if (st != tool78_stat_ack) return st; + + // now at 115.2kbaud, so let the physical layer switch to it + hw->set_baudrate(115200); + + // let's ignore the two data bytes for now + + 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); // TODO + 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); // TODO +} + +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; + + 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); // TODO // 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) { + 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); // TODO // aka tCS5 + if (st != tool78_stat_ack) return st; + + int nblocks = ((end - start + 255) / 256); + for (size_t off = 0; off < end - start; off += 256) { + busy_wait_us_32(tSD5); // TODO // aka tFD3 + + size_t todo = (end - start) - off; + if (todo > 256) todo = 256; + bool finalblk = off + 256 >= (end - start); + st = tool78_data_send(hw, todo, &src[off], finalblk); + if (st != tool78_stat_ack) return st; + + st = tool78_wait_status(hw, 2, tWT4); // TODO // aka tDS5 + 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 : (tWT5 * nblocks)); // TODO + 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) { + 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); // TODO // aka tCS2 + if (st != tool78_stat_ack) return st; + + //int nblocks = ((end - start + 255) / 256); + for (size_t off = 0; off < end - start; off += 256) { + busy_wait_us_32(tSD2); // TODO // aka tFD3 + + size_t todo = (end - start) - off; + if (todo > 256) todo = 256; + bool finalblk = off + 256 >= (end - start); + st = tool78_data_send(hw, todo, &src[off], finalblk); + if (st != tool78_stat_ack) return st; + + st = tool78_wait_status(hw, 2, tWT7); // TODO // 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 */) { + 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; + } + + int nblocks = ((end - start + 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)); // TODO + if (st != tool78_stat_ack) return st; + + return st; +} + +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_cmu_for_cmd; + } + + 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; + + st = tool78_wait_status(hw, 1, tWT11); // TODO // aka tCS11 + if (st != tool78_stat_ack) return st; + + st = tool78_data_recv(hw, sig_dest, nbyte, tFD2); // TODO // aka tSD11 + if (st != tool78_stat_ack) return st; + + // TODO: parity check of data + + 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); // TODO + if (st != tool78_stat_ack) return st; + + memset(vout, 0, 6); + st = tool78_data_recv(hw, vout, 6, tFD2); // TODO + 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) { + 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); // TODO // aka tCS10 + if (st != tool78_stat_ack) return st; + + *ckout = 0; + st = tool78_data_recv(hw, ckout, 2, tFD1); // TODO // 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); // TODO // aka tCS7 + if (st != tool78_stat_ack) return st; + + busy_wait_us_32(tSD7); // TODO // 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); // TODO // aka tDS7 + if (st != tool78_stat_ack) return st; + + if (!srl78) { // yeah... + st = tool78_wait_status(hw, 1, tWT15); // TODO + 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); // TODO + if (st != tool78_stat_ack) return st; + + // TODO: needs a modeset/re-entry sequence now? + + return st; +} + +// ---- + +enum tool78_stat tool78_init(struct tool78_hw* hw) { + if (!hw) return tool78_stat_internal_error; + + for (size_t i = 0; i < 16; ++i) { + if (!hw->init()) return tool78_stat_fatal_hw_error; + + enum tool78_stat st = tool78_do_reset(hw); + if (st == tool78_stat_timeout_error) { + hw->deinit(); + continue; + } + return st; + } + + // TODO: baudrate set/oscfreq set (if not 78k0 SPI) + // TODO: silicon sig get (not reqd if 78k0 but oh well) +} + diff --git a/src/tool78/tool78_cmds.h b/src/tool78/tool78_cmds.h index 5fef3ee..235ce4b 100644 --- a/src/tool78/tool78_cmds.h +++ b/src/tool78/tool78_cmds.h @@ -1,3 +1,46 @@ -// big TODO (implement separate commands & handle MCU differences) +#ifndef TOOL78_CMDS_H_ +#define TOOL78_CMDS_H_ + +#include "tool78_defs.h" +#include "tool78_hw.h" + +enum tool78_stat tool78_do_reset(struct tool78_hw* hw); + +enum tool78_stat tool78_do_baud_rate_set(struct tool78_hw* hw); +enum tool78_stat tool78_do_osc_freq_set(struct tool78_hw* hw); + +static inline enum tool78_stat tool78_do_generic_baudrate(struct tool78_hw* hw) { + if ((hw->target & tool78_mcu_mask) == tool78_mcu_78k0) + return tool78_do_osc_freq_set(hw); + else + return tool78_do_baud_rate_set(hw); +} + +enum tool78_stat tool78_do_chip_erase(struct tool78_hw* hw); +enum tool78_stat tool78_do_block_erase(struct tool78_hw* hw, uint32_t start, uint32_t end); + +enum tool78_stat tool78_do_programming(struct tool78_hw* hw, uint32_t start, + uint32_t end, const uint8_t* src); +enum tool78_stat tool78_do_verify(struct tool78_hw* hw, uint32_t start, + uint32_t end, const uint8_t* src); +enum tool78_stat tool78_do_block_blank_check(struct tool78_hw* hw, + uint32_t start, uint32_t end, bool check_flash_opt /* RL78 only */); +enum tool78_stat tool78_do_checksum(struct tool78_hw* hw, uint32_t start, + uint32_t end, uint16_t* ckout); + +enum tool78_stat tool78_do_silicon_signature(struct tool78_hw* hw, + tool78_silicon_sig_t* sig_dest); +enum tool78_stat tool78_do_version_get(struct tool78_hw* hw, tool78_version_t* vout); +enum tool78_stat tool78_do_security_set(struct tool78_hw* hw, + const struct tool78_security* sec); +enum tool78_stat tool78_do_security_get(struct tool78_hw* hw, + struct tool78_security* sec); +enum tool78_stat tool78_do_security_release(struct tool78_hw* hw); + +// ---- + +enum tool78_stat tool78_init(struct tool78_hw* hw); + +#endif diff --git a/src/tool78/tool78_defs.h b/src/tool78/tool78_defs.h index 1d5b879..227befe 100644 --- a/src/tool78/tool78_defs.h +++ b/src/tool78/tool78_defs.h @@ -84,6 +84,8 @@ enum tool78_cmd { tool78_cmd_security_set = 0xa0, // RL78 only tool78_cmd_security_get = 0xa1, + // RL78 only + tool78_cmd_security_release = 0xa2, tool78_cmd_checksum = 0xb0, // response format & length differ between all MCU versions! // length & first few bytes can be used to discern between MCUs @@ -94,6 +96,8 @@ enum tool78_cmd { }; enum tool78_stat { + tool78_stat_internal_error = 0x00, // error internal to this implementation code + tool78_stat_cmd_not_supported = 0x04, tool78_stat_parameter_error = 0x05, tool78_stat_ack = 0x06, @@ -109,6 +113,11 @@ enum tool78_stat { tool78_stat_read_error = 0x20, // 78k0/Kx2 SPI only tool78_stat_busy = 0xff + + tool78_stat_protocol_error = 0xc1, // low-level wire protocol violation + tool78_stat_bad_mcu_for_cmd = 0xc2, + tool78_stat_timeout_error = 0xc3, + tool78_stat_fatal_hw_error = 0xc4, }; // TODO: only known for RL78 from fail0overflow. verify! @@ -145,15 +154,87 @@ enum tool78_frame { tool78_frame_eot = 0x17, }; -static inline uint8_t tool78_calc_checksum8(size_t len, const uint8_t* data) { - uint8_t r = 0; +static inline uint8_t tool78_digest_checksum8(uint8_t r, const uint8_t* data) { for (size_t i = 0; i < len; ++i) r = r - data[i]; return r; } +static inline uint8_t tool78_calc_checksum8(size_t len, const uint8_t* data) { + return tool78_digest_checksum8(r, len, data); +} static inline uint8_t tool78_calc_ocd_checksum8(size_t len, const uint8_t* data) { return ~tool78_calc_checksum8(len, data); } // TODO: 16bit checksum (cf. command B0 Checksum) +__attribute__((__packed__, __align__(1))) struct tool78_silicon_sig_78k0 { + uint8_t ven; // vendor code. 0x10 == NEC + uint8_t met; // macro extension (0x7f) + uint8_t msc; // macro function code (0x04) + uint8_t dec; // device extension code (0x07) + uint8_t end[3]; // internal flash memory last address + uint8_t dev[10]; // device name + uint8_t scf; // security flag info + uint8_t bot; // boot block number (0x03) + // "for above fields except BOT, the lower 7 bits are used as data entity, + // and the highest bit is used as an odd parity" +}; +__attribute__((__packed__, __align__(1))) struct tool78_silicon_sig_78k0r { + uint8_t ven; // vendor code. 0x10 == NEC + uint8_t met; // macro extension (0x6f or 0x7f) + uint8_t msc; // macro function code (0x04) + uint8_t dec[3]; // device extension code + uint8_t uae[3]; // internal flash memory last address + uint8_t dev[10]; // device name + uint8_t scf; // security flag info + uint8_t bot; // boot block number (0x03) + uint8_t fswsh; // flash shield window start hi + uint8_t fswsl; // flash shield window start lo + uint8_t fsweh; // flash shield window end hi + uint8_t fswel; // flash shield window end lo + uint8_t res[2]; // reserved + // "for VEN, MET, MSC and DEC, the lower 7 bits are used as data entity, + // and the highest bit is used as an odd parity." +}; +__attribute__((__packed__, __align__(1))) struct tool78_silicon_sig_rl78 { + uint8_t dec[3]; // device code + uint8_t dev[10]; // device name + uint8_t cen[3]; // last address of code flash rom, little-endian + uint8_t den[3]; // last address of data flash rom, little-endian + uint8_t ver[3]; // firmware version number + // no parity bits +}; +__attribute__((__packed__, __align__(1))) typedef union tool78_silicon_sig { + struct tool78_silicon_sig_78k0 k780 ; + struct tool78_silicon_sig_78k0r k780r; + struct tool78_silicon_sig_rl78 rl78 ; +} tool78_silicon_sig_t; + +// same structure for 78k0 and 78k0r, not used in rl78 +__attribute__((__packed__, __align__(1))) typedef struct tool78_version { + uint8_t dv[3]; // all zero + uint8_t fw[3]; +} tool78_version_t; + +enum tool78_sec_flag { // 78k0/78k0r + tool78_sec_flag_boot_rw_allow = 1<<4, + tool78_sec_flag_prog_allow = 1<<2, + tool78_sec_flag_blk_erase_allow = 1<<1, + // always 1 on RL78 as chip erase doesn't exist on it + tool78_sec_flag_chip_erase_allow = 1<<0, + + tool78_sec_flag_default_78k = 0xe8, // 0b11101000: all set to 1 by default + tool78_sec_flag_default_rl78= 0xe9, // 0b11101000: all set to 1 by default + + tool78_sec_flag_boot_xchg = 1<<0 // rl78 only +}; + +struct tool78_security { + uint8_t flg; + uint8_t bot; + // ^ only these 2 used for 78k0 + uint16_t fsws; + uint16_t fswe; +}; + #endif diff --git a/src/tool78/tool78_hw.h b/src/tool78/tool78_hw.h index e663c6a..6c7669a 100644 --- a/src/tool78/tool78_hw.h +++ b/src/tool78/tool78_hw.h @@ -16,6 +16,7 @@ struct tool78_hw { bool (*init)(void); void (*deinit)(void); + void (*set_baudrate)(uint32_t rate); // returns -1 if an rx overrun occurred int (*has_available)(void); diff --git a/src/tool78/tool78_hw_78k0_spi.c b/src/tool78/tool78_hw_78k0_spi.c index c81894e..b004b81 100644 --- a/src/tool78/tool78_hw_78k0_spi.c +++ b/src/tool78/tool78_hw_78k0_spi.c @@ -93,12 +93,18 @@ static int t78k0_spi_send(int len, const uint8_t* data, int32_t timeout_us) { return t78k0_spi_xfer(len, data, NULL, timeout_us); } +static void t78k0_spi_set_baudrate(uint32_t baudrate) { + float div = (float)clock_get_hz(clk_sys) / (1*baudrate); + pio_sm_set_clkdiv(PINOUT_TOOL78_PIO, vars.smrx, div); +} + struct tool78_hw tool78_hw_78k0_spi = { .target = tool78k0_spi, .init = t78k0_spi_init, .deinit = t78k0_spi_deinit, + .set_baudrate = t78k0_spi_set_baudrate, .has_available = t78k0_spi_has_available, .recv = t78k0_spi_recv, diff --git a/src/tool78/tool78_hw_78k0_uart2.c b/src/tool78/tool78_hw_78k0_uart2.c index a7cce60..b9f89cd 100644 --- a/src/tool78/tool78_hw_78k0_uart2.c +++ b/src/tool78/tool78_hw_78k0_uart2.c @@ -71,12 +71,19 @@ static int t78k0_uart2_send(int len, const uint8_t* data, int32_t timeout_us) { len, data, timeout_us); } +static void t78k0_uart2_set_baudrate(uint32_t baudrate) { + float div = (float)clock_get_hz(clk_sys) / (8*baudrate); + pio_sm_set_clkdiv(PINOUT_TOOL78_PIO, vars.smrx, div); + pio_sm_set_clkdiv(PINOUT_TOOL78_PIO, vars.smtx, div); +} + struct tool78_hw tool78_hw_78k0_uart2 = { .target = tool78k0_uart2, .init = t78k0_uart2_init, .deinit = t78k0_uart2_deinit, + .set_baudrate = t78k0_uart2_set_baudrate, .has_available = t78k0_uart2_has_available, .recv = t78k0_uart2_recv, diff --git a/src/tool78/tool78_hw_78k0_uart2_extclk.c b/src/tool78/tool78_hw_78k0_uart2_extclk.c index 4c9083d..46d5ad3 100644 --- a/src/tool78/tool78_hw_78k0_uart2_extclk.c +++ b/src/tool78/tool78_hw_78k0_uart2_extclk.c @@ -79,6 +79,11 @@ static int t78k0_uart2_extclk_send(int len, const uint8_t* data, int32_t timeout len, data, timeout_us); } +static void t78k0_uart2_extclk_set_baudrate(uint32_t baudrate) { + float div = (float)clock_get_hz(clk_sys) / (8*baudrate); + pio_sm_set_clkdiv(PINOUT_TOOL78_PIO, vars.smrx, div); + pio_sm_set_clkdiv(PINOUT_TOOL78_PIO, vars.smtx, div); +} struct tool78_hw tool78_hw_78k0_uart2_extclk = { .target = tool78k0_uart2_extclk, @@ -86,6 +91,7 @@ struct tool78_hw tool78_hw_78k0_uart2_extclk = { .init = t78k0_uart2_extclk_init, .deinit = t78k0_uart2_extclk_deinit, + .set_baudrate = t78k0_uart2_extclk_set_baudrate, .has_available = t78k0_uart2_extclk_has_available, .recv = t78k0_uart2_extclk_recv, diff --git a/src/tool78/tool78_hw_78k0r_uart1.c b/src/tool78/tool78_hw_78k0r_uart1.c index b4047a7..d4dc6c9 100644 --- a/src/tool78/tool78_hw_78k0r_uart1.c +++ b/src/tool78/tool78_hw_78k0r_uart1.c @@ -30,19 +30,20 @@ static bool t78k0r_uart1_init(void) { tool78_uart_rx_program_init(PINOUT_TOOL78_PIO, vars.smrx, vars.rxoff, PINOUT_TOOL78_78K0R_TOOL0, 9600, true); - // wait for 0x00 byte + // wait for 0x00 "READY" byte uint8_t byte = 0xff; size_t s = t78k0r_uart1_recv(1, &byte, 50*1000); if (s == 0 || byte != 0x00) { t78k0r_uart1_deinit(); return false; } + busy_wait_us_32(120 + 20); // t01 or tCOM - busy_wait_us_32(120); // t01 - - byte = 0; - t78k0r_uart1_send(1, &byte, -1); - + // send two 0x00 "LOW" bytes + uint8_t byte = 0x00; + t78k0_uart2_send(1, &byte, -1); + busy_wait_us_32(120); // t12 + t78k0_uart2_send(1, &byte, -1); busy_wait_us_32(610); // t2C // now a reset command needs to be sent, but we leave that to the upper @@ -69,12 +70,19 @@ static int t78k0r_uart1_send(int len, const uint8_t* data, int32_t timeout_us) { len, data, timeout_us); } +static void t78k0r_uart1_set_baudrate(uint32_t baudrate) { + float div = (float)clock_get_hz(clk_sys) / (8*baudrate); + pio_sm_set_clkdiv(PINOUT_TOOL78_PIO, vars.smrx, div); + pio_sm_set_clkdiv(PINOUT_TOOL78_PIO, vars.smtx, div); +} + struct tool78_hw tool78_hw_78k0r_uart1 = { - .target = tool78rl_uart1, + .target = tool78k0r_uart1, .init = t78k0r_uart1_init, .deinit = t78k0r_uart1_deinit, + .set_baudrate = t78k0r_uart1_set_baudrate, .has_available = t78k0r_uart1_has_available, .recv = t78k0r_uart1_recv, diff --git a/src/tool78/tool78_hw_rl78_uart1.c b/src/tool78/tool78_hw_rl78_uart1.c index f0332f7..95d85ca 100644 --- a/src/tool78/tool78_hw_rl78_uart1.c +++ b/src/tool78/tool78_hw_rl78_uart1.c @@ -59,12 +59,19 @@ static int trl78_uart1_send(int len, const uint8_t* data, int32_t timeout_us) { len, data, timeout_us); } +static void trl78_uart1_set_baudrate(uint32_t baudrate) { + float div = (float)clock_get_hz(clk_sys) / (8*baudrate); + pio_sm_set_clkdiv(PINOUT_TOOL78_PIO, vars.smrx, div); + pio_sm_set_clkdiv(PINOUT_TOOL78_PIO, vars.smtx, div); +} + struct tool78_hw tool78_hw_rl78_uart1 = { .target = tool78rl_uart1, .init = trl78_uart1_init, .deinit = trl78_uart1_deinit, + .set_baudrate = trl78_uart1_set_baudrate, .has_available = trl78_uart1_has_available, .recv = trl78_uart1_recv, diff --git a/src/tool78/tool78_hw_rl78_uart2.c b/src/tool78/tool78_hw_rl78_uart2.c index d54e737..ce6aa10 100644 --- a/src/tool78/tool78_hw_rl78_uart2.c +++ b/src/tool78/tool78_hw_rl78_uart2.c @@ -65,12 +65,19 @@ static int trl78_uart2_send(int len, const uint8_t* data, int32_t timeout_us) { len, data, timeout_us); } +static void trl78_uart2_set_baudrate(uint32_t baudrate) { + float div = (float)clock_get_hz(clk_sys) / (8*baudrate); + pio_sm_set_clkdiv(PINOUT_TOOL78_PIO, vars.smrx, div); + pio_sm_set_clkdiv(PINOUT_TOOL78_PIO, vars.smtx, div); +} + struct tool78_hw tool78_hw_rl78_uart2 = { .target = tool78rl_uart2, .init = trl78_uart2_init, .deinit = trl78_uart2_deinit, + .set_baudrate = trl78_uart2_set_baudrate, .has_available = trl78_uart2_has_available, .recv = trl78_uart2_recv, diff --git a/src/tool78/tool78_hw_test_uart2.c b/src/tool78/tool78_hw_test_uart2.c index 2bef9e8..4ee06b2 100644 --- a/src/tool78/tool78_hw_test_uart2.c +++ b/src/tool78/tool78_hw_test_uart2.c @@ -54,12 +54,19 @@ static int test_send(int len, const uint8_t* data, int32_t timeout_us) { len, data, timeout_us); } +static void test_set_baudrate(uint32_t baudrate) { + float div = (float)clock_get_hz(clk_sys) / (8*baudrate); + pio_sm_set_clkdiv(PINOUT_TOOL78_PIO, vars.smrx, div); + pio_sm_set_clkdiv(PINOUT_TOOL78_PIO, vars.smtx, div); +} + struct tool78_hw tool78_hw_test_uart2 = { .target = tool78k0_uart2, .init = test_init, .deinit = test_deinit, + .set_baudrate = test_set_baudrate, .has_available = test_has_available, .recv = test_recv,