来源:公众号【鱼鹰谈单片机】
作者:鱼鹰Osprey
ID :emOsprey



挂起中断一般是设备支持挂起才会产生这个中断,比如鼠标(用于省电),本例程设置的描述符并没有支持挂起,所以,该中断不会产生。






正因为如此,我们不必考虑这个数据是否需要校验,是否存在错误的可能,只要拿来用即可。而枚举过程,所有的数据都是通过端点 0 来交互的,虽说是端点 0,实际上却包含了两个端点, IN 和 OUT,这里的方向是针对主机而言的,所以当主机发送数据过来时,存放在 OUT 端点,此时我们需要从 OUT 端点获取我们所需要的标准请求数据:而如果主机接收数据,那么从机就事先把数据存放在IN端点,当主机发送 IN 令牌包时,USB外设就会按照USB传输方式将数据自动发送给主机。关于STM32如何发送或接收USB数据,可以看这两个函数:


U32 USBD_WriteEP (U32 EPNum, U8 *pData, U32 cnt)
{
/* Double Buffering is not yet supported */
U32 num, *pv, n;
U16 statusEP;
static uint32_t time,send_cnt;
static uint32_t max,min = (uint32_t)-1;
static uint32_t curr_send_cnt;
curr_send_cnt = cnt;
if(EPNum == 0x82)
{
if(time == 0)
{
time = DWT->CYCCNT;
if(time==0)time=1;
}
send_cnt += cnt;
if(time != 0)
{
if((DWT->CYCCNT - time)/72 > 1000000)
{
time = DWT->CYCCNT;
if(send_cnt > max)
{
max = send_cnt;
}
if(send_cnt < min)
{
min = send_cnt;
}
send_cnt = 0;
}
}
}
num = EPNum & 0x0F;
pv = (U32 *)(USB_PMA_ADDR + 2 * ((pBUF_DSCR + num)->ADDR_TX));
printf("\nw%04x\n", (EPNum << 8) |cnt);
for (n = 0; n < (cnt + 1) / 2; n++)
{
*pv++ = *((__packed U16 *)pData);
// if(n < 8)
{
printf("%x ", (uint32_t)*(U8 *)pData);
printf("%x ", (uint32_t)*((U8 *)pData+1));
}
pData += 2;
}
printf("\n");
// printf("--\n");
(pBUF_DSCR + num)->COUNT_TX = cnt;
statusEP = EPxREG(num);
if ((statusEP & EP_STAT_TX) != EP_TX_STALL)
{ /* do not make EP valid if stalled */
EP_Status(EPNum, EP_TX_VALID);
}
return (cnt);
}
通过对端点 2 每隔 1 秒统计一次传输数据,可以大概计算USB批量传输的发送速率。最后,鱼鹰再简单介绍一下枚举过程时的控制传输流程:


因为上述内容太多,不再一一说明,大家对照鱼鹰给的例子和分享的资料自行学习即可,相信有了这个流程图,修改出属于自己的 USB 设备根本不是难事。总之,师傅领进门,修行靠个人。关于USB你能领悟多少,就看自己能花多少精力在这里了。鱼鹰这个系列的文章仅仅供各位道友入门使用,帮助大家快速理解USB 大概的内容,很多内容并没有详细介绍,所以鱼鹰从网上搜集了很多学习资料供各位参考,方便大家更系统的学习 USB 知识。如果发现资料或本系列笔记有误,请以官方资料为准。
-THE END-
如果对你有帮助,记得转发分享哦
微信公众号「鱼鹰谈单片机」
每周一更单片机知识
长按后前往图中包含的公众号关注
鱼鹰,一个被嵌入式耽误的畅销书作家
个人微信「EmbeddedOsprey」
长按后打开对方的名片关注