From 1a7a8c44847cf3d05878f5e47427d2617aa0a425 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Fri, 15 Mar 2024 18:33:15 +0800 Subject: [PATCH] serial_transfer: add 'rate' command This makes it possible to change the serial baud rate without uploading a new serial transfer program. I'm not sure how useful this will be, but it is simple enough to add. The client program is also substantially improved. Sincerely I do not understand how/why this works. Experimentally, I found that feeding the ft232h data in chunks of up to roughly 384 bytes works reliably, both for reads and writes. Larger chunk sizes are (as expected) faster, but the tranfers do not appear to be consistently correct in this case. I have no logical explanation for this. The size of the ft232h FIFO is 1K each for the transmit and receive buffer respectively. This also enables RTS/CTS hardware flow control. Surprisingly, this doesn't appear to affect reliability significantly. --- client.py | 85 +++++++++++++++++++++++++++---------- example/serial_transfer.cpp | 2 +- loader.lds | 4 +- serial_load.cpp | 30 ++++++++++--- sh7091/serial.cpp | 38 ++++++++++++++--- 5 files changed, 121 insertions(+), 38 deletions(-) diff --git a/client.py b/client.py index e1d5a9e..a6958b4 100644 --- a/client.py +++ b/client.py @@ -33,10 +33,10 @@ def symmetric(ser, b): l = [] mem = memoryview(b) i = 0 - chunk_size = 16 + chunk_size = 384 while i < len(b): - if i % 128 == 0: + if i % 1024 == 0: print(i, end=' ') sys.stdout.flush() while True: @@ -48,40 +48,45 @@ def symmetric(ser, b): chunk_size = min(chunk_size, len(b) - i) assert chunk_size > 0, chunk_size - ser.write(b[i:i+chunk_size]) + ser.write(mem[i:i+chunk_size]) i += chunk_size - time.sleep(0.1) - res = ser.read(ser.in_waiting) - l.extend(res) + orig_count = 1000 + count = orig_count + while count > 0: + if len(l) >= len(b): + break + time.sleep(1 / orig_count) + if ser.in_waiting: + res = ser.read(ser.in_waiting) + l.extend(res) + count -= 1 return bytes(l) -def do(ser, b): - _ = ser.read(ser.in_waiting) - ser.flush() - ser.flushInput() - ser.flushOutput() +def start_data(ser, b): _ = ser.read(ser.in_waiting) - ret = sync(ser, b'DATA') - #print(ret) size = len(b) args = struct.pack("= 4) { if (state.buf[0] == 'D' && state.buf[1] == 'A' && @@ -103,9 +101,19 @@ void load_recv(uint8_t c) debug("jump\n"); state.command = CMD_JUMP; } + } else if (state.buf[0] == 'R' && + state.buf[1] == 'A' && + state.buf[2] == 'T' && + state.buf[3] == 'E') { + if (state.len < 8) { + return; + } else { + debug("rate\n"); + state.command = CMD_RATE; + } } else { - move(&state.buf[0], &state.buf[4], state.len - 4); - state.len -= 4; + move(&state.buf[0], &state.buf[1], state.len - 1); + state.len -= 1; } } else { return; @@ -143,6 +151,14 @@ void load_recv(uint8_t c) debug("postjump\n"); return; break; + case CMD_RATE: + state.len = 0; + state.command = CMD_NONE; + debug("prerate\n"); + serial::init(state.addr1 & 0xff); + debug("postrate\n"); + return; + break; } } } diff --git a/sh7091/serial.cpp b/sh7091/serial.cpp index cc4073a..1233cac 100644 --- a/sh7091/serial.cpp +++ b/sh7091/serial.cpp @@ -9,22 +9,43 @@ namespace serial { +static inline void init_wait() +{ + sh7091.TMU.TSTR &= (~tmu::tstr::str1::counter_start) & 0xff; // stop TCNT1 + sh7091.TMU.TOCR = tmu::tocr::tcoe::tclk_is_external_clock_or_input_capture; + sh7091.TMU.TCR1 = tmu::tcr1::tpsc::p_phi_1024; // 1024 / 50MHz = 20.48 μs + sh7091.TMU.TCOR1 = 0xffff'ffff; + sh7091.TMU.TCNT1 = 0xffff'ffff; + sh7091.TMU.TSTR |= tmu::tstr::str1::counter_start; + + uint32_t start = sh7091.TMU.TCNT1; + while ((start - sh7091.TMU.TCNT1) < 1); + + sh7091.TMU.TSTR &= (~tmu::tstr::str1::counter_start) & 0xff; // stop TCNT1 +} + void init(uint8_t bit_rate) { using namespace scif; - sh7091.SCIF.SCSCR2 = 0; - sh7091.SCIF.SCSMR2 = 0; - sh7091.SCIF.SCBRR2 = bit_rate; // bps = 1562500 / (SCBRR2 + 1) + sh7091.SCIF.SCSCR2 = 0; // disable transmission / reception + + sh7091.SCIF.SCSPTR2 = 0; // clear output data pins sh7091.SCIF.SCFCR2 = scfcr2::tfrst::reset_operation_enabled | scfcr2::rfrst::reset_operation_enabled; sh7091.SCIF.SCFCR2 = scfcr2::rtrg::trigger_on_1_byte | scfcr2::ttrg::trigger_on_8_bytes - | scfcr2::mce::modem_signals_disabled; + | scfcr2::mce::modem_signals_enabled; + + sh7091.SCIF.SCSMR2 = scsmr2::chr::_8_bit_data + | scsmr2::pe::parity_disabled + | scsmr2::stop::_1_stop_bit + | scsmr2::cks::p_phi_clock; + + sh7091.SCIF.SCBRR2 = bit_rate; // bps = 1562500 / (SCBRR2 + 1) - sh7091.SCIF.SCSPTR2 = 0; sh7091.SCIF.SCFSR2 = (~scfsr2::er::bit_mask) & (~scfsr2::tend::bit_mask) & (~scfsr2::tdfe::bit_mask) @@ -32,10 +53,15 @@ void init(uint8_t bit_rate) & (~scfsr2::rdf::bit_mask) & (~scfsr2::dr::bit_mask) & 0xffff; - sh7091.SCIF.SCLSR2 = 0; // clear ORER + + + // wait 1 bit interval + init_wait(); sh7091.SCIF.SCSCR2 = scscr2::te::transmission_enabled | scscr2::re::reception_enabled; + + sh7091.SCIF.SCLSR2 = 0; // clear ORER } void character(const char c)