1 /*----------------------------------------------------------------------------
3 *----------------------------------------------------------------------------
5 * Purpose: USB Hardware Layer Module for Philips LPC17xx
7 *----------------------------------------------------------------------------
8 * This software is supplied "AS IS" without any warranties, express,
9 * implied or statutory, including but not limited to the implied
10 * warranties of fitness for purpose, satisfactory quality and
11 * noninfringement. Keil extends you a royalty-free right to reproduce
12 * and distribute executable files created using this software for use
13 * on NXP Semiconductors LPC microcontroller devices only. Nothing else
14 * gives you the right to use this software.
16 * Copyright (c) 2009 Keil - An ARM Company. All rights reserved.
17 *----------------------------------------------------------------------------
19 * V1.20 Added USB_ClearEPBuf
20 * V1.00 Initial Version
21 *----------------------------------------------------------------------------*/
22 #include "projectconfig.h" /* LPC13xx definitions */
32 * USB and IO Clock configuration only.
33 * The same as call PeriClkIOInit(IOCON_USB);
34 * The purpose is to reduce the code space for
35 * overall USB project and reserve code space for
40 void USBIOClkConfig( void )
42 /* Enable AHB clock to the GPIO domain. */
43 SCB_SYSAHBCLKCTRL
|= SCB_SYSAHBCLKCTRL_GPIO
;
45 /* Enable Timer32_1, IOCON, and USB blocks */
46 SCB_SYSAHBCLKCTRL
|= (SCB_SYSAHBCLKCTRL_CT32B1
| SCB_SYSAHBCLKCTRL_IOCON
| SCB_SYSAHBCLKCTRL_USB_REG
);
49 SCB_PDRUNCFG
&= ~(SCB_PDSLEEPCFG_USBPAD_PD
); // Power-up USB PHY
50 SCB_PDRUNCFG
&= ~(SCB_PDSLEEPCFG_USBPLL_PD
); // Power-up USB PLL
52 SCB_USBPLLCLKSEL
= SCB_USBPLLCLKSEL_SOURCE_MAINOSC
; // Select PLL Input
53 SCB_USBPLLCLKUEN
= SCB_USBPLLCLKUEN_UPDATE
; // Update Clock Source
54 SCB_USBPLLCLKUEN
= SCB_USBPLLCLKUEN_DISABLE
; // Toggle Update Register
55 SCB_USBPLLCLKUEN
= SCB_USBPLLCLKUEN_UPDATE
;
57 // Wait until the USB clock is updated
58 while (!(SCB_USBPLLCLKUEN
& SCB_USBPLLCLKUEN_UPDATE
));
60 // Set USB clock to 48MHz (12MHz x 4)
61 SCB_USBPLLCTRL
= (SCB_USBPLLCTRL_MULT_4
);
62 while (!(SCB_USBPLLSTAT
& SCB_USBPLLSTAT_LOCK
)); // Wait Until PLL Locked
63 SCB_USBCLKSEL
= SCB_USBCLKSEL_SOURCE_USBPLLOUT
;
65 // Set USB pin functions
66 IOCON_PIO0_1
&= ~IOCON_PIO0_1_FUNC_MASK
;
67 IOCON_PIO0_1
|= IOCON_PIO0_1_FUNC_CLKOUT
; // CLK OUT
68 IOCON_PIO0_3
&= ~IOCON_PIO0_3_FUNC_MASK
;
69 IOCON_PIO0_3
|= IOCON_PIO0_3_FUNC_USB_VBUS
; // VBus
70 IOCON_PIO0_6
&= ~IOCON_PIO0_6_FUNC_MASK
;
71 IOCON_PIO0_6
|= IOCON_PIO0_6_FUNC_USB_CONNECT
; // Soft Connect
77 * Delay number of clock cycles
78 * Parameters: Delay length
82 void delay (uint32_t length
)
86 for ( i
= 0; i
< length
; i
++ )
94 * Get Endpoint Physical Address
95 * Parameters: EPNum: Endpoint Number
98 * Return Value: Endpoint Physical Address
101 uint32_t EPAdr (uint32_t EPNum
)
105 val
= (EPNum
& 0x0F) << 1;
115 * Parameters: cmd: Command
119 void WrCmd (uint32_t cmd
)
121 USB_DEVINTCLR
= CCEMTY_INT
;
123 while ((USB_DEVINTST
& (CCEMTY_INT
| DEV_STAT_INT
)) == 0);
129 * Parameters: cmd: Command
134 void WrCmdDat (uint32_t cmd
, uint32_t val
)
142 * Write Command to Endpoint
143 * Parameters: cmd: Command
148 void WrCmdEP (uint32_t EPNum
, uint32_t cmd
)
150 WrCmd(CMD_SEL_EP(EPAdr(EPNum
)));
157 * Parameters: cmd: Command
158 * Return Value: Data Value
161 uint32_t RdCmdDat (uint32_t cmd
)
163 USB_DEVINTCLR
= CCEMTY_INT
| CDFULL_INT
;
165 while ((USB_DEVINTST
& (CDFULL_INT
| DEV_STAT_INT
)) == 0);
166 return (USB_CMDDATA
);
171 * USB Initialize Function
172 * Called by the User to initialize USB
178 // Setup USB clock and pins
182 /* It's important that only BULK and FRAME(ISO) can be routed
184 USB_DEVFIQSEL
= 0x01; /* SOF Use FIQ */
186 /* Enable the USB Interrupt */
187 NVIC_EnableIRQ(USB_FIQn
);
190 /* Enable the USB Interrupt */
191 NVIC_EnableIRQ(USB_IRQn
);
200 * USB Connect Function
201 * Called by the User to Connect/Disconnect USB
202 * Parameters: con: Connect/Disconnect
206 void USB_Connect (uint32_t con
)
208 WrCmdDat(CMD_SET_DEV_STAT
, DAT_WR_BYTE(con
? DEV_CON
: 0));
214 * Called automatically on USB Reset
218 void USB_Reset (void)
220 USB_DEVINTCLR
= 0x000FFFFF;
221 /* Enable all eight(8) EPs, note: EP won't be ready until it's
222 configured/enabled when device sending SetEPStatus command
223 to the command engine. */
224 USB_DEVINTEN
= DEV_STAT_INT
| (0xFF<<1) |
225 (USB_SOF_EVENT
? FRAME_INT
: 0);
231 * USB Suspend Function
232 * Called automatically on USB Suspend
236 void USB_Suspend (void)
238 /* Performed by Hardware */
243 * USB Resume Function
244 * Called automatically on USB Resume
248 void USB_Resume (void)
250 /* Performed by Hardware */
255 * USB Remote Wakeup Function
256 * Called automatically on USB Remote Wakeup
260 void USB_WakeUp (void)
262 if (USB_DeviceStatus
& USB_GETSTATUS_REMOTE_WAKEUP
)
264 WrCmdDat(CMD_SET_DEV_STAT
, DAT_WR_BYTE(DEV_CON
));
270 * USB Remote Wakeup Configuration Function
271 * Parameters: cfg: Enable/Disable
275 void USB_WakeUpCfg (uint32_t cfg
)
277 cfg
= cfg
; /* Not needed */
282 * USB Set Address Function
283 * Parameters: adr: USB Address
287 void USB_SetAddress (uint32_t adr
)
289 WrCmdDat(CMD_SET_ADDR
, DAT_WR_BYTE(DEV_EN
| adr
)); /* Don't wait for next */
290 WrCmdDat(CMD_SET_ADDR
, DAT_WR_BYTE(DEV_EN
| adr
)); /* Setup Status Phase */
295 * USB Configure Function
296 * Parameters: cfg: Configure/Deconfigure
300 void USB_Configure (uint32_t cfg
)
302 WrCmdDat(CMD_CFG_DEV
, DAT_WR_BYTE(cfg
? CONF_DVICE
: 0));
308 * Configure USB Endpoint according to Descriptor
309 * Parameters: pEPD: Pointer to Endpoint Descriptor
313 void USB_ConfigEP (USB_ENDPOINT_DESCRIPTOR
*pEPD
)
320 * Set Direction for USB Control Endpoint
321 * Parameters: dir: Out (dir == 0), In (dir <> 0)
325 void USB_DirCtrlEP (uint32_t dir
)
327 dir
= dir
; /* Not needed */
332 * Enable USB Endpoint
333 * Parameters: EPNum: Endpoint Number
334 * EPNum.0..3: Address
339 void USB_EnableEP (uint32_t EPNum
)
341 WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum
)), DAT_WR_BYTE(0));
346 * Disable USB Endpoint
347 * Parameters: EPNum: Endpoint Number
348 * EPNum.0..3: Address
353 void USB_DisableEP (uint32_t EPNum
)
355 WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum
)), DAT_WR_BYTE(EP_STAT_DA
));
361 * Parameters: EPNum: Endpoint Number
362 * EPNum.0..3: Address
367 void USB_ResetEP (uint32_t EPNum
)
369 WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum
)), DAT_WR_BYTE(0));
374 * Set Stall for USB Endpoint
375 * Parameters: EPNum: Endpoint Number
376 * EPNum.0..3: Address
381 void USB_SetStallEP (uint32_t EPNum
)
383 WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum
)), DAT_WR_BYTE(EP_STAT_ST
));
388 * Clear Stall for USB Endpoint
389 * Parameters: EPNum: Endpoint Number
390 * EPNum.0..3: Address
395 void USB_ClrStallEP (uint32_t EPNum
)
397 WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum
)), DAT_WR_BYTE(0));
402 * Clear USB Endpoint Buffer
403 * Parameters: EPNum: Endpoint Number
404 * EPNum.0..3: Address
409 void USB_ClearEPBuf (uint32_t EPNum
)
411 WrCmdEP(EPNum
, CMD_CLR_BUF
);
416 * Read USB Endpoint Data
417 * Parameters: EPNum: Endpoint Number
418 * EPNum.0..3: Address
420 * pData: Pointer to Data Buffer
421 * Return Value: Number of bytes read
424 uint32_t USB_ReadEP (uint32_t EPNum
, uint8_t *pData
)
428 USB_CTRL
= ((EPNum
& 0x0F) << 2) | CTRL_RD_EN
;
429 /* 3 clock cycles to fetch the packet length from RAM. */
435 } while ((cnt
& PKT_DV
) == 0);
436 cnt
&= PKT_LNGTH_MASK
;
438 for (n
= 0; n
< (cnt
+ 3) / 4; n
++)
440 *((uint32_t __attribute__((packed
)) *)pData
) = USB_RXDATA
;
446 if ((EPNum
& 0x80) != 0x04)
447 { /* Non-Isochronous Endpoint */
448 WrCmdEP(EPNum
, CMD_CLR_BUF
);
456 * Write USB Endpoint Data
457 * Parameters: EPNum: Endpoint Number
458 * EPNum.0..3: Address
460 * pData: Pointer to Data Buffer
461 * cnt: Number of bytes to write
462 * Return Value: Number of bytes written
465 uint32_t USB_WriteEP (uint32_t EPNum
, uint8_t *pData
, uint32_t cnt
)
469 USB_CTRL
= ((EPNum
& 0x0F) << 2) | CTRL_WR_EN
;
470 /* 3 clock cycles to fetch the packet length from RAM. */
474 for (n
= 0; n
< (cnt
+ 3) / 4; n
++)
476 USB_TXDATA
= *((uint32_t __attribute__((packed
)) *)pData
);
482 WrCmdEP(EPNum
, CMD_VALID_BUF
);
488 * Get USB Last Frame Number
490 * Return Value: Frame Number
493 uint32_t USB_GetFrame (void)
498 val
= RdCmdDat(DAT_RD_FRAME
);
499 val
= val
| (RdCmdDat(DAT_RD_FRAME
) << 8);
506 * USB Interrupt Service Routine
510 void USB_IRQHandler (void)
512 uint32_t disr
, val
, n
, m
;
514 disr
= USB_DEVINTST
; /* Device Interrupt Status */
515 USB_DEVINTCLR
= disr
;
517 /* Device Status Interrupt (Reset, Connect change, Suspend/Resume) */
518 if (disr
& DEV_STAT_INT
)
520 WrCmd(CMD_GET_DEV_STAT
);
521 val
= RdCmdDat(DAT_GET_DEV_STAT
); /* Device Status */
522 if (val
& DEV_RST
) { /* Reset */
528 if (val
& DEV_CON_CH
) { /* Connect change */
530 USB_Power_Event(val
& DEV_CON
);
533 if (val
& DEV_SUS_CH
) { /* Suspend/Resume */
534 if (val
& DEV_SUS
) { /* Suspend */
536 #if USB_SUSPEND_EVENT
539 } else { /* Resume */
550 /* Start of Frame Interrupt */
551 if (disr
& FRAME_INT
)
553 USB_DEVINTCLR
= FRAME_INT
;
560 /* NO error interrupt anymore, below code can be used
561 as example to get error status from command engine. */
562 /* Error Interrupt */
565 WrCmd(CMD_RD_ERR_STAT
);
566 val
= RdCmdDat(DAT_RD_ERR_STAT
);
567 USB_Error_Event(val
);
571 /* Endpoint's Interrupt */
572 if (disr
& (0xFF<<1)) {
573 /* if any of the EP0 through EP7 is set, or bit 1 through 9 on disr */
574 for (n
= 0; n
< USB_EP_NUM
; n
++) { /* Check All Endpoints */
575 /* skip frame interrupt at bit 0 in disr */
576 // if (disr & ((1 << n)<<1)) {
577 if ((disr
>>1) & (1 << n
)) {
579 /* clear EP interrupt by sending cmd to the command engine. */
580 WrCmd(CMD_SEL_EP_CLRI(n
));
581 val
= RdCmdDat(DAT_SEL_EP_CLRI(n
));
582 if ((n
& 1) == 0) { /* OUT Endpoint */
583 if (n
== 0) { /* Control OUT Endpoint */
584 if (val
& EP_SEL_STP
) { /* Setup Packet */
586 USB_P_EP
[0](USB_EVT_SETUP
);
592 USB_P_EP
[m
](USB_EVT_OUT
);
594 } else { /* IN Endpoint */
596 USB_P_EP
[m
](USB_EVT_IN
);