usb_istr.c详解
一、源代码
/**
******************************************************************************
* @file usb_istr.c
* @author MCD Application Team
* @version V4.0.0
* @date 21-January-2013
* @brief ISTR events interrupt service routines
******************************************************************************
* @attention
*
* <h2><center>© COPYRIGHT 2013 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "usb_lib.h"
#include "usb_prop.h"
#include "usb_pwr.h"
#include "usb_istr.h"
#include "SEGGER_RTT.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
__IO uint16_t wIstr; /* ISTR register last read value */
__IO uint8_t bIntPackSOF = 0; /* SOFs received between 2 consecutive packets */
__IO uint32_t esof_counter =0; /* expected SOF counter */
__IO uint32_t wCNTR=0;
/* Extern variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* function pointers to non-control endpoints service routines */
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,
};
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 : USB_Istr
* Description : ISTR events interrupt service routine
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void USB_Istr(void)
{
uint32_t i=0;
__IO uint32_t EP[8];
wIstr = _GetISTR();
#if (IMR_MSK & ISTR_SOF)//帧首中断标志
if (wIstr & ISTR_SOF & wInterrupt_Mask)
{
_SetISTR((uint16_t)CLR_SOF);//清除SOF中断标志
bIntPackSOF++;//统计共接收到多少SOF
#ifdef SOF_CALLBACK
SOF_Callback();
#endif
}
#endif
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (IMR_MSK & ISTR_CTR)//正确传输中断CTR标志
if (wIstr & ISTR_CTR & wInterrupt_Mask)
{
// SEGGER_RTT_printf(0, "USB ISTR_CTR\r\n");
/* servicing of the endpoint correct transfer interrupt */
//USB一次正确传输后,读取USB_ISTR的4bit判断数据传输方向,注意,这个必须放在 CTR_LP();否则会一直读取到的是端点0.
if(wIstr&0x10)
{
//数据从PC主机传输到USB模块
SEGGER_RTT_printf(0, "USB out ! EP_ID: %d\r\n",(wIstr&0x07));
}
else
{
//数据从USB模块传输到PC主机
SEGGER_RTT_printf(0, "USB in ! EP_ID: %d\r\n",(wIstr&0x07));
}
/* clear of the CTR flag into the sub */
CTR_LP();//调用正确传输中断服务程序
#ifdef CTR_CALLBACK
CTR_Callback();
#endif
}
#endif
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (IMR_MSK & ISTR_RESET)//复位中断标志
if (wIstr & ISTR_RESET & wInterrupt_Mask)
{
_SetISTR((uint16_t)CLR_RESET);//清除RESET中断标志
Device_Property.Reset();//调用复位函数
SEGGER_RTT_printf(0, "USB CLR_RESET\r\n");
#ifdef RESET_CALLBACK
RESET_Callback();
#endif
}
#endif
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (IMR_MSK & ISTR_DOVR)//分组缓冲区溢出中断标志
if (wIstr & ISTR_DOVR & wInterrupt_Mask)
{
_SetISTR((uint16_t)CLR_DOVR);
#ifdef DOVR_CALLBACK
DOVR_Callback();
#endif
}
#endif
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (IMR_MSK & ISTR_ERR)//错误中断标志
if (wIstr & ISTR_ERR & wInterrupt_Mask)
{
_SetISTR((uint16_t)CLR_ERR);
SEGGER_RTT_printf(0, "USB CLR_ERR\r\n");
#ifdef ERR_CALLBACK
ERR_Callback();
#endif
}
#endif
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (IMR_MSK & ISTR_WKUP)//唤醒中断标志
if (wIstr & ISTR_WKUP & wInterrupt_Mask)
{
_SetISTR((uint16_t)CLR_WKUP);
Resume(RESUME_EXTERNAL);
SEGGER_RTT_printf(0, "USB ISTR_WKUP\r\n");
#ifdef WKUP_CALLBACK
WKUP_Callback();
#endif
}
#endif
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (IMR_MSK & ISTR_SUSP)//挂起中断标志
if (wIstr & ISTR_SUSP & wInterrupt_Mask)
{
/* check if SUSPEND is possible */
if (fSuspendEnabled)//检查是否可以挂起
{
SEGGER_RTT_printf(0, "USB ISTR_SUSP ok\r\n");
Suspend();
}
else
{
/* if not possible then resume after xx ms */
Resume(RESUME_LATER);//如果不可以挂起,则在RESUME_LATER后恢复
SEGGER_RTT_printf(0, "USB ISTR_SUSP RESUME_LATER\r\n");
}
/* clear of the ISTR bit must be done after setting of CNTR_FSUSP */
_SetISTR((uint16_t)CLR_SUSP);//清除SUSP中断标志
#ifdef SUSP_CALLBACK
SUSP_Callback();
#endif
}
#endif
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (IMR_MSK & ISTR_ESOF)//期望帧首(ESOF)中断标志,当没有收到期望的SOF帧首时触发中断
if (wIstr & ISTR_ESOF & wInterrupt_Mask)
{
/* clear ESOF flag in ISTR */
_SetISTR((uint16_t)CLR_ESOF);//清除ESOF中断标志
SEGGER_RTT_printf(0, "USB CLR_ESOF\r\n");
if ((_GetFNR()&FNR_RXDP)!=0)
{
/* increment ESOF counter */
esof_counter ++;
/* test if we enter in ESOF more than 3 times with FSUSP =0 and RXDP =1=>> possible missing SUSP flag*/
if ((esof_counter >3)&&((_GetCNTR()&CNTR_FSUSP)==0))
{
/* this a sequence to apply a force RESET*/
/*Store CNTR value */
wCNTR = _GetCNTR();
/*Store endpoints registers status */
for (i=0;i<8;i++) EP[i] = _GetENDPOINT(i);
/*apply FRES */
wCNTR|=CNTR_FRES;
_SetCNTR(wCNTR);
/*clear FRES*/
wCNTR&=~CNTR_FRES;
_SetCNTR(wCNTR);
/*poll for RESET flag in ISTR*/
while((_GetISTR()&ISTR_RESET) == 0);
/* clear RESET flag in ISTR */
_SetISTR((uint16_t)CLR_RESET);
/*restore Enpoints*/
for (i=0;i<8;i++)
_SetENDPOINT(i, EP[i]);
esof_counter = 0;
}
}
else
{
esof_counter = 0;
}
/* resume handling timing is made with ESOFs 恢复ESOF的处理时间*/
Resume(RESUME_ESOF); /* request without change of the machine state */
#ifdef ESOF_CALLBACK
ESOF_Callback();
#endif
}
#endif
} /* USB_Istr */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
二、宏观介绍
这个文件比较简单,就是读取USB_ISTR的相应位,判断发生了哪种中断,对于每个中断的优先级有if语句的先后顺序来决定,然后每个中断调用相应的回调函数。
每个中断的开启与关闭有USB_CNTR的相应位来决定,这里在usb_conf.h中进行配置
总共会有两处地方会打开这个所有配置的中断:
a、USB从挂起状态回复
void Resume_Init(void)
{
uint16_t wCNTR;
/* ------------------ ONLY WITH BUS-POWERED DEVICES ---------------------- */
/* restart the clocks */
/* ... */
/* CNTR_LPMODE = 0 */
wCNTR = _GetCNTR();
wCNTR &= (~CNTR_LPMODE);
_SetCNTR(wCNTR);
/* restore full power */
/* ... on connected devices */
Leave_LowPowerMode();
/* reset FSUSP bit */
_SetCNTR(IMR_MSK);
/* reverse suspend preparation */
/* ... */
}
b、是在USB 初始化的时候
调用关系pProperty->Init(Device_Property->Init) ===》Virtual_Com_Port_init ===》USB_SIL_Init
/*******************************************************************************
* Function Name : USB_SIL_Init
* Description : Initialize the USB Device IP and the Endpoint 0.
* Input : None.
* Output : None.
* Return : Status.
*******************************************************************************/
uint32_t USB_SIL_Init(void)
{
/* USB interrupts initialization */
/* clear pending interrupts */
_SetISTR(0);
wInterrupt_Mask = IMR_MSK;
/* set interrupts mask */
_SetCNTR(wInterrupt_Mask);
return 0;
}
如下可以看到在PowerOn()中开启了RESET、SUS、WKUP中断
调用关系pProperty->Init(Device_Property->Init) ===》Virtual_Com_Port_init ===》PowerOn
RESULT PowerOn(void)
{
uint16_t wRegVal;
/*** cable plugged-in ? ***/
USB_Cable_Config(ENABLE);
/*** CNTR_PWDN = 0 ***/
wRegVal = CNTR_FRES;
_SetCNTR(wRegVal);
/*** CNTR_FRES = 0 ***/
wInterrupt_Mask = 0;
_SetCNTR(wInterrupt_Mask);
/*** Clear pending interrupts ***/
_SetISTR(0);
/*** Set interrupt mask ***/
wInterrupt_Mask = CNTR_RESETM | CNTR_SUSPM | CNTR_WKUPM;
_SetCNTR(wInterrupt_Mask);
return USB_SUCCESS;
}
三、细节详解
1、SOF中断
主机每1ms同步设备一次,这里用每5ms来查询一次端点1是否有数据输入。
#if (IMR_MSK & ISTR_SOF)//帧首中断标志
if (wIstr & ISTR_SOF & wInterrupt_Mask)
{
_SetISTR((uint16_t)CLR_SOF);//清除SOF中断标志
bIntPackSOF++;//统计共接收到多少SOF
#ifdef SOF_CALLBACK
SOF_Callback();
#endif
}
void SOF_Callback(void)
{
static uint32_t FrameCount = 0;
if(bDeviceState == CONFIGURED)
{
//每5ms循环查询一次VCOMPORT_IN_FRAME_INTERVAL=5
if (FrameCount++ == VCOMPORT_IN_FRAME_INTERVAL)
{
/* Reset the frame counter */
FrameCount = 0;
/* Check the data to be sent through IN pipe */
Handle_USBAsynchXfer();
}
}
}
2、CTR正确传输中断
#if (IMR_MSK & ISTR_CTR)//正确传输中断CTR标志
if (wIstr & ISTR_CTR & wInterrupt_Mask)
{
// SEGGER_RTT_printf(0, "USB ISTR_CTR\r\n");
/* servicing of the endpoint correct transfer interrupt */
//USB一次正确传输后,读取USB_ISTR的4bit判断数据传输方向,注意,这个必须放在 CTR_LP();否则会一直读取到的是端点0.
if(wIstr&0x10)
{
//数据从PC主机传输到USB模块
SEGGER_RTT_printf(0, "USB out ! EP_ID: %d\r\n",(wIstr&0x07));
}
else
{
//数据从USB模块传输到PC主机
SEGGER_RTT_printf(0, "USB in ! EP_ID: %d\r\n",(wIstr&0x07));
}
/* clear of the CTR flag into the sub */
CTR_LP();//调用正确传输中断服务程序
#ifdef CTR_CALLBACK
CTR_Callback();
#endif
}
#endif
端点正确完成一次数据传输后会触发这个中断,可以读取数据的传输方向,和具体是哪个端点,然后调用CTR_LP()函数, CTR_Callback()是没有调用的,下面详细介绍一下CTR_LP这个函数:
void CTR_LP(void)
{
__IO uint16_t wEPVal = 0;
/* stay in loop while pending interrupts */
while (((wIstr = _GetISTR()) & ISTR_CTR) != 0)
{
/* extract highest priority endpoint number */
EPindex = (uint8_t)(wIstr & ISTR_EP_ID);
if (EPindex == 0)
{
/* Decode and service control endpoint interrupt */
/* calling related service routine */
/* (Setup0_Process, In0_Process, Out0_Process) */
/* save RX & TX status */
/* and set both to NAK */
SaveRState = _GetENDPOINT(ENDP0);
SaveTState = SaveRState & EPTX_STAT;
SaveRState &= EPRX_STAT;
_SetEPRxTxStatus(ENDP0,EP_RX_NAK,EP_TX_NAK);
/* DIR bit = origin of the interrupt */
if ((wIstr & ISTR_DIR) == 0)
{
/* DIR = 0 */
/* DIR = 0 => IN int */
/* DIR = 0 implies that (EP_CTR_TX = 1) always */
_ClearEP_CTR_TX(ENDP0);
In0_Process();
/* before terminate set Tx & Rx status */
_SetEPRxTxStatus(ENDP0,SaveRState,SaveTState);
return;
}
else
{
/* DIR = 1 */
/* DIR = 1 & CTR_RX => SETUP or OUT int */
/* DIR = 1 & (CTR_TX | CTR_RX) => 2 int pending */
wEPVal = _GetENDPOINT(ENDP0);
if ((wEPVal &EP_SETUP) != 0)
{
_ClearEP_CTR_RX(ENDP0); /* SETUP bit kept frozen while CTR_RX = 1 */
Setup0_Process();
/* before terminate set Tx & Rx status */
_SetEPRxTxStatus(ENDP0,SaveRState,SaveTState);
return;
}
else if ((wEPVal & EP_CTR_RX) != 0)
{
_ClearEP_CTR_RX(ENDP0);
Out0_Process();
/* before terminate set Tx & Rx status */
_SetEPRxTxStatus(ENDP0,SaveRState,SaveTState);
return;
}
}
}/* if(EPindex == 0) */
else
{
/* Decode and service non control endpoints interrupt */
/* process related endpoint register */
wEPVal = _GetENDPOINT(EPindex);
if ((wEPVal & EP_CTR_RX) != 0)
{
/* clear int flag */
_ClearEP_CTR_RX(EPindex);
/* call OUT service function */
(*pEpInt_OUT[EPindex-1])();
} /* if((wEPVal & EP_CTR_RX) */
if ((wEPVal & EP_CTR_TX) != 0)
{
/* clear int flag */
_ClearEP_CTR_TX(EPindex);
/* call IN service function */
(*pEpInt_IN[EPindex-1])();
} /* if((wEPVal & EP_CTR_TX) != 0) */
}/* if(EPindex == 0) else */
}/* while(...) */
}
判断是哪个端点传输完成
if 端点0
if device—>pc
In0_Process();
else
if setup包
Setup0_Process();
else
Out0_Process();
else 非控制端点
if 接收主机数据
(*pEpInt_OUT[EPindex-1])();
if 发数据到主机
(*pEpInt_IN[EPindex-1])();
3、RESET复位中断
Device_Property.Reset()指向Virtual_Com_Port_Reset
#if (IMR_MSK & ISTR_RESET)//复位中断标志
if (wIstr & ISTR_RESET & wInterrupt_Mask)
{
_SetISTR((uint16_t)CLR_RESET);//清除RESET中断标志
Device_Property.Reset();//调用复位函数
SEGGER_RTT_printf(0, "USB CLR_RESET\r\n");
#ifdef RESET_CALLBACK
RESET_Callback();
#endif
}
#endif
void Virtual_Com_Port_Reset(void)
{
/* Set Virtual_Com_Port DEVICE as not configured */
pInformation->Current_Configuration = 0;
/* Current Feature initialization */
pInformation->Current_Feature = Virtual_Com_Port_ConfigDescriptor[7];
/* Set Virtual_Com_Port DEVICE with the default Interface*/
pInformation->Current_Interface = 0;
SetBTABLE(BTABLE_ADDRESS);
/* Initialize Endpoint 0 */
SetEPType(ENDP0, EP_CONTROL);
SetEPTxStatus(ENDP0, EP_TX_STALL);
SetEPRxAddr(ENDP0, ENDP0_RXADDR);
SetEPTxAddr(ENDP0, ENDP0_TXADDR);
Clear_Status_Out(ENDP0);
SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);
SetEPRxValid(ENDP0);
/* Initialize Endpoint 1 */
SetEPType(ENDP1, EP_BULK);
SetEPTxAddr(ENDP1, ENDP1_TXADDR);
SetEPTxStatus(ENDP1, EP_TX_NAK);
SetEPRxStatus(ENDP1, EP_RX_DIS);
/* Initialize Endpoint 2 */
SetEPType(ENDP2, EP_INTERRUPT);
SetEPTxAddr(ENDP2, ENDP2_TXADDR);
SetEPRxStatus(ENDP2, EP_RX_DIS);
SetEPTxStatus(ENDP2, EP_TX_NAK);
/* Initialize Endpoint 3 */
SetEPType(ENDP3, EP_BULK);
SetEPRxAddr(ENDP3, ENDP3_RXADDR);
SetEPRxCount(ENDP3, VIRTUAL_COM_PORT_DATA_SIZE);
SetEPRxStatus(ENDP3, EP_RX_VALID);
SetEPTxStatus(ENDP3, EP_TX_DIS);
/* Set this device to response on default address */
SetDeviceAddress(0);
bDeviceState = ATTACHED;
}
4、ERR错误中断
#if (IMR_MSK & ISTR_ERR)//错误中断标志
if (wIstr & ISTR_ERR & wInterrupt_Mask)
{
_SetISTR((uint16_t)CLR_ERR);
SEGGER_RTT_printf(0, "USB CLR_ERR\r\n");
#ifdef ERR_CALLBACK
ERR_Callback();
#endif
}
#endif
5、WKUP唤醒中断
#if (IMR_MSK & ISTR_WKUP)//唤醒中断标志
if (wIstr & ISTR_WKUP & wInterrupt_Mask)
{
_SetISTR((uint16_t)CLR_WKUP);
Resume(RESUME_EXTERNAL);
SEGGER_RTT_printf(0, "USB ISTR_WKUP\r\n");
#ifdef WKUP_CALLBACK
WKUP_Callback();
#endif
}
#endif
6、SUSP挂起中断
#if (IMR_MSK & ISTR_SUSP)//挂起中断标志
if (wIstr & ISTR_SUSP & wInterrupt_Mask)
{
/* check if SUSPEND is possible */
if (fSuspendEnabled)//检查是否可以挂起
{
SEGGER_RTT_printf(0, "USB ISTR_SUSP ok\r\n");
Suspend();
}
else
{
/* if not possible then resume after xx ms */
Resume(RESUME_LATER);//如果不可以挂起,则在RESUME_LATER后恢复
SEGGER_RTT_printf(0, "USB ISTR_SUSP RESUME_LATER\r\n");
}
/* clear of the ISTR bit must be done after setting of CNTR_FSUSP */
_SetISTR((uint16_t)CLR_SUSP);//清除SUSP中断标志
#ifdef SUSP_CALLBACK
SUSP_Callback();
#endif
}
#endif
7、ESOF期望帧首中断
#if (IMR_MSK & ISTR_ESOF)//期望帧首(ESOF)中断标志,当没有收到期望的SOF帧首时触发中断
if (wIstr & ISTR_ESOF & wInterrupt_Mask)
{
/* clear ESOF flag in ISTR */
_SetISTR((uint16_t)CLR_ESOF);//清除ESOF中断标志
SEGGER_RTT_printf(0, "USB CLR_ESOF\r\n");
if ((_GetFNR()&FNR_RXDP)!=0)
{
/* increment ESOF counter */
esof_counter ++;
/* test if we enter in ESOF more than 3 times with FSUSP =0 and RXDP =1=>> possible missing SUSP flag*/
if ((esof_counter >3)&&((_GetCNTR()&CNTR_FSUSP)==0))
{
/* this a sequence to apply a force RESET*/
/*Store CNTR value */
wCNTR = _GetCNTR();
/*Store endpoints registers status */
for (i=0;i<8;i++) EP[i] = _GetENDPOINT(i);
/*apply FRES */
wCNTR|=CNTR_FRES;
_SetCNTR(wCNTR);
/*clear FRES*/
wCNTR&=~CNTR_FRES;
_SetCNTR(wCNTR);
/*poll for RESET flag in ISTR*/
while((_GetISTR()&ISTR_RESET) == 0);
/* clear RESET flag in ISTR */
_SetISTR((uint16_t)CLR_RESET);
/*restore Enpoints*/
for (i=0;i<8;i++)
_SetENDPOINT(i, EP[i]);
esof_counter = 0;
}
}
else
{
esof_counter = 0;
}
/* resume handling timing is made with ESOFs 恢复ESOF的处理时间*/
Resume(RESUME_ESOF); /* request without change of the machine state */
#ifdef ESOF_CALLBACK
ESOF_Callback();
#endif
}
#endif