1 /* Copyright (c) 2010-2011 mbed.org, MIT License
3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
4 * and associated documentation files (the "Software"), to deal in the Software without
5 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
6 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
7 * Software is furnished to do so, subject to the following conditions:
9 * The above copyright notice and this permission notice shall be included in all copies or
10 * substantial portions of the Software.
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
24 // Get endpoint direction
25 #define IN_EP(endpoint) ((endpoint) & 1U ? true : false)
26 #define OUT_EP(endpoint) ((endpoint) & 1U ? false : true)
28 // Convert physical endpoint number to register bit
29 #define EP(endpoint) (1UL<<endpoint)
31 // Power Control for Peripherals register
32 #define PCUSB (1UL<<31)
34 // USB Clock Control register
35 #define DEV_CLK_EN (1UL<<1)
36 #define AHB_CLK_EN (1UL<<4)
38 // USB Clock Status register
39 #define DEV_CLK_ON (1UL<<1)
40 #define AHB_CLK_ON (1UL<<4)
42 // USB Device Interupt registers
43 #define FRAME (1UL<<0)
44 #define EP_FAST (1UL<<1)
45 #define EP_SLOW (1UL<<2)
46 #define DEV_STAT (1UL<<3)
47 #define CCEMPTY (1UL<<4)
48 #define CDFULL (1UL<<5)
49 #define RxENDPKT (1UL<<6)
50 #define TxENDPKT (1UL<<7)
51 #define EP_RLZED (1UL<<8)
52 #define ERR_INT (1UL<<9)
54 // USB Control register
57 #define LOG_ENDPOINT(endpoint) ((endpoint>>1)<<2)
59 // USB Receive Packet Length register
61 #define PKT_RDY (1UL<<11)
62 #define PKT_LNGTH_MASK (0x3ff)
64 // Serial Interface Engine (SIE)
65 #define SIE_WRITE (0x01)
66 #define SIE_READ (0x02)
67 #define SIE_COMMAND (0x05)
68 #define SIE_CMD_CODE(phase, data) ((phase<<8)|(data<<16))
71 #define SIE_CMD_SET_ADDRESS (0xD0)
72 #define SIE_CMD_CONFIGURE_DEVICE (0xD8)
73 #define SIE_CMD_SET_MODE (0xF3)
74 #define SIE_CMD_READ_FRAME_NUMBER (0xF5)
75 #define SIE_CMD_READ_TEST_REGISTER (0xFD)
76 #define SIE_CMD_SET_DEVICE_STATUS (0xFE)
77 #define SIE_CMD_GET_DEVICE_STATUS (0xFE)
78 #define SIE_CMD_GET_ERROR_CODE (0xFF)
79 #define SIE_CMD_READ_ERROR_STATUS (0xFB)
81 #define SIE_CMD_SELECT_ENDPOINT(endpoint) (0x00+endpoint)
82 #define SIE_CMD_SELECT_ENDPOINT_CLEAR_INTERRUPT(endpoint) (0x40+endpoint)
83 #define SIE_CMD_SET_ENDPOINT_STATUS(endpoint) (0x40+endpoint)
85 #define SIE_CMD_CLEAR_BUFFER (0xF2)
86 #define SIE_CMD_VALIDATE_BUFFER (0xFA)
88 // SIE Device Status register
89 #define SIE_DS_CON (1<<0)
90 #define SIE_DS_CON_CH (1<<1)
91 #define SIE_DS_SUS (1<<2)
92 #define SIE_DS_SUS_CH (1<<3)
93 #define SIE_DS_RST (1<<4)
95 // SIE Device Set Address register
96 #define SIE_DSA_DEV_EN (1<<7)
98 // SIE Configue Device register
99 #define SIE_CONF_DEVICE (1<<0)
101 // Select Endpoint register
102 #define SIE_SE_FE (1<<0)
103 #define SIE_SE_ST (1<<1)
104 #define SIE_SE_STP (1<<2)
105 #define SIE_SE_PO (1<<3)
106 #define SIE_SE_EPN (1<<4)
107 #define SIE_SE_B_1_FULL (1<<5)
108 #define SIE_SE_B_2_FULL (1<<6)
110 // Set Endpoint Status command
111 #define SIE_SES_ST (1<<0)
112 #define SIE_SES_DA (1<<5)
113 #define SIE_SES_RF_MO (1<<6)
114 #define SIE_SES_CND_ST (1<<7)
117 USBHAL
* USBHAL::instance
;
119 static volatile int epComplete
;
120 static uint32_t endpointStallState
;
122 static void SIECommand(uint32_t command
) {
123 // The command phase of a SIE transaction
124 LPC_USB
->USBDevIntClr
= CCEMPTY
;
125 LPC_USB
->USBCmdCode
= SIE_CMD_CODE(SIE_COMMAND
, command
);
126 while (!(LPC_USB
->USBDevIntSt
& CCEMPTY
));
129 static void SIEWriteData(uint8_t data
) {
130 // The data write phase of a SIE transaction
131 LPC_USB
->USBDevIntClr
= CCEMPTY
;
132 LPC_USB
->USBCmdCode
= SIE_CMD_CODE(SIE_WRITE
, data
);
133 while (!(LPC_USB
->USBDevIntSt
& CCEMPTY
));
136 static uint8_t SIEReadData(uint32_t command
) {
137 // The data read phase of a SIE transaction
138 LPC_USB
->USBDevIntClr
= CDFULL
;
139 LPC_USB
->USBCmdCode
= SIE_CMD_CODE(SIE_READ
, command
);
140 while (!(LPC_USB
->USBDevIntSt
& CDFULL
));
141 return (uint8_t)LPC_USB
->USBCmdData
;
144 static void SIEsetDeviceStatus(uint8_t status
) {
145 // Write SIE device status register
146 SIECommand(SIE_CMD_SET_DEVICE_STATUS
);
147 SIEWriteData(status
);
150 static uint8_t SIEgetDeviceStatus(void) {
151 // Read SIE device status register
152 SIECommand(SIE_CMD_GET_DEVICE_STATUS
);
153 return SIEReadData(SIE_CMD_GET_DEVICE_STATUS
);
156 void SIEsetAddress(uint8_t address
) {
157 // Write SIE device address register
158 SIECommand(SIE_CMD_SET_ADDRESS
);
159 SIEWriteData((address
& 0x7f) | SIE_DSA_DEV_EN
);
162 static uint8_t SIEselectEndpoint(uint8_t endpoint
) {
163 // SIE select endpoint command
164 SIECommand(SIE_CMD_SELECT_ENDPOINT(endpoint
));
165 return SIEReadData(SIE_CMD_SELECT_ENDPOINT(endpoint
));
168 static uint8_t SIEclearBuffer(void) {
169 // SIE clear buffer command
170 SIECommand(SIE_CMD_CLEAR_BUFFER
);
171 return SIEReadData(SIE_CMD_CLEAR_BUFFER
);
174 static void SIEvalidateBuffer(void) {
175 // SIE validate buffer command
176 SIECommand(SIE_CMD_VALIDATE_BUFFER
);
179 static void SIEsetEndpointStatus(uint8_t endpoint
, uint8_t status
) {
180 // SIE set endpoint status command
181 SIECommand(SIE_CMD_SET_ENDPOINT_STATUS(endpoint
));
182 SIEWriteData(status
);
185 static uint16_t SIEgetFrameNumber(void) __attribute__ ((unused
));
186 static uint16_t SIEgetFrameNumber(void) {
187 // Read current frame number
191 SIECommand(SIE_CMD_READ_FRAME_NUMBER
);
192 lowByte
= SIEReadData(SIE_CMD_READ_FRAME_NUMBER
);
193 highByte
= SIEReadData(SIE_CMD_READ_FRAME_NUMBER
);
195 return (highByte
<< 8) | lowByte
;
198 static void SIEconfigureDevice(void) {
199 // SIE Configure device command
200 SIECommand(SIE_CMD_CONFIGURE_DEVICE
);
201 SIEWriteData(SIE_CONF_DEVICE
);
204 static void SIEunconfigureDevice(void) {
205 // SIE Configure device command
206 SIECommand(SIE_CMD_CONFIGURE_DEVICE
);
210 static void SIEconnect(void) {
211 // Connect USB device
212 uint8_t status
= SIEgetDeviceStatus();
213 SIEsetDeviceStatus(status
| SIE_DS_CON
);
217 static void SIEdisconnect(void) {
218 // Disconnect USB device
219 uint8_t status
= SIEgetDeviceStatus();
220 SIEsetDeviceStatus(status
& ~SIE_DS_CON
);
224 static uint8_t selectEndpointClearInterrupt(uint8_t endpoint
) {
225 // Implemented using using EP_INT_CLR.
226 LPC_USB
->USBEpIntClr
= EP(endpoint
);
227 while (!(LPC_USB
->USBDevIntSt
& CDFULL
));
228 return (uint8_t)LPC_USB
->USBCmdData
;
232 static void enableEndpointEvent(uint8_t endpoint
) {
233 // Enable an endpoint interrupt
234 LPC_USB
->USBEpIntEn
|= EP(endpoint
);
237 static void disableEndpointEvent(uint8_t endpoint
) __attribute__ ((unused
));
238 static void disableEndpointEvent(uint8_t endpoint
) {
239 // Disable an endpoint interrupt
240 LPC_USB
->USBEpIntEn
&= ~EP(endpoint
);
243 static volatile uint32_t __attribute__((used
)) dummyRead
;
244 uint32_t USBHAL::endpointReadcore(uint8_t endpoint
, uint8_t *buffer
) {
245 // Read from an OUT endpoint
251 LPC_USB
->USBCtrl
= LOG_ENDPOINT(endpoint
) | RD_EN
;
252 while (!(LPC_USB
->USBRxPLen
& PKT_RDY
));
254 size
= LPC_USB
->USBRxPLen
& PKT_LNGTH_MASK
;
259 for (i
=0; i
<size
; i
++) {
261 // Fetch up to four bytes of data as a word
262 data
= LPC_USB
->USBRxData
;
266 *buffer
= (data
>>offset
) & 0xff;
269 // move on to the next byte
270 offset
= (offset
+ 8) % 32;
273 dummyRead
= LPC_USB
->USBRxData
;
276 LPC_USB
->USBCtrl
= 0;
278 if ((endpoint
>> 1) % 3 || (endpoint
>> 1) == 0) {
279 SIEselectEndpoint(endpoint
);
286 static void endpointWritecore(uint8_t endpoint
, uint8_t *buffer
, uint32_t size
) {
287 // Write to an IN endpoint
291 LPC_USB
->USBCtrl
= LOG_ENDPOINT(endpoint
) | WR_EN
;
293 LPC_USB
->USBTxPLen
= size
;
299 // Fetch next data byte into a word-sized temporary variable
302 // Add to current data word
303 temp
= temp
<< offset
;
306 // move on to the next byte
307 offset
= (offset
+ 8) % 32;
310 if ((offset
==0) || (size
==0)) {
311 // Write the word to the endpoint
312 LPC_USB
->USBTxData
= data
;
317 LPC_USB
->USBTxData
= 0;
320 // Clear WR_EN to cover zero length packet case
323 SIEselectEndpoint(endpoint
);
327 USBHAL::USBHAL(void) {
329 NVIC_DisableIRQ(USB_IRQn
);
331 // fill in callback array
332 epCallback
[0] = &USBHAL::EP1_OUT_callback
;
333 epCallback
[1] = &USBHAL::EP1_IN_callback
;
334 epCallback
[2] = &USBHAL::EP2_OUT_callback
;
335 epCallback
[3] = &USBHAL::EP2_IN_callback
;
336 epCallback
[4] = &USBHAL::EP3_OUT_callback
;
337 epCallback
[5] = &USBHAL::EP3_IN_callback
;
338 epCallback
[6] = &USBHAL::EP4_OUT_callback
;
339 epCallback
[7] = &USBHAL::EP4_IN_callback
;
340 epCallback
[8] = &USBHAL::EP5_OUT_callback
;
341 epCallback
[9] = &USBHAL::EP5_IN_callback
;
342 epCallback
[10] = &USBHAL::EP6_OUT_callback
;
343 epCallback
[11] = &USBHAL::EP6_IN_callback
;
344 epCallback
[12] = &USBHAL::EP7_OUT_callback
;
345 epCallback
[13] = &USBHAL::EP7_IN_callback
;
346 epCallback
[14] = &USBHAL::EP8_OUT_callback
;
347 epCallback
[15] = &USBHAL::EP8_IN_callback
;
348 epCallback
[16] = &USBHAL::EP9_OUT_callback
;
349 epCallback
[17] = &USBHAL::EP9_IN_callback
;
350 epCallback
[18] = &USBHAL::EP10_OUT_callback
;
351 epCallback
[19] = &USBHAL::EP10_IN_callback
;
352 epCallback
[20] = &USBHAL::EP11_OUT_callback
;
353 epCallback
[21] = &USBHAL::EP11_IN_callback
;
354 epCallback
[22] = &USBHAL::EP12_OUT_callback
;
355 epCallback
[23] = &USBHAL::EP12_IN_callback
;
356 epCallback
[24] = &USBHAL::EP13_OUT_callback
;
357 epCallback
[25] = &USBHAL::EP13_IN_callback
;
358 epCallback
[26] = &USBHAL::EP14_OUT_callback
;
359 epCallback
[27] = &USBHAL::EP14_IN_callback
;
360 epCallback
[28] = &USBHAL::EP15_OUT_callback
;
361 epCallback
[29] = &USBHAL::EP15_IN_callback
;
363 // Enable power to USB device controller
364 LPC_SC
->PCONP
|= PCUSB
;
367 LPC_USB
->USBClkCtrl
|= DEV_CLK_EN
| AHB_CLK_EN
;
368 while (LPC_USB
->USBClkSt
!= (DEV_CLK_ON
| AHB_CLK_ON
));
370 // Configure pins P0.29 and P0.30 to be USB D+ and USB D-
371 LPC_PINCON
->PINSEL1
&= 0xc3ffffff;
372 LPC_PINCON
->PINSEL1
|= 0x14000000;
374 // Disconnect USB device
377 // Configure pin P2.9 to be Connect
378 LPC_PINCON
->PINSEL4
&= 0xfffcffff;
379 LPC_PINCON
->PINSEL4
|= 0x00040000;
381 // Connect must be low for at least 2.5uS
384 // Set the maximum packet size for the control endpoints
385 realiseEndpoint(EP0IN
, MAX_PACKET_SIZE_EP0
, 0);
386 realiseEndpoint(EP0OUT
, MAX_PACKET_SIZE_EP0
, 0);
390 NVIC_SetVector(USB_IRQn
, (uint32_t)&_usbisr
);
392 // Enable interrupts for device events and EP0
393 LPC_USB
->USBDevIntEn
= EP_SLOW
| DEV_STAT
| FRAME
;
394 enableEndpointEvent(EP0IN
);
395 enableEndpointEvent(EP0OUT
);
398 USBHAL::~USBHAL(void) {
399 // Ensure device disconnected
401 // Disable USB interrupts
402 NVIC_DisableIRQ(USB_IRQn
);
405 void USBHAL::connect(void) {
406 NVIC_EnableIRQ(USB_IRQn
);
407 // Connect USB device
411 void USBHAL::disconnect(void) {
412 NVIC_DisableIRQ(USB_IRQn
);
413 // Disconnect USB device
417 void USBHAL::configureDevice(void) {
418 SIEconfigureDevice();
421 void USBHAL::unconfigureDevice(void) {
422 SIEunconfigureDevice();
425 void USBHAL::setAddress(uint8_t address
) {
426 SIEsetAddress(address
);
429 void USBHAL::EP0setup(uint8_t *buffer
) {
430 endpointReadcore(EP0OUT
, buffer
);
433 void USBHAL::EP0read(void) {
437 void USBHAL::EP0readStage(void) {
441 uint32_t USBHAL::EP0getReadResult(uint8_t *buffer
) {
442 return endpointReadcore(EP0OUT
, buffer
);
445 void USBHAL::EP0write(uint8_t *buffer
, uint32_t size
) {
446 endpointWritecore(EP0IN
, buffer
, size
);
449 void USBHAL::EP0getWriteResult(void) {
453 void USBHAL::EP0stall(void) {
454 // This will stall both control endpoints
455 stallEndpoint(EP0OUT
);
458 EP_STATUS
USBHAL::endpointRead(uint8_t endpoint
, uint32_t maximumSize
) {
462 EP_STATUS
USBHAL::endpointReadResult(uint8_t endpoint
, uint8_t * buffer
, uint32_t *bytesRead
) {
464 //for isochronous endpoint, we don't wait an interrupt
465 if ((endpoint
>> 1) % 3 || (endpoint
>> 1) == 0) {
466 if (!(epComplete
& EP(endpoint
)))
470 *bytesRead
= endpointReadcore(endpoint
, buffer
);
471 epComplete
&= ~EP(endpoint
);
475 EP_STATUS
USBHAL::endpointWrite(uint8_t endpoint
, uint8_t *data
, uint32_t size
) {
476 if (getEndpointStallState(endpoint
)) {
480 epComplete
&= ~EP(endpoint
);
482 endpointWritecore(endpoint
, data
, size
);
486 EP_STATUS
USBHAL::endpointWriteResult(uint8_t endpoint
) {
487 if (epComplete
& EP(endpoint
)) {
488 epComplete
&= ~EP(endpoint
);
495 bool USBHAL::realiseEndpoint(uint8_t endpoint
, uint32_t maxPacket
, uint32_t flags
) {
496 // Realise an endpoint
497 LPC_USB
->USBDevIntClr
= EP_RLZED
;
498 LPC_USB
->USBReEp
|= EP(endpoint
);
499 LPC_USB
->USBEpInd
= endpoint
;
500 LPC_USB
->USBMaxPSize
= maxPacket
;
502 while (!(LPC_USB
->USBDevIntSt
& EP_RLZED
));
503 LPC_USB
->USBDevIntClr
= EP_RLZED
;
506 endpointStallState
&= ~EP(endpoint
);
508 enableEndpointEvent(endpoint
);
512 void USBHAL::stallEndpoint(uint8_t endpoint
) {
514 if ( (endpoint
==EP0IN
) || (endpoint
==EP0OUT
) ) {
515 // Conditionally stall both control endpoints
516 SIEsetEndpointStatus(EP0OUT
, SIE_SES_CND_ST
);
518 SIEsetEndpointStatus(endpoint
, SIE_SES_ST
);
520 // Update stall state
521 endpointStallState
|= EP(endpoint
);
525 void USBHAL::unstallEndpoint(uint8_t endpoint
) {
526 // Unstall an endpoint. The endpoint will also be reinitialised
527 SIEsetEndpointStatus(endpoint
, 0);
529 // Update stall state
530 endpointStallState
&= ~EP(endpoint
);
533 bool USBHAL::getEndpointStallState(uint8_t endpoint
) {
534 // Returns true if endpoint stalled
535 return endpointStallState
& EP(endpoint
);
538 void USBHAL::remoteWakeup(void) {
543 LPC_USB
->USBClkCtrl
|= DEV_CLK_EN
| AHB_CLK_EN
;
544 while (LPC_USB
->USBClkSt
!= (DEV_CLK_ON
| AHB_CLK_ON
));
546 status
= SIEgetDeviceStatus();
547 SIEsetDeviceStatus(status
& ~SIE_DS_SUS
);
550 void USBHAL::_usbisr(void) {
555 void USBHAL::usbisr(void) {
558 if (LPC_USB
->USBDevIntSt
& FRAME
) {
559 // Start of frame event
560 SOF(SIEgetFrameNumber());
561 // Clear interrupt status flag
562 LPC_USB
->USBDevIntClr
= FRAME
;
565 if (LPC_USB
->USBDevIntSt
& DEV_STAT
) {
566 // Device Status interrupt
567 // Must clear the interrupt status flag before reading the device status from the SIE
568 LPC_USB
->USBDevIntClr
= DEV_STAT
;
570 // Read device status from SIE
571 devStat
= SIEgetDeviceStatus();
572 //printf("devStat: %d\r\n", devStat);
574 if (devStat
& SIE_DS_SUS_CH
) {
575 // Suspend status changed
576 if((devStat
& SIE_DS_SUS
) != 0) {
577 suspendStateChanged(0);
581 if (devStat
& SIE_DS_RST
) {
583 if((devStat
& SIE_DS_SUS
) == 0) {
584 suspendStateChanged(1);
590 if (LPC_USB
->USBDevIntSt
& EP_SLOW
) {
591 // (Slow) Endpoint Interrupt
593 // Process each endpoint interrupt
594 if (LPC_USB
->USBEpIntSt
& EP(EP0OUT
)) {
595 if (selectEndpointClearInterrupt(EP0OUT
) & SIE_SE_STP
) {
596 // this is a setup packet
601 LPC_USB
->USBDevIntClr
= EP_SLOW
;
604 if (LPC_USB
->USBEpIntSt
& EP(EP0IN
)) {
605 selectEndpointClearInterrupt(EP0IN
);
606 LPC_USB
->USBDevIntClr
= EP_SLOW
;
610 for (uint8_t num
= 2; num
< 16*2; num
++) {
611 if (LPC_USB
->USBEpIntSt
& EP(num
)) {
612 selectEndpointClearInterrupt(num
);
613 epComplete
|= EP(num
);
614 LPC_USB
->USBDevIntClr
= EP_SLOW
;
615 if ((instance
->*(epCallback
[num
- 2]))()) {
616 epComplete
&= ~EP(num
);