打印
[STM32F4]

OTG 主机对于 NAK 的延迟处理

[复制链接]
939|16
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
micoccd|  楼主 | 2021-11-12 17:12 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
问题:
该问题由某客户提出,发生在 STM32F405RGT6 器件上。据其工程师讲述: STM32F405RGT6 作为主机向 从机做
Bulk_Receivdata()传输,每次收到 NAK 时,主机会每隔 5us 左右重新发起 TokenIn,从机在这 段时间内没有准备好数据,
所以依然发送 NAK。客户想在 200us 左右发起 IN 令牌,这样给从设备以准 数据的时间(实际数据的准备时间预计为 300us
左右)。  

使用特权

评论回复
沙发
micoccd|  楼主 | 2021-11-12 17:13 | 只看该作者
调研:
首先看看在 STM32Cube 库中是如何处理 NAK 的,如图(一)所示:

从图(一)中得知,在 USB 中断处理函数( HAL_HCD_IRQHandler)中,在判断为 Host channel 中断 时,调用了
HCD_HC_IN_IRQHandler()函数来处理 IN 指令。而在 HCD_HC_IN_IRQHandler()函数中 判断如果是 NAK 引起的中断,
且该端点为控制传输或者是块传输的话,就重新使能这个通道。一旦重 新使能该通道,主机硬件又自动发送 IN 令牌来企图
从设备获取数据,直到设备准备好数据后, 不再回复 NAK 握手,而是回复主机要获取的数据,然后主机硬件回复 ACK 来结
束本次 transfer。

使用特权

评论回复
板凳
micoccd|  楼主 | 2021-11-12 17:15 | 只看该作者
结论:
通过以上的分析可以得知,该问题是由于库函数中对于 NAK 是自动重新发送 IN 令牌的,这样做的目的 是确保数据的及时响
应。根据客户的需求,我们可以使用定时器延时的方法,延长重新使能通道的时 间。

使用特权

评论回复
地板
micoccd|  楼主 | 2021-11-12 17:18 | 只看该作者
处理:
使用定时器来延迟重新使能该通道的时间,进而延迟重新发送 IN 令牌的时间。 基于 U 盘读写的例程。
一.在主函数中增加初始化 TIM3 的代码:
//Tomas Li add TimHandle.Instance = TIM3;
TimHandle.Init.Prescaler = 5;
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
TimHandle.Init.Period = 3000;
TimHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&TimHandle);
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
HAL_TIM_ConfigClockSource(&TimHandle, &sClockSourceConfig);
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&TimHandle, &sMasterConfig);
//Tomas Li add


使用特权

评论回复
5
micoccd|  楼主 | 2021-11-12 17:19 | 只看该作者
二.在 HAL_TIM_Base_MspInit()函数中增加中断初始化
//Tomas Li add
if(htim->Instance==TIM3)
{
/* Peripheral clock enable */
TIM3_CLK_ENABLE();
/* Peripheral interrupt init*/
/* Sets the priority grouping field */
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);
HAL_NVIC_SetPriority(TIM3_IRQn, 5, 1);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
}
//Tomas Li add

使用特权

评论回复
6
micoccd|  楼主 | 2021-11-12 17:20 | 只看该作者
三.在 main.h 文件中增加 TIM3 的宏定义代码:
//Tomas Li add
/* Definition for TIMx clock resources */
#define TIMx TIM3
#define TIMx_CLK_ENABLE TIM3_CLK_ENABLE
/* Definition for TIMx's NVIC */
#define TIMx_IRQn TIM3_IRQn
#define TIMx_IRQHandler TIM3_IRQHandler
//Tomas Li add


使用特权

评论回复
7
micoccd|  楼主 | 2021-11-12 17:21 | 只看该作者
四.在 HCD_HC_IN_IRQHandler()函数中增加判断块传输( Bulk)的语句并开启定时器  

else if (hhcd->hc[chnum].ep_type == EP_TYPE_CTRL)
{
/* re-activate the channel */
USBx_HC(chnum)->HCCHAR &= ~USB_OTG_HCCHAR_CHDIS;
USBx_HC(chnum)->HCCHAR |= USB_OTG_HCCHAR_CHENA;
}//tomas li add
else if((hhcd->hc[chnum].ep_type == EP_TYPE_BULK)){
chnum_dup=chnum; //Mark this value for TIM3 interrupt to used.
HAL_TIM_Base_Start_IT(&TimHandle);
//tomas li add
}


使用特权

评论回复
8
micoccd|  楼主 | 2021-11-12 17:22 | 只看该作者
五.在 TIM3 的回调函数 HAL_TIM_PeriodElapsedCallback()中重新使能通道并关闭定时器  

/* Add by Tomas */
USB_OTG_GlobalTypeDef *USBx = USB_OTG_FS;
/* re-activate the channel */
USBx_HC(chnum_dup)->HCCHAR |= USB_OTG_HCCHAR_CHENA; //enable channal
USBx_HC(chnum_dup)->HCCHAR &= ~USB_OTG_HCCHAR_CHDIS; //disable channal
HAL_TIM_Base_Stop_IT(htim);
/* Add by Tomas */


使用特权

评论回复
9
micoccd|  楼主 | 2021-11-12 17:23 | 只看该作者
结果:
实际在 U 盘的读写测试,可以正常的读写。使用 USB 分析仪,查看 IN 令牌的发送时间在不定期的变 化(结果如图二所示),
这是因为在重启通道之后,立即就会有一次 IN 的传输(这个时间是硬件决定 的)。而下一次的 IN 令牌,会在我们设置的时
间后再发出.

使用特权

评论回复
10
gouguoccc| | 2021-11-12 20:00 | 只看该作者
学习了,谢谢楼主分享经验。

使用特权

评论回复
11
sadicy| | 2021-11-13 15:07 | 只看该作者
只知道手机能OTG

使用特权

评论回复
12
xiaoqizi| | 2021-12-6 20:05 | 只看该作者
NAK是无应答吗

使用特权

评论回复
13
tpgf| | 2021-12-6 20:07 | 只看该作者
usb分析仪一般大概多少钱啊

使用特权

评论回复
14
木木guainv| | 2021-12-6 20:11 | 只看该作者
真的有些看不太懂

使用特权

评论回复
15
guanjiaer| | 2021-12-6 20:13 | 只看该作者
一般最多可以延迟多久呢

使用特权

评论回复
16
heimaojingzhang| | 2021-12-6 20:14 | 只看该作者
可以灵活设置吗

使用特权

评论回复
17
keaibukelian| | 2021-12-6 20:14 | 只看该作者
在其他型号上可以这么处理吗

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

102

主题

700

帖子

1

粉丝