EFM32 Happy Gecko Software Documentation  efm32hg-doc-5.1.2
em_usbdint.c
Go to the documentation of this file.
1 /**************************************************************************/
16 #include "em_device.h"
17 #if defined( USB_PRESENT ) && ( USB_COUNT == 1 )
18 #include "em_usb.h"
19 #if defined( USB_DEVICE )
20 
21 #include "em_cmu.h"
22 #include "em_core.h"
23 #include "em_usbtypes.h"
24 #include "em_usbhal.h"
25 #include "em_usbd.h"
26 
29 #define HANDLE_INT( x ) if ( status & x ) { Handle_##x(); status &= ~x; }
30 
31 static void Handle_USB_GINTSTS_ENUMDONE ( void );
32 static void Handle_USB_GINTSTS_IEPINT ( void );
33 static void Handle_USB_GINTSTS_OEPINT ( void );
34 static void Handle_USB_GINTSTS_RESETDET ( void );
35 static void Handle_USB_GINTSTS_SOF ( void );
36 static void Handle_USB_GINTSTS_USBRST ( void );
37 static void Handle_USB_GINTSTS_USBSUSP ( void );
38 static void Handle_USB_GINTSTS_WKUPINT ( void );
39 #if defined( USB_DOEP0INT_STUPPKTRCVD )
40 static void HandleOutEpIntr( uint32_t status, USBD_Ep_TypeDef *ep );
41 #else
42 static void ProcessSetup ( void );
43 static void ProcessOepData ( USBD_Ep_TypeDef *ep );
44 #endif
45 
46 #if ( USB_PWRSAVE_MODE )
47 /* Variables and prototypes for USB powerdown (suspend) functionality. */
48 static bool UsbPowerDown( void );
49 static bool UsbPowerUp( void );
50 static void RestoreEpCtrlRegisters(void);
51 
52 volatile bool USBD_poweredDown = false;
53 
54 /* Storage for backing up USB core registers. */
55 static uint32_t x_USB_GINTMSK;
56 #if defined(_USB_GOTGCTL_MASK)
57 static uint32_t x_USB_GOTGCTL;
58 #endif
59 static uint32_t x_USB_GAHBCFG;
60 static uint32_t x_USB_GUSBCFG;
61 static uint32_t x_USB_GRXFSIZ;
62 static uint32_t x_USB_GNPTXFSIZ;
63 static uint32_t x_USB_DCFG;
64 static uint32_t x_USB_DCTL;
65 static uint32_t x_USB_DAINTMSK;
66 static uint32_t x_USB_DIEPMSK;
67 static uint32_t x_USB_DOEPMSK;
68 static uint32_t x_USB_PCGCCTL;
69 
70 #if ( NUM_EP_USED > 0 )
71 static uint32_t x_USB_EP_CTL[ NUM_EP_USED ];
72 static uint32_t x_USB_EP_TSIZ[ NUM_EP_USED ];
73 static uint32_t x_USB_EP_DMAADDR[ NUM_EP_USED ];
74 #endif
75 
76 #if ( NUM_EP_USED > MAX_NUM_TX_FIFOS )
77 #define FIFO_CNT MAX_NUM_TX_FIFOS
78 #else
79 #define FIFO_CNT NUM_EP_USED
80 #endif
81 
82 #if ( FIFO_CNT > 0 )
83 static uint32_t x_USB_DIEPTXFS[ FIFO_CNT ];
84 #endif
85 
86 #if ( USB_PWRSAVE_MODE )
87 static uint32_t cmuStatus = 0;
88 #endif
89 
90 #endif /* if ( USB_PWRSAVE_MODE ) */
91 
92 /*
93  * USB_IRQHandler() is the first level handler for the USB peripheral interrupt.
94  */
95 void USB_IRQHandler( void )
96 {
97  uint32_t status;
98  bool servedVbusInterrupt = false;
100 
102 
103 #if ( USB_PWRSAVE_MODE )
104  if ( USBD_poweredDown )
105  {
106  /* Switch USBC clock from 32kHz to a 48MHz clock to be able to */
107  /* read USB peripheral registers. */
108  /* If we woke up from EM2, HFCLK is now HFRCO. */
109 
110  /* Restore clock oscillators.*/
111 #if defined( CMU_OSCENCMD_USHFRCOEN )
112  if ( ( CMU->STATUS & CMU_STATUS_USHFRCOENS ) == 0 )/*Wakeup from EM2 ?*/
113  {
114  CMU->OSCENCMD = ( cmuStatus
117  }
118 #else
119  if ( ( CMU->STATUS & CMU_STATUS_HFXOENS ) == 0 ) /* Wakeup from EM2 ? */
120  {
121  CMU->OSCENCMD = cmuStatus
123  }
124 #endif
125 
126  /* Select correct USBC clock.*/
127 #if defined( CMU_OSCENCMD_USHFRCOEN )
129  while ( ( CMU->STATUS & CMU_STATUS_USBCUSHFRCOSEL ) == 0 ){}
130 #else
131  CMU->CMD = CMU_CMD_USBCCLKSEL_HFCLKNODIV;
132  while ( ( CMU->STATUS & CMU_STATUS_USBCHFCLKSEL ) == 0 ){}
133 #endif
134  }
135 #endif /* if ( USB_PWRSAVE_MODE ) */
136 
137  if ( USB->IF && ( USB->CTRL & USB_CTRL_VREGOSEN ) )
138  {
139  if ( USB->IF & USB_IF_VREGOSH )
140  {
141  USB->IFC = USB_IFC_VREGOSH;
142 
143  if ( USB->STATUS & USB_STATUS_VREGOS )
144  {
145  servedVbusInterrupt = true;
146  DEBUG_USB_INT_LO_PUTS( "\nVboN" );
147 
148 #if ( USB_PWRSAVE_MODE )
149  if ( UsbPowerUp() )
150  {
151  USBDHAL_EnableUsbResetAndSuspendInt();
152  }
153  USBD_SetUsbState( USBD_STATE_POWERED );
154 #endif
155  }
156  }
157 
158  if ( USB->IF & USB_IF_VREGOSL )
159  {
160  USB->IFC = USB_IFC_VREGOSL;
161 
162  if ( ( USB->STATUS & USB_STATUS_VREGOS ) == 0 )
163  {
164  servedVbusInterrupt = true;
165  DEBUG_USB_INT_LO_PUTS( "\nVboF" );
166 
167 #if ( USB_PWRSAVE_MODE )
168 #if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF )
169  if ( !USBD_poweredDown )
170  {
171  USB->GINTMSK = 0;
172  USB->GINTSTS = 0xFFFFFFFF;
173  }
174 
175  UsbPowerDown();
176 #endif
177  USBD_SetUsbState( USBD_STATE_NONE );
178 #endif
179  }
180  }
181  }
182 
183  status = USBHAL_GetCoreInts();
184  if ( status == 0 )
185  {
187  if ( !servedVbusInterrupt )
188  {
189  DEBUG_USB_INT_LO_PUTS( "\nSinT" );
190  }
191  return;
192  }
193 
194  HANDLE_INT( USB_GINTSTS_RESETDET )
195  HANDLE_INT( USB_GINTSTS_WKUPINT )
196  HANDLE_INT( USB_GINTSTS_USBSUSP )
197  HANDLE_INT( USB_GINTSTS_SOF )
198  HANDLE_INT( USB_GINTSTS_ENUMDONE )
199  HANDLE_INT( USB_GINTSTS_USBRST )
200  HANDLE_INT( USB_GINTSTS_IEPINT )
201  HANDLE_INT( USB_GINTSTS_OEPINT )
202 
204 
205  if ( status != 0 )
206  {
207  DEBUG_USB_INT_LO_PUTS( "\nUinT" );
208  }
209 }
210 
211 /*
212  * Handle port enumeration interrupt. This has nothing to do with normal
213  * device enumeration.
214  */
215 static void Handle_USB_GINTSTS_ENUMDONE( void )
216 {
217 #if ( USB_PWRSAVE_MODE )
218  UsbPowerUp();
219 #endif
220 
221  USBDHAL_Ep0Activate( dev->ep0MpsCode );
222  dev->ep[ 0 ].state = D_EP_IDLE;
223  USBDHAL_EnableInts( dev );
224  DEBUG_USB_INT_LO_PUTS( "EnumD" );
225 }
226 
227 /*
228  * Handle IN endpoint transfer interrupt.
229  */
230 static void Handle_USB_GINTSTS_IEPINT( void )
231 {
232  int epnum;
233  uint16_t epint;
234  uint16_t epmask;
235  uint32_t status;
236  USBD_Ep_TypeDef *ep;
237 
238  DEBUG_USB_INT_HI_PUTCHAR( 'i' );
239 
240  // If we came here from suspended state, set correct state
242  {
243  USBD_SetUsbState( dev->savedState );
244  }
245 
246  epint = USBDHAL_GetAllInEpInts();
247  for ( epnum = 0, epmask = 1;
248  epnum <= MAX_NUM_IN_EPS;
249  epnum++, epmask <<= 1 )
250  {
251  if ( epint & epmask )
252  {
253  ep = USBD_GetEpFromAddr( USB_SETUP_DIR_MASK | epnum );
254  status = USBDHAL_GetInEpInts( ep );
255 
256  if ( status & USB_DIEP_INT_XFERCOMPL )
257  {
258  USB_DINEPS[ epnum ].INT = USB_DIEP_INT_XFERCOMPL;
259 
260  DEBUG_USB_INT_HI_PUTCHAR( 'c' );
261 
262  if ( epnum == 0 )
263  {
264  if ( ep->remaining > ep->packetSize )
265  {
266  ep->remaining -= ep->packetSize;
267  ep->xferred += ep->packetSize;
268  }
269  else
270  {
271  ep->xferred += ep->remaining;
272  ep->remaining = 0;
273  }
274  USBDEP_Ep0Handler( dev );
275  }
276  else
277  {
278  ep->xferred = ep->remaining -
279  ( ( USB_DINEPS[ epnum ].TSIZ &
282  ep->remaining -= ep->xferred;
283 
284  USBDEP_EpHandler( ep->addr );
285 #if defined( USB_DOEP0INT_STUPPKTRCVD )
286  if ( USB_DINEPS[ ep->num ].INT & USB_DIEP_INT_NAKINTRPT )
287  {
288  USB_DINEPS[ ep->num ].INT = USB_DIEP_INT_NAKINTRPT;
289  }
290 #endif
291  }
292  }
293  }
294  }
295 }
296 
297 /*
298  * Handle OUT endpoint transfer interrupt.
299  */
300 static void Handle_USB_GINTSTS_OEPINT( void )
301 {
302  int epnum;
303  uint16_t epint;
304  uint16_t epmask;
305  uint32_t status;
306  USBD_Ep_TypeDef *ep;
307 
308  DEBUG_USB_INT_HI_PUTCHAR( 'o' );
309 
310  // If we came here from suspended state, set correct state
312  {
313  USBD_SetUsbState( dev->savedState );
314  }
315 
316  epint = USBDHAL_GetAllOutEpInts();
317  for ( epnum = 0, epmask = 1;
318  epnum <= MAX_NUM_OUT_EPS;
319  epnum++, epmask <<= 1 )
320  {
321  if ( epint & epmask )
322  {
323  ep = USBD_GetEpFromAddr( epnum );
324  status = USBDHAL_GetOutEpInts( ep );
325 
326 #if defined( USB_DOEP0INT_STUPPKTRCVD )
327  HandleOutEpIntr( status, ep );
328 #else
329  if ( status & USB_DOEP_INT_XFERCOMPL )
330  {
331  USB_DOUTEPS[ epnum ].INT = USB_DOEP_INT_XFERCOMPL;
332  DEBUG_USB_INT_HI_PUTCHAR( 'c' );
333  ProcessOepData( ep );
334  }
335 
336  /* Setup Phase Done */
337  if ( status & USB_DOEP0INT_SETUP )
338  {
339  ProcessSetup();
340  }
341 #endif
342  }
343  }
344 }
345 
346 #if !defined( USB_DOEP0INT_STUPPKTRCVD )
347 static void ProcessOepData( USBD_Ep_TypeDef *ep )
348 {
349  if ( ep->num == 0 )
350  {
351  if ( ep->remaining > ep->packetSize )
352  {
353  ep->remaining -= ep->packetSize;
354  ep->xferred += ep->packetSize;
355  }
356  else
357  {
358  ep->xferred += ep->remaining;
359  ep->remaining = 0;
360  }
361  USBDEP_Ep0Handler( dev );
362  }
363  else
364  {
365  ep->xferred = ep->hwXferSize -
366  ( ( USB_DOUTEPS[ ep->num ].TSIZ & _USB_DOEP_TSIZ_XFERSIZE_MASK )>>
368  ep->remaining -= ep->xferred;
369  USBDEP_EpHandler( ep->addr );
370  }
371 }
372 #endif
373 
374 #if !defined( USB_DOEP0INT_STUPPKTRCVD )
375 static void ProcessSetup( void )
376 {
377  DEBUG_USB_INT_LO_PUTS( "\nS" );
378 
379  if ( USB->DOEP0INT & USB_DOEP0INT_BACK2BACKSETUP )
380  { /* Back to back setup packets received */
381  USB->DOEP0INT = USB_DOEP0INT_BACK2BACKSETUP;
382  DEBUG_USB_INT_LO_PUTS( "B2B" );
383 
384  dev->setup = (USB_Setup_TypeDef*)( USB->DOEP0DMAADDR - USB_SETUP_PKT_SIZE );
385  }
386  else
387  {
388  /* Read SETUP packet counter from hw. */
389  int supCnt = ( USB->DOEP0TSIZ & _USB_DOEP0TSIZ_SUPCNT_MASK )
391 
392  if ( supCnt == 3 )
393  supCnt = 2;
394 
395  dev->setup = &dev->setupPkt[ 2 - supCnt ];
396  }
397  USB->DOEP0TSIZ |= 3 << _USB_DOEP0TSIZ_SUPCNT_SHIFT;
398  USB->DOEP0DMAADDR = (uint32_t)dev->setupPkt;
399  USB->DOEP0INT = USB_DOEP0INT_SETUP;
400 
401  USBDEP_Ep0Handler( dev ); /* Call the SETUP handler for EP0 */
402 }
403 #endif
404 
405 /*
406  * Handle USB reset detected interrupt in suspend mode.
407  */
408 static void Handle_USB_GINTSTS_RESETDET ( void )
409 {
410 #if ( USB_PWRSAVE_MODE )
411  if ( ! USBD_poweredDown )
412  {
413  USB->GINTSTS = USB_GINTSTS_RESETDET;
414  }
415 
416  if ( UsbPowerUp() )
417  {
418  USB->GINTSTS = USB_GINTSTS_RESETDET;
419  }
420 
421 #if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF )
422  /* Power down immediately if VBUS is off. */
423  if ( ! ( USB->STATUS & USB_STATUS_VREGOS ) )
424  {
425  UsbPowerDown();
426  }
427 #endif
428 
429 #else
430  USB->GINTSTS = USB_GINTSTS_RESETDET;
431 #endif /* if ( USB_PWRSAVE_MODE ) */
432 
433  if ( USB->STATUS & USB_STATUS_VREGOS )
434  {
435  USBD_SetUsbState( USBD_STATE_DEFAULT );
436  }
437  else
438  {
439  USBD_SetUsbState( USBD_STATE_NONE );
440  }
441  DEBUG_USB_INT_LO_PUTS( "RsuP\n" );
442 }
443 
444 /*
445  * Handle Start Of Frame (SOF) interrupt.
446  */
447 static void Handle_USB_GINTSTS_SOF( void )
448 {
449  USB->GINTSTS = USB_GINTSTS_SOF;
450 
451  if ( dev->callbacks->sofInt )
452  {
453  dev->callbacks->sofInt(
455  }
456 }
457 
458 /*
459  * Handle USB port reset interrupt.
460  */
461 static void Handle_USB_GINTSTS_USBRST( void )
462 {
463  int i;
464 
465  DEBUG_USB_INT_LO_PUTS( "ReseT" );
466 
467  /* Clear Remote Wakeup Signalling */
468  USB->DCTL &= ~( DCTL_WO_BITMASK | USB_DCTL_RMTWKUPSIG );
469  USBHAL_FlushTxFifo( 0 );
470 
471  /* Clear pending interrupts */
472  for ( i = 0; i <= MAX_NUM_IN_EPS; i++ )
473  {
474  USB_DINEPS[ i ].INT = 0xFFFFFFFF;
475  }
476 
477  for ( i = 0; i <= MAX_NUM_OUT_EPS; i++ )
478  {
479  USB_DOUTEPS[ i ].INT = 0xFFFFFFFF;
480  }
481 
483 #if defined( USB_DOEPMSK_STSPHSERCVDMSK )
486 #else
488 #endif
489  USB->DIEPMSK = USB_DIEPMSK_XFERCOMPLMSK;
490 
491  /* Reset Device Address */
492  USB->DCFG &= ~_USB_DCFG_DEVADDR_MASK;
493 
494  /* Setup EP0 to receive SETUP packets */
495  USBDHAL_StartEp0Setup( dev );
496  USBDHAL_EnableInts( dev );
497 
498  if ( dev->callbacks->usbReset )
499  {
500  dev->callbacks->usbReset();
501  }
502 
503  USBD_SetUsbState( USBD_STATE_DEFAULT );
504  USBDHAL_AbortAllTransfers( USB_STATUS_DEVICE_RESET );
505 }
506 
507 /*
508  * Handle USB port suspend interrupt.
509  */
510 static void Handle_USB_GINTSTS_USBSUSP( void )
511 {
512  USBD_State_TypeDef state;
513 
514  USB->GINTSTS = USB_GINTSTS_USBSUSP;
515  USBDHAL_AbortAllTransfers( USB_STATUS_DEVICE_SUSPENDED );
516  DEBUG_USB_INT_LO_PUTS( "\nSusP" );
517 
519  {
520  USBD_SetUsbState( USBD_STATE_POWERED );
521  }
522 
523  state = USBD_GetUsbState();
524  if ( ( state == USBD_STATE_POWERED ) ||
525  ( state == USBD_STATE_DEFAULT ) ||
526  ( state == USBD_STATE_ADDRESSED ) ||
527  ( state == USBD_STATE_CONFIGURED ) )
528  {
529 #if ( USB_PWRSAVE_MODE )
530  UsbPowerDown();
531 #endif
532  USBD_SetUsbState( USBD_STATE_SUSPENDED );
533  }
534 }
535 
536 /*
537  * Handle USB port wakeup interrupt.
538  */
539 static void Handle_USB_GINTSTS_WKUPINT( void )
540 {
541 #if ( USB_PWRSAVE_MODE )
542  if ( ! USBD_poweredDown )
543  {
544  USB->GINTSTS = USB_GINTSTS_WKUPINT;
545  }
546 
547  if ( UsbPowerUp() )
548  {
549  USB->GINTSTS = USB_GINTSTS_WKUPINT;
550  USBDHAL_StartEp0Setup( dev );
551  USBDHAL_Ep0Activate( dev->ep0MpsCode );
552  }
553 #else
554  USB->GINTSTS = USB_GINTSTS_WKUPINT;
555 #endif
556 
557  USBD_SetUsbState( dev->savedState );
558  DEBUG_USB_INT_LO_PUTS( "WkuP\n" );
559 }
560 
561 #if ( USB_PWRSAVE_MODE )
562 /*
563  * Backup essential USB core registers, and set the core in partial powerdown
564  * mode. Optionally prepare entry into EM2.
565  */
566 static bool UsbPowerDown( void )
567 {
568 #if ( NUM_EP_USED > 0 ) || ( FIFO_CNT > 0 )
569  int i;
570 #endif
571 #if ( NUM_EP_USED > 0 )
572  int epNum;
573  USBD_Ep_TypeDef *ep;
574 #endif
575 
576  if ( !USBD_poweredDown )
577  {
578  USBD_poweredDown = true;
579  DEBUG_USB_INT_LO_PUTCHAR( '\\' );
580 
581  /* Backup USB core registers. */
582  x_USB_GINTMSK = USB->GINTMSK;
583 #if defined(_USB_GOTGCTL_MASK)
584  x_USB_GOTGCTL = USB->GOTGCTL;
585 #endif
586  x_USB_GAHBCFG = USB->GAHBCFG;
587  x_USB_GUSBCFG = USB->GUSBCFG;
588  x_USB_GRXFSIZ = USB->GRXFSIZ;
589  x_USB_GNPTXFSIZ = USB->GNPTXFSIZ;
590  x_USB_DCFG = USB->DCFG;
591  x_USB_DCTL = USB->DCTL;
592  x_USB_DAINTMSK = USB->DAINTMSK;
593  x_USB_DIEPMSK = USB->DIEPMSK;
594  x_USB_DOEPMSK = USB->DOEPMSK;
595  x_USB_PCGCCTL = USB->PCGCCTL;
596 
597 #if ( NUM_EP_USED > 0 )
598  for ( i = 0; i < NUM_EP_USED; i++ )
599  {
600  ep = &dev->ep[ i+1 ];
601  epNum = ep->num;
602  if ( ep->in )
603  {
604  x_USB_EP_CTL[ i ] = USB_DINEPS[ epNum ].CTL;
605  x_USB_EP_TSIZ[ i ] = USB_DINEPS[ epNum ].TSIZ;
606  x_USB_EP_DMAADDR[ i ] = USB_DINEPS[ epNum ].DMAADDR;
607  }
608  else
609  {
610  x_USB_EP_CTL[ i ] = USB_DOUTEPS[ epNum ].CTL;
611  x_USB_EP_TSIZ[ i ] = USB_DOUTEPS[ epNum ].TSIZ;
612  x_USB_EP_DMAADDR[ i ] = USB_DOUTEPS[ epNum ].DMAADDR;
613  }
614  }
615 #endif
616 
617 #if ( FIFO_CNT > 0 )
618  for ( i = 0; i < FIFO_CNT; i++ )
619  {
620  x_USB_DIEPTXFS[ i ] = USB_DIEPTXFS[ i ];
621  }
622 #endif
623 
624  /* Prepare for wakeup on resume and reset. */
625  USB->DCFG = (USB->DCFG & ~_USB_DCFG_RESVALID_MASK) |
627  USB->DCFG |= USB_DCFG_ENA32KHZSUSP;
629 
630  /* Enter partial powerdown mode. */
631  USB->PCGCCTL |= USB_PCGCCTL_PWRCLMP;
632  USB->PCGCCTL |= USB_PCGCCTL_RSTPDWNMODULE;
633  USB->PCGCCTL |= USB_PCGCCTL_STOPPCLK;
634 
635  /* Record current clock settings. */
636  cmuStatus = CMU->STATUS;
637 
638 #if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ENTEREM2 )
639  /* Enter EM2 on interrupt exit. */
640  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk;
641 #endif
642 
643  /* Switch USBC clock to 32 kHz. */
644 #if ( USB_USBC_32kHz_CLK == USB_USBC_32kHz_CLK_LFXO )
646  while ( ( CMU->STATUS & CMU_STATUS_USBCLFXOSEL ) == 0 ){}
647 #else
649  while ( ( CMU->STATUS & CMU_STATUS_USBCLFRCOSEL ) == 0 ){}
650 #endif
651 
652  return true;
653  }
654  return false;
655 }
656 #endif /* if ( USB_PWRSAVE_MODE ) */
657 
658 #if ( USB_PWRSAVE_MODE )
659 /*
660  * Exit USB core partial powerdown mode, restore essential USB core registers.
661  * Will prevent re-entry back to EM2.
662  * Returns true if a powerup sequence was performed.
663  */
664 static bool UsbPowerUp( void )
665 {
666  if ( USBD_poweredDown )
667  {
668  USBD_poweredDown = false;
669  DEBUG_USB_INT_LO_PUTCHAR( '/' );
670 
671 #if !defined( USB_CORECLK_HFRCO ) || !defined( CMU_OSCENCMD_USHFRCOEN )
672  /* Switch HFCLK from HFRCO to HFXO. */
674 #endif
675 
676  /* Turn off HFRCO when not needed. */
677  if ( ( cmuStatus & CMU_STATUS_HFRCOENS ) == 0 )
678  {
679  CMU->OSCENCMD = CMU_OSCENCMD_HFRCODIS;
680  }
681 
682  /* Exit partial powerdown mode. */
683  USB->PCGCCTL &= ~USB_PCGCCTL_STOPPCLK;
685 
686  if (( USB->GINTSTS & ( USB_GINTSTS_WKUPINT | USB_GINTSTS_RESETDET ) ) == 0)
687  {
688  USB->DCTL = x_USB_DCTL | USB_DCTL_RMTWKUPSIG;
689  USB->DCTL = x_USB_DCTL;
690  }
691 
692  /* Restore USB core registers. */
693  USB->GUSBCFG = x_USB_GUSBCFG;
694  USB->DCFG = x_USB_DCFG;
695 
696  RestoreEpCtrlRegisters();
697 
698  USB->PCGCCTL = x_USB_PCGCCTL;
699  USB->DOEPMSK = x_USB_DOEPMSK;
700  USB->DIEPMSK = x_USB_DIEPMSK;
701  USB->DAINTMSK = x_USB_DAINTMSK;
702  USB->DCTL = x_USB_DCTL;
703  USB->GNPTXFSIZ = x_USB_GNPTXFSIZ;
704  USB->GRXFSIZ = x_USB_GRXFSIZ;
705  USB->GAHBCFG = x_USB_GAHBCFG;
706 #if defined(_USB_GOTGCTL_MASK)
707  USB->GOTGCTL = x_USB_GOTGCTL;
708 #endif
709  USB->GINTMSK = x_USB_GINTMSK;
710 
711  USB->DCTL |= USB_DCTL_PWRONPRGDONE;
712 
713 #if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ENTEREM2 )
714  /* Do not reenter EM2 on interrupt exit. */
715  SCB->SCR &= ~(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk);
716 #endif
717 
718  return true;
719  }
720  return false;
721 }
722 #endif /* if ( USB_PWRSAVE_MODE ) */
723 
724 /*
725  * Drive resume signalling on USB bus,
726  * exit USB core partial powerdown mode if necessary.
727  */
728 void USBDINT_RemoteWakeup(void)
729 {
730 #if (USB_PWRSAVE_MODE)
731  if (USBD_poweredDown)
732  {
733  USBD_poweredDown = false;
734  DEBUG_USB_INT_LO_PUTCHAR('|');
735 
736  // Restore HF clock if we just woke up from EM2.
737 #if defined( CMU_OSCENCMD_USHFRCOEN )
738  if ( ( CMU->STATUS & CMU_STATUS_USHFRCOENS ) == 0 )
739  {
740  CMU->OSCENCMD = ( cmuStatus
743  }
744 #else
745  if ( ( CMU->STATUS & CMU_STATUS_HFXOENS ) == 0 )
746  {
747  CMU->OSCENCMD = cmuStatus
749  }
750 #endif
751 
752 #if !defined( USB_CORECLK_HFRCO ) || !defined( CMU_OSCENCMD_USHFRCOEN )
753  // Switch HFCLK from HFRCO to HFXO.
755 #endif
756 
757  // Select 48MHz for USBC clock.
758 #if defined( CMU_OSCENCMD_USHFRCOEN )
760  while ( ( CMU->STATUS & CMU_STATUS_USBCUSHFRCOSEL ) == 0 ){}
761 #else
762  CMU->CMD = CMU_CMD_USBCCLKSEL_HFCLKNODIV;
763  while ( ( CMU->STATUS & CMU_STATUS_USBCHFCLKSEL ) == 0 ){}
764 #endif
765 
766  // Exit partial powerdown mode.
767  USB->PCGCCTL &= ~USB_PCGCCTL_STOPPCLK;
769 
770  /* Restore USB core registers. */
771  USB->GUSBCFG = x_USB_GUSBCFG;
772  USB->DCFG = x_USB_DCFG;
773 
774  // Turn on resume signalling.
775  USB->DCTL = x_USB_DCTL | USB_DCTL_RMTWKUPSIG;
776 
777  USBTIMER_DelayMs(2);
778  USB->GINTSTS = 0xFFFFFFFF; // Clear all pending interrupt flags.
779 
780  RestoreEpCtrlRegisters();
781 
782  USB->DOEPMSK = x_USB_DOEPMSK;
783  USB->DIEPMSK = x_USB_DIEPMSK;
784  USB->DAINTMSK = x_USB_DAINTMSK;
785  USB->GNPTXFSIZ = x_USB_GNPTXFSIZ;
786  USB->GRXFSIZ = x_USB_GRXFSIZ;
787  USB->GAHBCFG = x_USB_GAHBCFG;
788 #if defined(_USB_GOTGCTL_MASK)
789  USB->GOTGCTL = x_USB_GOTGCTL;
790 #endif
791  USB->GINTMSK = x_USB_GINTMSK;
792 
793 #if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ENTEREM2 )
794  // Make sure we won't reenter EM2 on an eventual interrupt exit.
795  SCB->SCR &= ~(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk);
796 #endif
797 
799  USBTIMER_DelayMs( 10 );
801 
802  USBDHAL_ClearRemoteWakeup();
803  // Setup EP0 for new commands.
804  USBDHAL_StartEp0Setup( dev );
805  USBDHAL_Ep0Activate( dev->ep0MpsCode );
806  }
807  else
808  {
809 #endif // if (USB_PWRSAVE_MODE)
810  USBDHAL_SetRemoteWakeup();
811 
813  USBTIMER_DelayMs( 10 );
815 
816  USBDHAL_ClearRemoteWakeup();
817 #if (USB_PWRSAVE_MODE)
818  }
819 #endif
820 }
821 
822 #if (USB_PWRSAVE_MODE)
823 static void RestoreEpCtrlRegisters(void)
824 {
825 #if ( NUM_EP_USED > 0 ) || ( FIFO_CNT > 0 )
826  int i;
827 #endif
828 #if ( NUM_EP_USED > 0 )
829  int epNum;
830  uint32_t tmp;
831  USBD_Ep_TypeDef *ep;
832 #endif
833 
834 #if (FIFO_CNT > 0)
835  for (i = 0; i < FIFO_CNT; i++)
836  {
837  USB_DIEPTXFS[i] = x_USB_DIEPTXFS[i];
838  }
839 #endif
840 
841 #if (NUM_EP_USED > 0)
842  for (i = 0; i < NUM_EP_USED; i++)
843  {
844  ep = &dev->ep[i+1];
845  epNum = ep->num;
846 
847  tmp = x_USB_EP_CTL[i]
852 
853  if (x_USB_EP_CTL[i] & USB_DIEP_CTL_DPIDEOF)
854  {
856  }
857  else
858  {
860  }
861 
862  if (x_USB_EP_CTL[i] & USB_DIEP_CTL_NAKSTS)
863  {
864  tmp |= USB_DIEP_CTL_SNAK;
865  }
866  else
867  {
868  tmp |= USB_DIEP_CTL_CNAK;
869  }
870 
871  if (ep->in)
872  {
873  USB_DINEPS[epNum].CTL = tmp;
874  USB_DINEPS[epNum].TSIZ = x_USB_EP_TSIZ[i];
875  USB_DINEPS[epNum].DMAADDR = x_USB_EP_DMAADDR[i];
876  }
877  else
878  {
879  USB_DOUTEPS[epNum].CTL = tmp;
880  USB_DOUTEPS[epNum].TSIZ = x_USB_EP_TSIZ[i];
881  USB_DOUTEPS[epNum].DMAADDR = x_USB_EP_DMAADDR[i];
882  }
883  }
884 #endif
885 }
886 #endif // if (USB_PWRSAVE_MODE)
887 
888 #if defined( USB_DOEP0INT_STUPPKTRCVD )
889 static void HandleOutEpIntr( uint32_t status, USBD_Ep_TypeDef *ep )
890 {
891  uint32_t doeptsiz;
892 
893  if ( ep->num == 0 )
894  {
895  if ( status & USB_DOEP0INT_XFERCOMPL )
896  {
897  USB->DOEP0INT = USB_DOEP0INT_XFERCOMPL;
898  doeptsiz = USB->DOEP0TSIZ;
899 
900  if ( ep->state == D_EP_IDLE )
901  {
902  if ( status & USB_DOEP0INT_STUPPKTRCVD )
903  {
904  USB->DOEP0INT = USB_DOEP0INT_STUPPKTRCVD;
905  }
906  status = USBDHAL_GetOutEpInts( ep );
907  doeptsiz = USB->DOEP0TSIZ;
908 
909  if ( status & USB_DOEP0INT_SETUP )
910  {
911 retry:
912  /* Already started data stage, clear setup */
913  USB->DOEP0INT = USB_DOEP0INT_SETUP;
914  status &= ~USB_DOEP0INT_SETUP;
915  {
916  int supCnt = ( doeptsiz & _USB_DOEP0TSIZ_SUPCNT_MASK )
918 
919  if ( supCnt == 3 )
920  supCnt = 2;
921 
922  dev->setup = &dev->setupPkt[ 2 - supCnt ];
923  }
924  DEBUG_USB_INT_LO_PUTS( "\nS" );
925  USBDEP_Ep0Handler( dev );
926 
927  /* Prepare for more setup packets */
928  if ( ep->state == D_EP0_IN_STATUS || ep->state == D_EP_TRANSMITTING )
929  {
930  USBDHAL_StartEp0Setup( dev );
931  }
932  }
933  else /* xfercompl && idle && !setup */
934  {
935  status = USBDHAL_GetOutEpInts( ep );
936  if ( status & USB_DOEP0INT_SETUP )
937  goto retry;
938  USBDHAL_StartEp0Setup( dev );
939  }
940  }
941  else /* ep0state != EP0_IDLE */
942  {
943  if ( ep->state == D_EP_RECEIVING )
944  {
945  if ( ep->remaining > ep->packetSize )
946  {
947  ep->remaining -= ep->packetSize;
948  ep->xferred += ep->packetSize;
949  }
950  else
951  {
952  ep->xferred += ep->remaining;
953  ep->remaining = 0;
954  }
955  USBDEP_Ep0Handler( dev );
956  }
957  else if ( ep->state == D_EP0_OUT_STATUS )
958  {
959  USBDEP_Ep0Handler( dev );
960  }
961  }
962  } /* if ( status & USB_DOEP0INT_XFERCOMPL ) */
963 
964  if ( status & USB_DOEP0INT_STSPHSERCVD )
965  {
966  USB->DOEP0INT = USB_DOEP0INT_STSPHSERCVD;
967  }
968 
969  if ( status & USB_DOEP0INT_SETUP )
970  {
971  USB->DOEP0INT = USB_DOEP0INT_SETUP;
972  {
973  int supCnt = ( USB->DOEP0TSIZ & _USB_DOEP0TSIZ_SUPCNT_MASK )
975 
976  if ( supCnt == 3 )
977  supCnt = 2;
978 
979  dev->setup = &dev->setupPkt[ 2 - supCnt ];
980  }
981  DEBUG_USB_INT_LO_PUTS( "\nS" );
982  USBDEP_Ep0Handler( dev );
983  }
984  }
985  else /* epnum != 0 */
986  {
987  if ( status & USB_DOEP_INT_XFERCOMPL )
988  {
989  USB_DOUTEPS[ ep->num ].INT = USB_DOEP_INT_XFERCOMPL;
990 
991  ep->xferred = ep->hwXferSize -
992  ( ( USB_DOUTEPS[ ep->num ].TSIZ & _USB_DOEP_TSIZ_XFERSIZE_MASK )>>
994  ep->remaining -= ep->xferred;
995 
996  USBDEP_EpHandler( ep->addr );
997  }
998  }
999 }
1000 #endif
1001 
1004 #endif /* defined( USB_DEVICE ) */
1005 #endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
USB protocol stack library API for EFM32/EZR32.
Clock management unit (CMU) API.
void CMU_ClockSelectSet(CMU_Clock_TypeDef clock, CMU_Select_TypeDef ref)
Select reference clock/oscillator used for a clock branch.
Definition: em_cmu.c:2521
#define USB_DCFG_ENA32KHZSUSP
Definition: efm32hg_usb.h:787
#define USB_DIEP_CTL_CNAK
Definition: efm32hg_usb.h:1305
#define USB_DAINTMSK_INEPMSK0
Definition: efm32hg_usb.h:1068
#define CORE_DECLARE_IRQ_STATE
Definition: em_core.h:85
#define USB_GINTMSK_WKUPINTMSK
Definition: efm32hg_usb.h:605
#define USB_DOEPMSK_XFERCOMPLMSK
Definition: efm32hg_usb.h:970
#define USB_IF_VREGOSL
Definition: efm32hg_usb.h:217
#define USB_STATUS_VREGOS
Definition: efm32hg_usb.h:198
#define USB_DIEP_CTL_NAKSTS
Definition: efm32hg_usb.h:1279
#define USB_DIEP_CTL_SETD0PIDEF
Definition: efm32hg_usb.h:1315
#define CORE_ATOMIC_IRQ_ENABLE()
Definition: em_core.h:123
#define USB
#define _USB_DOEP0TSIZ_SUPCNT_SHIFT
Definition: efm32hg_usb.h:1553
#define USB_DOEPMSK_SETUPMSK
Definition: efm32hg_usb.h:985
#define USB_GINTSTS_ENUMDONE
Definition: efm32hg_usb.h:466
#define _USB_DSTS_SOFFN_MASK
Definition: efm32hg_usb.h:915
#define CMU_STATUS_USBCUSHFRCOSEL
Definition: efm32hg_cmu.h:642
#define _USB_DIEP_TSIZ_XFERSIZE_SHIFT
Definition: efm32hg_usb.h:1393
#define USB_GINTSTS_SOF
Definition: efm32hg_usb.h:431
CMSIS Cortex-M Peripheral Access Layer for Silicon Laboratories microcontroller devices.
#define _USB_DOEP_TSIZ_XFERSIZE_SHIFT
Definition: efm32hg_usb.h:1707
#define USB_SETUP_DIR_MASK
Definition: em_usb.h:68
#define USB_GINTSTS_USBSUSP
Definition: efm32hg_usb.h:456
#define USB_IFC_VREGOSH
Definition: efm32hg_usb.h:240
#define USB_DIEPMSK_XFERCOMPLMSK
Definition: efm32hg_usb.h:926
#define CORE_ATOMIC_IRQ_DISABLE()
Definition: em_core.h:120
void USBTIMER_DelayMs(uint32_t msec)
Active wait millisecond delay function. Can also be used inside interrupt handlers.
Definition: em_usbtimer.c:138
#define CMU_STATUS_USHFRCOENS
Definition: efm32hg_cmu.h:652
USB Setup request package.
Definition: em_usb.h:377
USBD_State_TypeDef
USB device state enumerator.
Definition: em_usb.h:358
#define _USB_DOEP0TSIZ_SUPCNT_MASK
Definition: efm32hg_usb.h:1554
#define _USB_DCFG_RESVALID_SHIFT
Definition: efm32hg_usb.h:813
#define _USB_DCFG_DEVADDR_MASK
Definition: efm32hg_usb.h:793
#define USB_PCGCCTL_PWRCLMP
Definition: efm32hg_usb.h:1749
#define USB_DCTL_RMTWKUPSIG
Definition: efm32hg_usb.h:821
#define CORE_ENTER_ATOMIC()
Definition: em_core.h:138
#define USB_DOEP0INT_STUPPKTRCVD
Definition: efm32hg_usb.h:1535
#define USB_IFC_VREGOSL
Definition: efm32hg_usb.h:245
#define _USB_DSTS_SOFFN_SHIFT
Definition: efm32hg_usb.h:914
#define USB_GINTSTS_IEPINT
Definition: efm32hg_usb.h:481
#define USB_DIEP_CTL_SNAK
Definition: efm32hg_usb.h:1310
#define CMU_STATUS_AUXHFRCOENS
Definition: efm32hg_cmu.h:577
#define USB_DOEP0INT_BACK2BACKSETUP
Definition: efm32hg_usb.h:1515
#define CMU_STATUS_USBCLFRCOSEL
Definition: efm32hg_cmu.h:637
USB protocol stack library API for EFM32/EZR32.
#define CMU_STATUS_HFXOENS
Definition: efm32hg_cmu.h:567
Core interrupt handling API.
#define USB_DIEP_INT_NAKINTRPT
Definition: efm32hg_usb.h:1384
#define USB_IF_VREGOSH
Definition: efm32hg_usb.h:212
#define CMU_OSCENCMD_USHFRCOEN
Definition: efm32hg_cmu.h:449
#define USB_GINTSTS_OEPINT
Definition: efm32hg_usb.h:486
#define CORE_EXIT_ATOMIC()
Definition: em_core.h:142
#define USB_DIEP_INT_XFERCOMPL
Definition: efm32hg_usb.h:1339
USBD_State_TypeDef USBD_GetUsbState(void)
Get current USB device state.
Definition: em_usbd.c:186
#define _USB_DOEP_TSIZ_XFERSIZE_MASK
Definition: efm32hg_usb.h:1708
#define CMU_CMD_USBCCLKSEL_USHFRCO
Definition: efm32hg_cmu.h:496
#define CMU_STATUS_HFRCOENS
Definition: efm32hg_cmu.h:557
#define USB_DIEP_CTL_DPIDEOF
Definition: efm32hg_usb.h:1270
#define USB_DOEPMSK_STSPHSERCVDMSK
Definition: efm32hg_usb.h:995
#define CMU_OSCENCMD_HFRCODIS
Definition: efm32hg_cmu.h:404
#define USB_DIEP_CTL_SETD1PIDOF
Definition: efm32hg_usb.h:1320
#define USB_GINTSTS_WKUPINT
Definition: efm32hg_usb.h:511
#define USB_PCGCCTL_STOPPCLK
Definition: efm32hg_usb.h:1739
USB protocol stack library, low level USB peripheral access.
#define USB_DOEP0INT_STSPHSERCVD
Definition: efm32hg_usb.h:1510
#define USB_DOEP_INT_XFERCOMPL
Definition: efm32hg_usb.h:1648
#define _USB_DCFG_RESVALID_MASK
Definition: efm32hg_usb.h:814
#define USB_SETUP_PKT_SIZE
Definition: em_usb.h:186
#define CMU_CMD_USBCCLKSEL_LFRCO
Definition: efm32hg_cmu.h:495
USB protocol stack library, internal type definitions.
#define USB_DAINTMSK_OUTEPMSK0
Definition: efm32hg_usb.h:1088
#define CMU_STATUS_USBCLFXOSEL
Definition: efm32hg_cmu.h:632
#define USB_CTRL_VREGOSEN
Definition: efm32hg_usb.h:181
#define USB_DOEP0INT_XFERCOMPL
Definition: efm32hg_usb.h:1485
#define CMU_CMD_USBCCLKSEL_LFXO
Definition: efm32hg_cmu.h:494
#define _USB_DIEP_TSIZ_XFERSIZE_MASK
Definition: efm32hg_usb.h:1394
#define USB_GINTSTS_RESETDET
Definition: efm32hg_usb.h:506
#define USB_DCTL_PWRONPRGDONE
Definition: efm32hg_usb.h:877
#define USB_DOEP0INT_SETUP
Definition: efm32hg_usb.h:1500
#define USB_GINTSTS_USBRST
Definition: efm32hg_usb.h:461
#define CMU
#define USB_PCGCCTL_RSTPDWNMODULE
Definition: efm32hg_usb.h:1754
#define USB_GINTMSK_RESETDETMSK
Definition: efm32hg_usb.h:600