[STM32F1] 【每周分享】以stm32f103为例谈谈tinyusb的性能测试与优化 tinyusb是一款MIT协议开源的跨平台USB host/device协议栈专为嵌入式系统设计各种常见的usb class都有实现常见的或不常见的usb ip都有支持比如像dwc2、musb、chipidea、stm32 fsdev等。更为友好的是它自带了大量的测试样例也自带了各种常见MCU开发板的移植。当下支持usb device的MCU很常见所以tinyusb在这些MCU上应用很广泛由此一个常见的话题是如何评价目标MCU tinyusb的性能在获得性能数据后如何提升性能。一个比较好的测试场景是usb cdc loopback设备所谓loopback就是把收到的数据再发回去然后上位机通过c或者python写的程序与下位机的cdc交互测量读写一大块数据的时间从而获得性能数据。此方法优点是usb cdc设备可通用操作系统usb cdc驱动所以我们不用再实现上位机操作系统下的驱动;另usb cdc是bulk传输在usb设备无其他端点时可以简单认为测得的cdc性能数据即MCU的usb性能数据。测试用例usb cdc loopback的实现如上所述tinyusb自带大量的测试样例我们通常不会从头开始写而是基于测试样例改。tinyusb在examples/device/cdc_dual_ports/有一个双cdc端口的实现例子原来的实现是把usb cdc端口收到的数据写到uart中去为实现测试性能的usb cdc loopback, 笔者将其中的cdc_task函数修改如下复制staticvoidcdc_task(void) {for(uint8_titf 0; itf CFG_TUD_CDC; itf) {// connected() check for DTR bit// Most but not all terminal client set this when making connection// if ( tud_cdc_n_connected(itf) ){if(tud_cdc_n_available(itf)) {uint8_tbuf[64];uint32_tcount tud_cdc_n_read(itf, buf,sizeof(buf));// echo backtud_cdc_n_write(itf, buf, count);}}}}目标MCU和开发板笔者选中基于STM32F103C8T6的小蓝板板子非常流行且价格便宜tinyusb也有现成的移植hw/bsp/stm32f1/boards/stm32f103_bluepill编译小蓝板固件和烧录复制cdexamples/device/cdc_dual_portsmakeBOARDstm32f103_bluepill编译出的固件在_build/stm32f103_bluepill/cdc_dual_ports.bin将其烧录到小蓝板即可比如笔者使用openocd烧录复制openocd-f interface/stlink.cfg -f target/stm32f1x.cfg -cprogram _build/stm32f103_bluepill/cdc_dual_ports.bin verify reset exit 0x8000000openocd烧录固件的截图烧录完毕后板子自动重启用usb线缆连接PC机与板子usb口PC linux dmesg信息如下:可以看到基于tinyusb的cdc acm设备已经被PC识别接下来需要来个性能测试的上位机为简单起见直接python脚本吧。上位机测试python程序笔者使用的python程序代码如下复制#!/usr/bin/python3importsysimportserialfromtimeimportperf_counterdefformat_bytes(size):B float(size)KB float(1024)MB float(KB **2)# 1,048,576ifB KB:return{0} {1}.format(B,B)elifKB B MB:return{0:.2f} KB.format(B/KB)else:return{0:.2f} MB.format(B/MB)defmain():iflen(sys.argv) !2:print(No port name specified)exit()ser serial.Serial(sys.argv[1], baudrate115200)data bytes()foriinrange(4096):data data bytes(range(256))print(Testing port, sys.argv[1])t_start perf_counter()ser.write(data)t_stop perf_counter()print(Throughput:, format_bytes(4096*256/ (t_stop - t_start)) /s)if__name__ __main__:main()测得的性能数据性能数据分析这个数据可以算比较差的。STM32F103的usb特征是full speed usb device理论速率12Mbps考虑到协议负载等理论上的传输性能大概在1MB/s上下。性能优化措施据笔者对于tinyusb源码分析发现tinyusb默认设置是比较保守的追求资源占用最少。例如默认编译优化选项是”-Os“而非常见的-O2或-O3, 且各buf size也是设置最小的。笔者在STM32F103平台采取性能优化措施如下去掉cdc dual port中的一个笔者只用一个cdc port,故而删除dual port中一个以节省资源编译”-Os“改成”-O2“复制diff --git a/examples/build_system/make/toolchain/gcc_common.mk b/examples/build_system/make/toolchain/gcc_common.mkindex42fd01183..9364177a0100644--- a/examples/build_system/make/toolchain/gcc_common.mk b/examples/build_system/make/toolchain/gcc_common.mk -39,739,7 CFLAGS_CLANG \# -Wconversion# Size Optimization as default-CFLAGS_OPTIMIZED ? -OsCFLAGS_OPTIMIZED ? -O2# Debugging/Optimizationifeq ($(DEBUG),1)增大CFG_TUD_CDC_EP_BUFSIZE与CFG_TUD_CDC_RX/TX_BUFSIZE复制--- a/examples/device/cdc_dual_ports/src/tusb_config.h b/examples/device/cdc_dual_ports/src/tusb_config.h-91,791,7#endif//------------- CLASS -------------//-#define CFG_TUD_CDC 2#define CFG_TUD_CDC 1#define CFG_TUD_MSC 0#define CFG_TUD_HID 0#define CFG_TUD_MIDI 0-100,11100,11#define CFG_TUD_CDC_NOTIFY 1// Enable use of notification endpoint// CDC FIFO size of TX and RX-#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)-#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)#define CFG_TUD_CDC_RX_BUFSIZE 4096#define CFG_TUD_CDC_TX_BUFSIZE 4096// CDC Endpoint transfer buffer size, more is faster-#define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)#define CFG_TUD_CDC_EP_BUFSIZE 4096再次编译烧录后性能测试如下可以看到经笔者优化后usb cdc基本达到期望的性能。。---------------------作者xhackerustc链接https://bbs.21ic.com/icview-3502794-1-1.html来源21ic.com此文章已获得原创/原创奖标签著作权归21ic所有任何人未经允许禁止转载。