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