tool78 stuff

This commit is contained in:
Triss 2021-11-07 20:58:00 +01:00
parent 42e447f3a8
commit 1b1ed215eb
11 changed files with 819 additions and 10 deletions

636
src/tool78/tool78_cmds.c Normal file
View File

@ -0,0 +1,636 @@
#include <pico/time.h>
#include <pico/timeout_helper.h>
#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)
}

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,