⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usbd_otghs.c

📁 Atmel的AT91SAM9263芯片的usb存储源程序
💻 C
📖 第 1 页 / 共 4 页
字号:

    // 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 + -