pInformation = &Device_Info;
pInformation->ControlState = 2;
pProperty = &Device_Property;
pUser_Standard_Requests = &User_Standard_Requests;
/* Initialize devices one by one */
pProperty->Init();
{
Joystick_init,
Joystick_Reset,
Joystick_Status_In,
Joystick_Status_Out,
Joystick_Data_Setup,
Joystick_NoData_Setup,
Joystick_Get_Interface_Setting,
Joystick_GetDeviceDescriptor,
Joystick_GetConfigDescriptor,
Joystick_GetStringDescriptor,
0,
0x40 /*MAX PACKET SIZE*/
};
{
Joystick_GetConfiguration,
Joystick_SetConfiguration,
Joystick_GetInterface,
Joystick_SetInterface,
Joystick_GetStatus,
Joystick_ClearFeature,
Joystick_SetEndPointFeature,
Joystick_SetDeviceFeature,
Joystick_SetDeviceAddress
};
ID*/
Get_SerialNum();
//获取设备序列号,转变为unicode字符串
pInformation->Current_Configuration = 0;
/* Connect the device */
PowerOn();
//连接USB设备,实质是能让主机检测到了。
/* USB interrupts initialization */
_SetISTR(0);
/* clear pending interrupts */
wInterrupt_Mask = IMR_MSK;
_SetCNTR(wInterrupt_Mask); /* set interrupts mask */
bDeviceState = UNCONNECTED;
UserToPMABufferCopy(Mouse_Buffer, GetEPTxAddr(ENDP1), 4);
//从用户复制四个字节到端点1缓冲区,控制端点的输入缓冲区。
SetEPTxValid(ENDP1); /* enable endpoint for transmission */
wIstr = _GetISTR();
if (wIstr & ISTR_RESET & wInterrupt_Mask)
{
_SetISTR((u16)CLR_RESET); //清复位中断
Device_Property.Reset();
}
if (wIstr & ISTR_WKUP & wInterrupt_Mask)
{
_SetISTR((u16)CLR_WKUP);
Resume(RESUME_EXTERNAL);
}
if (wIstr & ISTR_SUSP & wInterrupt_Mask)
{
if (fSuspendEnabled) /* check if SUSPEND is possible */
{
Suspend();
}
else
{
/* if not possible then resume after xx ms */
Resume(RESUME_LATER);
}
/* clear of the ISTR bit must be done after setting of CNTR_FSUSP */
_SetISTR((u16)CLR_SUSP);
}
if (wIstr & ISTR_CTR & wInterrupt_Mask)
{
CTR_LP(); /* servicing of the endpoint correct transfer interrupt */
}
控制寄存器CNTR
|
传输完成中断允许位。CTRM,1有效,如果SIE置位传输完成标志,则相应的数据传输完成中断发生。
第15位
|
包缓冲区溢出中断允许位
|
错误中断允许位
|
唤醒中断允许位。WKUPM。1有效,如果唤醒请求标志位置位,则产生唤醒中断。
|
挂起中断允许位。SUSPM,1有效,当总线挂起标志置位时,发生挂起中断。
|
复位中断允许位。RESETM。1有效,软件强制复位和总线复位信号,都能触发复位中断。
|
帧首中断允许位
|
期望帧首中断允许位。ESOFM。它的含义是没有收到帧首信号,允许发生中断。
第8位
|
|
|
|
|
向主机发送的唤醒请求,RESUME。1有效,主机收到该信号,将唤醒设备。这个由软件置位。
第4位
|
强制挂起控制,FSUSP。1有效。与由于总线无活动引起挂起的效果相同。
|
低功耗模式。前提是先进入挂起状态。由软件设置,一般又硬件复位(被唤醒后自动清零)。
|
断电模式控制位。PDWN。此位为1时,USB模块关闭。
|
强制复位控制。FRES。与总线上的复位信号产生相同的效果。也能产生复位中断.
第0位。
|
中断状态寄存器ISTR
|
CTR标志,数据传输完成后硬件置1.
|
PMAOVR标志
|
ERR标志
|
WKUP请求,总线检测到主机唤醒请求时由硬件置位。
|
SUSP请求标志位。
|
RESET请求标志位。
|
SOF帧首标志
|
ESOF,期待帧首标志。
|
|
|
|
DIR传输方向,此位由硬件控制。IN时为0,OUT为1.
第4位。
|
发生数据传输的端点的地址。
| ||||
端点状态和配置寄存器,8个寄存器,支持8个双向端点和16个单向端点。
|
CTR_RX,正确接收标志位。
第15位。
|
DTOG_RX,用于检测的数据翻转位。一般由硬件自动设置,软件写1可使其手动翻转。
|
STAT_RX,占据两位。
00表示该端点不可用,无回应。
01表示响应STALL
10响应NAK
11表示端点有效,可接收数据。
| |
|
SETUP标志。收到SETUP令牌包时置位。用户收到数据后需检查次位。
第11位。
|
EP_TYPE,两位,表示端点类型。
00表示批量端点。
01表示控制端点
10表示等时端点。
11表示中断端点。
|
EP_KIND,端点特殊类型。在EP_TYPE=01时,表示设备期望主机的0字节状态包。
| |
|
CTR_TX。
正确发送标志。主机的IN包之后。
第7位。
|
DTOG_TX,用于检测的数据翻转位。一般由硬件自动设置,软件写1可使其手动翻转。
|
STAT_TX,占据两位。
00表示该端点不可用,无回应。
01表示响应STALL
10响应NAK
11表示端点有效,可发送数据。
| |
|
端点地址:EA【3:0】,表明该寄存器对应的端点号码。比如1、2号寄存器都可以对应端点1(在双缓冲情况下)。
第3-0位。
| |||
端点描述符表相关寄存器
EXTI_InitStructure.EXTI_Line = EXTI_Line18; // USB resume from suspend mode
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);
pInformation = &Device_Info;
pInformation->ControlState = 2;
pProperty = &Device_Property;
//这个是设备本身支持的属性和方法
pUser_Standard_Requests = &User_Standard_Requests; //这个是主机请求的实现方法。
pProperty->Init();
//回调设备的初始化例程。
u8 USBbmRequestType;
/* bmRequestType */
u8 USBbRequest;
/* bRequest */
u16_u8 USBwValues;
/* wValue */
u16_u8 USBwIndexs;
/* wIndex */
u16_u8 USBwLengths;
/* wLength */
u8 ControlState;
/* of type CONTROL_STATE */
u8 Current_Feature;
u8 Current_Configuration;
/* Selected configuration */
u8 Current_Interface;
/* Selected interface of current configuration */
u8 Current_AlternateSetting;/* Selected Alternate Setting of current
interface*/
ENDPOINT_INFO Ctrl_Info;
//端点信息结构体
——Get_SerialNum();
wRegVal = CNTR_FRES;
_SetCNTR(wRegVal);
//这句话实际上使能了USB模块的电源,因为上电复位时,CNTR寄存器的断电控制为PDWN位是1,模块是断电的。
wInterrupt_Mask=CNTR_RESETM| CNTR_SUSPM | CNTR_WKUPM;
_SetCNTR(wInterrupt_Mask);
if (wIstr & ISTR_RESET & wInterrupt_Mask)
{
_SetISTR((u16)CLR_RESET);
//先清除复位中断位
Device_Property.Reset();
//进入设备定义的复位过程。实际上是调用JoyStick_Reset()函数进行处理。
}
pInformation->Current_Configuration = 0;
//当前配置为0
pInformation->Current_Interface = 0;/当前接口为0
pInformation->Current_Feature = Joystick_ConfigDescriptor[7];
//需要总线供电
SetBTABLE(BTABLE_ADDRESS); //设置包缓冲区地址。
SetEPType(ENDP0, EP_CONTROL);
//端点0为控制端点
SetEPTxStatus(ENDP0, EP_TX_STALL);
//端点状态为发送无效,也就是主机IN令牌包来的时候,回送一个STALL。
SetEPRxAddr(ENDP0, ENDP0_RXADDR); //设置端点0描述符表,包括接收缓冲区地址、最大允许接收的字节数、发送缓冲区地址三个量。
SetEPTxAddr(ENDP0, ENDP0_TXADDR); //这是发送缓冲区地址
Clear_Status_Out(ENDP0);
//清除EP_KIND的STATUS_OUT位,如果改位被设置,在控制模式下只对0字节数据包相应。其它的都返回STALL。主要用于控制传输的状态过程。
SetEPRxCount(ENDP0, Device_Property.MaxPacketSize); //接收缓冲区支持64个字节。
SetEPRxValid(ENDP0);
//使能端点0的接收,因为很快就要接收SETUP令牌包后面跟着的数据包了。
SetEPType(ENDP1, EP_INTERRUPT);
//端点1为中断端点。
SetEPTxAddr(ENDP1, ENDP1_TXADDR); //设置发送缓冲区地址。
SetEPTxCount(ENDP1, 4);
//每次发送四个字节
SetEPRxStatus(ENDP1, EP_RX_DIS);
//接收禁止,只发送Mouse信息,而不从主机接收。
SetEPTxStatus(ENDP1, EP_TX_NAK); //现在发送端点还不允许发送数据。
bDeviceState = ATTACHED;
//连接状态改为已经连接,默认地址状态。
SetDeviceAddress(0); //地址默认为0.
PowerOn();
//这句执行完,设备被主机检测到,并且能够响应复位中断了。
_SetISTR(0);
/* clear pending interrupts */
wInterrupt_Mask = IMR_MSK;
_SetCNTR(wInterrupt_Mask); /* set interrupts mask */
bDeviceState = UNCONNECTED;
//设备状态置位为未连接状态。这里我不太理解。这时候即使复位中断未发生,最起码设备已经算是连接入总线了,为什么这个状态还要设置为
“未连接”呢?
//如果是端点0,这里的确是端点0
{
SaveRState = _GetEPRxStatus(ENDP0); //保存端点0状态,原本是有效状态。
SaveTState = _GetEPTxStatus(ENDP0);
_SetEPRxStatus(ENDP0, EP_RX_NAK); //在本次数据处理好之前,对主机发来的数据包以NAK回应
_SetEPTxStatus(ENDP0, EP_TX_NAK);
if ((wIstr & ISTR_DIR) == 0) //如果是IN令牌,数据被取走
{
_ClearEP_CTR_TX(ENDP0);
In0_Process();
//调用该程序处理固件数据输出后的工作。
_SetEPRxStatus(ENDP0, SaveRState);
_SetEPTxStatus(ENDP0, SaveTState);
return;
}
Else
//DIR=1时,要么是SETUP包,要么是OUT包。
{
//这里先分析SETUP包。
wEPVal = _GetENDPOINT(ENDP0);
//获取整个端点0状态
if ((wEPVal & EP_CTR_TX) != 0)
//这种情况一般不太可能,
{
//如果出现表示同时 TX和RX 同时置位。
}
else if ((wEPVal &EP_SETUP) != 0)
//我们的程序会执行到这里
{
_ClearEP_CTR_RX(ENDP0);
Setup0_Process();
//主要是调用该程序来处理主机请求。
_SetEPRxStatus(ENDP0, SaveRState);
_SetEPTxStatus(ENDP0, SaveTState);
return;
}
else if ((wEPVal & EP_CTR_RX) != 0) //暂时不执行的代码先删除掉。
{
}
}
}/* if(EPindex == 0) */
后面处理其他端点的代码就先不看了。
}/* while(...) */
if (pInformation->ControlState != PAUSE)
{
pInformation->USBbmRequestType = *pBuf.b++; //请求类型,表明方向和接收对象(设备、接口还是端点)此时为80,表明设备到主机
pInformation->USBbRequest = *pBuf.b++; /* 请求代码,第一次时应该是6,表明主机要获取设备描述符。 */
pBuf.w++;
pInformation->USBwValue = ByteSwap(*pBuf.w++); /* wValue */
pBuf.w++;
//我觉得这里可能有些问题。
pInformation->USBwIndex
= ByteSwap(*pBuf.w++); /* wIndex */
pBuf.w++;
pInformation->USBwLength = *pBuf.w; /* wLength */
}
pInformation->ControlState = SETTING_UP;
if (pInformation->USBwLength == 0)
{
NoData_Setup0();
}
else
{
Data_Setup0();
//这次是有数据传输的,所以有进入该该函数。
}
return Post0_Process();
CopyRoutine = NULL; //这是一个函数指针,由用户提供。
wOffset = 0;
if (Request_No == GET_DESCRIPTOR) //如果是获取设备描述符
{
if(Type_Recipient==(STANDARD_REQUEST| EVICE_RECIPIENT))
{
u8 wValue1 = pInformation->USBwValue1;
if (wValue1 == DEVICE_DESCRIPTOR)
{
CopyRoutine = pProperty->GetDeviceDescriptor;
} //获取设备描述符的操作由用户提供。
if (CopyRoutine)
{
pInformation->Ctrl_Info.Usb_wOffset = wOffset;
pInformation->Ctrl_Info.CopyData = CopyRoutine;
(*CopyRoutine)(0); //这个函数这里调用的目的只是设置了pInformation中需要写入的描述符的长度。
Result = USB_SUCCESS;
}
if (ValBit(pInformation->USBbmRequestType, 7))
//此时为80
{
//上面这个语句主要是判断传输方向。如果为1,则是设备到主机
vu32 wLength = pInformation->USBwLength; 这个一般是64
if (pInformation->Ctrl_Info.Usb_wLength > wLength)
{
//设备描述符长度18
pInformation->Ctrl_Info.Usb_wLength = wLength;
}
//有些细节暂时先放着
pInformation->Ctrl_Info.PacketSize = pProperty->MaxPacketSize;
DataStageIn();
//最主要是调用这个函数完成描述符的输出准备
}
DataBuffer = (*pEPinfo->CopyData)(Length); //这个是取得用户描述符缓冲区的地址。这里共18个字节
UserToPMABufferCopy(DataBuffer, GetEPTxAddr(ENDP0), Length);//这个函数将设备描述符复制到用户的发送缓冲区。
SetEPTxCount(ENDP0, Length);
//设置发送字节的数目、18
pEPinfo->Usb_wLength -= Length; 等于0
pEPinfo->Usb_wOffset += Length; 偏移到18
vSetEPTxStatus(EP_TX_VALID); //使能端点发送,只要主机的IN令牌包一来,SIE就会将描述符返回给主机。
USB_StatusOut();/* 这个实际上是使接收也有效,主机可取消IN。 */
pInformation->ControlState = ControlState;
if ((ControlState == IN_DATA) || (ControlState == LAST_IN_DATA))
{
第一次取设备描述符只取一次。
DataStageIn();
//此次调用后,当前状态变成WAIT_STATUS_OUT,表明设备等待状态过程,主机输出0字节。
/* ControlState may be changed outside the function */
ControlState = pInformation->ControlState;
}返回时调用Post0_Process(void)函数,这个函数没做什么事。
else if (ControlState == WAIT_STATUS_OUT)
{
(*pProperty->Process_Status_OUT)();
//这是个空函数,什么也不做。
ControlState = STALLED;
//状态转为STALLED。
}
else if (RequestNo == SET_ADDRESS)
{
Result = USB_SUCCESS;
}
ControlState = WAIT_STATUS_IN;/* After no data stage SETUP */
USB_StatusIn(); //这句话是一个关键,它是一个宏,实际是准备好发送0字节的状态数据包。因为地址设置没有数据过程,建立阶段后直接进入状态阶段,主机发IN令牌包,设备返回0字节数据包,主机再ACK。
vSetEPTxStatus(EP_TX_VALID); \ //设置发送有效,发送字节数为0
}
else if (ControlState == WAIT_STATUS_IN)
{
if ((pInformation->USBbRequest == SET_ADDRESS) &&
(Type_Recipient==(STANDARD_REQUEST|DEVICE_RECIPIENT)))
{
SetDeviceAddress(pInformation->USBwValue0);
pUser_Standard_Requests->User_SetDeviceAddress(); //这个函数就一个赋值语句,bDeviceState = ADDRESSED。
}
(*pProperty->Process_Status_IN)(); //这是一个空函数。
ControlState = STALLED;
}
SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);
//将端点0的缓冲区大小设置为64字节
if (pInformation->ControlState == STALLED)
{
vSetEPRxStatus(EP_RX_STALL);
vSetEPTxStatus(EP_TX_STALL);
}
vSetEPTxStatus(EP_TX_VALID);
USB_StatusOut();/* 本来期待IN令牌包,但用户可以取消数据阶段,一般不会用到 */
ControlState = WAIT_STATUS_OUT;
vSetEPTxStatus(EP_TX_STALL);
//转入状态阶段。
Send0LengthData();
ControlState = LAST_IN_DATA;
Data_Mul_MaxPacketSize = FALSE; //这一次发送0个字节,状态转为最后输入阶段。
if (Result != USB_SUCCESS)
{
Result = (*pProperty->Class_NoData_Setup)(RequestNo); //这里就是调用用户提供的类特殊请求的处理函数。结果发现用户提供的类特殊请求(针对无数据情况)只支持SET_PROTOCOL。针对有数据情况只支持:GET_PROTOCOL。
if ((Type_Recipient==(CLASS_REQUEST | INTERFACE_RECIPIENT))
&& (RequestNo == SET_PROTOCOL))
{
return Joystick_SetProtocol();
}
}
if (Request_No == GET_DESCRIPTOR)
{
if(Type_Recipient==(STANDARD_REQUEST| EVICE_RECIPIENT))
{
u8 wValue1 = pInformation->USBwValue1;
if (wValue1 == DEVICE_DESCRIPTOR)
{
CopyRoutine = pProperty->GetDeviceDescriptor;
}
else if (wValue1 == CONFIG_DESCRIPTOR)
{
CopyRoutine = pProperty->GetConfigDescriptor;
}
else if (wValue1 == STRING_DESCRIPTOR)
{
CopyRoutine = pProperty->GetStringDescriptor;
}
/* End of GET_DESCRIPTOR */
}
}
Result= (*pProperty->Class_Data_Setup)(pInformation->USBbRequest);
Mouse_Buffer[1] = X;
Mouse_Buffer[2] = Y;
/*copy mouse position info in ENDP1 Tx Packet Memory Area*/
UserToPMABufferCopy(Mouse_Buffer, GetEPTxAddr(ENDP1), 4);
/* enable endpoint for transmission */
SetEPTxValid(ENDP1);
if ((wEPVal & EP_CTR_TX) != 0)
{
/* clear int flag */
_ClearEP_CTR_TX(EPindex);
(*pEpInt_IN[EPindex-1])();
} /* if((wEPVal & EP_CTR_TX) != 0) */
3651



被折叠的 条评论
为什么被折叠?



