您的位置 首页 汽车

s3c2440的USB主机控制器

s3c2440提供了USB主机接口,它与OHCIv1.0完全兼容。要使用该功能,就必须熟悉OHCIv1.0规范;而要熟悉OHCIv1.0规范,那么还必须先熟悉…

s3c2440供给了USB主机接口,它与OHCI v1.0彻底兼容。要运用该功用,就有必要了解OHCI v1.0标准;而要了解OHCI v1.0标准,那么还有必要先了解USB v1.1协议。因而触及到该部分的内容较多,要想正确运用s3c2440所供给的USB主机接口也不是一件简略的作业。在这儿,我首要介绍USB设备枚举进程中所触及到的一些常识,并给出详细的完结程序。

OHCI(Open HCI)是现在运用比较广泛的三种USB主机操控器标准之一。USB体系结构是由四个首要部分组成:客户软件/USB驱动,主机操控器驱动(HCD),主机操控器(HC)和USB驱动。前两者由软件完结,后两者由硬件完结。而OHCI便是标准了主机操控器驱动和主机操控器之间的接口,以及它们的根本操作。在主机操控器驱动和主机操控器之间,有两个通讯通道,第一个是运用坐落HC的一套可操作寄存器,它们包含操控寄存器、状况寄存器和列表指针寄存器;另一个通道是运用称为主机操控器通讯域(HCCA)的同享内存。

USB界说了四种数据传输类型:操控传输、批量传输、间断传输和同步传输。在OHCI标准中把数据传输类型分为两类:周期传输和非周期传输。同步传输和间断传输归于周期传输,操控传输和批量传输归于非周期传输。USB界说了每帧的周期为1.0毫秒,为了确保每一帧都能发生周期传输和非周期传输,一般地,OHCI把每一帧的带宽分为四个部分,首先是发送SOF,然后对错周期传输,紧接着是周期传输,假如周期传输完毕后,还有时刻,则剩下的时刻依然留给非周期传输。

端点描绘符(ED)和传输描绘符(TD)是两个最根本的通讯模块。ED包含了一个端点的信息,它被HC用来办理运用端点。ED的典型参数包含端点地址、传输速度、最大数据包巨细,别的ED还供给了TD链表的停靠地(锚点)。TD是一个依赖于ED的内存缓存区,用于与端点之间进行数据传输。当HC存取一个ED,而且找到一个有用的TD地址时,则HC就完结了一个简略的与端点之间的传输使命,这个端点是由ED结语,而所存取的数据内存地址由TD指定。当一切的被TD所界说的数据传输完毕后,TD就从ED中解链出来,并链接到完结列表中。这个完结列表能够被HCD所处理,以供给一些完结信息。

ED的数据结构长度为16字节,它的数据域有:
FA:USB的功用地址;
EN:USB功用内的端点地址;
D:数据流的传输方向,是IN,OUT,仍是有TD来决议传输方向;
S:速度,全速仍是低速;
K:用于设置越过当时ED;
F:链接于ED的TD的方式,是通用TD格局仍是同步TD格局;
MPS:数据传输的最大字节巨细;
TailP:TD列表的尾指针;
H:用于间断当时TD列表的处理;
C:数据翻转进位位;
HeadP:TD列表的头指针;
NextED:下一个要处理的ED指针。

依据上述阐明,咱们能够界说ED为下面的数据类型:
typedef struct _ED {
volatile unsigned int Control;
volatile unsigned int TailP;
volatile unsigned int HeadP;
volatile unsigned int NextEd;
} ED, *P_ED;

咱们ED有必要是16字节地址对齐方式,因而咱们有必要用下面的方式来声明它的变量:
__align(16) ED ed;

咱们能够用下面的函数来创立一个ED:
__inline void CreateEd(
unsigned int EDAddr,//ED地址指针
unsigned int MaxPacket,//MPS
unsigned int TDFormat,//F
unsigned int Skip,//K
unsigned int Speed,//S
unsigned int Direction,//D
unsigned int EndPt,//EN
unsigned int FuncAddress,//FA
unsigned int TDQTailPntr,//TailP
unsigned int TDQHeadPntr,//HeadP
unsigned int ToggleCarry,//C
unsigned int NextED)//NextED
{
P_ED pED = (P_ED) EDAddr;
pED->Control = (MaxPacket << 16) | (TDFormat << 15) |(Skip << 14) | (Speed << 13)
| Direction << 11) | (EndPt << 7) | FuncAddress;
pED->TailP = (TDQTailPntr & 0xFFFFFFF0);
pED->HeadP = (TDQHeadPntr & 0xFFFFFFF0) | (ToggleCarry << 1);
pED->NextEd = (NextED & 0xFFFFFFF0);
}

TD共有两种类型:通用TD和同步TD。通用TD用于间断、操控和批量端点,同步TD用于同步传输。在这儿,咱们只给出通用TD的数据结构和界说。

通用TD的数据结构长度也是16字节,它的数据域有:
R:缓存凑整,用于设置是否需求最终一个数据包的长度与所界说的长度共同;
DP:方向,是IN,OUT,仍是SETUP;
DI:延时刻断;
T:数据翻转;
EC:传输过错计数;
CC:条件码,为上一次妄图传输的状况;
CBP:将要被传输的数据内存物理地址;
NextTD:下一个TD;
BE:将要被传输的数据内存物理末字节地址;

依据上述阐明,咱们能够界说通用TD为下面的数据类型:
typedef struct _TD {
volatile unsigned int Control;
volatile unsigned int CBP;
volatile unsigned int NextTD;
volatile unsigned int BE;
} TD, *P_TD;

咱们通用TD有必要是16字节地址对齐方式,因而咱们有必要用下面的方式来声明它的变量:
__align(16) TD td[4];

咱们能够用下面的函数来创立一个通用TD:
__inline void CreateGenTd(
unsigned int GenTdAddr,//TD地址指针
unsigned int DataToggle,//T
unsigned int DelayInterrupt,//DI
unsigned int Direction,//DP
unsigned int BufRnding,//R
unsigned int CurBufPtr,//CBP
unsigned int NextTD,//NextTD
unsigned int BuffLen)//被传输的数据长度,由该变量能够得到BE
{
P_TD pTD = (P_TD) GenTdAddr;
pTD->Control = (DataToggle << 24) | (DelayInterrupt << 21)
| (Direction << 19) | (BufRnding << 18);
pTD->CBP = CurBufPtr;
pTD->NextTD = (NextTD & 0xFFFFFFF0);
pTD->BE = (BuffLen) ? CurBufPtr + BuffLen – 1 : CurBufPtr;
}

下面咱们给出HCCA的数据结构,它的长度为256字节,包含128字节的HCCA间断表,2字节的HCCA帧数,2字节的HCCA便签(一共HC是否正在更新HCCA帧数),4字节的HCCA完结行列头指针,以及116字节的保存区。依据上述阐明,咱们能够界说HCCA为下面的数据类型:
typedef struct _HCCA {
volatile unsigned int HccaInterruptTable[32];
volatile unsigned short HccaFrameNumber;
volatile unsigned short HccaPad1;
volatile unsigned int HccaDoneHead;
volatile unsigned char reserved[116];
} HCCA, *P_HCCA;

咱们HCCA有必要是256字节地址对齐方式,因而咱们有必要用下面的方式来声明它的变量:
__align(256) HCCA hcca;

OHCI是依据寄存器层描绘的USB主机操控器的标准,因而HC包含了一些片内可操作寄存器,这些寄存器相同能够被HCD所运用。下面咱们就简略介绍OHCI中的寄存器。
HcRevision:HCI标准版别;
HcControl:HC的操作形式,CBSR——在非周期行列中,被服务的操控ED与批量ED之间的份额;CLE——下一帧操控行列处理使能;HCFS——USB主机操控器功用状况,包含复位、重新开端、操作和间断;
HcCommandStatus:HC接纳来至HCD的指令,也可反映HC的当时状况,HCR——软件复位HC;CLF——结语是否有操控行列TD;
HcInterruptStatus:供给各种能够触发硬件间断事情的状况;
HcInterruptEnable:使能用于操控发生硬件间断事情的位;
HcInterruptDisable:无效用于操控发生硬件间断事情的位
HcHCCA:HCCA的物理地址;
HcPeriodCurrentED:当时同步或间断ED的物理地址;
HcControlHeadED:操控行列的第一个ED的物理地址;
HcControlCurrentED:当时操控敌对ED的物理地址;
HcBulkHeadED:批量行列的第一个ED的物理地址;
HcBulkCurrentED:当时批量敌对ED的物理地址;
HcDoneHead:被增加在完结行列中的最近一个TD的物理地址;
HcFmInterval:包含一个14位的FI——用于一共一帧之内所占用的比特时刻,2个接连的SOFs,和一个15位PSMPS——用于一共在没有引发调度溢出下可发送或接纳全速最大包巨细,FI,PSMPS的推荐值为0x2EDF和0x2778。
HcFmRemaining:14位的倒计数器,以一共当时帧所剩时刻;
HcFmNumber:16位计数器,以供给时序参阅;
HcPeriodicStart:14位可编程数值,以结语HC在什么时刻开端碑文周期行列;
HcLSThreshold:11位数值,用于结语是否在EOF之前碑文最大8位LS包传输;
HcRhDescriptorA:第一个对跟集线器进行描绘的寄存器;
HcRhDescriptorB:第二个对跟集线器进行描绘的寄存器;
HcRhStatus:包含集线器状况域和集线器状况更改域;
HcRhPortStstus[1:NDP]:用于操控和陈述每个端口上的事情,在s3c2440中,NDP为2

下面给出OHCI的初始化,它都是依据寄存器的。依据OHCI标准,HCD应该完结下列初始化进程:
●初始化HCCA数据内存单元
●初始化可操作寄存器,以匹配当时设备数据状况
●设置HcHCCA
●设置HcInterruptEnable
●设置HcControl
●设置HcPeriodicStart

结合本文所介绍的实践内容,OHCI的初始化函数为:
void OHCIInit( )
{
unsigned int fminterval;

//复位
rHcControl = 0;
//写HCCA
rHcHCCA = (volatile unsigned )&hcca;

//设置帧距离
fminterval = 0x2edf;
rHcFmInterval =((((fminterval – 210) * 6) / 7) << 16)| fminterval;
rHcPeriodicStart= (fminterval * 9) / 10;

//初始化HcDoneHead
rHcDoneHead = 0x00;
hcca.HccaDoneHead = 0x0000;

//设置HC为运转状况
rHcControl = 0x80;
}

主机对USB设备的辨认进程称为设备枚举,因而枚举关于USB至关重要。在本文,只进行下列简略的5步枚举进程:
1、主机要求得到设备描绘符,SETUP数据包为:0x80, 0x06,0x00,0x01,0x00,0x00,0x40,0x00,得到的数据长度最大为0x40;
2、第二个SETUP包是为设备分配一个地址,内容一般为:0x00,0x05,0x02,0x00,0x00,0x00,0x00,0x00。其间的02一共为设备分配的地址为0x02,今后咱们再对该设备操作时,就只能运用0x02这个地址值;
3、主机用新的地址再次获取设备描绘符,SETUP包为:0x80,0x06,0x00,0x01,0x00,0x00,0x12,0x00,与前次不同,这次得到数据长度时实践的数据长度0x12;
4、主机读取设备悉数装备描绘符,SETUP包为:0x80,0x06,0x00,0x02,0x00,0x00,0x40,0x00,咱们主机不知道设备描绘符的长度,因而这儿只需求得到0x40个字节;
5、主机发送SETUP数据包:0x00,0x09,0x01,0x00,0x00,0x00,0x00,0x00,用以设置装备,答应一切端点进入作业状况。
对USB设备枚举咱们只做了简略的介绍,关于枚举的其他进程以及SETUP数据包各个字节的详细意义,请阅览USB协议的第9章。

下面咱们就首要介绍OHCI标准是怎么完结USB设备枚举的。前面咱们现已介绍过了,OHCI数据传输首要依托ED和TD,其间TD是挂靠在ED上的。ED首要用来设置传输的各种参数,TD则首要担任详细的数据传输。依据USB协议,USB的设备枚举只触及操控传输。操控传输最少有两个业务阶段:树立和状况,操控传输能够有挑选性地包含树立和状况阶段之间的数据阶段。在这儿,操控写传输不需求数据阶段,而操控读需求在树立和状况之间增加主机要读取到的数据。一般来说,完结一次操控写传输需求3个TD:第一个发送Setup包,第二个用于接纳握手或零长度的数据包,第三个用于发送状况;而完结一次操控读传输需求4个TD:第一个发送Setup包,第二个用于接纳数据,第三个用于发送一个零长度的数据包,,第四个用于接纳状况。

下面给出详细的USB设备枚举的函数。在进行枚举之前,主机一定要结语有USB设备的存在。正确情况下,在结语进程中,假如在一段给守时刻没有检测到设备,则主机以为没有USB设备。“一段给定的时刻”应该由守时器来完结。在这儿,为了简化程序,咱们只用计数来替代守时。
int USB_Enum()
{
int i;
//判别有无USB设备
for(i=0;i<100000;i++)
{
if (rHcRhPortStatus1 & 0x01)
{
rHcRhPortStatus1 = (1 << 4);//端口复位
while (rHcRhPortStatus1 & (1 << 4))
;//等候复位完毕
rHcRhPortStatus1 = (1 << 1);//使能该端口
break;
}
else if (rHcRhPortStatus2 & 0x01)
{
rHcRhPortStatus2 = (1 << 4);//端口复位
while (rHcRhPortStatus2 & (1 << 4))
;//等候复位完毕
rHcRhPortStatus2 = (1 << 1);//使能该端口
break;
}
}

if (i>90000)
return 0x44;

//第一步,主机得到设备描绘符
CreateEd(
(unsigned int) &ed,// ED Address
64,// Max packet
0,// TD format
0,// Skip
0,// Speed
0x0,// Direction
0x0,// Endpoint
0x0,// Func Address,初始为0
(unsigned int) &td[3],// TDQTailPointer
(unsigned int) &td[0],// TDQHeadPointer
0,// ToggleCarry
0x0);// NextED

//树立PID
CreateGenTd(
(unsigned int) &td[0],// TD Address
2,// Data Toggle
0x2,// DelayInterrupt
0x0,// Direction
1,// Buffer Rounding
(unsigned int) pSetup1,// Current Buffer Pointer,界说的全局变量数组
//const char pSetup1[8] ={0x80,0x06,0x00,0x01,0x00,0x00,0x40,0x00};
(unsigned int) &td[1],// Next TD
8);// Buffer Length

//接纳数据
CreateGenTd(
(unsigned int) &td[1],// TD Address
0,// Data Toggle
0x2,// DelayInterrupt
0x2,// Direction
1,// Buffer Rounding
(unsigned int) pData1,// Current Buffer Pointer,界说的全局变量数组
// char pData1[0x40];经过读取该数组,能够获悉设备描绘符
(unsigned int) &td[2],// Next TD
0x40);// Buffer Length

//零长度数据包
CreateGenTd(
(unsigned int) &td[2],// TD Address
3,// Data Toggle
0x2,// DelayInterrupt
0x1,// Direction
1,// Buffer Rounding
0x0,// Current Buffer Pointer
(unsigned int) &td[3],// Next TD
0x0);// Buffer Length

//接纳状况
CreateGenTd(
(unsigned int) &td[3],// TD Address
3,// Data Toggle
0x2,// DelayInterrupt
0x2,// Direction
1,// Buffer Rounding
0x0,// Current Buffer Pointer
(unsigned int) 0,// Next TD
0x0);// Buffer Length

//设置寄存器
rHcControlHeadED = (unsigned int )& ed;
rHcControlCurrentED = (unsigned int )& ed;

//操控列表处理使能,开端作业
rHcControl = 0x90;

//告诉HC操控列表已填充
rHcCommandStatus = 0x02;

//第二步为设备分配地址
CreateEd(
(unsigned int) &ed,// ED Address
64,// Max packet
0,// TD format
0,// Skip
0,// Speed
0x0,// Direction
0,// Endpoint
0,// Func Address
(unsigned int) &td[2],// TDQTailPointer
(unsigned int) &td[0],// TDQHeadPointer
0,// ToggleCarry
0x0);// NextED

//树立PID
CreateGenTd(
(unsigned int) &td[0],// TD Address
2,// Data Toggle
2,// DelayInterrupt
0,// Direction
1,// Buffer Rounding
(unsigned int) pSetup2,// Current Buffer Pointer,界说的全局变量数组
//const char pSetup2[8] ={0x00,0x05,0x02,0x00,0x00,0x00,0x00,0x00};
(unsigned int) &td[1],// Next TD
8);// Buffer Length

//接纳零长度数据包
CreateGenTd(
(unsigned int) &td[1],// TD Address
0,// Data Toggle
2,// DelayInterrupt
2,// Direction
1,// Buffer Rounding
(unsigned int) 0,// Current Buffer Pointer
(unsigned int) &td[2],// Next TD
0);// Buffer Length

//发送状况
CreateGenTd(
(unsigned int) &td[2],// TD Address
3,// Data Toggle
2,// DelayInterrupt
1,// Direction
1,// Buffer Rounding
0x0,// Current Buffer Pointer
(unsigned int) 0,// Next TD
0x0);// Buffer Length

rHcControlHeadED = (unsigned int )& ed;
rHcControlCurrentED = (unsigned int )& ed;
rHcControl = 0x90;
rHcCommandStatus = 0x02;

//第三步,主机用新的地址再次获取设备描绘符
CreateEd(
(unsigned int) &ed, // ED Address
64,// Max packet
0,// TD format
0,// Skip
0,// Speed
0x0,// Direction
0x0,// Endpoint
0x2,// Func Address,新的地址
(unsigned int) &td[3],// TDQTailPointer
(unsigned int) &td[0],// TDQHeadPointer
0,// ToggleCarry
0x0);// NextED

CreateGenTd(
(unsigned int) &td[0],// TD Address
2,// Data Toggle
0x2,// DelayInterrupt
0x0,// Direction
1,// Buffer Rounding
(unsigned int) pSetup3,// Current Buffer Pointer,界说的全局变量数组
//const char pSetup3[8] ={0x80,0x06,0x00,0x01,0x00,0x00,0x12,0x00};
(unsigned int) &td[1],// Next TD
8);// Buffer Length

CreateGenTd(
(unsigned int) &td[1],// TD Address
0,// Data Toggle
0x2,// DelayInterrupt
0x2,// Direction
1,// Buffer Rounding
(unsigned int) pData3,// Current Buffer Pointer,界说的全局变量数组
// char pData3[0x12];经过读取该数组,能够获悉设备描绘符
(unsigned int) &td[2],// Next TD
0x12);// Buffer Length

CreateGenTd(
(unsigned int) &td[2],// TD Address
3,// Data Toggle
0x2,// DelayInterrupt
0x1,// Direction
1,// Buffer Rounding
0x0,// Current Buffer Pointer
(unsigned int) &td[3],// Next TD
0x0);// Buffer Length

CreateGenTd(
(unsigned int) &td[3],// TD Address
3,// Data Toggle
0x2,// DelayInterrupt
0x2,// Direction
1,// Buffer Rounding
0x0,// Current Buffer Pointer
(unsigned int) 0,// Next TD
0x0);// Buffer Length

rHcControlHeadED = (unsigned int )& ed;
rHcControlCurrentED = (unsigned int )& ed;
rHcControl = 0x90;
rHcCommandStatus = 0x02;

//第四步,主机读取设备悉数装备描绘符
CreateEd(
(unsigned int) &ed, // ED Address
64,// Max packet
0,// TD format
0,// Skip
0,// Speed
0x0,// Direction
0x0,// Endpoint
0x2,// Func Address
(unsigned int) &td[3],// TDQTailPointer
(unsigned int) &td[0],// TDQHeadPointer
0,// ToggleCarry
0x0);// NextED

CreateGenTd(
(unsigned int) &td[0],// TD Address
2,// Data Toggle
0x2,// DelayInterrupt
0x0,// Direction
1,// Buffer Rounding
(unsigned int) pSetup4,// Current Buffer Pointer,界说的全局变量数组
//const char pSetup4[8] ={0x80,0x06,0x00,0x02,0x00,0x00,0x40,0x00};
(unsigned int) &td[1],// Next TD
8);// Buffer Length

CreateGenTd(
(unsigned int) &td[1],// TD Address
0,// Data Toggle
0x2,// DelayInterrupt
0x2,// Direction
1,// Buffer Rounding
(unsigned int) pData4,// Current Buffer Pointer,界说的全局变量数组
// char pData4[0x40];经过读取该数组,能够获悉装备描绘符
(unsigned int) &td[2],// Next TD
0x40);// Buffer Length

CreateGenTd(
(unsigned int) &td[2],// TD Address
3,// Data Toggle
0x2,// DelayInterrupt
0x1,// Direction
1,// Buffer Rounding
0x0,// Current Buffer Pointer
(unsigned int) &td[3],// Next TD
0x0);// Buffer Length

CreateGenTd(
(unsigned int) &td[3],// TD Address
3,// Data Toggle
0x2,// DelayInterrupt
0x2,// Direction
1,// Buffer Rounding
0x0,// Current Buffer Pointer
(unsigned int) 0,// Next TD
0x0);// Buffer Length

rHcControlHeadED = (unsigned int )& ed;
rHcControlCurrentED = (unsigned int )& ed;
rHcControl = 0x90;
rHcCommandStatus = 0x02;

//第五步,主机发送SETUP数据包,用以设置装备,答应一切端点进入作业状况。
CreateEd(
(unsigned int) &ed, // ED Address
64,// Max packet
0,// TD format
0,// Skip
0,// Speed
0x0,// Direction
0,// Endpoint
2,// Func Address
(unsigned int) &td[2],// TDQTailPointer
(unsigned int) &td[0],// TDQHeadPointer
0,// ToggleCarry
0x0);// NextED

CreateGenTd(
(unsigned int) &td[0],// TD Address
2,// Data Toggle
2,// DelayInterrupt
0,// Direction
1,// Buffer Rounding
(unsigned int) pSetup5,// Current Buffer Pointer,界说的全局变量数组
//const char pSetup5[8] ={0x00,0x09,0x01,0x00,0x00,0x00,0x00,0x00};
(unsigned int) &td[1],// Next TD
8);// Buffer Length

CreateGenTd(
(unsigned int) &td[1],// TD Address
0,// Data Toggle
2,// DelayInterrupt
2,// Direction
1,// Buffer Rounding
(unsigned int) 0,// Current Buffer Pointer
(unsigned int) &td[2],// Next TD
0);// Buffer Length

CreateGenTd(
(unsigned int) &td[2],// TD Address
3,// Data Toggle
2,// DelayInterrupt
1,// Direction
1,// Buffer Rounding
0x0,// Current Buffer Pointer
(unsigned int) 0,// Next TD
0x0);// Buffer Length

rHcControlHeadED = (unsigned int )& ed;
rHcControlCurrentED = (unsigned int )& ed;
rHcControl = 0x90;
rHcCommandStatus = 0x02;

return 0x88;
}

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/qiche/265517.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部