diff --git a/2023-12_usb-real-data-rates.md b/2023-12_usb-real-data-rates.md index bacf107ff2f43608030d0ba72d5dc77cb7cbad9d..f1343b3854f4057f51c5a5616446fe4a175de798 100644 --- a/2023-12_usb-real-data-rates.md +++ b/2023-12_usb-real-data-rates.md @@ -88,9 +88,103 @@ There's a nice natural alignment with this and the rest of these systems (which For future-architecture, my assumption is that I would do something like... one process does oversight, then we build one process per link layer, and probably even one per port, with user-application code going somewhere else. -So, I presume this will be a lot heavier-handed programming wise, I'll put a stake down before carrying on. +So, I presume this will be a lot heavier-handed programming wise, I'll put a stake down before carrying on. Neil also reminded me that Urumbu has implemented multiprocessing, so I should take a look at that as well. ---- +### Due Dilligence on Serial Sources + +The underlying 0.4MBit/s is pretty underwhelming, I should: + +- revisit with smaller packets, to check +- delete COBS and see what happens, +- delete the .ctr(), basically, right? +- return to SAMD21 +- ... do native-rp2040-codes + +So let's start with a baseline of 32 packets, with the existing (COBS, etc). In this test, we wrap things up using COBS, and we are basically doing two memcpy: one from the application code into the SerialCOBS class, and then again when we encode, and (actually, presumably) a third time when the arduino core copies it out. Since I'm going to end up counting time with python, I've changed stamps-collection for this (stamps were previously minted on the embedded side). + + + +So, all the way down, we'll just absolutely blast the bytes upstream with little regard for any amount of flow control, etc. + + + +So, there is about ~ 15% overhead reduction there ~ in that we shift from ~ 0.4MBit/s to ~ 0.475 ish. But we are now missing flow-control and framing. We also deleted an information-gather-encode-and-decode (in the datagram) step. + +When we bump from 133MHz to 240MHz, we see this tightening up in the distribution, which is rad... and which suggests a lower bound to packet delay (?) - + + + +So, I could try on a D21 - might as well (**note the x-axis is stretched 4x!**) + + + +This is actually much worse, down to ~ 0.15MBit/s. + +Here's what the basics of those were: + +```cpp +// py-transport-tester +// using the RP2040 at 133 MHz + +void setup() { + Serial.begin(); + pinMode(PIN_LED_B, OUTPUT); + digitalWrite(PIN_LED_B, HIGH); +} + +uint32_t lastBlink = 0; + +void loop() { + // write forever, + if(Serial.availableForWrite()){ + while(Serial.availableForWrite()){ + Serial.write(125); + } + } + // blink to see hangups + if(lastBlink + 100 < millis()){ + lastBlink = millis(); + digitalWrite(PIN_LED_B, !digitalRead(PIN_LED_B)); + } +} +``` + +```python +import time, serial +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt + +class UsbSerial: + def __init__(self, port, baudrate=115200): + self.port = port + self.ser = serial.Serial(port, baudrate=baudrate, timeout=1) + + def write(self, data: bytes): + self.ser.write(data) + + def read(self): + return self.ser.read() + +ser = UsbSerial("COM23") + +stamp_count = 1000 +pck_len = 32 + +stamps = np.zeros(stamp_count) + +for i in range(stamp_count): + count = 0 + while True: + if count >= 32: + stamps[i] = time.perf_counter() * 1e6 + break + byte = ser.read() + if byte: + count += 1 + +print("stamps, ", stamps) +``` --- diff --git a/code/serial_multi_sink_asyncio/multi_sink_blocking.py b/code/serial_multi_sink_asyncio/multi_sink_blocking.py index 833f5be12216b5619ad3449abc0ae513d6fb1faf..4ef7da39521964b49279cea66cd8f1d392c69149 100644 --- a/code/serial_multi_sink_asyncio/multi_sink_blocking.py +++ b/code/serial_multi_sink_asyncio/multi_sink_blocking.py @@ -1,4 +1,4 @@ -from cobs_usb_serial import CobsUsbSerial +from cobs_usb_serial_async import CobsUsbSerial import struct import numpy as np import pandas as pd diff --git a/code/serial_sink_simple/serial_list.py b/code/serial_sink_simple/serial_list.py new file mode 100644 index 0000000000000000000000000000000000000000..5f25377227f77c79dc2db925a16f5a5a280f412b --- /dev/null +++ b/code/serial_sink_simple/serial_list.py @@ -0,0 +1,20 @@ +import serial.tools.list_ports + +def list_serial_ports(): + ports = serial.tools.list_ports.comports() + for port in ports: + print(f"Port: {port.device}") + print(f" - Description: {port.description}") + if port.serial_number: + print(f" - Serial Number: {port.serial_number}") + if port.manufacturer: + print(f" - Manufacturer: {port.manufacturer}") + if port.product: + print(f" - Product: {port.product}") + if port.vid is not None: + print(f" - VID: {port.vid:04X}") + if port.pid is not None: + print(f" - PID: {port.pid:04X}") + print() + +list_serial_ports() diff --git a/code/serial_sink_simple/sink_simple.py b/code/serial_sink_simple/sink_simple.py new file mode 100644 index 0000000000000000000000000000000000000000..0c26725e418730463c9442f592437d2c6b62ed49 --- /dev/null +++ b/code/serial_sink_simple/sink_simple.py @@ -0,0 +1,77 @@ +import time, serial +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt + +class UsbSerial: + def __init__(self, port, baudrate=115200): + self.port = port + self.ser = serial.Serial(port, baudrate=baudrate, timeout=1) + + def write(self, data: bytes): + self.ser.write(data) + + def read(self): + return self.ser.read() + +ser = UsbSerial("COM23") + +stamp_count = 1000 +pck_len = 32 + +stamps = np.zeros(stamp_count) + +for i in range(stamp_count): + count = 0 + while True: + if count >= 32: + stamps[i] = time.perf_counter() * 1e6 + break + byte = ser.read() + if byte: + count += 1 + +print("stamps, ", stamps) + +def plot_stamps(stamps): + # make df from stamps + df = pd.DataFrame({'timestamps': stamps}) + + # calculate deltas between stamps + df['deltas'] = df['timestamps'].diff() + + # clean NaN's + df = df.dropna() + + # wipe obviously-wrong deltas (i.e. the 1st, which goes 0-start-us) + df = df[df['deltas'] < 100000] + + # Plotting + fig, ax1 = plt.subplots(figsize=(11, 3)) + + ax1.set_xlim([250, 1100]) + + # Primary x-axis (time deltas) + df['deltas'].plot(kind='hist', bins=100, ax=ax1) + ax1.set_xlabel('Time-Stamp Deltas (us) and equivalent (MBits/s)') + ax1.set_ylabel(f'Frequency (of {stamp_count})') + + # get axis ticks to calculate equivalent bandwidths + x_ticks = ax1.get_xticks() + ax1.set_xticks(x_ticks) + bandwidths = [((pck_len * 8) * (1e6 / x)) / 1e6 for x in x_ticks] + ticks = [] + + for i in range(len(x_ticks)): + print(i, x_ticks[i], bandwidths[i]) + ticks.append(f"{x_ticks[i]:.0f} ({bandwidths[i]:.3f})") + + ax1.set_xticklabels(ticks) + + plt.title(f'Single-Source COBS Data Sink Deltas, pck_len={pck_len}') + + plt.tight_layout() + + plt.show() + +plot_stamps(stamps) \ No newline at end of file diff --git a/code/serial_source_simple/serial_source_simple.ino b/code/serial_source_simple/serial_source_simple.ino new file mode 100644 index 0000000000000000000000000000000000000000..94e16345b2b2a28195bf26f0fa157f36314c5cbb --- /dev/null +++ b/code/serial_source_simple/serial_source_simple.ino @@ -0,0 +1,24 @@ +// py-transport-tester +// using the RP2040 at 133 MHz + +void setup() { + Serial.begin(9600); + pinMode(PIN_LED_B, OUTPUT); + digitalWrite(PIN_LED_B, HIGH); +} + +uint32_t lastBlink = 0; + +void loop() { + // write forever, + if(Serial.availableForWrite()){ + while(Serial.availableForWrite()){ + Serial.write(125); + } + } + // blink to see hangups + if(lastBlink + 100 < millis()){ + lastBlink = millis(); + digitalWrite(PIN_LED_B, !digitalRead(PIN_LED_B)); + } +} diff --git a/images/2023-12-27_simple-01-baseline.png b/images/2023-12-27_simple-01-baseline.png new file mode 100644 index 0000000000000000000000000000000000000000..304539cfacb0085fde9860dce5fb4a7e6fdcda7a Binary files /dev/null and b/images/2023-12-27_simple-01-baseline.png differ diff --git a/images/2023-12-27_simple-02-cobsless.png b/images/2023-12-27_simple-02-cobsless.png new file mode 100644 index 0000000000000000000000000000000000000000..71acf648c26ec711c9b9ba30861975e8113fef34 Binary files /dev/null and b/images/2023-12-27_simple-02-cobsless.png differ diff --git a/images/2023-12-27_simple-03-cobsless-240mhz.png b/images/2023-12-27_simple-03-cobsless-240mhz.png new file mode 100644 index 0000000000000000000000000000000000000000..d0e9a07e2c356b9a4feaa214e55c3ac8fe7c2b39 Binary files /dev/null and b/images/2023-12-27_simple-03-cobsless-240mhz.png differ diff --git a/images/2023-12-27_simple-04-cobsless-d21.png b/images/2023-12-27_simple-04-cobsless-d21.png new file mode 100644 index 0000000000000000000000000000000000000000..2d7b96c6eb1c3ea31ff815c3a53171d386d2d0e5 Binary files /dev/null and b/images/2023-12-27_simple-04-cobsless-d21.png differ