RT-AICHIP-sample
usbhw.c
[詳解]
1 /*----------------------------------------------------------------------------
2  * U S B - K e r n e l
3  *----------------------------------------------------------------------------
4  * Name: usbhw.c
5  * Purpose: USB Hardware Layer Module for Philips LPC17xx
6  * Version: V1.20
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.
15  *
16  * Copyright (c) 2009 Keil - An ARM Company. All rights reserved.
17  *----------------------------------------------------------------------------
18  * History:
19  * V1.20 Added USB_ClearEPBuf
20  * V1.00 Initial Version
21  *----------------------------------------------------------------------------*/
22 #include "LPC13xx.h" /* LPC13xx definitions */
23 #include "usb.h"
24 #include "usbcfg.h"
25 #include "usbreg.h"
26 #include "usbhw.h"
27 #include "usbcore.h"
28 #include "usbuser.h"
29 
30 
31 /*
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
36  * USB debugging.
37  * Parameters: None
38  * Return Value: None
39  */
40 void USBIOClkConfig( void )
41 {
42  /* Enable AHB clock to the GPIO domain. */
43  LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6);
45  //LPC_IOCON->PIO0_1 &= ~0x07;
46  //LPC_IOCON->PIO0_1 |= 0x01; /* CLK OUT */
48  /* Enable AHB clock to the USB block. */
49  LPC_SYSCON->SYSAHBCLKCTRL |= (1<<14);
51  //LPC_IOCON->PIO0_3 &= ~0x1F;
52  //LPC_IOCON->PIO0_3 |= 0x01; /* Secondary function VBUS */
53  LPC_IOCON->PIO0_3 |= 0x08; //pull down でインプットピンに設定
54  LPC_IOCON->PIO0_3 &= ~0x10;
55  LPC_GPIO0->DIR &= ~0x0008;
57  //LPC_IOCON->PIO0_6 &= ~0x07;
58  //LPC_IOCON->PIO0_6 |= 0x01; /* Secondary function SoftConn */
59  LPC_IOCON->PIO0_6 &= 0x0;
60  LPC_GPIO0->DIR |= 0x0040;
61  LPC_GPIO0->DATA &= ~0x0040;
62  return;
63 }
64 
65 /*
66  * Delay number of clock cycles
67  * Parameters: Delay length
68  * Return Value: None
69  */
70 
71 void delay (uint32_t length ) {
72  uint32_t i;
73 
74  for ( i = 0; i < length; i++ );
75  return;
76 }
77 
78 /*
79  * Get Endpoint Physical Address
80  * Parameters: EPNum: Endpoint Number
81  * EPNum.0..3: Address
82  * EPNum.7: Dir
83  * Return Value: Endpoint Physical Address
84  */
85 
87  uint32_t val;
88 
89  val = (EPNum & 0x0F) << 1;
90  if (EPNum & 0x80) {
91  val += 1;
92  }
93  return (val);
94 }
95 
96 
97 /*
98  * Write Command
99  * Parameters: cmd: Command
100  * Return Value: None
101  */
102 
103 void WrCmd (uint32_t cmd) {
104 
105  LPC_USB->DevIntClr = CCEMTY_INT;
106  LPC_USB->CmdCode = cmd;
107  while ((LPC_USB->DevIntSt & (CCEMTY_INT | DEV_STAT_INT)) == 0);
108 }
109 
110 
111 /*
112  * Write Command Data
113  * Parameters: cmd: Command
114  * val: Data
115  * Return Value: None
116  */
117 
118 void WrCmdDat (uint32_t cmd, uint32_t val) {
119 
120  WrCmd(cmd);
121  WrCmd(val);
122 }
123 
124 
125 /*
126  * Write Command to Endpoint
127  * Parameters: cmd: Command
128  * val: Data
129  * Return Value: None
130  */
131 
132 void WrCmdEP (uint32_t EPNum, uint32_t cmd){
133 
134  WrCmd(CMD_SEL_EP(EPAdr(EPNum)));
135  WrCmd(cmd);
136 }
137 
138 
139 /*
140  * Read Command Data
141  * Parameters: cmd: Command
142  * Return Value: Data Value
143  */
144 
146 
147  LPC_USB->DevIntClr = CCEMTY_INT | CDFULL_INT;
148  LPC_USB->CmdCode = cmd;
149  while ((LPC_USB->DevIntSt & (CDFULL_INT | DEV_STAT_INT)) == 0);
150  return (LPC_USB->CmdData);
151 }
152 
153 
154 /*
155  * USB Initialize Function
156  * Called by the User to initialize USB
157  * Return Value: None
158  */
159 
160 void USB_Init (void) {
161 
162 #if USB_FIQ_EVENT
163  /* It's important that only BULK and FRAME(ISO) can be routed
164  to FIQ. */
165  LPC_USB->DevFIQSel = 0x01; /* SOF Use FIQ */
166 
167  /* Enable the USB Interrupt */
168  NVIC_EnableIRQ(USB_FIQn);
169 #endif
170 
171  /* Enable the USB Interrupt */
172  NVIC_EnableIRQ(USB_IRQn);
173 
174  USB_Reset();
175  USB_SetAddress(0);
176  return;
177 }
178 
179 
180 /*
181  * USB Connect Function
182  * Called by the User to Connect/Disconnect USB
183  * Parameters: con: Connect/Disconnect
184  * Return Value: None
185  */
186 
187 void USB_Connect (uint32_t con) {
189 }
190 
191 
192 /*
193  * USB Reset Function
194  * Called automatically on USB Reset
195  * Return Value: None
196  */
197 
198 void USB_Reset (void) {
199 
200  LPC_USB->DevIntClr = 0x000FFFFF;
201  /* Enable all eight(8) EPs, note: EP won't be ready until it's
202  configured/enabled when device sending SetEPStatus command
203  to the command engine. */
204  LPC_USB->DevIntEn = DEV_STAT_INT | (0xFF<<1) |
205  (USB_SOF_EVENT ? FRAME_INT : 0);
206  return;
207 }
208 
209 
210 /*
211  * USB Suspend Function
212  * Called automatically on USB Suspend
213  * Return Value: None
214  */
215 
216 void USB_Suspend (void) {
217  /* Performed by Hardware */
218 }
219 
220 
221 /*
222  * USB Resume Function
223  * Called automatically on USB Resume
224  * Return Value: None
225  */
226 
227 void USB_Resume (void) {
228  /* Performed by Hardware */
229 }
230 
231 
232 /*
233  * USB Remote Wakeup Function
234  * Called automatically on USB Remote Wakeup
235  * Return Value: None
236  */
237 
238 void USB_WakeUp (void) {
239 
242  }
243 }
244 
245 
246 /*
247  * USB Remote Wakeup Configuration Function
248  * Parameters: cfg: Enable/Disable
249  * Return Value: None
250  */
251 
253  cfg = cfg; /* Not needed */
254 }
255 
256 
257 /*
258  * USB Set Address Function
259  * Parameters: adr: USB Address
260  * Return Value: None
261  */
262 
264  WrCmdDat(CMD_SET_ADDR, DAT_WR_BYTE(DEV_EN | adr)); /* Don't wait for next */
265  WrCmdDat(CMD_SET_ADDR, DAT_WR_BYTE(DEV_EN | adr)); /* Setup Status Phase */
266 }
267 
268 
269 /*
270  * USB Configure Function
271  * Parameters: cfg: Configure/Deconfigure
272  * Return Value: None
273  */
274 
276 
278  return;
279 }
280 
281 
282 /*
283  * Configure USB Endpoint according to Descriptor
284  * Parameters: pEPD: Pointer to Endpoint Descriptor
285  * Return Value: None
286  */
287 
288 void USB_ConfigEP (USB_ENDPOINT_DESCRIPTOR *pEPD) {
289  return;
290 }
291 
292 
293 /*
294  * Set Direction for USB Control Endpoint
295  * Parameters: dir: Out (dir == 0), In (dir <> 0)
296  * Return Value: None
297  */
298 
300  dir = dir; /* Not needed */
301 }
302 
303 
304 /*
305  * Enable USB Endpoint
306  * Parameters: EPNum: Endpoint Number
307  * EPNum.0..3: Address
308  * EPNum.7: Dir
309  * Return Value: None
310  */
311 
312 void USB_EnableEP (uint32_t EPNum) {
314 }
315 
316 
317 /*
318  * Disable USB Endpoint
319  * Parameters: EPNum: Endpoint Number
320  * EPNum.0..3: Address
321  * EPNum.7: Dir
322  * Return Value: None
323  */
324 
325 void USB_DisableEP (uint32_t EPNum) {
327 }
328 
329 
330 /*
331  * Reset USB Endpoint
332  * Parameters: EPNum: Endpoint Number
333  * EPNum.0..3: Address
334  * EPNum.7: Dir
335  * Return Value: None
336  */
337 
338 void USB_ResetEP (uint32_t EPNum) {
340 }
341 
342 
343 /*
344  * Set Stall for USB Endpoint
345  * Parameters: EPNum: Endpoint Number
346  * EPNum.0..3: Address
347  * EPNum.7: Dir
348  * Return Value: None
349  */
350 
351 void USB_SetStallEP (uint32_t EPNum) {
353 }
354 
355 
356 /*
357  * Clear Stall for USB Endpoint
358  * Parameters: EPNum: Endpoint Number
359  * EPNum.0..3: Address
360  * EPNum.7: Dir
361  * Return Value: None
362  */
363 
364 void USB_ClrStallEP (uint32_t EPNum) {
366 }
367 
368 
369 /*
370  * Clear USB Endpoint Buffer
371  * Parameters: EPNum: Endpoint Number
372  * EPNum.0..3: Address
373  * EPNum.7: Dir
374  * Return Value: None
375  */
376 
377 void USB_ClearEPBuf (uint32_t EPNum) {
378  WrCmdEP(EPNum, CMD_CLR_BUF);
379 }
380 
381 
382 /*
383  * Read USB Endpoint Data
384  * Parameters: EPNum: Endpoint Number
385  * EPNum.0..3: Address
386  * EPNum.7: Dir
387  * pData: Pointer to Data Buffer
388  * Return Value: Number of bytes read
389  */
390 
392  uint32_t cnt, n;
393 
394  LPC_USB->Ctrl = ((EPNum & 0x0F) << 2) | CTRL_RD_EN;
395  /* 3 clock cycles to fetch the packet length from RAM. */
396  delay( 5 );
397 
398  do {
399  cnt = LPC_USB->RxPLen;
400  } while ((cnt & PKT_DV) == 0);
401  cnt &= PKT_LNGTH_MASK;
402 
403  for (n = 0; n < (cnt + 3) / 4; n++) {
404  *((uint32_t __attribute__((packed)) *)pData) = LPC_USB->RxData;
405  pData += 4;
406  }
407 
408  LPC_USB->Ctrl = 0;
409 
410  if ((EPNum & 0x80) != 0x04) { /* Non-Isochronous Endpoint */
411  WrCmdEP(EPNum, CMD_CLR_BUF);
412  }
413 
414  return (cnt);
415 }
416 
417 
418 /*
419  * Write USB Endpoint Data
420  * Parameters: EPNum: Endpoint Number
421  * EPNum.0..3: Address
422  * EPNum.7: Dir
423  * pData: Pointer to Data Buffer
424  * cnt: Number of bytes to write
425  * Return Value: Number of bytes written
426  */
427 
429  uint32_t n;
430 
431  LPC_USB->Ctrl = ((EPNum & 0x0F) << 2) | CTRL_WR_EN;
432  /* 3 clock cycles to fetch the packet length from RAM. */
433  delay( 5 );
434  LPC_USB->TxPLen = cnt;
435 
436  for (n = 0; n < (cnt + 3) / 4; n++) {
437  LPC_USB->TxData = *((uint32_t __attribute__((packed)) *)pData);
438  pData += 4;
439  }
440 
441  LPC_USB->Ctrl = 0;
442 
443  WrCmdEP(EPNum, CMD_VALID_BUF);
444 
445  return (cnt);
446 }
447 
448 /*
449  * Get USB Last Frame Number
450  * Parameters: None
451  * Return Value: Frame Number
452  */
453 
455  uint32_t val;
456 
458  val = RdCmdDat(DAT_RD_FRAME);
459  val = val | (RdCmdDat(DAT_RD_FRAME) << 8);
460 
461  return (val);
462 }
463 
464 
465 /*
466  * USB Interrupt Service Routine
467  */
468 
469 void USB_IRQHandler (void)
470 {
471  uint32_t disr, val, n, m;
472 
473  disr = LPC_USB->DevIntSt; /* Device Interrupt Status */
474  LPC_USB->DevIntClr = disr;
475 
476  /* Device Status Interrupt (Reset, Connect change, Suspend/Resume) */
477  if (disr & DEV_STAT_INT) {
479  val = RdCmdDat(DAT_GET_DEV_STAT); /* Device Status */
480  if (val & DEV_RST) { /* Reset */
481  USB_Reset();
482 #if USB_RESET_EVENT
483  USB_Reset_Event();
484 #endif
485  }
486  if (val & DEV_CON_CH) { /* Connect change */
487 #if USB_POWER_EVENT
488  USB_Power_Event(val & DEV_CON);
489 #endif
490  }
491  if (val & DEV_SUS_CH) { /* Suspend/Resume */
492  if (val & DEV_SUS) { /* Suspend */
493  USB_Suspend();
494 #if USB_SUSPEND_EVENT
496 #endif
497  } else { /* Resume */
498  USB_Resume();
499 #if USB_RESUME_EVENT
501 #endif
502  }
503  }
504  goto isr_end;
505  }
506 
507 #if USB_SOF_EVENT
508  /* Start of Frame Interrupt */
509  if (disr & FRAME_INT) {
510  LPC_USB->DevIntClr = FRAME_INT;
511  USB_SOF_Event();
512  SOFIRQCount++;
513  }
514 #endif
515 
516 #if USB_ERROR_EVENT
517  /* NO error interrupt anymore, below code can be used
518  as example to get error status from command engine. */
519  /* Error Interrupt */
520  if (disr & ERR_INT) {
521  WrCmd(CMD_RD_ERR_STAT);
522  val = RdCmdDat(DAT_RD_ERR_STAT);
523  USB_Error_Event(val);
524  }
525 #endif
526 
527  /* Endpoint's Interrupt */
528  if (disr & (0xFF<<1)) {
529  /* if any of the EP0 through EP7 is set, or bit 1 through 9 on disr */
530  for (n = 0; n < USB_EP_NUM; n++) { /* Check All Endpoints */
531  /* skip frame interrupt at bit 0 in disr */
532 // if (disr & ((1 << n)<<1)) {
533  if ((disr>>1) & (1 << n)) {
534  m = n >> 1;
535  /* clear EP interrupt by sending cmd to the command engine. */
537  val = RdCmdDat(DAT_SEL_EP_CLRI(n));
538  if ((n & 1) == 0) { /* OUT Endpoint */
539  if (n == 0) { /* Control OUT Endpoint */
540  if (val & EP_SEL_STP) { /* Setup Packet */
541  if (USB_P_EP[0]) {
543  continue;
544  }
545  }
546  }
547  if (USB_P_EP[m]) {
548  USB_P_EP[m](USB_EVT_OUT);
549  }
550  } else { /* IN Endpoint */
551  if (USB_P_EP[m]) {
552  USB_P_EP[m](USB_EVT_IN);
553  }
554  }
555  }
556  }
557  }
558 isr_end:
559  return;
560 }
561 
562 
564 void USB_IRQ (void)
565 {
566  uint32_t disr, val, n, m;
567 
568  disr = LPC_USB->DevIntSt; /* Device Interrupt Status */
569  LPC_USB->DevIntClr = disr;
570 
571  /* Device Status Interrupt (Reset, Connect change, Suspend/Resume) */
572  if (disr & DEV_STAT_INT) {
574  val = RdCmdDat(DAT_GET_DEV_STAT); /* Device Status */
575  if (val & DEV_RST) { /* Reset */
576  USB_Reset();
577 #if USB_RESET_EVENT
578  USB_Reset_Event();
579 #endif
580  }
581  if (val & DEV_CON_CH) { /* Connect change */
582 #if USB_POWER_EVENT
583  USB_Power_Event(val & DEV_CON);
584 #endif
585  }
586  if (val & DEV_SUS_CH) { /* Suspend/Resume */
587  if (val & DEV_SUS) { /* Suspend */
588  USB_Suspend();
589 #if USB_SUSPEND_EVENT
591 #endif
592  } else { /* Resume */
593  USB_Resume();
594 #if USB_RESUME_EVENT
596 #endif
597  }
598  }
599  goto isr_end;
600  }
601 
602 #if USB_SOF_EVENT
603  /* Start of Frame Interrupt */
604  if (disr & FRAME_INT) {
605  LPC_USB->DevIntClr = FRAME_INT;
606  USB_SOF_Event();
607  SOFIRQCount++;
608  }
609 #endif
610 
611 #if USB_ERROR_EVENT
612  /* NO error interrupt anymore, below code can be used
613  as example to get error status from command engine. */
614  /* Error Interrupt */
615  if (disr & ERR_INT) {
616  WrCmd(CMD_RD_ERR_STAT);
617  val = RdCmdDat(DAT_RD_ERR_STAT);
618  USB_Error_Event(val);
619  }
620 #endif
621 
622  /* Endpoint's Interrupt */
623  if (disr & (0xFF<<1)) {
624  /* if any of the EP0 through EP7 is set, or bit 1 through 9 on disr */
625  for (n = 0; n < USB_EP_NUM; n++) { /* Check All Endpoints */
626  /* skip frame interrupt at bit 0 in disr */
627 // if (disr & ((1 << n)<<1)) {
628  if ((disr>>1) & (1 << n)) {
629  m = n >> 1;
630  /* clear EP interrupt by sending cmd to the command engine. */
632  val = RdCmdDat(DAT_SEL_EP_CLRI(n));
633  if ((n & 1) == 0) { /* OUT Endpoint */
634  if (n == 0) { /* Control OUT Endpoint */
635  if (val & EP_SEL_STP) { /* Setup Packet */
636  if (USB_P_EP[0]) {
638  continue;
639  }
640  }
641  }
642  if (USB_P_EP[m]) {
643  USB_P_EP[m](USB_EVT_OUT);
644  }
645  } else { /* IN Endpoint */
646  if (USB_P_EP[m]) {
647  USB_P_EP[m](USB_EVT_IN);
648  }
649  }
650  }
651  }
652  }
653 isr_end:
654  return;
655 }
656 
657 
void USB_Configure(uint32_t cfg)
Definition: usbhw.c:275
#define DAT_RD_FRAME
Definition: usbreg.h:54
void USB_ResetEP(uint32_t EPNum)
Definition: usbhw.c:338
void USB_EnableEP(uint32_t EPNum)
Definition: usbhw.c:312
uint32_t USB_ReadEP(uint32_t EPNum, uint8_t *pData)
Definition: usbhw.c:391
void USB_SOF_Event(void)
#define CMD_CFG_DEV
Definition: usbreg.h:49
#define DEV_SUS
Definition: usbreg.h:90
uint32_t EPAdr(uint32_t EPNum)
Definition: usbhw.c:86
void WrCmdDat(uint32_t cmd, uint32_t val)
Definition: usbhw.c:118
void USB_Suspend_Event(void)
void USB_ConfigEP(USB_ENDPOINT_DESCRIPTOR *pEPD)
Definition: usbhw.c:288
#define EP_STAT_DA
Definition: usbreg.h:127
#define CMD_RD_FRAME
Definition: usbreg.h:53
void USB_Power_Event(uint32_t power)
#define DAT_GET_DEV_STAT
Definition: usbreg.h:60
void(*const USB_P_EP[USB_LOGIC_EP_NUM])(uint32_t event)
Definition: usbuser.c:148
#define CMD_CLR_BUF
Definition: usbreg.h:70
#define PKT_LNGTH_MASK
Definition: usbreg.h:39
uint32_t RdCmdDat(uint32_t cmd)
Definition: usbhw.c:145
void USB_DisableEP(uint32_t EPNum)
Definition: usbhw.c:325
#define CDFULL_INT
Definition: usbreg.h:34
void USB_Init(void)
Definition: usbhw.c:160
void USB_Reset(void)
Definition: usbhw.c:198
#define USB_SOF_EVENT
Definition: usbcfg.h:104
void USB_Resume_Event(void)
#define DEV_SUS_CH
Definition: usbreg.h:91
#define CMD_SET_DEV_STAT
Definition: usbreg.h:58
uint32_t USB_GetFrame(void)
Definition: usbhw.c:454
void USB_SetAddress(uint32_t adr)
Definition: usbhw.c:263
void USB_IRQ(void)
Definition: usbhw.c:564
#define DEV_CON
Definition: usbreg.h:88
#define PKT_DV
Definition: usbreg.h:40
unsigned char uint8_t
Definition: type.h:27
#define DAT_WR_BYTE(x)
Definition: usbreg.h:64
void USB_Suspend(void)
Definition: usbhw.c:216
uint32_t USB_WriteEP(uint32_t EPNum, uint8_t *pData, uint32_t cnt)
Definition: usbhw.c:428
void USBIOClkConfig(void)
Definition: usbhw.c:40
void USB_ClearEPBuf(uint32_t EPNum)
Definition: usbhw.c:377
void delay(uint32_t length)
Definition: usbhw.c:71
void USB_Connect(uint32_t con)
Definition: usbhw.c:187
#define EP_SEL_STP
Definition: usbreg.h:119
#define USB_EVT_SETUP
Definition: usbuser.h:33
void USB_IRQHandler(void)
Definition: usbhw.c:469
void WrCmdEP(uint32_t EPNum, uint32_t cmd)
Definition: usbhw.c:132
#define DEV_EN
Definition: usbreg.h:75
#define CMD_SET_ADDR
Definition: usbreg.h:48
#define CMD_VALID_BUF
Definition: usbreg.h:71
#define CTRL_RD_EN
Definition: usbreg.h:44
#define EP_STAT_ST
Definition: usbreg.h:126
void USB_SetStallEP(uint32_t EPNum)
Definition: usbhw.c:351
#define DEV_STAT_INT
Definition: usbreg.h:32
#define CCEMTY_INT
Definition: usbreg.h:33
#define CMD_GET_DEV_STAT
Definition: usbreg.h:59
#define CTRL_WR_EN
Definition: usbreg.h:45
void USB_DirCtrlEP(uint32_t dir)
Definition: usbhw.c:299
#define CMD_SEL_EP_CLRI(x)
Definition: usbreg.h:67
#define DEV_CON_CH
Definition: usbreg.h:89
void USB_WakeUpCfg(uint32_t cfg)
Definition: usbhw.c:252
#define CONF_DVICE
Definition: usbreg.h:78
#define DEV_RST
Definition: usbreg.h:92
void WrCmd(uint32_t cmd)
Definition: usbhw.c:103
#define USB_EVT_IN
Definition: usbuser.h:35
typedef __attribute__
#define CMD_SEL_EP(x)
Definition: usbreg.h:65
#define USB_EP_NUM
Definition: usbcfg.h:59
void USB_WakeUp(void)
Definition: usbhw.c:238
void USB_Reset_Event(void)
void USB_ClrStallEP(uint32_t EPNum)
Definition: usbhw.c:364
#define CMD_SET_EP_STAT(x)
Definition: usbreg.h:69
#define FRAME_INT
Definition: usbreg.h:23
void USB_Resume(void)
Definition: usbhw.c:227
#define USB_GETSTATUS_REMOTE_WAKEUP
Definition: usb.h:73
#define USB_EVT_OUT
Definition: usbuser.h:34
void USB_Error_Event(uint32_t error)
#define DAT_SEL_EP_CLRI(x)
Definition: usbreg.h:68
unsigned int uint32_t
Definition: type.h:29
uint16_t USB_DeviceStatus
Definition: usbcore.c:62