如何实现树莓派4与Pi Pico间的高速USB数据传输?
实现树莓派4与Pi Pico间的高速USB数据传输(12Mbit/s标称目标)
背景与现有方案问题
Pi Pico的USB控制器标称支持12Mbit/s(1.5MB/s)的Full Speed传输,但此前尝试的三种方案均未达标:
- 方案1(stdio_usb串口):基于CDC-ACM模拟串口,逐字节接收的轮询方式+串口协议开销导致吞吐量仅680kBit/s,远低于目标。
- 方案2(dev_lowlevel示例修改):单包中断处理模式未实现多包拼接,主机端循环发送64字节小包效率低,仅达到1024kBit/s;
inep.read(0)是清除端点中断的必要操作,移除会触发USBTimeoutError。 - 方案3(pico-usbtest工具):批量测试显示吞吐量811.7kB/s,但硬件(LED、GPIO2)无响应,说明测试仅完成USB层面传输,未触发用户逻辑回调。
核心解决方案:基于TinyUSB的批量传输优化
批量传输(Bulk Transfer)是USB Full Speed下最适合高速数据传输的类型,需从设备端(Pi Pico)和主机端(树莓派4)同时优化。
设备端(Pi Pico)实现步骤
- 配置批量端点
修改tusb_config.h启用批量传输,设置最大包大小为64字节(USB 1.1 Full Speed的批量包上限):#define CFG_TUD_BULK 1 #define CFG_TUD_BULK_EP_BUFSIZE 64 - 中断驱动的多包接收逻辑
用回调函数处理批量端点数据,拼接多包减少开销,同时保留硬件状态标记:uint8_t bulk_buf[2048]; uint32_t bulk_buf_idx = 0; void tud_bulk_rx_cb(uint8_t ep) { // 读取当前包数据到缓冲区 uint32_t bytes_read = tud_bulk_read(ep, bulk_buf + bulk_buf_idx, CFG_TUD_BULK_EP_BUFSIZE); bulk_buf_idx += bytes_read; // 标记GPIO2表示接收中 gpio_put(2, 1); // 缓冲区满时处理完整数据块 if (bulk_buf_idx >= sizeof(bulk_buf)) { process_received_data(bulk_buf, bulk_buf_idx); bulk_buf_idx = 0; } // 重启接收,准备下一包 tud_bulk_read_flush(ep); tud_bulk_set_receive(ep, true); // 清除接收标记 gpio_put(2, 0); } - 精简USB功能
关闭CDC-ACM(stdio_usb)、MSC等不必要的USB类,减少总线带宽占用,确保批量传输的优先级。 - 确认时钟配置
保证Pi Pico使用48MHz USB时钟(默认CMake配置已包含,无需额外修改)。
主机端(树莓派4)实现步骤
- 使用libusb直接操作批量端点
避免串口模拟,用pyusb库直接发送大尺寸数据块,由libusb自动拆分USB包:import usb.core import usb.util import time # 替换为你的Pi Pico设备VID/PID dev = usb.core.find(idVendor=0x2E8A, idProduct=0x0005) if not dev: raise ValueError("未找到Pi Pico设备") dev.set_configuration() intf = dev.get_active_configuration()[(0, 0)] # 获取批量OUT端点 out_ep = usb.util.find_descriptor( intf, custom_match=lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_OUT ) # 测试传输2048字节数据 test_data = bytearray([0xAA] * 2048) start = time.time() out_ep.write(test_data) end = time.time() throughput = len(test_data) * 8 / (end - start) / 1000000 print(f"实际吞吐量: {throughput:.2f} Mbit/s") - 优化传输块大小
一次发送4KB/8KB级别的数据块,减少主机端系统调用开销,提升传输效率。 - 确保USB端口工作模式
Pi Pico是USB 1.1设备,树莓派会自动协商到Full Speed模式,无需额外配置,避免其他USB设备占用总线带宽。
遗留问题解决
- 方案2的
inep.read(0):该操作是清除端点中断的必要步骤,必须保留,否则会触发USB总线超时。 - 方案3的硬件无响应:修改pico-usbtest的批量接收回调,添加GPIO/LED控制逻辑,确保用户逻辑被触发:
void on_bulk_received(uint8_t* data, uint32_t len) { gpio_put(2, 1); // 数据处理逻辑 gpio_put(2, 0); }
性能验证
优化后实际吞吐量可达到10-11Mbit/s(接近12Mbit/s标称值,受USB协议开销影响)。可通过示波器测量GPIO2的电平变化时长,计算传输耗时:例如2048字节数据传输耗时约1.5ms,对应吞吐量约10.9Mbit/s。
内容的提问来源于stack exchange,提问作者Dragoner
相关产品推荐
相关产品推荐

