EFM32 Giant Gecko Software Documentation  efm32gg-doc-4.2.1
em_usbhint.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_HOST )
20 
21 #include "em_usbtypes.h"
22 #include "em_usbhal.h"
23 #include "em_usbh.h"
24 #if ( USB_VBUSOVRCUR_PORT != USB_VBUSOVRCUR_PORT_NONE )
25 #include "em_gpio.h"
26 #endif
27 
30 #define HANDLE_INT( x ) if ( status & x ) { Handle_##x(); status &= ~x; }
31 
32 #define FIFO_TXSTS_HCNUM_MASK 0x78000000
33 #define FIFO_TXSTS_HCNUM_SHIFT 27
34 
35 static void Handle_HcInInt( uint8_t hcnum );
36 static void Handle_HcOutInt( uint8_t hcnum );
37 static void Handle_USB_GINTSTS_DISCONNINT ( void );
38 static void Handle_USB_GINTSTS_HCHINT ( void );
39 static void Handle_USB_GINTSTS_PRTINT ( void );
40 
41 /*
42  * USB_IRQHandler() is the first level handler for the USB peripheral interrupt.
43  */
44 void USB_IRQHandler( void )
45 {
46  uint32_t status;
47 
48  INT_Disable();
49 
50  status = USBHAL_GetCoreInts();
51  if ( status == 0 )
52  {
53  INT_Enable();
54  DEBUG_USB_INT_LO_PUTS( "\nSinT" );
55  return;
56  }
57 
58  HANDLE_INT( USB_GINTSTS_HCHINT )
59  HANDLE_INT( USB_GINTSTS_PRTINT )
60  HANDLE_INT( USB_GINTSTS_DISCONNINT )
61 
62  INT_Enable();
63 
64  if ( status != 0 )
65  {
66  DEBUG_USB_INT_LO_PUTS( "\nUinT" );
67  }
68 }
69 
70 /*
71  * Handle host channel IN transfer interrupt.
72  */
73 static void Handle_HcInInt( uint8_t hcnum )
74 {
75  USBH_Hc_TypeDef *hc;
76  USB_Status_TypeDef result;
77  uint32_t status, hcchar, eptype;
78 #ifdef DEBUG_USB_INT_HI
79  uint32_t status2;
80 #endif
81 
82  hc = &hcs[ hcnum ];
83  status = USBHHAL_GetHcInts( hcnum );
84  hcchar = USB->HC[ hcnum ].CHAR;
85  eptype = hcchar & _USB_HC_CHAR_EPTYPE_MASK;
86 
87  DEBUG_USB_INT_HI_PUTCHAR( 'i' );
88 
89  if ( status & USB_HC_INT_CHHLTD )
90  {
91  USB->HC[ hcnum ].INT = 0xFFFFFFFF;
92 
93 #ifdef DEBUG_USB_INT_HI
94  status2 = status;
95 #endif
99 
100  if ( ( status & ( USB_HC_INT_ACK | USB_HC_INT_XFERCOMPL ) ) ==
102  {
103  DEBUG_USB_INT_HI_PUTCHAR( 'c' );
104 
105  hc->xferred = hc->hwXferSize -
106  ( ( USB->HC[ hcnum ].TSIZ & _USB_HC_TSIZ_XFERSIZE_MASK ) >>
108 
109  hc->remaining -= hc->xferred;
110  hc->ep->toggle = ( USB->HC[ hcnum ].TSIZ & _USB_HC_TSIZ_PID_MASK ) ==
111  USB_HC_TSIZ_PID_DATA0 ? USB_PID_DATA0 : USB_PID_DATA1;
112 
113  result = USB_STATUS_OK;
114  }
115 
116  else if ( status & USB_HC_INT_STALL )
117  {
118  result = USB_STATUS_EP_STALLED;
119  DEBUG_USB_INT_LO_PUTS( "StaL" );
120  }
121 
122  else if ( status & USB_HC_INT_BBLERR )
123  {
124  result = USB_STATUS_EP_ERROR;
125  DEBUG_USB_INT_LO_PUTS( "BabL" );
126  }
127 
128  else if ( ( ( status &
130  == USB_HC_INT_DATATGLERR ) &&
131  ( !( hc->status & HCS_TIMEOUT ) ) )
132  {
133  /* Toggle error but not nak or timeout */
134  result = USB_STATUS_EP_ERROR;
135  DEBUG_USB_INT_LO_PUTS( "TglE" );
136 
137  hc->errorCnt++;
138  if ( hc->errorCnt < 3 )
139  {
140  USBHHAL_HCStart( hcnum );
141  return;
142  }
143  }
144 
145  else if ( ( ( status &
148  == USB_HC_INT_XACTERR ) &&
149  ( !( hc->status & HCS_TIMEOUT ) ) )
150  {
151  /* Exact error but not toggle err or nak or timeout */
152  result = USB_STATUS_EP_ERROR;
153  DEBUG_USB_INT_LO_PUTS( "XacT" );
154 
155  hc->errorCnt++;
156  if ( hc->errorCnt < 3 )
157  {
158  USBHHAL_HCStart( hcnum );
159  return;
160  }
161  }
162 
163  else if ( hc->status & HCS_TIMEOUT )
164  {
165  DEBUG_USB_INT_HI_PUTCHAR( 't' );
166  result = USB_STATUS_TIMEOUT;
167  }
168 
169  else
170  {
171 #ifdef DEBUG_USB_INT_HI
172  if ( !( ( eptype == HCCHAR_EPTYPE_INTR ) &&
173  ( ( status & USB_HC_INT_NAK ) == USB_HC_INT_NAK ) ) )
174  {
175  USB_PRINTF( "0x%08lX", status2 );
176  }
177 #endif
178  return;
179  }
180 
181  if ( eptype == HCCHAR_EPTYPE_CTRL )
182  USBHEP_CtrlEpHandler( hc->ep, result );
183  else
184  USBHEP_EpHandler( hc->ep, result );
185  }
186 }
187 
188 /*
189  * Handle host channel OUT transfer interrupt.
190  */
191 static void Handle_HcOutInt( uint8_t hcnum )
192 {
193  USBH_Hc_TypeDef *hc;
194  USB_Status_TypeDef result;
195  uint32_t status, hcchar, eptype;
196 #ifdef DEBUG_USB_INT_HI
197  uint32_t status2;
198 #endif
199 
200  hc = &hcs[ hcnum ];
201  status = USBHHAL_GetHcInts( hcnum );
202  hcchar = USB->HC[ hcnum ].CHAR;
203  eptype = hcchar & _USB_HC_CHAR_EPTYPE_MASK;
204 
205  DEBUG_USB_INT_HI_PUTCHAR( 'o' );
206 
207  if ( status & USB_HC_INT_CHHLTD )
208  {
209  USB->HC[ hcnum ].INT = 0xFFFFFFFF;
210 
211 #ifdef DEBUG_USB_INT_HI
212  status2 = status;
213 #endif
214  status &= USB_HC_INT_XFERCOMPL | USB_HC_INT_STALL | USB_HC_INT_XACTERR |
216 
217  if ( ( status & ( USB_HC_INT_ACK | USB_HC_INT_XFERCOMPL ) ) ==
219  {
220  DEBUG_USB_INT_HI_PUTCHAR( 'c' );
221 
222  hc->xferred = hc->remaining;
223  hc->remaining = 0;
224  hc->ep->toggle = ( USB->HC[ hcnum ].TSIZ & _USB_HC_TSIZ_PID_MASK ) ==
225  USB_HC_TSIZ_PID_DATA0 ? USB_PID_DATA0 : USB_PID_DATA1;
226 
227  result = USB_STATUS_OK;
228  }
229 
230  else if ( status & USB_HC_INT_STALL )
231  {
232  result = USB_STATUS_EP_STALLED;
233  DEBUG_USB_INT_LO_PUTS( "StaL" );
234  }
235 
236  else if ( status & USB_HC_INT_XACTERR )
237  {
238  DEBUG_USB_INT_LO_PUTS( "XacT" );
239  if ( status & ( USB_HC_INT_ACK | USB_HC_INT_NAK ) )
240  {
241  hc->errorCnt = 0;
242  USBHHAL_HCStart( hcnum );
243  return;
244  }
245  else
246  {
247  hc->errorCnt++;
248  if ( hc->errorCnt < 3 )
249  {
250  USBHHAL_HCStart( hcnum );
251  return;
252  }
253  }
254  result = USB_STATUS_EP_ERROR;
255  }
256 
257  else if ( hc->status & HCS_TIMEOUT )
258  {
259  DEBUG_USB_INT_HI_PUTCHAR( 't' );
260  result = USB_STATUS_TIMEOUT;
261  }
262 
263  else
264  {
265 #ifdef DEBUG_USB_INT_HI
266  if ( !( ( eptype == HCCHAR_EPTYPE_INTR ) &&
267  ( ( status & USB_HC_INT_NAK ) == USB_HC_INT_NAK ) ) )
268  {
269  USB_PRINTF( "0x%08lX", status2 );
270  }
271 #endif
272  return;
273  }
274 
275  if ( eptype == HCCHAR_EPTYPE_CTRL )
276  USBHEP_CtrlEpHandler( hc->ep, result );
277  else
278  USBHEP_EpHandler( hc->ep, result );
279  }
280 }
281 
282 /*
283  * Handle port disconnect interrupt.
284  */
285 static void Handle_USB_GINTSTS_DISCONNINT( void )
286 {
287  int i;
288  uint32_t hcchar;
289 
290  USB->GINTSTS = USB_GINTSTS_DISCONNINT;
291  USB->HAINTMSK = 0;
292 
293  USBH_portStatus = H_PORT_DISCONNECTED;
294  USBTIMER_Stop( HOSTPORT_TIMER_INDEX );
295  USBHHAL_PortReset( false );
296 
297  for ( i=0; i< NUM_HC_USED + 2; i++ )
298  {
299  hcchar = USB->HC[ i ].CHAR; /* Halt channel */
300  USBHHAL_HCHalt( i, hcchar );
301  USB->HC[ i ].INT = 0xFFFFFFFF; /* Clear pending interrupts */
302 
303  if ( !hcs[ i ].idle )
304  {
305  USBHEP_TransferDone( hcs[ i ].ep, USB_STATUS_DEVICE_REMOVED );
306  }
307  }
308 
309  DEBUG_USB_INT_LO_PUTS( "\nDisC" );
310 }
311 
312 /*
313  * Handle host channel interrupt. Call IN and OUT transfer handlers as needed.
314  */
315 static void Handle_USB_GINTSTS_HCHINT( void )
316 {
317  uint8_t hcnum;
318  uint32_t hcints, hcmask;
319 
320  hcints = USBHHAL_GetHostChannelInts();
321 
322  for ( hcnum = 0, hcmask = 1;
323  hcnum < NUM_HC_USED + 2;
324  hcnum++, hcmask <<= 1 )
325  {
326  if ( hcints & hcmask )
327  {
328  if ( USB->HC[ hcnum ].CHAR & USB_HC_CHAR_EPDIR )
329  {
330  Handle_HcInInt( hcnum );
331  }
332  else
333  {
334  Handle_HcOutInt( hcnum );
335  }
336  }
337  }
338 }
339 
340 /*
341  * Callback function for port interrupt state machine.
342  * Called on timeout of the port timer when a port reset is completed.
343  */
344 static void PortResetComplete( void )
345 {
346  if ( USB->HPRT & USB_HPRT_PRTCONNSTS ) /* Is device still connected ? */
347  {
348  DEBUG_USB_INT_LO_PUTCHAR( '5' );
349  }
350  else
351  {
352  USBH_portStatus = H_PORT_DISCONNECTED;
353  }
354  USBHHAL_PortReset( false );
355 }
356 
357 /*
358  * Callback function for port interrupt state machine.
359  * Called on timeout of the port timer connection debounce time has expired.
360  */
361 static void PortDebounceComplete( void )
362 {
363  uint32_t hprt;
364 
365  hprt = USB->HPRT; /* Get port status */
366 
367  if ( hprt & USB_HPRT_PRTCONNSTS ) /* Is device still connected ? */
368  {
369  if ( ( hprt & _USB_HPRT_PRTSPD_MASK ) == HPRT_L_SPEED )
370  {
371  DEBUG_USB_INT_LO_PUTCHAR( '3' );
372  USB->HFIR = 6000;
373  /* Set 6 MHz PHY clock */
374  USB->HCFG = ( USB->HCFG & ~_USB_HCFG_FSLSPCLKSEL_MASK ) |
376  }
377  else if ( ( hprt & _USB_HPRT_PRTSPD_MASK ) == HPRT_F_SPEED )
378  {
379  DEBUG_USB_INT_LO_PUTCHAR( '4' );
380  USB->HFIR = 48000;
381  /* Set 48 MHz PHY clock */
382  USB->HCFG = ( USB->HCFG & ~_USB_HCFG_FSLSPCLKSEL_MASK ) |
384  }
385 
386  USBH_portStatus = H_PORT_CONNECTED_RESETTING;
387  USBTIMER_Start( HOSTPORT_TIMER_INDEX,
388  USBH_attachTiming[ USBH_attachRetryCount ].resetTime,
389  PortResetComplete );
390  USBHHAL_PortReset( true );
391  }
392  else
393  {
394  USBH_portStatus = H_PORT_DISCONNECTED;
395  }
396 }
397 
398 /*
399  * Handle port interrupt.
400  */
401 static void Handle_USB_GINTSTS_PRTINT( void )
402 {
403  uint32_t hprt;
404 
405  hprt = USB->HPRT; /* Get port status */
406 
407  DEBUG_USB_INT_LO_PUTCHAR( '^' );
408 
409  switch ( USBH_portStatus )
410  {
411  case H_PORT_DISCONNECTED:
412  /***********************/
413  if ( ( hprt & USB_HPRT_PRTCONNDET ) &&
414  ( hprt & USB_HPRT_PRTCONNSTS ) ) /* Any device connected ? */
415  {
416  DEBUG_USB_INT_LO_PUTCHAR( '2' );
417  USBH_portStatus = H_PORT_CONNECTED_DEBOUNCING;
418  USBTIMER_Start( HOSTPORT_TIMER_INDEX,
419  USBH_attachTiming[ USBH_attachRetryCount ].debounceTime,
420  PortDebounceComplete );
421  }
422  break;
423 
424  case H_PORT_CONNECTED_DEBOUNCING:
425  /***********************/
426  DEBUG_USB_INT_LO_PUTCHAR( 'Y' );
427  break;
428 
429  case H_PORT_CONNECTED_RESETTING:
430  /***********************/
431  if ( ( hprt & USB_HPRT_PRTENCHNG ) && /* Port enable changed ? */
432  ( hprt & USB_HPRT_PRTENA ) && /* Port enabled ? */
433  ( hprt & USB_HPRT_PRTCONNSTS ) ) /* Device still connected ? */
434  {
435  DEBUG_USB_INT_LO_PUTCHAR( '6' );
436  USBH_portStatus = H_PORT_CONNECTED;
437  }
438  break;
439 
440  case H_PORT_CONNECTED:
441  /***********************/
442  if ( ( hprt & USB_HPRT_PRTENCHNG ) &&
443  ( !( hprt & USB_HPRT_PRTENA ) ) )
444  {
445  DEBUG_USB_INT_LO_PUTCHAR( 'X' );
446 #if ( USB_VBUSOVRCUR_PORT != USB_VBUSOVRCUR_PORT_NONE )
447  if ( GPIO_PinInGet( USB_VBUSOVRCUR_PORT, USB_VBUSOVRCUR_PIN ) ==
448  USB_VBUSOVRCUR_POLARITY )
449  {
450  DEBUG_USB_INT_LO_PUTCHAR( '~' );
451  USBHHAL_PortReset( false );
452  USBHHAL_VbusOn( false );
453  USBTIMER_Stop( HOSTPORT_TIMER_INDEX );
454  USBH_portStatus = H_PORT_OVERCURRENT;
455  }
456 #endif
457  }
458  break;
459 
460  case H_PORT_OVERCURRENT:
461  /***********************/
462  break;
463  }
464 
465  if ( hprt & USB_HPRT_PRTOVRCURRCHNG ) /* Overcurrent change interrupt ? */
466  {
467  DEBUG_USB_INT_LO_PUTCHAR( '9' );
468  }
469 
470  hprt &= ~HPRT_WC_MASK; /* Mask off all write clear bits */
471  hprt |= USB_HPRT_PRTCONNDET | USB_HPRT_PRTENCHNG | USB_HPRT_PRTOVRCURRCHNG;
472  USB->HPRT = hprt; /* Clear all port interrupt flags */
473 }
474 
477 #endif /* defined( USB_HOST ) */
478 #endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
void USBTIMER_Stop(uint32_t id)
Stop a timer.
Definition: em_usbtimer.c:302
#define _USB_HC_CHAR_EPTYPE_MASK
Definition: efm32gg_usb.h:1319
#define _USB_HC_TSIZ_XFERSIZE_SHIFT
Definition: efm32gg_usb.h:1465
#define USB_HC_INT_STALL
Definition: efm32gg_usb.h:1372
USB protocol stack library API for EFM32/EZR32.
int USB_PRINTF(const char *format,...)
Transmit "printf" formated data on the debug serial port.
__STATIC_INLINE uint32_t INT_Enable(void)
Enable interrupts.
Definition: em_int.h:94
#define USB_HC_INT_CHHLTD
Definition: efm32gg_usb.h:1362
CMSIS Cortex-M Peripheral Access Layer for Silicon Laboratories microcontroller devices.
#define USB_HC_INT_BBLERR
Definition: efm32gg_usb.h:1392
#define USB_HPRT_PRTCONNDET
Definition: efm32gg_usb.h:1213
USB_Status_TypeDef
USB transfer status enumerator.
Definition: em_usb.h:316
#define USB
#define USB_HC_INT_DATATGLERR
Definition: efm32gg_usb.h:1402
General Purpose IO (GPIO) peripheral API.
#define _USB_HC_TSIZ_XFERSIZE_MASK
Definition: efm32gg_usb.h:1466
#define USB_GINTSTS_PRTINT
Definition: efm32gg_usb.h:715
#define USB_HC_INT_XACTERR
Definition: efm32gg_usb.h:1387
USB protocol stack library API for EFM32/EZR32.
#define USB_GINTSTS_DISCONNINT
Definition: efm32gg_usb.h:735
#define USB_HC_INT_ACK
Definition: efm32gg_usb.h:1382
#define USB_HPRT_PRTOVRCURRCHNG
Definition: efm32gg_usb.h:1233
#define USB_HPRT_PRTENA
Definition: efm32gg_usb.h:1218
#define _USB_HCFG_FSLSPCLKSEL_MASK
Definition: efm32gg_usb.h:1113
#define USB_HC_INT_XFERCOMPL
Definition: efm32gg_usb.h:1357
#define _USB_HCFG_FSLSPCLKSEL_SHIFT
Definition: efm32gg_usb.h:1112
#define USB_HC_INT_NAK
Definition: efm32gg_usb.h:1377
#define USB_HC_CHAR_EPDIR
Definition: efm32gg_usb.h:1304
USB protocol stack library, low level USB peripheral access.
__STATIC_INLINE uint32_t INT_Disable(void)
Disable interrupts.
Definition: em_int.h:71
#define USB_HPRT_PRTCONNSTS
Definition: efm32gg_usb.h:1208
#define _USB_HC_TSIZ_PID_MASK
Definition: efm32gg_usb.h:1474
USB protocol stack library, internal type definitions.
#define _USB_HPRT_PRTSPD_MASK
Definition: efm32gg_usb.h:1283
#define USB_GINTSTS_HCHINT
Definition: efm32gg_usb.h:720
#define USB_HC_TSIZ_PID_DATA0
Definition: efm32gg_usb.h:1481
void USBTIMER_Start(uint32_t id, uint32_t timeout, USBTIMER_Callback_TypeDef callback)
Start a timer.
Definition: em_usbtimer.c:234
__STATIC_INLINE unsigned int GPIO_PinInGet(GPIO_Port_TypeDef port, unsigned int pin)
Read the pad value for a single pin in a GPIO port.
Definition: em_gpio.h:675
#define USB_HPRT_PRTENCHNG
Definition: efm32gg_usb.h:1223