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.
This commit is contained in:
parent
328e9e18bd
commit
1a7a8c4484
81
client.py
81
client.py
@ -33,10 +33,10 @@ def symmetric(ser, b):
|
|||||||
l = []
|
l = []
|
||||||
mem = memoryview(b)
|
mem = memoryview(b)
|
||||||
i = 0
|
i = 0
|
||||||
chunk_size = 16
|
chunk_size = 384
|
||||||
|
|
||||||
while i < len(b):
|
while i < len(b):
|
||||||
if i % 128 == 0:
|
if i % 1024 == 0:
|
||||||
print(i, end=' ')
|
print(i, end=' ')
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
while True:
|
while True:
|
||||||
@ -48,40 +48,45 @@ def symmetric(ser, b):
|
|||||||
|
|
||||||
chunk_size = min(chunk_size, len(b) - i)
|
chunk_size = min(chunk_size, len(b) - i)
|
||||||
assert chunk_size > 0, chunk_size
|
assert chunk_size > 0, chunk_size
|
||||||
ser.write(b[i:i+chunk_size])
|
ser.write(mem[i:i+chunk_size])
|
||||||
i += chunk_size
|
i += chunk_size
|
||||||
|
|
||||||
time.sleep(0.1)
|
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)
|
res = ser.read(ser.in_waiting)
|
||||||
l.extend(res)
|
l.extend(res)
|
||||||
|
count -= 1
|
||||||
|
|
||||||
return bytes(l)
|
return bytes(l)
|
||||||
|
|
||||||
def do(ser, b):
|
def start_data(ser, b):
|
||||||
_ = ser.read(ser.in_waiting)
|
|
||||||
ser.flush()
|
|
||||||
ser.flushInput()
|
|
||||||
ser.flushOutput()
|
|
||||||
_ = ser.read(ser.in_waiting)
|
_ = ser.read(ser.in_waiting)
|
||||||
|
|
||||||
ret = sync(ser, b'DATA')
|
|
||||||
#print(ret)
|
|
||||||
size = len(b)
|
size = len(b)
|
||||||
args = struct.pack("<II", size, dest)
|
args = struct.pack("<II", size, dest)
|
||||||
#print("dargs", args)
|
ret = sync(ser, b'DATA' + args)
|
||||||
ret = sync(ser, args)
|
|
||||||
#print(ret)
|
|
||||||
if ret != b'data\n':
|
if ret != b'data\n':
|
||||||
print(".", end=' ')
|
print(".", end=' ')
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
sync(ser, b'prime', wait=0)
|
sync(ser, b'prime', wait=0)
|
||||||
do(ser, b)
|
start_data(ser, b)
|
||||||
|
return
|
||||||
print("\nDATA")
|
print("\nDATA")
|
||||||
|
|
||||||
|
def do(ser, b):
|
||||||
|
start_data(ser, b)
|
||||||
|
|
||||||
start = time.monotonic()
|
start = time.monotonic()
|
||||||
ret = symmetric(ser, b)
|
ret = symmetric(ser, b)
|
||||||
|
#print("\nHERE", len(ret), len(b))
|
||||||
end = time.monotonic()
|
end = time.monotonic()
|
||||||
duration = end - start
|
duration = end - start
|
||||||
print("duration", duration)
|
print("\n\nduration:", duration, "\n\n")
|
||||||
print(ret[-5:])
|
print(ret[-5:])
|
||||||
if ret[:-5] != b:
|
if ret[:-5] != b:
|
||||||
print("ret != b; dumped to asdf.bin")
|
print("ret != b; dumped to asdf.bin")
|
||||||
@ -90,9 +95,8 @@ def do(ser, b):
|
|||||||
print("did not jump")
|
print("did not jump")
|
||||||
return
|
return
|
||||||
|
|
||||||
ret = sync(ser, b'JUMP', wait=0)
|
|
||||||
args = struct.pack("<I", dest)
|
args = struct.pack("<I", dest)
|
||||||
ser.write(args)
|
ret = sync(ser, b'JUMP' + args, wait=0)
|
||||||
print()
|
print()
|
||||||
console(ser)
|
console(ser)
|
||||||
|
|
||||||
@ -107,8 +111,45 @@ def console(ser):
|
|||||||
with open(sys.argv[1], 'rb') as f:
|
with open(sys.argv[1], 'rb') as f:
|
||||||
b = f.read()
|
b = f.read()
|
||||||
|
|
||||||
with serial.Serial('/dev/ttyUSB0', 120192, timeout=1) as ser:
|
def baudrate_from_scbrr2(n):
|
||||||
#with serial.Serial('/dev/ttyUSB0', 312500, timeout=1) as ser:
|
return 1562500 / (n+1)
|
||||||
|
|
||||||
|
def change_rate(old_rate, new_rate):
|
||||||
|
with serial.Serial(port='/dev/ttyUSB0',
|
||||||
|
baudrate=baudrate_from_scbrr2(old_rate),
|
||||||
|
bytesize=serial.EIGHTBITS,
|
||||||
|
parity=serial.PARITY_NONE,
|
||||||
|
stopbits=serial.STOPBITS_ONE,
|
||||||
|
timeout=1,
|
||||||
|
xonxoff=False,
|
||||||
|
#rtscts=False,
|
||||||
|
rtscts=True,
|
||||||
|
) as ser:
|
||||||
|
buf = b'\x00\x00\x00\x00'
|
||||||
|
start_data(ser, buf)
|
||||||
|
ret = symmetric(ser, buf)
|
||||||
|
print('ret', ret)
|
||||||
|
|
||||||
|
print("change rate", int(baudrate_from_scbrr2(new_rate)))
|
||||||
|
args = struct.pack("<I", new_rate & 0xff)
|
||||||
|
ret = sync(ser, b'RATE' + args, wait=1)
|
||||||
|
print(ret)
|
||||||
|
|
||||||
|
old_rate = 1
|
||||||
|
new_rate = 1
|
||||||
|
if old_rate != new_rate:
|
||||||
|
change_rate(old_rate, new_rate)
|
||||||
|
|
||||||
|
with serial.Serial(port='/dev/ttyUSB0',
|
||||||
|
baudrate=baudrate_from_scbrr2(new_rate),
|
||||||
|
bytesize=serial.EIGHTBITS,
|
||||||
|
parity=serial.PARITY_NONE,
|
||||||
|
stopbits=serial.STOPBITS_ONE,
|
||||||
|
timeout=1,
|
||||||
|
xonxoff=False,
|
||||||
|
#rtscts=False,
|
||||||
|
rtscts=True,
|
||||||
|
) as ser:
|
||||||
#console(ser)
|
#console(ser)
|
||||||
print("waiting: ", end=' ')
|
print("waiting: ", end=' ')
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
@ -10,7 +10,7 @@ void main() __attribute__((section(".text.main")));
|
|||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
//serial::init(12);
|
serial::init(1);
|
||||||
load_init();
|
load_init();
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl")
|
OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl")
|
||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
p1ram : ORIGIN = 0x8c020000, LENGTH = 0xfe0000
|
p1ram : ORIGIN = 0x8c010000, LENGTH = 0xff0000
|
||||||
p2ram : ORIGIN = 0xac020000, LENGTH = 0xfe0000
|
p2ram : ORIGIN = 0xac010000, LENGTH = 0xff0000
|
||||||
ldram : ORIGIN = 0x8cfff000, LENGTH = 0x1000
|
ldram : ORIGIN = 0x8cfff000, LENGTH = 0x1000
|
||||||
}
|
}
|
||||||
SECTIONS
|
SECTIONS
|
||||||
|
@ -9,6 +9,7 @@ enum load_command {
|
|||||||
CMD_NONE,
|
CMD_NONE,
|
||||||
CMD_DATA, // DATA 0000 0000 {data}
|
CMD_DATA, // DATA 0000 0000 {data}
|
||||||
CMD_JUMP, // JUMP 0000
|
CMD_JUMP, // JUMP 0000
|
||||||
|
CMD_RATE, // RATE 0000
|
||||||
};
|
};
|
||||||
|
|
||||||
struct load_state {
|
struct load_state {
|
||||||
@ -48,9 +49,8 @@ void load_init()
|
|||||||
void debug(const char * s)
|
void debug(const char * s)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
|
while ((sh7091.SCIF.SCFSR2 & scif::scfsr2::tdfe::bit_mask) == 0);
|
||||||
while ((c = *s++)) {
|
while ((c = *s++)) {
|
||||||
using namespace scif;
|
|
||||||
while ((sh7091.SCIF.SCFSR2 & scfsr2::tdfe::bit_mask) == 0);
|
|
||||||
sh7091.SCIF.SCFTDR2 = (uint8_t)c;
|
sh7091.SCIF.SCFTDR2 = (uint8_t)c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,12 +75,10 @@ void jump_to_func(const uint32_t addr)
|
|||||||
|
|
||||||
void load_recv(uint8_t c)
|
void load_recv(uint8_t c)
|
||||||
{
|
{
|
||||||
if (state.command == CMD_NONE)
|
|
||||||
state.buf[state.len++] = c;
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
switch (state.command) {
|
switch (state.command) {
|
||||||
case CMD_NONE:
|
case CMD_NONE:
|
||||||
|
state.buf[state.len++] = c;
|
||||||
if (state.len >= 4) {
|
if (state.len >= 4) {
|
||||||
if (state.buf[0] == 'D' &&
|
if (state.buf[0] == 'D' &&
|
||||||
state.buf[1] == 'A' &&
|
state.buf[1] == 'A' &&
|
||||||
@ -103,9 +101,19 @@ void load_recv(uint8_t c)
|
|||||||
debug("jump\n");
|
debug("jump\n");
|
||||||
state.command = CMD_JUMP;
|
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 {
|
} else {
|
||||||
move(&state.buf[0], &state.buf[4], state.len - 4);
|
debug("rate\n");
|
||||||
state.len -= 4;
|
state.command = CMD_RATE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
move(&state.buf[0], &state.buf[1], state.len - 1);
|
||||||
|
state.len -= 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
@ -143,6 +151,14 @@ void load_recv(uint8_t c)
|
|||||||
debug("postjump\n");
|
debug("postjump\n");
|
||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
|
case CMD_RATE:
|
||||||
|
state.len = 0;
|
||||||
|
state.command = CMD_NONE;
|
||||||
|
debug("prerate\n");
|
||||||
|
serial::init(state.addr1 & 0xff);
|
||||||
|
debug("postrate\n");
|
||||||
|
return;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,22 +9,43 @@
|
|||||||
|
|
||||||
namespace serial {
|
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)
|
void init(uint8_t bit_rate)
|
||||||
{
|
{
|
||||||
using namespace scif;
|
using namespace scif;
|
||||||
|
|
||||||
sh7091.SCIF.SCSCR2 = 0;
|
sh7091.SCIF.SCSCR2 = 0; // disable transmission / reception
|
||||||
sh7091.SCIF.SCSMR2 = 0;
|
|
||||||
sh7091.SCIF.SCBRR2 = bit_rate; // bps = 1562500 / (SCBRR2 + 1)
|
sh7091.SCIF.SCSPTR2 = 0; // clear output data pins
|
||||||
|
|
||||||
sh7091.SCIF.SCFCR2 = scfcr2::tfrst::reset_operation_enabled
|
sh7091.SCIF.SCFCR2 = scfcr2::tfrst::reset_operation_enabled
|
||||||
| scfcr2::rfrst::reset_operation_enabled;
|
| scfcr2::rfrst::reset_operation_enabled;
|
||||||
|
|
||||||
sh7091.SCIF.SCFCR2 = scfcr2::rtrg::trigger_on_1_byte
|
sh7091.SCIF.SCFCR2 = scfcr2::rtrg::trigger_on_1_byte
|
||||||
| scfcr2::ttrg::trigger_on_8_bytes
|
| 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)
|
sh7091.SCIF.SCFSR2 = (~scfsr2::er::bit_mask)
|
||||||
& (~scfsr2::tend::bit_mask)
|
& (~scfsr2::tend::bit_mask)
|
||||||
& (~scfsr2::tdfe::bit_mask)
|
& (~scfsr2::tdfe::bit_mask)
|
||||||
@ -32,10 +53,15 @@ void init(uint8_t bit_rate)
|
|||||||
& (~scfsr2::rdf::bit_mask)
|
& (~scfsr2::rdf::bit_mask)
|
||||||
& (~scfsr2::dr::bit_mask)
|
& (~scfsr2::dr::bit_mask)
|
||||||
& 0xffff;
|
& 0xffff;
|
||||||
sh7091.SCIF.SCLSR2 = 0; // clear ORER
|
|
||||||
|
|
||||||
|
// wait 1 bit interval
|
||||||
|
init_wait();
|
||||||
|
|
||||||
sh7091.SCIF.SCSCR2 = scscr2::te::transmission_enabled
|
sh7091.SCIF.SCSCR2 = scscr2::te::transmission_enabled
|
||||||
| scscr2::re::reception_enabled;
|
| scscr2::re::reception_enabled;
|
||||||
|
|
||||||
|
sh7091.SCIF.SCLSR2 = 0; // clear ORER
|
||||||
}
|
}
|
||||||
|
|
||||||
void character(const char c)
|
void character(const char c)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user