既然學習了USB,那就必須的搞懂USB設備與USB主機數據是怎么通訊的。這里主要講設備端,因為我們的代碼是做USB設備用的。
USB_HP_CAN1_TX_IRQn = 19, /*!< USB Device High Priority or CAN1 TX Interrupts */
USB_LP_CAN1_RX0_IRQn = 20, /*!< USB Device Low Priority or CAN1 RX0 Interrupts */
void USB_LP_CAN1_RX0_IRQHandler(void)
{
USB_Istr();
}
#if (IMR_MSK & ISTR_CTR) //正確傳輸中斷CTR標志
if (wIstr & ISTR_CTR & wInterrupt_Mask)//讀出的中斷標志是CRT中斷標志,且CRT中斷使能了
{
CTR_LP(); //調用正確傳輸中斷服務程序
#ifdef CTR_CALLBACK
CTR_Callback(); //當定義了CTR_CALLBACK,則調用CTR_Callback,像鈎子函數一樣,在發生CRT中斷時做點什么
#endif
}
/*******************************************************************************
* Function Name : CTR_LP.
* Description : 低優先級的端點正確傳輸中斷服務程序
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void CTR_LP(void)
{
__IO uint16_t wEPVal = 0;
while (((wIstr = _GetISTR()) & ISTR_CTR) != 0) //讀取中斷狀態寄存器的值,看是否是CRT(正確傳輸中斷)
{
EPindex = (uint8_t)(wIstr & ISTR_EP_ID); //獲取產生中斷的端點號,
if (EPindex == 0) //如果端點0
{
SaveRState = _GetENDPOINT(ENDP0); //讀取端點0的狀態寄存器
SaveTState = SaveRState & EPTX_STAT; //保存端點0發送狀態
SaveRState &= EPRX_STAT; //保存端點0接收狀態
_SetEPRxTxStatus(ENDP0,EP_RX_NAK,EP_TX_NAK);//設置端點0對主機以NAK方式響應所有的接收和發送請求
if ((wIstr & ISTR_DIR) == 0) //如果是IN令牌
{
_ClearEP_CTR_TX(ENDP0); //清除端點0正確發送標志位
In0_Process(); //處理IN令牌包
/* before terminate set Tx & Rx status */
_SetEPRxTxStatus(ENDP0,SaveRState,SaveTState);//在傳輸之前設置端點0接收發送狀態位
return;
}
else //OUT令牌
{
wEPVal = _GetENDPOINT(ENDP0); //獲取端點0的端點寄存器的值
if ((wEPVal &EP_SETUP) != 0) //SETUP分組傳輸完成標志位
{
_ClearEP_CTR_RX(ENDP0); //清除端點0的接收標志位
Setup0_Process(); //端點0建立階段的數據處理
_SetEPRxTxStatus(ENDP0,SaveRState,SaveTState);//設置端點0階接收發送標志位
return;
}
else if ((wEPVal & EP_CTR_RX) != 0) //正確接收標志位
{
_ClearEP_CTR_RX(ENDP0); //清除端點0正確標志位
Out0_Process(); //處理OUT令牌包
_SetEPRxTxStatus(ENDP0,SaveRState,SaveTState);//設置端點0的接收發送狀態
return;
}
}
}/* if(EPindex == 0) */
else //如果非0端點
{
wEPVal = _GetENDPOINT(EPindex); //獲取該端點的端點寄存器的值
if ((wEPVal & EP_CTR_RX) != 0) //正確接收標志
{
_ClearEP_CTR_RX(EPindex); //清除端點正確接收標志
(*pEpInt_OUT[EPindex-1])(); //調用注冊過的端點OUT處理函數
} /* if((wEPVal & EP_CTR_RX) */
if ((wEPVal & EP_CTR_TX) != 0) //正確發送標志
{
_ClearEP_CTR_TX(EPindex); //清除正確發送標志
(*pEpInt_IN[EPindex-1])(); //調用注冊過的端點IN處理函數
} /* if((wEPVal & EP_CTR_TX) != 0) */
}/* if(EPindex == 0) else */
}/* while(...) */
}
/*定義指向指針的函數指針數組,函數指針分別指向7個端點輸入服務程序*/
void (*pEpInt_IN[7])(void) =
{
EP1_IN_Callback,
EP2_IN_Callback,
EP3_IN_Callback,
EP4_IN_Callback,
EP5_IN_Callback,
EP6_IN_Callback,
EP7_IN_Callback,
};
/*定義指向指針的函數指針數組,函數指針分別指向7個端點輸出服務程序*/
void (*pEpInt_OUT[7])(void) =
{
EP1_OUT_Callback,
EP2_OUT_Callback,
EP3_OUT_Callback,
EP4_OUT_Callback,
EP5_OUT_Callback,
EP6_OUT_Callback,
EP7_OUT_Callback,
};
/*******************************************************************************
* Function Name : EP1_OUT_Callback.
* Description : 端點1輸出回調函數
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void EP1_OUT_Callback(void)
{
PMAToUserBufferCopy(USB_Receive_Buffer, ENDP1_RXADDR, REPORT_COUNT); //PMA緩沖區接收到的數據拷貝到用戶自定義緩沖區USB_Receive_Buffer中
SetEPRxStatus(ENDP1, EP_RX_VALID); //設置端點的接收狀態為有效,因為端點接收到數據后會端點狀態自動設置成停止狀態
USB_Received_Flag=1; //設置接收到數據標志位
}
/**
* @brief 通過USB發送數據
* @param data 數據存儲首地址
* @param dataNum 發送的數據字節數
* @retval 發送的字節數
*/
uint32_t USB_SendData(uint8_t *data,uint32_t dataNum)
{
//將數據通過USB發送出去
UserToPMABufferCopy(data, ENDP2_TXADDR, dataNum);//拷貝數據到PMA中
SetEPTxCount(ENDP2, REPORT_COUNT); //從端點2發送64字節數據
SetEPTxValid(ENDP2); //使能端點2的發送狀態
return dataNum;
}