现在的位置: 首页 > 综合 > 正文

usbhw.c

2013年08月26日 ⁄ 综合 ⁄ 共 11867字 ⁄ 字号 评论关闭

/*----------------------------------------------------------------------------
 *      U S B  -  K e r n e l
 *----------------------------------------------------------------------------
 * Name:    usbhw.c
 * Purpose: USB Hardware Layer Module for NXP's LPC17xx MCU
 * Version: V1.20
 * Copyright (c) 2009 Keil - An ARM Company. All rights reserved.
 *----------------------------------------------------------------------------
 * History:
 *          V1.20 Added USB_ClearEPBuf
 *          V1.00 Initial Version
 *----------------------------------------------------------------------------*/
#ifdef __BUILD_WITH_EXAMPLE__
#include "lpc177x_8x_libcfg.h"
#else
#include "lpc177x_8x_libcfg_default.h"
#endif /* __BUILD_WITH_EXAMPLE__ */

#ifdef _USB_DEV_MASS_STORAGE
#include "LPC177x_8x.h"                        /* LPC177x_8x.h definitions */
#include "usb.h"
#include "usbcfg.h"
#include "usbreg.h"
#include "usbhw.h"
#include "usbcore.h"
#include "usbuser.h"
#include "lpc_types.h"
#include "bsp.h"

/** @addtogroup USBDEV_MscUsbHw
 * @{
 */

#define EP_MSK_CTRL 0x0001      /* Control Endpoint Logical Address Mask */
#define EP_MSK_BULK 0xC924      /* Bulk Endpoint Logical Address Mask */
#define EP_MSK_INT  0x4492      /* Interrupt Endpoint Logical Address Mask */
#define EP_MSK_ISO  0x1248      /* Isochronous Endpoint Logical Address Mask */

#if USB_DMA
#endif

//获取端点物理地址
//Parameters:   EPNum: Endpoint Number
//                  EPNum.0..3: Address
//                  EPNum.7:    Dir
//Return Value: Endpoint Physical   Address
uint32_t EPAdr (uint32_t EPNum)
{
    uint32_t val;
    val = (EPNum & 0x0F) << 1;
    if (EPNum & 0x80)
    {
        val += 1;
    }
    return (val);
}

//写入命令
void WrCmd (uint32_t cmd)
{
    LPC_USB->DevIntClr = CCEMTY_INT;
    LPC_USB->CmdCode = cmd;
    while ((LPC_USB->DevIntSt & CCEMTY_INT) == 0);
}

//写入命令 数据
void WrCmdDat (uint32_t cmd, uint32_t val)
{
    LPC_USB->DevIntClr = CCEMTY_INT;
    LPC_USB->CmdCode = cmd;
    while ((LPC_USB->DevIntSt & CCEMTY_INT) == 0);
   
    LPC_USB->DevIntClr = CCEMTY_INT;
    LPC_USB->CmdCode = val;
    while ((LPC_USB->DevIntSt & CCEMTY_INT) == 0);
}

//Write Command to Endpoint
//Parameters:   cmd:     Command
//       val:   Data
void WrCmdEP (uint32_t EPNum, uint32_t cmd)
{
    LPC_USB->DevIntClr = CCEMTY_INT;
    LPC_USB->CmdCode = CMD_SEL_EP(EPAdr(EPNum));
    while ((LPC_USB->DevIntSt & CCEMTY_INT) == 0);
    LPC_USB->DevIntClr = CCEMTY_INT;
    LPC_USB->CmdCode = cmd;
    while ((LPC_USB->DevIntSt & CCEMTY_INT) == 0);
}

//Read Command Data
//Parameters:      cmd:   Command
uint32_t RdCmdDat (uint32_t cmd)
{
    LPC_USB->DevIntClr = CCEMTY_INT | CDFULL_INT;
    LPC_USB->CmdCode = cmd;
    while ((LPC_USB->DevIntSt & CDFULL_INT) == 0);
    return (LPC_USB->CmdData);
}

//  USB Initialize Function
//   Called by the User to initialize USB
void USB_Init (void) {
    #if 0
    #else
    LPC_IOCON->P0_31 &= ~0x07;    // P0.31 D2+, D2- is dedicated pin.
    LPC_IOCON->P0_31 |= 0x1;
   
    LPC_IOCON->P0_14  &= ~0x07;    // USB_SoftConnect
    LPC_IOCON->P0_14  |= 0x3;
   
    LPC_IOCON->P1_30  &= ~0x07;   // USB_VBUS
    LPC_IOCON->P1_30  |= 0x2;
   
    LPC_IOCON->P0_13  &= ~0x07;   // USB_LED
    LPC_IOCON->P0_13  |= 0x1;
   
    LPC_SC->PCONP |= (1UL<<31);   //使能设备控制器
   
    LPC_USB->USBClkCtrl = 0x1A;   //设备 端口选择 AHB时钟使能

    //等待设置生效
    while ((LPC_USB->USBClkSt & 0x1A) != 0x1A);
   
    //使能 USBRxData 寄存器从 OUT 端点缓冲区中读取数,读完后硬件清0
    //使能 USBTxData 寄存器将数据写入 IN 端点缓冲区,写完后硬件清0
    LPC_USB->StCtrl = 0x3;
    #endif

    NVIC_EnableIRQ(USB_IRQn);               /* enable USB interrupt */

    #if (_CURR_USING_BRD == _IAR_OLIMEX_BOARD)
        LPC_USB->I2C_CTL |= (1<<8);
        while(LPC_USB->I2C_CTL & (1<<8));
    #endif

    USB_Reset();
    USB_SetAddress(0);
}

//  USB Connect Function
//   Called by the User to Connect/Disconnect USB
//    Parameters:      con:   Connect/Disconnect
//    Return Value:    None
void USB_Connect (uint32_t con)
{
    WrCmdDat(CMD_SET_DEV_STAT, DAT_WR_BYTE(con ? DEV_CON : 0));
    #if (_CURR_USING_BRD == _IAR_OLIMEX_BOARD)
    LPC_USB->I2C_STS |= (1<<0);
    LPC_USB->I2C_TX = 0x15A;                // Send ISP1301 address, R/W=0
    LPC_USB->I2C_TX = 0x006;                // Send OTG Control (Clear/Set) register address
    LPC_USB->I2C_TX = 0x201;                // Set DP_PULLUP bit, send STOP condition
    while(!LPC_USB->I2C_STS &(1<<0));
    #endif
}

//USB   Reset Function
//Called    automatically on USB Reset
void USB_Reset (void)
{
    #if USB_DMA
    #endif

    LPC_USB->EpInd = 0;
    //最大包长度值
    LPC_USB->MaxPSize = USB_MAX_PACKET0;
    LPC_USB->EpInd = 1;
    LPC_USB->MaxPSize = USB_MAX_PACKET0;
    while ((LPC_USB->DevIntSt & EP_RLZED_INT) == 0);
   
    //端点中断
    LPC_USB->EpIntClr  = 0xFFFFFFFF;
    LPC_USB->EpIntEn   = 0xFFFFFFFF ^ USB_DMA_EP;
   
    //设备中断使能
    LPC_USB->DevIntClr = 0xFFFFFFFF;
    LPC_USB->DevIntEn  = DEV_STAT_INT | EP_SLOW_INT |
                 (USB_SOF_EVENT   ? FRAME_INT : 0) |
                 (USB_ERROR_EVENT ? ERR_INT   : 0);

    #if USB_DMA
    #endif
}

//Called automatically on USB Suspend
void USB_Suspend (void)
{
}

//   Called automatically on USB Resume
void USB_Resume (void)
{
}

//Called automatically on USB Remote Wakeup
void USB_WakeUp (void)
{
    if (USB_DeviceStatus & USB_GETSTATUS_REMOTE_WAKEUP)
    {
        WrCmdDat(CMD_SET_DEV_STAT, DAT_WR_BYTE(DEV_CON));
    }
}

//  USB Remote Wakeup Configuration Function
//    Parameters:      cfg:   Enable/Disable
void USB_WakeUpCfg (uint32_t cfg)
{
}

//    Parameters:      adr:   USB Address
void USB_SetAddress (uint32_t adr)
{
    WrCmdDat(CMD_SET_ADDR, DAT_WR_BYTE(DEV_EN | adr)); /* Don't wait for next */
    WrCmdDat(CMD_SET_ADDR, DAT_WR_BYTE(DEV_EN | adr)); /*  Setup Status Phase */
}

//  USB Configure Function
//    Parameters:      cfg:   Configure/Deconfigure
void USB_Configure (uint32_t cfg)
{
    WrCmdDat(CMD_CFG_DEV, DAT_WR_BYTE(cfg ? CONF_DVICE : 0));
    LPC_USB->ReEp = 0x00000003;
    while ((LPC_USB->DevIntSt & EP_RLZED_INT) == 0);
    LPC_USB->DevIntClr = EP_RLZED_INT;
}

//  Configure USB Endpoint according to Descriptor
//  Parameters:      pEPD:  Pointer to Endpoint Descriptor
void USB_ConfigEP (USB_ENDPOINT_DESCRIPTOR *pEPD)
{
    uint32_t num;
    num = EPAdr(pEPD->bEndpointAddress);
    LPC_USB->ReEp |= (1 << num);
    LPC_USB->EpInd = num;
    LPC_USB->MaxPSize = pEPD->wMaxPacketSize;
    while ((LPC_USB->DevIntSt & EP_RLZED_INT) == 0);
    LPC_USB->DevIntClr = EP_RLZED_INT;
}

//  Set Direction for USB Control Endpoint
//    Parameters:      dir:   Out (dir == 0), In (dir <> 0)
void USB_DirCtrlEP (uint32_t dir)
{
}

//  Enable USB Endpoint
//    Parameters:        EPNum: Endpoint Number
//                       EPNum.0..3: Address
//                       EPNum.7:    Dir
void USB_EnableEP (uint32_t EPNum)
{
    WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum)), DAT_WR_BYTE(0));
}

//Disable USB Endpoint
//    Parameters:      EPNum: Endpoint Number
//                       EPNum.0..3: Address
//                       EPNum.7:    Dir
void USB_DisableEP (uint32_t EPNum)
{
    WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum)), DAT_WR_BYTE(EP_STAT_DA));
}

//  Reset USB Endpoint
//    Parameters:      EPNum: Endpoint Number
//                       EPNum.0..3: Address
//                       EPNum.7:    Dir
void USB_ResetEP (uint32_t EPNum) {
    WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum)), DAT_WR_BYTE(0));
}

//  Set Stall for USB Endpoint
//    Parameters:      EPNum: Endpoint Number
//                       EPNum.0..3: Address
//                       EPNum.7:    Dir
void USB_SetStallEP (uint32_t EPNum)
{
    WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum)), DAT_WR_BYTE(EP_STAT_ST));
}

//  Clear Stall for USB Endpoint
//    Parameters:      EPNum: Endpoint Number
//                       EPNum.0..3: Address
//                       EPNum.7:    Dir
void USB_ClrStallEP (uint32_t EPNum)
{
    WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum)), DAT_WR_BYTE(0));
}

//  Clear USB Endpoint Buffer
//    Parameters:      EPNum: Endpoint Number
//                       EPNum.0..3: Address
//                       EPNum.7:    Dir
void USB_ClearEPBuf (uint32_t EPNum)
{
    WrCmdEP(EPNum, CMD_CLR_BUF);
}

//Read USB Endpoint Data
//Parameters:   EPNum: Endpoint Number
//                  EPNum.0..3: Address
//                  EPNum.7:    Dir
//                  pData: Pointer to Data Buffer
//Return Value: Number of bytes read
uint32_t USB_ReadEP (uint32_t EPNum, uint8_t *pData)
{
    uint32_t cnt, n;
    LPC_USB->Ctrl = ((EPNum & 0x0F) << 2) | CTRL_RD_EN;

    do {
        cnt = LPC_USB->RxPLen;
    } while ((cnt & PKT_RDY) == 0);
   
    cnt &= PKT_LNGTH_MASK;

    for (n = 0; n < (cnt + 3) / 4; n++)

    {
        *((__packed uint32_t *)pData) = LPC_USB->RxData;
        pData += 4;
    }
    LPC_USB->Ctrl = 0;

    if (((EP_MSK_ISO >> EPNum) & 1) == 0)

    {   /* Non-Isochronous Endpoint */
        WrCmdEP(EPNum, CMD_CLR_BUF);
    }
    return (cnt);
}

//Write USB Endpoint Data
//  Parameters:     EPNum: Endpoint Number
//                      EPNum.0..3: Address
//                      EPNum.7:    Dir
//                      pData: Pointer to Data Buffer
//                      cnt:   Number of bytes to write
//  Return Value:   Number of bytes written
uint32_t USB_WriteEP (uint32_t EPNum, uint8_t *pData, uint32_t cnt)
{
    uint32_t n;
   
    LPC_USB->Ctrl = ((EPNum & 0x0F) << 2) | CTRL_WR_EN;
    LPC_USB->TxPLen = cnt;

    for (n = 0; n < (cnt + 3) / 4; n++)

    {
        LPC_USB->TxData = *((__packed uint32_t *)pData);
        pData += 4;
    }
    LPC_USB->Ctrl = 0;
    WrCmdEP(EPNum, CMD_VALID_BUF);
    return (cnt);
}

#if USB_DMA
#endif /* USB_DMA */

//  Get USB Last Frame Number
//    Parameters:      None
//    Return Value:    Frame Number
uint32_t USB_GetFrame (void)
{
    uint32_t val;
    WrCmd(CMD_RD_FRAME);
    val = RdCmdDat(DAT_RD_FRAME);
    val = val | (RdCmdDat(DAT_RD_FRAME) << 8);
    return (val);
}

//USB Interrupt Service Routine
void USB_IRQHandler (void)
{
    uint32_t disr, val, n, m;
    uint32_t episr, episrCur;

    disr = LPC_USB->DevIntSt;                   /* Device   Interrupt Status */

    /* Device   Status Interrupt (Reset, Connect change, Suspend/Resume) */
    if (disr & DEV_STAT_INT)
    {
        LPC_USB->DevIntClr = DEV_STAT_INT;
        WrCmd(CMD_GET_DEV_STAT);
       
        val = RdCmdDat(DAT_GET_DEV_STAT);       /* Device Status */
        if (val & DEV_RST)                      /* Reset */
        {  
            USB_Reset();
            #if   USB_RESET_EVENT
            USB_Reset_Event();
            #endif
        }
        if (val & DEV_CON_CH)                   /* Connect change */
        {                
            #if   USB_POWER_EVENT
            USB_Power_Event(val & DEV_CON);
            #endif
        }
        if (val & DEV_SUS_CH)                   /* Suspend/Resume */
        {                
            if (val & DEV_SUS)                  /* Suspend */
            {                 
                USB_Suspend();
                #if USB_SUSPEND_EVENT
                USB_Suspend_Event();
                #endif
            } else                              /* Resume */
            {                             
                USB_Resume();
                #if USB_RESUME_EVENT
                USB_Resume_Event();
                #endif
            }
        }
        goto isr_end;
    }

    #if USB_SOF_EVENT                           /* Start of Frame Interrupt */
    //每1ms产生一次帧中断。该位用在同步包的传输中
    if (disr & FRAME_INT)
    {
        USB_SOF_Event();
    }
    #endif

    #if USB_ERROR_EVENT                         /* Error Interrupt */
    if (disr & ERR_INT)
    {
        WrCmd(CMD_RD_ERR_STAT);
        val = RdCmdDat(DAT_RD_ERR_STAT);
        USB_Error_Event(val);
    }
    #endif

    //慢速中断
    if (disr & EP_SLOW_INT)
    {
        episrCur = 0;
        episr    = LPC_USB->EpIntSt;
        for (n = 0; n < USB_EP_NUM; n++)        /* Check All Endpoints */
        {    
            if (episr == episrCur)
            {
                break;                          /* break if all EP interrupts handled */
            }
            if (episr & (1 << n))
            {
                episrCur |= (1 << n);
                m = n >> 1;

                LPC_USB->EpIntClr = (1 << n);
                while ((LPC_USB->DevIntSt & CDFULL_INT) == 0);
                val = LPC_USB->CmdData;

                if ((n & 1) == 0)               //OUT Endpoint */
                {                
                    if (n == 0)                 //Control OUT Endpoint */
                    {                   
                        if (val & EP_SEL_STP)   //Setup Packet */
                        {        
                            if (USB_P_EP[0])
                            {
                                USB_P_EP[0](USB_EVT_SETUP);
                                continue;
                            }
                        }
                    }
                    if (USB_P_EP[m])
                    {
                        USB_P_EP[m](USB_EVT_OUT);
                    }
                } else
                {                               //IN Endpoint */
                    if (USB_P_EP[m])
                    {
                        USB_P_EP[m](USB_EVT_IN);
                    }
                }
            }
        }
        LPC_USB->DevIntClr = EP_SLOW_INT;
    }

    #if USB_DMA
    #endif /* USB_DMA */

    isr_end:
    return;
}

#endif /*_USB_DEV_MASS_STORAGE*/

 

抱歉!评论已关闭.