在
OHCI
的体系下,判断数据是否传输完毕是需要通过中断程序来判断的,当
USB
主机设置了
HcControl
和
HcCommandStatus
寄存器开始传输数据后,
AM9200
自动开始数据传输,并且定期的检查
HcDoneHead
寄存器的内容,并且将其转移到
HCCA.DoneHead
。然后产生中断,触发中断处理程序。
在中断处理程序中,需要检查
HcInterruptStatus
寄存器的内容,判断
WDH
位是否为
1
,以便确定是否有
TD
被处理完毕。一般来说,其余的中断状态位不用理会。当发现有
TD
被处理完毕,则还需要判断已经完成的
TD
是否是当前传输命令的最后一个
TD
,如果是则标志命令执行结束,上层程序可以进行后续处理。
/**
* OHCI
中断处理程序
*/
void
AT91F_UHP_Handler(
void
)
{
unsigned
int
status;
unsigned
char
idx;
unsigned
char
cc;
//unsigned int control;
//
得到
HcInterruptStatus
寄存器的内容
status = ohciGetIntrStatus();
//
检查
WDH
位,判断是否有
TD
传输完毕
if
((status & OHCI_HC_INTR_WDH) != 0)
{
//
根据当前执行的命令类型,确定
TD
的数量
switch
(usbCmdState.
cmdType
)
{
case
USB_CMD_TYPE_BULK_WRITE:
case
USB_CMD_TYPE_BULK_READ:
idx = 3;
break
;
case
USB_CMD_TYPE_CTRL_READ:
idx = 2;
break
;
case
USB_CMD_TYPE_CTRL_WRITE:
idx = 1;
break
;
default
:
usbCmdState.
state
= USB_CMD_OVER;
ohciClearIntrStatus();
return
;
}
//
取得当前完成的
TD
的
Complete Code
值
cc = getTdCC(ohciGetHccaDoneHead());
//
判断当前完成的
TD
是否是命令的最后一个
TD
if
(ohciGetHccaDoneHead() == usbGetLastTdAddr(idx))
{
usbCmdState.
cmdResult
= cc;
usbCmdState.
state
= USB_CMD_OVER;
}
else
{
//
当前
TD
不是最后一个
TD
,但是执行失败,不会继续处理
TD
列表,因此需要返回
if
(cc)
{
usbCmdState.
cmdResult
= cc;
usbCmdState.
state
= USB_CMD_OVER;
}
else
//
当前
TD
不是最后一个
TD
,等待继续处理
usbCmdState.
state
++;
}
}
//
清除
HcInterruptStatus
寄存器的内容,以便能够产生新的中断
ohciClearIntrStatus();
}
|
在最初的代码中,不是通过中断来判断
TD
数据是否处理完毕的,而是直接调用
ohciGetIntrStatus()
函数并判断返回值的,但是实际调试时发现这样不能正确得到
TD
数据处理完毕的信息。通过对中断程序的实际调试发现,因为
ED
会带有多个
TD
,
AM9200
在处理的时候可能是处理速度的原因,会产生
1
个或多个中断,因此在中断处理程序中需要判断当前结束的
TD
是否是当前命令的最后一个
TD
,这样才能确保整个
ED
处理完毕。
说实话,我不认为上面的判断
ED
队列执行完毕的方法是好的方法,本来我一直以为会有一个寄存器,在
ED
队列处理完毕的时候会跳出来告诉我说队列执行完毕了,可是找了半天也没有找到,只好采用这个笨方法了。
本文转自 tywali 51CTO博客,原文链接:http://blog.51cto.com/lancelot/261181,如需转载请自行联系原作者