📄 usbd_otghs.c
字号:
// Activates a remote wakeup
pInterface->OTGHS_DEVCTRL |= AT91C_OTGHS_RMWKUP;
}
//------------------------------------------------------------------------------
// \brief Handles attachment or detachment from the USB when the VBus power
// line status changes.
// \param pUsb Pointer to a S_usb instance
// \return true if VBus is present, false otherwise
// \see S_usb
//------------------------------------------------------------------------------
static bool OTGHS_Attach(const S_usb *pUsb)
{
AT91PS_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
TRACE_DEBUG_L("Attach(");
// Check if VBus is present
if (!ISSET(USB_GetState(pUsb), USB_STATE_POWERED)
&& BRD_IsVBusConnected(pInterface)) {
// Powered state:
// MCK + UDPCK must be on
// Pull-Up must be connected
// Transceiver must be disabled
// Invoke the Resume callback
USB_ResumeCallback(pUsb);
OTGHS_EnableMCK(pUsb);
OTGHS_EnableOTGHSCK(pUsb);
// Enable the transceiver
OTGHS_EnableTransceiver(pUsb);
// Reconnect the pull-up if needed
if (ISSET(*(pUsb->pState), USB_STATE_SHOULD_RECONNECT)) {
USB_Connect(pUsb);
CLEAR(*(pUsb->pState), USB_STATE_SHOULD_RECONNECT);
}
// Clear the Suspend and Resume interrupts
pInterface->OTGHS_DEVICR = \
AT91C_OTGHS_WAKEUP | AT91C_OTGHS_EORSM | AT91C_OTGHS_SUSP;
// Enable interrupt
pInterface->OTGHS_DEVIER = AT91C_OTGHS_EORST | AT91C_OTGHS_WAKEUP | AT91C_OTGHS_EORSM;
// The device is in Powered state
SET(*(pUsb->pState), USB_STATE_POWERED);
}
else if (ISSET(USB_GetState(pUsb), USB_STATE_POWERED)
&& !BRD_IsVBusConnected(pInterface)) {
// Attached state:
// MCK + UDPCK off
// Pull-Up must be disconnected
// Transceiver must be disabled
// Warning: MCK must be enabled to be able to write in UDP registers
// It may have been disabled by the Suspend interrupt, so re-enable it
OTGHS_EnableMCK(pUsb);
// Disable interrupts
pInterface->OTGHS_DEVIDR &= ~(AT91C_OTGHS_WAKEUP | AT91C_OTGHS_EORSM
| AT91C_OTGHS_SUSP | AT91C_OTGHS_SOF);
OTGHS_DisableEndpoints(pUsb);
// Disconnect the pull-up if needed
if (ISSET(USB_GetState(pUsb), USB_STATE_DEFAULT)) {
USB_Disconnect(pUsb);
SET(*(pUsb->pState), USB_STATE_SHOULD_RECONNECT);
}
OTGHS_DisableTransceiver(pUsb);
OTGHS_DisableMCK(pUsb);
OTGHS_DisableOTGHSCK(pUsb);
// The device leaves the all states except Attached
CLEAR(*(pUsb->pState), USB_STATE_POWERED | USB_STATE_DEFAULT
| USB_STATE_ADDRESS | USB_STATE_CONFIGURED | USB_STATE_SUSPENDED);
// Invoke the Suspend callback
USB_SuspendCallback(pUsb);
}
TRACE_DEBUG_L("%d) ", ISSET(USB_GetState(pUsb), USB_STATE_POWERED));
return ISSET(USB_GetState(pUsb), USB_STATE_POWERED);
}
//------------------------------------------------------------------------------
// \brief Sets the device address
//
// This function directly accesses the S_usb_request instance located
// in the S_usb structure to extract its new address.
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
static void OTGHS_SetAddress(S_usb const *pUsb)
{
unsigned short wAddress = USB_GetSetup(pUsb)->wValue;
AT91PS_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
TRACE_DEBUG_L("SetAddr(%d) ", wAddress);
// Set address
pInterface->OTGHS_DEVCTRL = wAddress & AT91C_OTGHS_UADD;
pInterface->OTGHS_DEVCTRL |= AT91C_OTGHS_ADDEN;
}
//------------------------------------------------------------------------------
// \brief Changes the device state from Address to Configured, or from
// Configured to Address.
//
// This method directly access the last received SETUP packet to
// decide on what to do.
// \see S_usb
//------------------------------------------------------------------------------
static void OTGHS_SetConfiguration(S_usb const *pUsb)
{
unsigned short wValue = USB_GetSetup(pUsb)->wValue;
TRACE_DEBUG_L("SetCfg() ");
// Check the request
if (wValue != 0) {
// Enter Configured state
SET(*(pUsb->pState), USB_STATE_CONFIGURED);
}
else {
// Go back to Address state
CLEAR(*(pUsb->pState), USB_STATE_CONFIGURED);
// Abort all transfers
OTGHS_DisableEndpoints(pUsb);
}
}
//------------------------------------------------------------------------------
// \brief Enables the pull-up on the D+ line to connect the device to the USB.
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
static void OTGHS_Connect(const S_usb *pUsb)
{
#if defined(INTERNAL_PULLUP)
CLEAR(OTGHS_GetDriverInterface(pUsb)->OTGHS_DEVCTRL, AT91C_OTGHS_DETACH);
#elif defined(INTERNAL_PULLUP_MATRIX)
TRACE_DEBUG_L("PUON 1\n\r");
AT91C_BASE_MATRIX->MATRIX_USBPCR |= AT91C_MATRIX_USBPCR_PUON;
#else
BRD_ConnectPullUp(UDP_GetDriverInterface(pUsb));
#endif
}
//------------------------------------------------------------------------------
// \brief Disables the pull-up on the D+ line to disconnect the device from
// the bus.
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
static void OTGHS_Disconnect(const S_usb *pUsb)
{
#if defined(INTERNAL_PULLUP)
SET(OTGHS_GetDriverInterface(pUsb)->OTGHS_DEVCTRL, AT91C_OTGHS_DETACH);
#elif defined(INTERNAL_PULLUP_MATRIX)
TRACE_DEBUG_L("PUON 0\n\r");
AT91C_BASE_MATRIX->MATRIX_USBPCR &= ~AT91C_MATRIX_USBPCR_PUON;
#else
BRD_DisconnectPullUp(UDP_GetDriverInterface(pUsb));
#endif
// Device leaves the Default state
CLEAR(*(pUsb->pState), USB_STATE_DEFAULT);
}
//------------------------------------------------------------------------------
// \brief Certification test for High Speed device.
// \param pUsb Pointer to a S_usb instance
// \param bIndex char for the test choice
// \see S_usb
//------------------------------------------------------------------------------
static void OTGHS_Test(const S_usb *pUsb, unsigned char bIndex)
{
AT91PS_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
pInterface->OTGHS_DEVIDR &= ~AT91C_OTGHS_SUSP;
pInterface->OTGHS_DEVCTRL |= AT91C_OTGHS_SPDCONF_HS; // remove suspend ?
switch( bIndex ) {
case TEST_PACKET:
TRACE_DEBUG_M("TEST_PACKET ");
pInterface->OTGHS_DEVCTRL |= AT91C_OTGHS_TSTPCKT;
break;
case TEST_J:
TRACE_DEBUG_M("TEST_J ");
pInterface->OTGHS_DEVCTRL |= AT91C_OTGHS_TSTJ;
break;
case TEST_K:
TRACE_DEBUG_M("TEST_K ");
pInterface->OTGHS_DEVCTRL |= AT91C_OTGHS_TSTK;
break;
case TEST_SEO_NAK:
TRACE_DEBUG_M("TEST_SEO_NAK ");
pInterface->OTGHS_DEVIDR = 0xFFFFFFFF;
break;
case TEST_SEND_ZLP:
pInterface->OTGHS_DEVEPTCCR[0] = AT91C_OTGHS_TXINI;
TRACE_DEBUG_M("SEND_ZLP ");
break;
TRACE_DEBUG_M("\n\r");
}
}
//------------------------------------------------------------------------------
// \brief Certification test for High Speed device.
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
static bool OTGHS_IsHighSpeed(const S_usb *pUsb)
{
AT91PS_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
bool status = false;
if(AT91C_OTGHS_SPEED_SR_HS == (pInterface->OTGHS_SR & (0x03<<12))) {
// High Speed
status = true;
}
return status;
}
//------------------------------------------------------------------------------
// \brief Initializes the specified USB driver
//
// This function initializes the current FIFO bank of endpoints,
// configures the pull-up and VBus lines, disconnects the pull-up and
// then trigger the Init callback.
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
static void OTGHS_Init(const S_usb *pUsb)
{
AT91PS_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
unsigned char i;
TRACE_DEBUG_L("Init()\n\r");
// Enable USB macro
SET(OTGHS_GetDriverInterface(pUsb)->OTGHS_CTRL, AT91C_OTGHS_USBECTRL);
pInterface->OTGHS_DEVCTRL &=~ AT91C_OTGHS_DETACH; // detach
//// Force FS (for debug or test)
// pDriver->OTGHS_DEVCTRL |= AT91C_OTGHS_SPDCONF_FS;
pInterface->OTGHS_DEVCTRL &= ~AT91C_OTGHS_SPDCONF_FS; // Normal mode
pInterface->OTGHS_DEVCTRL &= ~( AT91C_OTGHS_LS | AT91C_OTGHS_TSTJ
| AT91C_OTGHS_TSTK | AT91C_OTGHS_TSTPCKT
| AT91C_OTGHS_OPMODE2 ); // Normal mode
// With OR without DMA !!!
// Initialization of DMA
for( i=1; i<=((AT91C_BASE_OTGHS->OTGHS_IPFEATURES & AT91C_OTGHS_DMA_CHANNEL_NBR)>>4); i++ ) {
// RESET endpoint canal DMA:
// DMA stop channel command
AT91C_BASE_OTGHS->OTGHS_DEVDMA[i].OTGHS_DEVDMACONTROL = 0; // STOP command
// Disable endpoint
AT91C_BASE_OTGHS->OTGHS_DEVEPTCDR[i] = 0XFFFFFFFF;
// Reset endpoint config
AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[i] = 0;
// Reset DMA channel (Buff count and Control field)
AT91C_BASE_OTGHS->OTGHS_DEVDMA[i].OTGHS_DEVDMACONTROL = 0x02; // NON STOP command
// Reset DMA channel 0 (STOP)
AT91C_BASE_OTGHS->OTGHS_DEVDMA[i].OTGHS_DEVDMACONTROL = 0; // STOP command
// Clear DMA channel status (read the register for clear it)
AT91C_BASE_OTGHS->OTGHS_DEVDMA[i].OTGHS_DEVDMASTATUS = AT91C_BASE_OTGHS->OTGHS_DEVDMA[i].OTGHS_DEVDMASTATUS;
}
// Enable clock OTG pad
pInterface->OTGHS_CTRL &= ~AT91C_OTGHS_FRZCLKCTRL;
// Clear General IT
pInterface->OTGHS_SCR = 0x01FF;
// Clear OTG Device IT
pInterface->OTGHS_DEVICR = 0xFF;
// Clear OTG Host IT
pInterface->OTGHS_HSTICR = 0x7F;
// Reset all Endpoints Fifos
pInterface->OTGHS_DEVEPT |= (0x7F<<16);
pInterface->OTGHS_DEVEPT &= ~(0x7F<<16);
// Disable all endpoints
pInterface->OTGHS_DEVEPT &= ~0x7F;
// Bypass UTMI problems // jcb to be removed with new version of UTMI
// pInterface->OTGHS_TSTA2 = (1<<6)|(1<<7)|(1<<8);
// pInterface->OTGHS_TSTA2 = (1<<8);
pInterface->OTGHS_TSTA2 = 0;
// External pull-up on D+
// Configure
BRD_ConfigurePullUp(pInterface);
// Detach
OTGHS_Disconnect(pUsb);
// Device is in the Attached state
*(pUsb->pState) = USB_STATE_ATTACHED;
// Disable the UDP transceiver and interrupts
OTGHS_EnableMCK(pUsb);
SET(pInterface->OTGHS_DEVIER, AT91C_OTGHS_EORSM);
OTGHS_DisableMCK(pUsb);
OTGHS_Disconnect(pUsb);
// Test ID
if( 0 != (pInterface->OTGHS_SR & AT91C_OTGHS_ID) ) {
TRACE_INFO("ID=1: PERIPHERAL\n\r");
}
else {
TRACE_INFO("ID=0: HOST\n\r");
}
// Test VBUS
if( 0 != (pInterface->OTGHS_SR & AT91C_OTGHS_VBUSSR) ) {
TRACE_INFO("VBUS = 1\n\r");
}
else {
TRACE_INFO("VBUS = 0\n\r");
}
// Test SPEED
if(AT91C_OTGHS_SPEED_SR_HS == (pInterface->OTGHS_SR & (0x03<<12))) {
TRACE_INFO("HIGH SPEED\n\r");
}
else if(AT91C_OTGHS_SPEED_SR_LS == (pInterface->OTGHS_SR & (0x03<<12))) {
TRACE_INFO("LOW SPEED\n\r");
}
else {
TRACE_INFO("FULL SPEED\n\r");
}
// Configure interrupts
USB_InitCallback(pUsb);
pInterface->OTGHS_CTRL |= AT91C_OTGHS_VBUSTI;
}
//------------------------------------------------------------------------------
// Global variables
//------------------------------------------------------------------------------
// \brief Low-level driver methods to use with the OTGHS USB controller
// \see S_driver_methods
const S_driver_methods sOTGHSMethods = {
OTGHS_Init,
OTGHS_Write,
OTGHS_Read,
OTGHS_Stall,
OTGHS_Halt,
OTGHS_RemoteWakeUp,
OTGHS_ConfigureEndpoint,
OTGHS_Attach,
OTGHS_SetAddress,
OTGHS_SetConfiguration,
OTGHS_Handler,
OTGHS_Connect,
OTGHS_Disconnect,
OTGHS_Test,
OTGHS_IsHighSpeed
};
// \brief Default driver when an UDP controller is present on a chip
const S_usb_driver sDefaultDriver = {
AT91C_BASE_OTGHS,
AT91C_BASE_OTGHS_EPTFIFO,
0,
AT91C_ID_OTGHS,
AT91C_PMC_OTG,
&sOTGHSMethods
};
#endif //#ifdef CHIP_OTGHS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -