STM32的USB多包数据传送
因为我看到STM32的USB都没有对发送状态进行检测 , 当多于传送缓冲器的数据要传送时 , 估计就会出错了 , 所以找下这篇文章 , 但没有找到原始作者 , 但也在此谢过了!
STM32的多包数据传送(转贴)
SMT32F103 , 根据例程 Custom_HID 修改 , 利用 EP1 以 EP_INTERRUPT 的方式发送包 ,
原来的例程每次发送 2 个字节 , 现在修改后包的长度不超过 64 字节时发送是正常的 , 但当
一个包长超过 64 字节时就发送失败 , 没有数据出来(程序没有死机) , 该改的地方都已经修
改了 , 不知道哪个地方还没有改到位 , 谢谢!
现 象 就 是 超 过 63 字 节 的 包 死 活 也 发 不 出 去 , 而 且 发 送 包 的 大 小 还 与
CustomHID_ConfigDescriptor 里面的 EP1 IN endpoint 描述里包大小有关 , 没道理啊 , 其他
的 MCU 这地方设置为 8 照样发送 256B 以上的包 。
在 Custom_HID 例程上修改了如下代码:
【STM32的USB多包数据传送】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 的
地址 。
//、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
下面是我的部分程序 是在官方USB模拟串口程序上改的 , 专门用于测试发送状态下连续发送数据
u8 my_string[]={"2013我们希望rn"};
u16 myint=0;
inc_my_string()
{
myint++;
if(myint>9999)myint=0;
my_string[0]=myint/1000+'0';
my_string[1]=(myint00)/100+'0';
my_string[2]=(myint0)/10+'0';
my_string[3]=(myint)+'0';
}
//通过电脑发送的数据在EP3_OUT_Callback中可以获取到
//发向电脑的数据可以在USB_Send_Data函数中传送
int main(void)
{
Init_System();//系统初始化
Set_USBClock();//设置USB时钟
USB_Interrupts_Config(); //配置USB中断
USB_Init();//初始化USB
while (1)
{
if (GetEPTxStatus(ENDP1) != EP_TX_VALID)
//奇怪 , 我把这句换成if(GetEPTxStatus(ENDP1)==EP_TX_NAK)就会漏掉一些递增的数据 搞不懂?没时间深究
{
inc_my_string();
USB_Send_Data(my_string,14);//发送递增计数 看模拟的串口数据有没有漏掉的
}
}
}
推荐阅读
- 51单片机学习之路 —— 1.6 单片机的中断_2
- 卫生间吊顶风水解析
- 看看!日本卫生间的设计多人性化
- 解析卫生间隔断材料的选择
- **办公室风水的成功秘诀赶紧把自己的办公室布置起来
- 你不知道的办公室风水禁忌
- 冰锐好喝吗 冰锐和锐澳哪个更好喝
- 最吉利的卧室方位卧室风水摆设小窍门
- 摆脱冬季干燥 室内加湿的N种方法
- 欧式别墅室内设计 品味不一样的欧洲风情