新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > STM32--USB详细使用说明

STM32--USB详细使用说明

作者: 时间:2016-11-27 来源:网络 收藏

***************(3)**************

1.获取设备描述符

usb_int.c的文件里面

低优先级中断 在控制 中断 批量传输下使用(在单缓冲模式下使用)
当一次正确的OUT,SETUP,IN数据传输完成后,硬件会自动设置此位为NAK状态,使应用程序有足够的时间处理完当前传输的数据后,响应下一个数据分组

void CTR_LP(void)
{
__IO uint16_t wEPVal = 0;

while (((wIstr = _GetISTR()) & ISTR_CTR) != 0)
{

EPindex = (uint8_t)(wIstr & ISTR_EP_ID);//读出端点ID
if (EPindex == 0)//如果是端点0
{





SaveRState = _GetENDPOINT(ENDP0);//读取端点0寄存器USB_EP0R
SaveTState = SaveRState & EPTX_STAT;//保存发送状态位
SaveRState &= EPRX_STAT;//保存接受状态位
_SetEPRxTxStatus(ENDP0,EP_RX_NAK,EP_TX_NAK);//端点以NAK分组响应所有的发送和接受请求(解释在上面)

if ((wIstr & ISTR_DIR) == 0)//IN令牌,数据被取走

{



_ClearEP_CTR_TX(ENDP0);//清除正确发送标志位
In0_Process();//处理INT事件

_SetEPRxTxStatus(ENDP0,SaveRState,SaveTState);
return;
}
else
{


wEPVal = _GetENDPOINT(ENDP0);//得到端点0寄存器的数据
if ((wEPVal &EP_SETUP) != 0)//SETUP分组传输完成标志
{
_ClearEP_CTR_RX(ENDP0);
Setup0_Process();//处理SETUP事件

//程序会进入到这个函数里面

_SetEPRxTxStatus(ENDP0,SaveRState,SaveTState);
return;
}

else if ((wEPVal & EP_CTR_RX) != 0)
{
_ClearEP_CTR_RX(ENDP0);
Out0_Process();//处理OUT事件

_SetEPRxTxStatus(ENDP0,SaveRState,SaveTState);
return;
}
}
}
else//如果是除端点0以外的端点
{


wEPVal = _GetENDPOINT(EPindex);//得到相应端点寄存器值
if ((wEPVal & EP_CTR_RX) != 0)//检测正确接收标志 PC-USB OUT int
{

_ClearEP_CTR_RX(EPindex);//清除相应的标志


(*pEpInt_OUT[EPindex-1])();//调用OUT int服务功能

}

if ((wEPVal & EP_CTR_TX) != 0)//检测正确发送标志 USB-PC IN int
{

_ClearEP_CTR_TX(EPindex);//清除相应的标志


(*pEpInt_IN[EPindex-1])();//调用IN int服务功能
}

}

}
}

usb_coer.c的文件里面,主要是得到主机发来的标准请求命令

uint8_t Setup0_Process(void)
{

union
{
uint8_t* b;
uint16_t* w;
} pBuf;

#ifdef STM32F10X_CL
USB_OTG_EP *ep;
uint16_t offset = 0;
ep = PCD_GetOutEP(ENDP0);
pBuf.b = ep->xfer_buff;
#else
uint16_t offset = 1;
//得到接受缓冲区地址寄存器地址
pBuf.b = PMAAddr + (uint8_t *)(_GetEPRxAddr(ENDP0) * 2);
#endif

if (pInformation->ControlState != PAUSE)
{
pInformation->USBbmRequestType = *pBuf.b++;

pInformation->USBbRequest = *pBuf.b++;

pBuf.w += offset;
pInformation->USBwValue = ByteSwap(*pBuf.w++);

pBuf.w += offset;
pInformation->USBwIndex = ByteSwap(*pBuf.w++);

pBuf.w += offset;
pInformation->USBwLength = *pBuf.w;

}

pInformation->ControlState = SETTING_UP;
if (pInformation->USBwLength == 0)
{

NoData_Setup0();
}
else
{

Data_Setup0();//由于是有数据的传输,所有要进入到这个函数
}
return Post0_Process();
}

usb_core.c的文件里面,这里只是选取了GET DESCRIPTOR

的程序部分,其他的部分删除了

void Data_Setup0(void)
{
uint8_t *(*CopyRoutine)(uint16_t);
RESULT Result;
uint32_t Request_No = pInformation->USBbRequest;

uint32_t Related_Endpoint, Reserved;
uint32_t wOffset, Status;

CopyRoutine = NULL;
wOffset = 0;

//看标准请求码格式就知道了
if (Request_No == GET_DESCRIPTOR)
{
//pInformation->USBbmRequestType是下面的两种 标准请求或设备请求
if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))
{
uint8_t wValue1 = pInformation->USBwValue1;//高一字节得到描述表种类 一共有5种
if (wValue1 == DEVICE_DESCRIPTOR)//设备描述
{
CopyRoutine = pProperty->GetDeviceDescriptor;
}
else if (wValue1 == CONFIG_DESCRIPTOR)
{
CopyRoutine = pProperty->GetConfigDescriptor;//配置描述
}
else if (wValue1 == STRING_DESCRIPTOR)
{
CopyRoutine = pProperty->GetStringDescriptor;//字符串描述
}
}
}

if (CopyRoutine)
{
pInformation->Ctrl_Info.Usb_wOffset = wOffset;//本子程序的wOffset是0
pInformation->Ctrl_Info.CopyData = CopyRoutine;//使指针pInformation->Ctrl_Info.CopyData指向CopyRoutine


(*CopyRoutine)(0);//第一次执行时Length=0 返回的是有效数据的长度 存储到pInformation->Ctrl_Info.Usb_wLength
Result = USB_SUCCESS;
}
else
{//如果标准请求不存在 看类 厂商请求中是否有
Result = (*pProperty->Class_Data_Setup)(pInformation->USBbRequest);
if (Result == USB_NOT_READY)
{
pInformation->ControlState = PAUSE;
return;
}
}

if (pInformation->Ctrl_Info.Usb_wLength == 0xFFFF)//如果字符的长度是0xffff
{

pInformation->ControlState = PAUSE;
return;
}
if ((Result == USB_UNSUPPORT) || (pInformation->Ctrl_Info.Usb_wLength == 0))
{

pInformation->ControlState = STALLED;
return;
}

if (ValBit(pInformation->USBbmRequestType, 7))//D7表示数据传输方向 1:设备向主机
{

__IO uint32_t wLength = pInformation->USBwLength;

//设置使其为USB主机设置的长度 本程序HID 鼠标 pProperty->MaxPacketSize是0x40
if (pInformation->Ctrl_Info.Usb_wLength > wLength)//字符的长度大于主机要求的长度

{
pInformation->Ctrl_Info.Usb_wLength = wLength;

//将其设置为主机要求的
}
else if (pInformation->Ctrl_Info.Usb_wLength < pInformation->USBwLength)//字符的长度小于主机要求的
{
if (pInformation->Ctrl_Info.Usb_wLength < pProperty->MaxPacketSize) //如果字符的长度长度小于每包数据最大字节数
{
Data_Mul_MaxPacketSize = FALSE;
}
else if ((pInformation->Ctrl_Info.Usb_wLength % pProperty->MaxPacketSize) == 0)//如果是其整数倍
{
Data_Mul_MaxPacketSize = TRUE;
}
}

pInformation->Ctrl_Info.PacketSize = pProperty->MaxPacketSize;
DataStageIn();
}
else//主机向设备
{
pInformation->ControlState = OUT_DATA;
vSetEPRxStatus(EP_RX_VALID);
}

return;
}

usb_coer.c的文件里面

void DataStageIn(void)
{
ENDPOINT_INFO *pEPinfo = &pInformation->Ctrl_Info;//端点信息保存在指针变量中
uint32_t save_wLength = pEPinfo->Usb_wLength;//得到字符的长度
uint32_t ControlState = pInformation->ControlState;//得到当前的状态

uint8_t *DataBuffer;
uint32_t Length;

if ((save_wLength == 0) && (ControlState == LAST_IN_DATA))//如果字符长度为0 且控制状态是最后输入的数据
{
if(Data_Mul_MaxPacketSize == TRUE)//如果字符的长度是数据包的整数倍
{

Send0LengthData();
ControlState = LAST_IN_DATA;
Data_Mul_MaxPacketSize = FALSE;//这一次发送0字节 状态转为最后输入阶段
}
else//字符的长度比数据包要小
{//数据已经发送完

ControlState = WAIT_STATUS_OUT;

#ifdef STM32F10X_CL
PCD_EP_Read (ENDP0, 0, 0);
#endif
#ifndef STM32F10X_CL
vSetEPTxStatus(EP_TX_STALL);//设置端点的发送状态停止
#endif
}
goto Expect_Status_Out;
}

Length = pEPinfo->PacketSize;//得到数据包大小 64字节
ControlState = (save_wLength <= Length) ? LAST_IN_DATA : IN_DATA;//比较大小得到是LAST_IN_DATA还是IN_DATA 18字节<64字节 ControlState = LAST_IN_DATA

if (Length > save_wLength)
{
Length = save_wLength;
}

DataBuffer = (*pEPinfo->CopyData)(Length);//DataBuffer指向要复制数据的地址 这个地址是随Usb_wOffset变化的

#ifdef STM32F10X_CL
PCD_EP_Write (ENDP0, DataBuffer, Length);
#else
//GetEPTxAddr(ENDP0) 得到发送缓冲区相应端点的地址
//将DataBuffer中的数据复制到相应的发送缓冲区中
UserToPMABufferCopy(DataBuffer, GetEPTxAddr(ENDP0), Length);
#endif

SetEPTxCount(ENDP0, Length);//设置相应的端点要发送的字节数

pEPinfo->Usb_wLength -= Length;//等于0
pEPinfo->Usb_wOffset += Length;//偏移到18
vSetEPTxStatus(EP_TX_VALID);//使能发送端点 只要主机的IN令牌包一来 SIE就会将描述符返回给主机

USB_StatusOut();
//设置接收端点有效 这个实际上使接受也有效,

Expect_Status_Out:
pInformation->ControlState = ControlState;//保存控制状态
}

***************(4)**************

uint8_t In0_Process(void)
{
uint32_t ControlState = pInformation->ControlState;

if ((ControlState == IN_DATA) || (ControlState ==LAST_IN_DATA))//进入到这里

{
DataStageIn();//第一次取设备描述符只取一次当前的状态变为WAIT_STATUS_IN表明设备等待状态过程 主机输出0字节

ControlState = pInformation->ControlState;
}

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();
}
(*pProperty->Process_Status_IN)();
ControlState = STALLED;//变为这个状态
}

else
{
ControlState = STALLED;
}

pInformation->ControlState = ControlState;

return Post0_Process();
}



关键词: STM32USB使用说

评论


技术专区

关闭