原创 如何使用STM32的USB非控制端点发送多个数据包

2008-8-29 11:06 9361 15 16 分类: MCU/ 嵌入式

以下是网友提出的问题和我对这个问题的说明。






SMT32F103,根据例程Custom_HID修改,利用EP1 以EP_INTERRUPT 的方式 发送包,原来的例程每次发送2个字节,现在修改后包的长度不超过64字节时发送是正常的,但当一个包长超过64字节时就发送失败,没有数据出来(程序没有死机),该改的地方都已经修改了,不知道哪个地方还没有改到位,谢谢!


现象就是 超过63字节的包死活也发不出去,而且发送包的大小 还与 CustomHID_ConfigDescriptor里面的 EP1 IN endpoint 描述里包大小有关 ,没道理啊,其他的MCU 这地方设置为8 照样发送256B 以上的包。


在Custom_HID例程上修改了如下代码:
1.usb_proc.c 的CustomHID_Reset()里  SetEPTxCount(ENDP1, 64);
2.关闭 DMA中断,不让ADC采样后发送EP1包
3.在main.c里 重复发送一个128B的包,
   while(1){
    for(i=0;i<2;i++)
       { SetEPTxAddr(ENDP1, ENDP1_TXADDR+i*64);
      SetEPTxValid(ENDP1);    
       Delay(10000);      
        }
     }       
4. 由于一个包是128B,最大包长是64B,所以分两次发送出来,奇怪的是所有例程发送包时都没有查发送状态的处理,也没有找到相应的状态等待函数,这样的话,是不是出现第一个包还没有发送完,第二个包就冲掉了第一个包的数据?
5. 所以问题很简单,就是如何发送一个多数据包,发送函数要如何写?


以下是关于这个问题的解答:



分两次发送是对的,但关键是每次发送前需要检查上次发送是否完成。

检查一个端点的发送是否结束有2种方法,第一种方法是当发送结束(设备收到ACK)时,有一个发送结束中断,这个中断由USB库处理,并通过EP1_IN_Callback这个回调函数交由用户程序确认,你可以搜索一下,例子中把EP1_IN_Callback定义为NOP_Process,没有处理这个回调事件。如果要用这种方法检测端点发送结束,你需要自己定义回调函数并做相应处理。

检测端点发送结束的另一个方法是查询这个端点的状态,如果端点状态处于EP_TX_VALID,说明发送未结束,如果端点状态处于EP_TX_NAK,说明发送结束。使用下述调用可以得到端点1的发送状态:
   GetEPTxStatus(ENDP1)



按照你的思路,可以使用第二种方法实现发送多个数据包的功能。

假定要发送150个字节的MyBuffer,EP1的最大包长设为64字节。

u8 MyBuffer[150];
int packetN;
packetN = 3;
while (1) {
   if (packetN < 3) { // 有数据需要发送时置packetN为'0'
     if (GetEPTxStatus(ENDP1) == EP_TX_NAK) {
       if (packetN == 0) { // 拷贝头64字节到发送缓冲区
         UserToPMABufferCopy(MyBuffer, ENDP1_TXADDR, 64);
         SetEPTxCount(ENDP1, 64);
       }
       else if (packetN == 1) { // 拷贝第2个64字节到发送缓冲区
         UserToPMABufferCopy(MyBuffer+64, ENDP1_TXADDR, 64);
         SetEPTxCount(ENDP1, 64);
       }
       else if (packetN == 2) { // 拷贝最后22字节到发送缓冲区
         UserToPMABufferCopy(MyBuffer+128, ENDP1_TXADDR, 22);
         SetEPTxCount(ENDP1, 22);
       }
       packetN++;
       SetEPTxStatus(ENDP1, EP_TX_VALID);
     }
   }
   ...... // 其它操作
}

这里使用了一个变量记录应该发送第几个数据包,当程序的其它部分准备好数据后只要设置这个变量packetN=0,上述发送操作就会启动,程序的其它部分只需检测packetN==3即可知道MyBuffer是否已经腾空,程序的其它部分可以使用MyBuffer继续其它操作,注意这时数据不一定已经全部发送完毕。



你的另一个问题在于这一行:SetEPTxAddr(ENDP1, ENDP1_TXADDR+i*64);

ENDP1_TXADDR是专门的发送缓冲区,它的长度是有限的,而且是每32位编址中只有低16位有效;所以需要使用函数UserToPMABufferCopy()操作这个发送缓冲区,这个函数已经在USB库的手册中说明。



最后一个问题是:如果你的程序中使用了ENDP1_RXADDR,因为你改变了ENDP1包的长度,即改变了发送缓冲区的长度,需要在usb_conf.h中重新定义以下ENDP1_RXADDR的地址。
PARTNER CONTENT

文章评论1条评论)

登录后参与讨论

用户214048 2009-8-4 19:51

中断方式怎么做呢? 我用中断方式做的时候数据总是出错。。。。
相关推荐阅读
用户1090342 2010-08-05 12:33
使用STM32定时器输出任意相位差的方波
记得曾经有不少人问起这个问题,方法十分简单,不用说明,看图即知(这里画了2路输出,同样道理可以产生3路甚至4路输出)。此方法不但可以在STM32上实现,因为STM8定时器的多数功能与STM32一样,所...
用户1090342 2010-05-06 16:11
STM32的功能引脚重映射和复用功能
STM32中有很多内置外设的输入输出引脚都具有重映射(remap)的功能,本文对一些在使用引脚重映射时所遇到的有关问题加以说明。我们知道每个内置外设都有若干个输入输出引脚,一般这些引脚的输出脚位都是固...
用户1090342 2010-04-23 11:04
改正了每次只能发送一个字节的USB虚拟串口例程
目前发布的STM32_USB-FS-Device_Lib中有一个USB虚拟串口的例程,这个例程演示了把STM32配置为一个USB虚拟串口设备,STM32从它的USART接口接收数据并通过USB传送到上...
用户1090342 2010-03-06 12:30
STM32定时器的预装载寄存器与影子寄存器之间的关系
本文的说明依据STM32参考手册(RM0008)第10版:英文:http://www.st.com/stonline/products/literature/rm/13902.pdf中译文:http:...
用户1090342 2010-02-26 12:18
使用BSRR和BRR寄存器直接操作STM32的I/O端口
STM32的每个GPIO端口都有两个特别的寄存器,GPIOx_BSRR和GPIOx_BRR寄存器,通过这两个寄存器可以直接对对应的GPIOx端口置'1'或置'0'。GPIOx_BSRR的高16位中每一...
用户1090342 2010-01-28 16:23
如何使用STM32的USB库支持延迟HID的GET_REPORT请求
首先,请参考我的另一篇博客:以HID的SET REPORT为例说明如何使用STM32的USB库支持控制端点0如果要支持HID的GET_REPORT请求,按照上一篇博客中的说明,只需要在STM32 US...
我要评论
1
15
关闭 站长推荐上一条 /3 下一条