STMCU小助手
发布时间:2022-2-7 21:06
|
USB 1.0的最高12Mbps.) V" P2 x1 S3 S) [/ h ^' ] USB 2.0的高速模式480Mbps,全速模式12Mbps,低速模式1.5Mbps8 [$ k t% D. \( d* y 而是设置STM32端的USART的波特率。PC与STM32传输速度是以USB1.1的理论速度传输的,是不能设置的。 接收到数据,置NAK->将缓冲区数据拷贝到用户区(用户处理过程)->发ACK通知主机完成了完整的接收可以发送下一个->主机发送下一个, 前天测试自己编写的USB驱动程序时候发现从主机到STM32的OUT传输(主机到设备)速率竟然只有最高33KB/S,实在是晕死了。经过研究后发现是 驱动程序中设置的PIPE MaxTransferSize参数的关系,原先设置64只能33KB/S,后参考其他USB设备驱动程序的值,设置成了65535,再测试USB OUT的速度,达到了500KB/S,终于解决了驱动程序的瓶颈。不过算下USB 2.0全速的通讯速率是12Mb/S,排除掉CRC、令牌、SOF等等开销怎么也应该不止最大500KB/S啊。到网上看了看,基本上应该能达到 600KB/S~700KB/S以上,我现在的速度应该还有很大的提升才是。$ h6 Z& u% W" H4 h5 j2 W. Q 看看程序,发现1 Q% f& h. m. b! p8 ?2 ?) ]6 O& U void EP3_OUT_Callback(void)//EP3 OUT的回调函数,当EP3接收到数据时候中断调用该函数 { count_out = GetEPRxCount(ENDP3);//获得接收到的数据长度. @& _9 p' Z+ U% C PMAToUserBufferCopy(buffer_out, ENDP3_RXADDR, count_out);//将数据从USB EP3 RX的缓冲区拷贝到用户指定的数组中 SetEPRxValid(ENDP3); //完成拷贝后置有效状态,从而EP3发送ACK主机可以进行下一个数据包的发送. b. F, z) k3 X; g. }: P } 试着将PMAToUserBufferCopy这句注释掉(这样STM32就不处理接收到的数据了)后再测试速度,惊奇地发现速度竟然达到了 997KB/S!晚上仔细想了想,数据肯定是要使用的,这个数据拷贝的过程的时间消费总是少不了的;由于通常情况下USB设备BULK数据接收的步骤就 是:接收到数据,置NAK->将缓冲区数据拷贝到用户区(用户处理过程)->发ACK通知主机完成了完整的接收可以发送下一个->主机 发送下一个,按照以上的步骤USB接收一步步的进行,只要STM32不完成数据处理,状态就一直是NAK,主机就会不停地发送该数据包,浪费了带宽,因此 就会导致我上面最大速度500KB/S难以再增加的情况!不甘心啊~~ 昨天晚上又仔细研究了STM32的技术参考手册的USB章节内容,里面提到BULK可以采用双缓冲机制(PING-PONG)进行处理,正好可以解决上面 的情况。双缓冲机制的原理就是分配2块接收缓冲,STM32的用户处理和USB接口可以分别交替占用2个缓冲区,当USB端点接收数据写其中一个缓冲区的 时候,用户的应用程序可以同时处理另一个缓冲区,这样缓冲区依次交换占有者,只要用户处理程序在USB端点接收的时间片段内完成处理,就能够完全不影响 USB的通讯速度! 程序部分修改 一、EP3_OUT的设置修改,0 E" I. F6 w+ S! c //ZYP:修改EP3为BULK双缓冲方式------------------------- SetEPType(ENDP3, EP_BULK);" I v w4 H% R, t SetEPDoubleBuff(ENDP3);+ {# }5 ?. a' A1 ~( H1 r SetEPDblBuffAddr(ENDP3, ENDP3_BUF0Addr, ENDP3_BUF1Addr);, z% L. {* _ b SetEPDblBuffCount(ENDP3, EP_DBUF_OUT, VIRTUAL_COM_PORT_DATA_SIZE); ClearDTOG_RX(ENDP3);5 W8 ]; N: [; e1 A7 B4 F3 | ClearDTOG_TX(ENDP3);% b8 Z: |; K* B0 Z ToggleDTOG_TX(ENDP3); SetEPRxStatus(ENDP3, EP_RX_VALID);8 w4 P0 ^( T/ D$ O4 V J SetEPTxStatus(ENDP3, EP_TX_DIS); //------------------------------------------------------ 二、EP3_OUT回调函数的修改 void EP3_OUT_Callback(void) { //ZYP:以下是修改成EP3双缓冲OUT后的处理函数! }; L1 r5 e. H9 G1 Y, l if (GetENDPOINT(ENDP3) & EP_DTOG_TX)//先判断本次接收到的数据是放在哪块缓冲区的& n- j, `/ u' e& ? {& X; h- W2 K, ~7 ?' ]1 M" I# L4 L FreeUserBuffer(ENDP3, EP_DBUF_OUT); //先释放用户对缓冲区的占有,这样的话USB的下一个接收过程可以立刻进行,用另一块缓冲区,同时用户并行进行下面处理,在另一块接收完之前,处理完用户数据就行,否则缓冲区竞争。+ [% ~9 a! ?+ I# E9 P count_out = GetEPDblBuf0Count(ENDP3);//读取接收到的字节数, PMAToUserBufferCopy(buffer_out, ENDP3_BUF0Addr, count_out);6 Q3 Z- x( ~3 n, J% L }4 I8 n& j: ^- R, V2 } else {0 W; X* ?$ ^) o* }5 _* E FreeUserBuffer(ENDP3, EP_DBUF_OUT);, h T/ r6 n% E( \4 _% f$ A* z1 | count_out = GetEPDblBuf1Count(ENDP3); PMAToUserBufferCopy(buffer_out, ENDP3_BUF1Addr, count_out); }; h' u6 q8 `( n7 `% S }, w$ ]9 k) ~& g2 S& X- v 经过上面的修改,终于解决了STM32在处理接收数据时导致主机等待的情况,用BUS HOUND软件测试了下 & i/ @& J1 |$ X/ ?# r PS:上面的FreeUserBuffer(ENDP3, EP_DBUF_OUT); 这句话的上下位置是关键,如果放到函数的后面,则仍旧会有主机等待STM32处理数据的情况,速度仍然是500KB/S! 把这句话放在拷贝函数的前面的话就真正把双缓冲PING-PONG机制用起来了。大致算了下 PMAToUserBufferCopy(buffer_out, ENDP3_BUF1Addr, count_out);这句话当count_out为最大值64的时候STM32执行需要302个周期,72MHZ情况下约4.2微秒执行时间,而USB 传输按照12Mb/s的线速度传输64字节的数据至少也得40微秒,因此只要PMAToUserBufferCopy的时间不超过40微秒,就不会导致缓 冲区竞争的情况。 / M1 G# J! ?6 S& G. X/ Z+ K4 C* m5 Z |
实战经验 | 基于STM32G0B1的全桥移相+同步整流PWM解决方案
DMA 原理从 0 到 1:为什么它能解放 CPU?一文讲透 DMA 的工作流程
【福利三:逢7发帖赢大礼】8、基于STM32G070板子的Ymodem串口协议IAP Bootloader开发
【福利三:逢7发帖赢大礼】7、基于STM32G070板子TF卡的FATFS移植
【福利三:逢7发帖赢大礼】6、基于STM32G070板子spiflash的FATFS移植
【福利三:逢7发帖赢大礼】5、基于STM32G070板子IRDA红外遥控接收解码
【福利三:逢7发帖赢大礼】4、基于STM32G070板子SPI flash 移植SFUD库
【福利三:逢7发帖赢大礼】基于STM32G070板子的uart shell移植设计
【福利三:逢7发帖赢大礼】3、基于STM32G070板子的YModem串口协议通信
【福利三:逢7发帖赢大礼】2、基于STM32G070板子的OLED移植U8G2库
微信公众号
手机版