mirror of
https://github.com/MarlinFirmware/Marlin.git
synced 2024-11-28 06:21:31 +00:00
a5cf3a190c
* Fix mistake in gitignore file and add in missing core files. The missing leading slash on "lib" meant all folders names lib in the directory tree are ignored, rather than just the top level PlatformIO lib folder * Add LiquidCrystal Library and associated headers modified to compile.
812 lines
21 KiB
C++
812 lines
21 KiB
C++
/*----------------------------------------------------------------------------
|
|
* 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
|
|
*----------------------------------------------------------------------------
|
|
* This software is supplied "AS IS" without any warranties, express,
|
|
* implied or statutory, including but not limited to the implied
|
|
* warranties of fitness for purpose, satisfactory quality and
|
|
* noninfringement. Keil extends you a royalty-free right to reproduce
|
|
* and distribute executable files created using this software for use
|
|
* on NXP Semiconductors LPC family microcontroller devices only. Nothing
|
|
* else gives you the right to use this software.
|
|
*
|
|
* Copyright (c) 2009 Keil - An ARM Company. All rights reserved.
|
|
*----------------------------------------------------------------------------
|
|
* History:
|
|
* V1.20 Added USB_ClearEPBuf
|
|
* V1.00 Initial Version
|
|
*----------------------------------------------------------------------------*/
|
|
extern "C" {
|
|
#include "LPC17xx.h" /* LPC17xx definitions */
|
|
}
|
|
|
|
#include "usb.h"
|
|
#include "usbcfg.h"
|
|
#include "usbreg.h"
|
|
#include "usbhw.h"
|
|
#include "usbcore.h"
|
|
#include "usbuser.h"
|
|
|
|
#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
|
|
uint32_t UDCA[USB_EP_NUM] __attribute__((section("USB_RAM"))); /* UDCA in USB RAM */
|
|
uint32_t DD_NISO_Mem[4*DD_NISO_CNT] __attribute__((section("USB_RAM"))); /* Non-Iso DMA Descriptor Memory */
|
|
uint32_t DD_ISO_Mem [5*DD_ISO_CNT] __attribute__((section("USB_RAM"))); /* Iso DMA Descriptor Memory */
|
|
uint32_t udca[USB_EP_NUM]; /* UDCA saved values */
|
|
uint32_t DDMemMap[2];
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Get Endpoint Physical Address
|
|
* 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);
|
|
}
|
|
|
|
|
|
/*
|
|
* Write Command
|
|
* Parameters: cmd: Command
|
|
* Return Value: None
|
|
*/
|
|
|
|
void WrCmd (uint32_t cmd) {
|
|
|
|
LPC_USB->USBDevIntClr = CCEMTY_INT;
|
|
LPC_USB->USBCmdCode = cmd;
|
|
while ((LPC_USB->USBDevIntSt & CCEMTY_INT) == 0);
|
|
}
|
|
|
|
|
|
/*
|
|
* Write Command Data
|
|
* Parameters: cmd: Command
|
|
* val: Data
|
|
* Return Value: None
|
|
*/
|
|
|
|
void WrCmdDat (uint32_t cmd, uint32_t val) {
|
|
|
|
LPC_USB->USBDevIntClr = CCEMTY_INT;
|
|
LPC_USB->USBCmdCode = cmd;
|
|
while ((LPC_USB->USBDevIntSt & CCEMTY_INT) == 0);
|
|
LPC_USB->USBDevIntClr = CCEMTY_INT;
|
|
LPC_USB->USBCmdCode = val;
|
|
while ((LPC_USB->USBDevIntSt & CCEMTY_INT) == 0);
|
|
}
|
|
|
|
|
|
/*
|
|
* Write Command to Endpoint
|
|
* Parameters: cmd: Command
|
|
* val: Data
|
|
* Return Value: None
|
|
*/
|
|
|
|
void WrCmdEP (uint32_t EPNum, uint32_t cmd){
|
|
|
|
LPC_USB->USBDevIntClr = CCEMTY_INT;
|
|
LPC_USB->USBCmdCode = CMD_SEL_EP(EPAdr(EPNum));
|
|
while ((LPC_USB->USBDevIntSt & CCEMTY_INT) == 0);
|
|
LPC_USB->USBDevIntClr = CCEMTY_INT;
|
|
LPC_USB->USBCmdCode = cmd;
|
|
while ((LPC_USB->USBDevIntSt & CCEMTY_INT) == 0);
|
|
}
|
|
|
|
|
|
/*
|
|
* Read Command Data
|
|
* Parameters: cmd: Command
|
|
* Return Value: Data Value
|
|
*/
|
|
|
|
uint32_t RdCmdDat (uint32_t cmd) {
|
|
|
|
LPC_USB->USBDevIntClr = CCEMTY_INT | CDFULL_INT;
|
|
LPC_USB->USBCmdCode = cmd;
|
|
while ((LPC_USB->USBDevIntSt & CDFULL_INT) == 0);
|
|
return (LPC_USB->USBCmdData);
|
|
}
|
|
|
|
|
|
/*
|
|
* USB Initialize Function
|
|
* Called by the User to initialize USB
|
|
* Return Value: None
|
|
*/
|
|
|
|
void USB_Init (void) {
|
|
|
|
LPC_PINCON->PINSEL1 &= ~((3<<26)|(3<<28)); /* P0.29 D+, P0.30 D- */
|
|
LPC_PINCON->PINSEL1 |= ((1<<26)|(1<<28)); /* PINSEL1 26.27, 28.29 = 01 */
|
|
|
|
//todo: VBUS not used by smoothieboard (though spec requires it for self powered devices), pin used for beeper
|
|
//todo: Goodlink used for servo4?
|
|
//LPC_PINCON->PINSEL3 &= ~((3<< 4)|(3<<28)); /* P1.18 GoodLink, P1.30 VBUS */
|
|
//LPC_PINCON->PINSEL3 |= ((1<< 4)|(2<<28)); /* PINSEL3 4.5 = 01, 28.29 = 10 */
|
|
|
|
LPC_PINCON->PINSEL4 &= ~((3<<18) ); /* P2.9 SoftConnect */
|
|
LPC_PINCON->PINSEL4 |= ((1<<18) ); /* PINSEL4 18.19 = 01 */
|
|
|
|
LPC_SC->PCONP |= (1UL<<31); /* USB PCLK -> enable USB Per. */
|
|
|
|
LPC_USB->USBClkCtrl = 0x1A; /* Dev, PortSel, AHB clock enable */
|
|
while ((LPC_USB->USBClkSt & 0x1A) != 0x1A);
|
|
|
|
NVIC_EnableIRQ(USB_IRQn); /* enable USB interrupt */
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
/*
|
|
* USB Reset Function
|
|
* Called automatically on USB Reset
|
|
* Return Value: None
|
|
*/
|
|
|
|
void USB_Reset (void) {
|
|
#if USB_DMA
|
|
uint32_t n;
|
|
#endif
|
|
|
|
LPC_USB->USBEpInd = 0;
|
|
LPC_USB->USBMaxPSize = USB_MAX_PACKET0;
|
|
LPC_USB->USBEpInd = 1;
|
|
LPC_USB->USBMaxPSize = USB_MAX_PACKET0;
|
|
while ((LPC_USB->USBDevIntSt & EP_RLZED_INT) == 0);
|
|
|
|
LPC_USB->USBEpIntClr = 0xFFFFFFFF;
|
|
LPC_USB->USBEpIntEn = 0xFFFFFFFF ^ USB_DMA_EP;
|
|
LPC_USB->USBDevIntClr = 0xFFFFFFFF;
|
|
LPC_USB->USBDevIntEn = DEV_STAT_INT | EP_SLOW_INT |
|
|
(USB_SOF_EVENT ? FRAME_INT : 0) |
|
|
(USB_ERROR_EVENT ? ERR_INT : 0);
|
|
|
|
WrCmdDat(CMD_SET_MODE, DAT_WR_BYTE(INAK_BI));
|
|
|
|
|
|
#if USB_DMA
|
|
LPC_USB->USBUDCAH = USB_RAM_ADR;
|
|
LPC_USB->USBDMARClr = 0xFFFFFFFF;
|
|
LPC_USB->USBEpDMADis = 0xFFFFFFFF;
|
|
LPC_USB->USBEpDMAEn = USB_DMA_EP;
|
|
LPC_USB->USBEoTIntClr = 0xFFFFFFFF;
|
|
LPC_USB->USBNDDRIntClr = 0xFFFFFFFF;
|
|
LPC_USB->USBSysErrIntClr = 0xFFFFFFFF;
|
|
LPC_USB->USBDMAIntEn = 0x00000007;
|
|
DDMemMap[0] = 0x00000000;
|
|
DDMemMap[1] = 0x00000000;
|
|
for (n = 0; n < USB_EP_NUM; n++) {
|
|
udca[n] = 0;
|
|
UDCA[n] = 0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
* USB Suspend Function
|
|
* Called automatically on USB Suspend
|
|
* Return Value: None
|
|
*/
|
|
|
|
void USB_Suspend (void) {
|
|
/* Performed by Hardware */
|
|
}
|
|
|
|
|
|
/*
|
|
* USB Resume Function
|
|
* Called automatically on USB Resume
|
|
* Return Value: None
|
|
*/
|
|
|
|
void USB_Resume (void) {
|
|
/* Performed by Hardware */
|
|
}
|
|
|
|
|
|
/*
|
|
* USB Remote Wakeup Function
|
|
* Called automatically on USB Remote Wakeup
|
|
* Return Value: None
|
|
*/
|
|
|
|
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
|
|
* Return Value: None
|
|
*/
|
|
|
|
void USB_WakeUpCfg (uint32_t cfg) {
|
|
/* Not needed */
|
|
}
|
|
|
|
|
|
/*
|
|
* USB Set Address Function
|
|
* Parameters: adr: USB Address
|
|
* Return Value: None
|
|
*/
|
|
|
|
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
|
|
* Return Value: None
|
|
*/
|
|
|
|
void USB_Configure (uint32_t cfg) {
|
|
|
|
WrCmdDat(CMD_CFG_DEV, DAT_WR_BYTE(cfg ? CONF_DVICE : 0));
|
|
|
|
LPC_USB->USBReEp = 0x00000003;
|
|
while ((LPC_USB->USBDevIntSt & EP_RLZED_INT) == 0);
|
|
LPC_USB->USBDevIntClr = EP_RLZED_INT;
|
|
}
|
|
|
|
|
|
/*
|
|
* Configure USB Endpoint according to Descriptor
|
|
* Parameters: pEPD: Pointer to Endpoint Descriptor
|
|
* Return Value: None
|
|
*/
|
|
|
|
void USB_ConfigEP (USB_ENDPOINT_DESCRIPTOR *pEPD) {
|
|
uint32_t num;
|
|
|
|
num = EPAdr(pEPD->bEndpointAddress);
|
|
LPC_USB->USBReEp |= (1 << num);
|
|
LPC_USB->USBEpInd = num;
|
|
LPC_USB->USBMaxPSize = pEPD->wMaxPacketSize;
|
|
while ((LPC_USB->USBDevIntSt & EP_RLZED_INT) == 0);
|
|
LPC_USB->USBDevIntClr = EP_RLZED_INT;
|
|
}
|
|
|
|
|
|
/*
|
|
* Set Direction for USB Control Endpoint
|
|
* Parameters: dir: Out (dir == 0), In (dir <> 0)
|
|
* Return Value: None
|
|
*/
|
|
|
|
void USB_DirCtrlEP (uint32_t dir) {
|
|
/* Not needed */
|
|
}
|
|
|
|
|
|
/*
|
|
* Enable USB Endpoint
|
|
* Parameters: EPNum: Endpoint Number
|
|
* EPNum.0..3: Address
|
|
* EPNum.7: Dir
|
|
* Return Value: None
|
|
*/
|
|
|
|
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
|
|
* Return Value: None
|
|
*/
|
|
|
|
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
|
|
* Return Value: None
|
|
*/
|
|
|
|
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
|
|
* Return Value: None
|
|
*/
|
|
|
|
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
|
|
* Return Value: None
|
|
*/
|
|
|
|
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
|
|
* Return Value: None
|
|
*/
|
|
|
|
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->USBCtrl = ((EPNum & 0x0F) << 2) | CTRL_RD_EN;
|
|
|
|
do {
|
|
cnt = LPC_USB->USBRxPLen;
|
|
} while ((cnt & PKT_RDY) == 0);
|
|
cnt &= PKT_LNGTH_MASK;
|
|
|
|
for (n = 0; n < (cnt + 3) / 4; n++) {
|
|
*((__packed uint32_t *)pData) = LPC_USB->USBRxData;
|
|
pData += 4;
|
|
}
|
|
LPC_USB->USBCtrl = 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->USBCtrl = ((EPNum & 0x0F) << 2) | CTRL_WR_EN;
|
|
|
|
LPC_USB->USBTxPLen = cnt;
|
|
|
|
for (n = 0; n < (cnt + 3) / 4; n++) {
|
|
LPC_USB->USBTxData = *((__packed uint32_t *)pData);
|
|
pData += 4;
|
|
}
|
|
LPC_USB->USBCtrl = 0;
|
|
WrCmdEP(EPNum, CMD_VALID_BUF);
|
|
return (cnt);
|
|
}
|
|
|
|
#if USB_DMA
|
|
|
|
/* DMA Descriptor Memory Layout */
|
|
const uint32_t DDAdr[2] = { DD_NISO_ADR, DD_ISO_ADR };
|
|
const uint32_t DDSz [2] = { 16, 20 };
|
|
|
|
|
|
/*
|
|
* Setup USB DMA Transfer for selected Endpoint
|
|
* Parameters: EPNum: Endpoint Number
|
|
* pDD: Pointer to DMA Descriptor
|
|
* Return Value: TRUE - Success, FALSE - Error
|
|
*/
|
|
|
|
uint32_t USB_DMA_Setup(uint32_t EPNum, USB_DMA_DESCRIPTOR *pDD) {
|
|
uint32_t num, ptr, nxt, iso, n;
|
|
|
|
iso = pDD->Cfg.Type.IsoEP; /* Iso or Non-Iso Descriptor */
|
|
num = EPAdr(EPNum); /* Endpoint's Physical Address */
|
|
|
|
ptr = 0; /* Current Descriptor */
|
|
nxt = udca[num]; /* Initial Descriptor */
|
|
while (nxt) { /* Go through Descriptor List */
|
|
ptr = nxt; /* Current Descriptor */
|
|
if (!pDD->Cfg.Type.Link) { /* Check for Linked Descriptors */
|
|
n = (ptr - DDAdr[iso]) / DDSz[iso]; /* Descriptor Index */
|
|
DDMemMap[iso] &= ~(1 << n); /* Unmark Memory Usage */
|
|
}
|
|
nxt = *((uint32_t *)ptr); /* Next Descriptor */
|
|
}
|
|
|
|
for (n = 0; n < 32; n++) { /* Search for available Memory */
|
|
if ((DDMemMap[iso] & (1 << n)) == 0) {
|
|
break; /* Memory found */
|
|
}
|
|
}
|
|
if (n == 32) return (FALSE); /* Memory not available */
|
|
|
|
DDMemMap[iso] |= 1 << n; /* Mark Memory Usage */
|
|
nxt = DDAdr[iso] + n * DDSz[iso]; /* Next Descriptor */
|
|
|
|
if (ptr && pDD->Cfg.Type.Link) {
|
|
*((uint32_t *)(ptr + 0)) = nxt; /* Link in new Descriptor */
|
|
*((uint32_t *)(ptr + 4)) |= 0x00000004; /* Next DD is Valid */
|
|
} else {
|
|
udca[num] = nxt; /* Save new Descriptor */
|
|
UDCA[num] = nxt; /* Update UDCA in USB */
|
|
}
|
|
|
|
uint32_t * nxt_ptr = (uint32_t *)nxt;
|
|
/* Fill in DMA Descriptor */
|
|
*nxt_ptr++ = 0; /* Next DD Pointer */
|
|
*nxt_ptr++ = (pDD->Cfg.Type.ATLE) |
|
|
(pDD->Cfg.Type.IsoEP << 4) |
|
|
(pDD->MaxSize << 5) |
|
|
(pDD->BufLen << 16);
|
|
*nxt_ptr++ = pDD->BufAdr;
|
|
*nxt_ptr++ = pDD->Cfg.Type.LenPos << 8;
|
|
if (iso) {
|
|
*nxt_ptr = pDD->InfoAdr;
|
|
}
|
|
|
|
return (TRUE); /* Success */
|
|
}
|
|
|
|
|
|
/*
|
|
* Enable USB DMA Endpoint
|
|
* Parameters: EPNum: Endpoint Number
|
|
* EPNum.0..3: Address
|
|
* EPNum.7: Dir
|
|
* Return Value: None
|
|
*/
|
|
|
|
void USB_DMA_Enable (uint32_t EPNum) {
|
|
LPC_USB->USBEpDMAEn = 1 << EPAdr(EPNum);
|
|
}
|
|
|
|
|
|
/*
|
|
* Disable USB DMA Endpoint
|
|
* Parameters: EPNum: Endpoint Number
|
|
* EPNum.0..3: Address
|
|
* EPNum.7: Dir
|
|
* Return Value: None
|
|
*/
|
|
|
|
void USB_DMA_Disable (uint32_t EPNum) {
|
|
LPC_USB->USBEpDMADis = 1 << EPAdr(EPNum);
|
|
}
|
|
|
|
|
|
/*
|
|
* Get USB DMA Endpoint Status
|
|
* Parameters: EPNum: Endpoint Number
|
|
* EPNum.0..3: Address
|
|
* EPNum.7: Dir
|
|
* Return Value: DMA Status
|
|
*/
|
|
|
|
uint32_t USB_DMA_Status (uint32_t EPNum) {
|
|
uint32_t ptr, val;
|
|
|
|
ptr = UDCA[EPAdr(EPNum)]; /* Current Descriptor */
|
|
if (ptr == 0)
|
|
return (USB_DMA_INVALID);
|
|
|
|
val = *((uint32_t *)(ptr + 3*4)); /* Status Information */
|
|
switch ((val >> 1) & 0x0F) {
|
|
case 0x00: /* Not serviced */
|
|
return (USB_DMA_IDLE);
|
|
case 0x01: /* Being serviced */
|
|
return (USB_DMA_BUSY);
|
|
case 0x02: /* Normal Completition */
|
|
return (USB_DMA_DONE);
|
|
case 0x03: /* Data Under Run */
|
|
return (USB_DMA_UNDER_RUN);
|
|
case 0x08: /* Data Over Run */
|
|
return (USB_DMA_OVER_RUN);
|
|
case 0x09: /* System Error */
|
|
return (USB_DMA_ERROR);
|
|
}
|
|
|
|
return (USB_DMA_UNKNOWN);
|
|
}
|
|
|
|
|
|
/*
|
|
* Get USB DMA Endpoint Current Buffer Address
|
|
* Parameters: EPNum: Endpoint Number
|
|
* EPNum.0..3: Address
|
|
* EPNum.7: Dir
|
|
* Return Value: DMA Address (or -1 when DMA is Invalid)
|
|
*/
|
|
|
|
uint32_t USB_DMA_BufAdr (uint32_t EPNum) {
|
|
uint32_t ptr, val;
|
|
|
|
ptr = UDCA[EPAdr(EPNum)]; /* Current Descriptor */
|
|
if (ptr == 0)
|
|
{
|
|
return ((uint32_t)(-1)); /* DMA Invalid */
|
|
}
|
|
|
|
val = *((uint32_t *)(ptr + 2*4)); /* Buffer Address */
|
|
return (val); /* Current Address */
|
|
}
|
|
|
|
|
|
/*
|
|
* Get USB DMA Endpoint Current Buffer Count
|
|
* Number of transfered Bytes or Iso Packets
|
|
* Parameters: EPNum: Endpoint Number
|
|
* EPNum.0..3: Address
|
|
* EPNum.7: Dir
|
|
* Return Value: DMA Count (or -1 when DMA is Invalid)
|
|
*/
|
|
|
|
uint32_t USB_DMA_BufCnt (uint32_t EPNum) {
|
|
uint32_t ptr, val;
|
|
|
|
ptr = UDCA[EPAdr(EPNum)]; /* Current Descriptor */
|
|
if (ptr == 0)
|
|
{
|
|
return ((uint32_t)(-1)); /* DMA Invalid */
|
|
}
|
|
val = *((uint32_t *)(ptr + 3*4)); /* Status Information */
|
|
return (val >> 16); /* Current Count */
|
|
}
|
|
|
|
|
|
#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->USBDevIntSt; /* Device Interrupt Status */
|
|
|
|
/* Device Status Interrupt (Reset, Connect change, Suspend/Resume) */
|
|
if (disr & DEV_STAT_INT) {
|
|
LPC_USB->USBDevIntClr = 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 */
|
|
if (disr & FRAME_INT) {
|
|
LPC_USB->USBDevIntClr = FRAME_INT;
|
|
USB_SOF_Event();
|
|
}
|
|
#endif
|
|
|
|
#if USB_ERROR_EVENT
|
|
/* Error Interrupt */
|
|
if (disr & ERR_INT) {
|
|
LPC_USB->USBDevIntClr = ERR_INT;
|
|
WrCmd(CMD_RD_ERR_STAT);
|
|
val = RdCmdDat(DAT_RD_ERR_STAT);
|
|
USB_Error_Event(val);
|
|
}
|
|
#endif
|
|
|
|
/* Endpoint's Slow Interrupt */
|
|
if (disr & EP_SLOW_INT) {
|
|
episrCur = 0;
|
|
episr = LPC_USB->USBEpIntSt;
|
|
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->USBEpIntClr = (1 << n);
|
|
while ((LPC_USB->USBDevIntSt & CDFULL_INT) == 0);
|
|
val = LPC_USB->USBCmdData;
|
|
|
|
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->USBDevIntClr = EP_SLOW_INT;
|
|
}
|
|
|
|
#if USB_DMA
|
|
|
|
if (LPC_USB->USBDMAIntSt & 0x00000001) { /* End of Transfer Interrupt */
|
|
val = LPC_USB->USBEoTIntSt;
|
|
for (n = 2; n < USB_EP_NUM; n++) { /* Check All Endpoints */
|
|
if (val & (1 << n)) {
|
|
m = n >> 1;
|
|
if ((n & 1) == 0) { /* OUT Endpoint */
|
|
if (USB_P_EP[m]) {
|
|
USB_P_EP[m](USB_EVT_OUT_DMA_EOT);
|
|
}
|
|
} else { /* IN Endpoint */
|
|
if (USB_P_EP[m]) {
|
|
USB_P_EP[m](USB_EVT_IN_DMA_EOT);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
LPC_USB->USBEoTIntClr = val;
|
|
}
|
|
|
|
if (LPC_USB->USBDMAIntSt & 0x00000002) { /* New DD Request Interrupt */
|
|
val = LPC_USB->USBNDDRIntSt;
|
|
for (n = 2; n < USB_EP_NUM; n++) { /* Check All Endpoints */
|
|
if (val & (1 << n)) {
|
|
m = n >> 1;
|
|
if ((n & 1) == 0) { /* OUT Endpoint */
|
|
if (USB_P_EP[m]) {
|
|
USB_P_EP[m](USB_EVT_OUT_DMA_NDR);
|
|
}
|
|
} else { /* IN Endpoint */
|
|
if (USB_P_EP[m]) {
|
|
USB_P_EP[m](USB_EVT_IN_DMA_NDR);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
LPC_USB->USBNDDRIntClr = val;
|
|
}
|
|
|
|
if (LPC_USB->USBDMAIntSt & 0x00000004) { /* System Error Interrupt */
|
|
val = LPC_USB->USBSysErrIntSt;
|
|
for (n = 2; n < USB_EP_NUM; n++) { /* Check All Endpoints */
|
|
if (val & (1 << n)) {
|
|
m = n >> 1;
|
|
if ((n & 1) == 0) { /* OUT Endpoint */
|
|
if (USB_P_EP[m]) {
|
|
USB_P_EP[m](USB_EVT_OUT_DMA_ERR);
|
|
}
|
|
} else { /* IN Endpoint */
|
|
if (USB_P_EP[m]) {
|
|
USB_P_EP[m](USB_EVT_IN_DMA_ERR);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
LPC_USB->USBSysErrIntClr = val;
|
|
}
|
|
|
|
#endif /* USB_DMA */
|
|
|
|
isr_end:
|
|
return;
|
|
}
|