1 /**
2 * @file xmc_usbd.c
3 * @date 2015-06-20
4 *
5 * @cond
6 **********************************************************************************
7 * XMClib v2.1.24 - XMC Peripheral Driver Library
8 *
9 * Copyright (c) 2015-2019, Infineon Technologies AG
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification,are permitted provided that the following conditions are met:
14 *
15 * Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 *
18 * Redistributions in binary form must reproduce the above copyright notice,
19 * this list of conditions and the following disclaimer in the documentation
20 * and/or other materials provided with the distribution.
21 *
22 * Neither the name of the copyright holders nor the names of its contributors
23 * may be used to endorse or promote products derived from this software without
24 * specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY,OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 *
38 * To improve the quality of the software, users are encouraged to share
39 * modifications, enhancements or bug fixes with Infineon Technologies AG
40 * dave@infineon.com).
41 **********************************************************************************
42 *
43 * Change History
44 * --------------
45 *
46 * 2015-02-16:
47 * - Initial Version.<br>
48 * 2015-03-18:
49 * - Updated the XMC_USBD_EndpointStall() to fix issue on USB clear stall. <br>
50 * - Updated the XMC_USBD_EndpointConfigure() to fix issue in EP0 configuration.<br>
51 * - Updated the XMC_USBD_IRQHandler()(Removed the DAVE_CE check on SOF event).<br>
52 * 2015-06-20:
53 * - Removed GetDriverVersion API.<br>
54 * - Updated the XMC_USBD_IsEnumDone() API.<br>
55 * - Updated the copy right in the file header.<br>
56 * - Updated the XMC_USBD_Disable() API to gate the clock after programming the SCU registers.<br>
57 *
58 * @endcond
59 *
60 */
61
62
63 /*******************************************************************************
64 * HEADER FILES
65 *******************************************************************************/
66 #include <xmc_usbd.h>
67
68 #if defined(USB0)
69
70 /**< macro to check the maximum number of endpoints used*/
71 #define XMC_USBD_CHECK_INPUT_MAX_NUM_EPS(usbd_max_num_eps) \
72 ((usbd_max_num_eps == XMC_USBD_MAX_NUM_EPS_1 ) || \
73 (usbd_max_num_eps == XMC_USBD_MAX_NUM_EPS_2 ) || \
74 (usbd_max_num_eps == XMC_USBD_MAX_NUM_EPS_3 ) || \
75 (usbd_max_num_eps == XMC_USBD_MAX_NUM_EPS_4 ) || \
76 (usbd_max_num_eps == XMC_USBD_MAX_NUM_EPS_5 ) || \
77 (usbd_max_num_eps == XMC_USBD_MAX_NUM_EPS_6 ) || \
78 (usbd_max_num_eps == XMC_USBD_MAX_NUM_EPS_7 ))
79
80 /*******************************************************************************
81 *GLOBAL DATA
82 *******************************************************************************/
83 /*
84 * Endpoint Out Fifo Size
85 */
86 uint32_t XMC_USBD_EP_OUT_BUFFERSIZE[7] = {0U,0U,0U,0U,0U,0U,0U};
87 /*
88 * Endpoint In Fifo Size
89 */
90 uint32_t XMC_USBD_EP_IN_BUFFERSIZE[7] = {0U,0U,0U,0U,0U,0U,0U};
91 /*
92 * Device definition
93 */
94 XMC_USBD_DEVICE_t xmc_device;
95 #ifdef __GNUC__ /*GCC*/
96 /*
97 * Endpoint Out Fifo
98 */
99 static __attribute__((aligned(4))) uint8_t XMC_USBD_EP_OUT_BUFFER[7][256] __attribute__((section("USB_RAM")));
100 /*
101 * Endpoint In Fifo
102 */
103 static __attribute__((aligned(4))) uint8_t XMC_USBD_EP_IN_BUFFER[7][256] __attribute__((section("USB_RAM")));
104 #endif
105 #if defined(__ICCARM__)
106 #pragma data_alignment=4
107 /*
108 * Endpoint Out Fifo
109 */
110 static uint8_t XMC_USBD_EP_OUT_BUFFER[7][256] @ ".dram";
111 /*
112 * Endpoint In Fifo
113 */
114 #pragma data_alignment=4
115 static uint8_t XMC_USBD_EP_IN_BUFFER[7][256] @ ".dram";
116 #endif
117 #if defined(__CC_ARM)
118 /*
119 * Endpoint Out Fifo
120 */
121 static __attribute__((aligned(4))) uint8_t XMC_USBD_EP_OUT_BUFFER[7][256] __attribute__((section ("RW_IRAM1")));
122 /*
123 * Endpoint In Fifo
124 */
125 static __attribute__((aligned(4))) uint8_t XMC_USBD_EP_IN_BUFFER[7][256] __attribute__((section ("RW_IRAM1")));
126 #endif
127 XMC_USBD_t *usbd_init;
128
129 /*******************************************************************************
130 *LOCAL ROUTINES
131 *******************************************************************************/
132 /*Local routines prototypes*/
133 uint8_t XMC_USBD_lDeviceActive(const XMC_USBD_t *const obj);
134 static void XMC_USBD_lReadFifo(const uint32_t ep_num,const uint32_t byte_count);
135 static uint32_t XMC_USBD_lWriteFifo(XMC_USBD_EP_t *ep);
136 static void XMC_USBD_lFlushTXFifo(const uint8_t fifo_num);
137 static void XMC_USBD_lFlushRXFifo(void);
138 static uint8_t XMC_USBD_lAssignTXFifo(void);
139 static void XMC_USBD_lStartReadXfer(XMC_USBD_EP_t *const ep);
140 static void XMC_USBD_lStartWriteXfer(XMC_USBD_EP_t *const ep);
141 static void XMC_USBD_lHandleEnumDone(void);
142 static void XMC_USBD_lHandleOEPInt(const XMC_USBD_t *const obj);
143 static void XMC_USBD_lHandleRxFLvl(void);
144 static void XMC_USBD_lHandleIEPInt(const XMC_USBD_t *const obj);
145 static void XMC_USBD_lUnassignFifo(const uint8_t fifo_nr);
146 static void XMC_USBD_lHandleUSBReset(const XMC_USBD_t *const obj);
147 static void XMC_USBD_lHandleOTGInt(void);
148 static void XMC_USBD_lClearEventOTG(uint32_t event);
149
150 /**
151 * The device driver
152 */
153 const XMC_USBD_DRIVER_t Driver_USBD0 =
154 {
155 .GetCapabilities = XMC_USBD_GetCapabilities,
156 .Initialize = XMC_USBD_Init,
157 .Uninitialize = XMC_USBD_Uninitialize,
158 .DeviceConnect = XMC_USBD_DeviceConnect,
159 .DeviceDisconnect = XMC_USBD_DeviceDisconnect,
160 .DeviceGetState = XMC_USBD_DeviceGetState,
161 .DeviceSetAddress = XMC_USBD_DeviceSetAddress,
162 .EndpointConfigure = XMC_USBD_EndpointConfigure,
163 .EndpointUnconfigure = XMC_USBD_EndpointUnconfigure,
164 .EndpointStall = XMC_USBD_EndpointStall,
165 .EndpointReadStart = XMC_USBD_EndpointReadStart,
166 .EndpointRead = XMC_USBD_EndpointRead,
167 .EndpointWrite = XMC_USBD_EndpointWrite,
168 .EndpointAbort = XMC_USBD_EndpointAbort,
169 .GetFrameNumber = XMC_USBD_GetFrameNumber,
170 .IsEnumDone = XMC_USBD_IsEnumDone
171 };
172
173 /**
174 * @brief Checks if device is active
175 *
176 * Therefore the endpoint inInUse flag are checked and if one endpoint is in use, 1 is returned,
177 * else 0 is returned.
178 * @return 1 if an endpoint is active else 0
179 */
XMC_USBD_lDeviceActive(const XMC_USBD_t * const obj)180 uint8_t XMC_USBD_lDeviceActive(const XMC_USBD_t *const obj)
181 {
182 uint8_t i;
183 uint8_t result = 0U;
184 for (i = 0U; i < (uint8_t)obj->usbd_max_num_eps; i++)
185 {
186 if (xmc_device.ep[i].inInUse || xmc_device.ep[i].outInUse)
187 {
188 result = 1U;
189 }
190 }
191 return result;
192 }
193
194
195 /**
196 * @brief Read data from the rx fifo
197 *
198 * The data from the fifo is copied in to the buffer specified by @ref xfer_buffer and
199 * the transfer values get updated. If the endpoint is disabled or the buffer not existent
200 * the function exits.
201 *
202 * @arg ep_num the endpoint to read for
203 * @arg byte_count the byte count to read
204 */
XMC_USBD_lReadFifo(const uint32_t ep_num,const uint32_t byte_count)205 static void XMC_USBD_lReadFifo(const uint32_t ep_num,const uint32_t byte_count)
206 {
207 XMC_USBD_EP_t * ep = &xmc_device.ep[ep_num];
208 uint32_t word_count;
209 uint32_t temp_data;
210 uint32_t temp_word_count;
211 volatile uint32_t *fifo = xmc_device.fifo[0U];
212 uint32_t i;
213 depctl_data_t data;
214 data.d32 = xmc_device.endpoint_out_register[ep_num]->doepctl;
215 word_count = (byte_count >> 2U );
216 temp_word_count = (word_count << 2U);
217 /* Check if ep is enabled and has buffer */
218 if (!data.b.usbactep)
219 {
220 /*Do Nothing*/
221 }
222 else if (ep->xferBuffer == NULL)
223 {
224 /*Do Nothing*/
225 }
226 else
227 {
228 /* store the data */
229 for (i = 0U;i < word_count; i++)
230 {
231 *(((uint32_t*)ep->xferBuffer)+i) = *fifo;
232 }
233 /* space is not devidable by 4 */
234 if (byte_count!=temp_word_count)
235 {
236 temp_data = *fifo;
237 for (i = 0U;(temp_word_count + i) < byte_count;i++)
238 {
239 ep->xferBuffer[(word_count << 2)+i] = (uint8_t)((temp_data & ((uint32_t)0xFFU << (i * 8U))) >> (i * 8U));
240 }
241 }
242
243 /* save the amount of data */
244 ep->xferCount += byte_count;
245 ep->xferBuffer += byte_count;
246 }
247 }
248
249 /**
250 * @brief Write data to an endpoint fifo
251 *
252 * The data from the @ref xfer_buffer gets copied in to the tx fifo of the endpoint until the buffer has been read
253 *completely or the tx fifo is full. The transfer values are not updated.
254 *
255 * @arg[in] ep the endpoint to use
256 * @return the number of bytes written to the fifo
257 */
XMC_USBD_lWriteFifo(XMC_USBD_EP_t * const ep)258 static uint32_t XMC_USBD_lWriteFifo(XMC_USBD_EP_t *const ep)
259 {
260 dtxfsts_data_t freeSpace;
261 volatile uint32_t *fifo;
262 uint32_t byte_count;
263 uint32_t word_count;
264 uint32_t result;
265 uint32_t i;
266 fifo = xmc_device.fifo[ep->address_u.address_st.number]; /* fifo */
267 freeSpace.d32 = xmc_device.endpoint_in_register[ep->address_u.address_st.number]->dtxfsts;
268 /* calculate the length and the amount of dwords to copy based on the fifo status */
269 byte_count = ep->xferLength - ep->xferCount;
270 if (!byte_count)
271 {
272 result = 0U;
273 }
274 else
275 {
276 /* add the unaligned bytes to the word count to compare with the fifo space */
277 word_count = ((uint32_t)byte_count + 3U) >> 2U;
278 if (word_count > (uint32_t)freeSpace.b.txfspcavail )
279 {
280 word_count = (uint32_t)freeSpace.b.txfspcavail;
281 byte_count = (uint32_t)word_count << (uint32_t)2U;
282 }
283
284 /* copy data dword wise */
285 for (i = 0U; i < word_count;ep->xferBuffer+= 4U)
286 {
287 *fifo = *(uint32_t*)ep->xferBuffer;
288 i++;
289 }
290 result=byte_count;
291 }
292 return result;
293 }
294
295 /**
296 * @brief Flush a tx fifo
297 *
298 * @param[in] fifo_num Fifo number to flush
299 *
300 * @note Use 0x10 as parameter to flush all tx fifos.
301 */
XMC_USBD_lFlushTXFifo(const uint8_t fifo_num)302 static void XMC_USBD_lFlushTXFifo(const uint8_t fifo_num)
303 {
304 volatile grstctl_t data;
305 uint32_t count;
306 data.d32 = 0U;
307 /*flush fifo */
308 data.b.txfflsh = 1U;
309 data.b.txfnum = fifo_num;
310 xmc_device.global_register->grstctl = data.d32;
311 for (count = 0U;count < 1000U; count++){}
312 do
313 {
314 data.d32 = xmc_device.global_register->grstctl;
315 } while (data.b.txfflsh);
316 count = 0U;
317 while (count++ < 1000U)
318 {
319 /* wait 3 phy clocks */
320 }
321 }
322
323 /**
324 * @brief Flush the rx fifo
325 */
XMC_USBD_lFlushRXFifo(void)326 static void XMC_USBD_lFlushRXFifo(void)
327 {
328 volatile grstctl_t data;
329 uint32_t count;
330
331 data.d32 = 0U;
332 data.b.rxfflsh = 1U;
333 /* flush FIFO */
334 xmc_device.global_register->grstctl = data.d32;
335 do
336 {
337 for (count = 0U; count < 1000U; count++){}
338 data.d32 = xmc_device.global_register->grstctl;
339 } while (data.b.rxfflsh);
340 count = 0U;
341 while (count++ < 1000U)
342 {
343 /* wait 3 phy clocks */
344 }
345 }
346
347 /*
348 * Support Functions
349 */
350
351 /**
352 * @brief Assign a free tx fifo
353 *
354 * A free tx fifo will be searched and the number will be returned.
355 *
356 * @return Fifo number for a free fifo
357 */
XMC_USBD_lAssignTXFifo(void)358 static uint8_t XMC_USBD_lAssignTXFifo(void)
359 {
360 uint16_t mask = 1U;
361 uint8_t i = 0U;
362 uint8_t result = 0U;
363 while( (i < (uint8_t)XMC_USBD_NUM_TX_FIFOS)&&((xmc_device.txfifomsk & mask) != 0U))
364 {
365 mask = (uint16_t)(mask << 1U);
366 i++;
367 }
368 if ((xmc_device.txfifomsk & mask) == 0U)
369 {
370 xmc_device.txfifomsk |= mask;
371 result=i;
372 }
373 return result;
374 }
375
376 /**
377 * @brief Free a tx fifo
378 *
379 * Mark an used tx fifo as free.
380 * @param[in] fifo_nr Fifo number to free
381 */
XMC_USBD_lUnassignFifo(const uint8_t fifo_nr)382 static void XMC_USBD_lUnassignFifo(const uint8_t fifo_nr)
383 {
384 xmc_device.txfifomsk = (uint16_t)((uint32_t)xmc_device.txfifomsk & (uint32_t)(~((uint32_t)((uint32_t)1U << fifo_nr))));
385 }
386
387 /**
388 * @brief Start a transfer for an out endpoint
389 *
390 * Based on the transfer values of the endpoint, the out endpoint registers will be programmed
391 * to start a new out transfer.
392 *
393 * @note No checking of the transfer values are done in this function. Be sure,
394 * that the transfer values are reasonable (e.g. buffer size is not exceeded).
395 *
396 * @param[in] ep Endpoint to start the transfer
397 */
XMC_USBD_lStartReadXfer(XMC_USBD_EP_t * const ep)398 static void XMC_USBD_lStartReadXfer(XMC_USBD_EP_t *const ep)
399 {
400 deptsiz_data_t data;
401 depctl_data_t epctl;
402
403 data.d32 = 0U;
404 if ((ep->xferTotal - ep->xferLength) > ep->maxTransferSize)
405 {
406 ep->xferLength += ep->maxTransferSize;
407 }
408 else
409 {
410 ep->xferLength = ep->xferTotal;
411 }
412 if (ep->address_u.address_st.number == 0U)
413 {
414 /* Setup the endpoint to receive 3 setup packages and one normal package.*/
415 /* Cast the data pointer to use only one variable */
416 deptsiz0_data_t *ep0_data = (deptsiz0_data_t*)&data;
417 ep0_data->b.pktcnt = 0x1U;
418 ep0_data->b.supcnt = 0x3U;
419 ep0_data->b.xfersize = (uint8_t)ep->xferTotal;
420 }
421 else
422 {
423 /* If requested length is zero, just receive one zero length packet */
424 if (ep->xferLength == 0U)
425 {
426 data.b.xfersize = 0U;
427 data.b.pktcnt = 1U;
428 }
429 else
430 {
431 /* setup endpoint to recive a amount of packages by given size */
432 data.b.pktcnt = (uint16_t)(((ep->xferLength - ep->xferCount) + (ep->maxPacketSize -(uint32_t)1U))/ep->maxPacketSize);
433 data.b.xfersize =(uint32_t)(ep->xferLength - ep->xferCount);
434 }
435 }
436 if(usbd_init->usbd_transfer_mode == XMC_USBD_USE_DMA)
437 {
438 /* Programm dma address if needed */
439 xmc_device.endpoint_out_register[ep->address_u.address_st.number]->doepdma = (uint32_t)(ep->xferBuffer);
440 }
441 /* setup endpoint size and enable endpoint */
442 xmc_device.endpoint_out_register[ep->address_u.address_st.number]->doeptsiz = data.d32;
443
444 epctl.d32 = xmc_device.endpoint_out_register[ep->address_u.address_st.number]->doepctl;
445 epctl.b.cnak = 1U;
446 epctl.b.epena = 1U;
447 xmc_device.endpoint_out_register[ep->address_u.address_st.number]->doepctl = epctl.d32;
448 }
449
450 /**
451 * @brief Start a new in transfer
452 *
453 * Based on the transfer values of the endpoint the in endpoint registers will be programmed
454 * to start a new in transfer
455 *
456 * @param[in] ep Endpoint to start the transfer
457 */
XMC_USBD_lStartWriteXfer(XMC_USBD_EP_t * const ep)458 static void XMC_USBD_lStartWriteXfer(XMC_USBD_EP_t *const ep)
459 {
460 deptsiz_data_t size;
461 depctl_data_t ctl;
462
463 size.d32 = 0U;
464 ctl.d32 = xmc_device.endpoint_in_register[ep->address_u.address_st.number]->diepctl;
465
466 if ((ep->xferTotal - ep->xferLength) < ep->maxTransferSize)
467 {
468 ep->xferLength = ep->xferTotal;
469 }
470 else
471 {
472 ep->xferLength += ep->maxTransferSize;
473 }
474 if (ep->xferLength == 0U)
475 {
476 size.b.xfersize = 0U;
477 size.b.pktcnt = 1U;
478 }
479 else
480 {
481 if (ep->address_u.address_st.number == 0U)
482 {
483 size.b.pktcnt = 1U;
484 /* ep->maxXferSize equals maxPacketSize */
485 size.b.xfersize = (uint32_t)(ep->xferLength - ep->xferCount);
486 }
487 else
488 {
489 size.b.xfersize =(uint32_t)(ep->xferLength - ep->xferCount);
490 size.b.pktcnt = (uint16_t)(((uint16_t)(ep->xferLength - ep->xferCount) + (uint16_t)((uint16_t)ep->maxPacketSize - 1U))/
491 ep->maxPacketSize);
492 }
493 if(usbd_init->usbd_transfer_mode == XMC_USBD_USE_DMA)
494 {
495 /* Program dma*/
496 xmc_device.endpoint_in_register[ep->address_u.address_st.number]->diepdma = (uint32_t)ep->xferBuffer;
497 }
498 if(usbd_init->usbd_transfer_mode == XMC_USBD_USE_FIFO)
499 {
500 /* enable fifo empty interrupt */
501 xmc_device.device_register->dtknqr4_fifoemptymsk |= (uint32_t)((uint32_t)1U << (uint8_t)ep->address_u.address_st.number);
502 }
503 }
504
505 /* Program size of transfer and enable endpoint */
506 xmc_device.endpoint_in_register[ep->address_u.address_st.number]->dieptsiz = size.d32;
507 ctl.b.epena = 1U;
508 ctl.b.cnak = 1U;
509 xmc_device.endpoint_in_register[ep->address_u.address_st.number]->diepctl = ctl.d32;
510 }
511
512
513 /**
514 * @brief Handles the USBD reset interrupt
515 *
516 * When ever the host sets the bus into reset condition the usb otg_core generates
517 * an interrupt, which is handled by this function. It resets the complete otg_core
518 * into the default state.
519 */
XMC_USBD_lHandleUSBReset(const XMC_USBD_t * const obj)520 static void XMC_USBD_lHandleUSBReset(const XMC_USBD_t *const obj)
521 {
522 uint32_t i;
523 depctl_data_t epctl;
524 dctl_data_t dctl;
525 fifosize_data_t gnptxfsiz;
526 daint_data_t daint;
527 dcfg_data_t dcfg;
528
529 /* Clear the Remote Wakeup Signaling */
530 dctl.d32 = xmc_device.device_register->dctl;
531 dctl.b.rmtwkupsig = 1U;
532 xmc_device.device_register->dctl = dctl.d32;
533
534 /* enable naks for all eps */
535 for (i = 0U;i < (uint8_t)XMC_USBD_NUM_EPS;i++)
536 {
537 epctl.d32 = xmc_device.endpoint_out_register[i]->doepctl;
538 epctl.b.snak = 1U;
539 epctl.b.stall = 0U;
540 xmc_device.endpoint_out_register[i]->doepctl = epctl.d32;
541 }
542
543 /* Configure fifos */
544 /* Calculate the size of the rx fifo */
545 xmc_device.global_register->grxfsiz = 64U;
546 /* Calculate the size of the tx fifo for ep 0 */
547 gnptxfsiz.d32 = 0U;
548 gnptxfsiz.b.depth = 16U;
549 gnptxfsiz.b.startaddr = 64U;
550 xmc_device.global_register->gnptxfsiz = gnptxfsiz.d32;
551 /* calculate the size for the rest */
552 for (i = 1U;i < (uint8_t)XMC_USBD_NUM_TX_FIFOS;i++)
553 {
554 xmc_device.global_register->dtxfsiz[i- 1U] = (uint32_t)(((256U + (i*(64U)))/4U) | ((uint32_t)16U << 16U));
555 }
556
557 /* flush the fifos for proper operation */
558 XMC_USBD_lFlushTXFifo(0x10U); /* 0x10 == all fifos, see doc */
559 XMC_USBD_lFlushTXFifo(0x0U);
560 XMC_USBD_lFlushRXFifo();
561 /* Flush learning queue not needed due to fifo config */
562 /* enable ep0 interrupts */
563 daint.d32 = 0U;
564 daint.b.inep0 = 1U;
565 daint.b.outep0 = 1U;
566 xmc_device.device_register->daintmsk = daint.d32;
567
568 /* enable endpoint interrupts */
569 /* out ep interrupts */
570 XMC_USBD_EnableEventOUTEP(((uint32_t)XMC_USBD_EVENT_OUT_EP_TX_COMPLET | (uint32_t)XMC_USBD_EVENT_OUT_EP_DISABLED |
571 (uint32_t)XMC_USBD_EVENT_OUT_EP_SETUP | (uint32_t)XMC_USBD_EVENT_OUT_EP_AHB_ERROR));
572
573 /*in ep interrupts */
574 XMC_USBD_EnableEventINEP(((uint32_t)XMC_USBD_EVENT_IN_EP_TX_COMPLET | (uint32_t)XMC_USBD_EVENT_IN_EP_DISABLED |
575 (uint32_t)XMC_USBD_EVENT_IN_EP_AHB_ERROR | (uint32_t)XMC_USBD_EVENT_IN_EP_TIMEOUT));
576
577
578 /* Clear device Address */
579 dcfg.d32 = xmc_device.device_register->dcfg;
580 dcfg.b.devaddr = 0U;
581 xmc_device.device_register->dcfg = dcfg.d32;
582
583 if(obj->usbd_transfer_mode == XMC_USBD_USE_FIFO)
584 {
585 /* Clear Empty interrupt */
586 xmc_device.device_register->dtknqr4_fifoemptymsk = 0U;
587 }
588
589 xmc_device.ep[0U].outInUse = 0U;
590 xmc_device.ep[0U].inInUse = 0U;
591
592 xmc_device.DeviceEvent_cb(XMC_USBD_EVENT_RESET);
593
594 /* clear reset intr */
595 XMC_USBD_ClearEvent(XMC_USBD_EVENT_RESET);
596 }
597
598 /**
599 * @brief Handle OTG Interrupt
600 *
601 * It detects especially connect and disconnect events.
602 */
XMC_USBD_lHandleOTGInt(void)603 static void XMC_USBD_lHandleOTGInt(void)
604 {
605 gotgint_data_t data;
606 data.d32 = xmc_device.global_register->gotgint;
607 if (data.b.sesenddet)
608 {
609 xmc_device.IsPowered = 0U;
610 xmc_device.DeviceEvent_cb(XMC_USBD_EVENT_POWER_OFF);
611 }
612 XMC_USBD_lClearEventOTG(data.d32);
613
614 }
615
616 /**
617 * @brief Interrupt handler for device enumeration done.
618 *
619 * Handles the enumeration done from dwc_otg, when the host has enumerated the device.
620 */
XMC_USBD_lHandleEnumDone(void)621 static void XMC_USBD_lHandleEnumDone(void)
622 {
623 /* Normaly we need to check dctl
624 * We are always fullspeed, so max it up. */
625 depctl_data_t epctl;
626 gusbcfg_data_t gusbcfg;
627
628 epctl.d32=xmc_device.endpoint_in_register[0U]->diepctl;
629 epctl.b.mps = 0x00U; /* 64 Byte, this is also automatically set for out ep */
630 xmc_device.endpoint_in_register[0U]->diepctl = epctl.d32;
631
632 /* update device connected flag */
633 xmc_device.IsConnected = 1U;
634 xmc_device.IsPowered = 1U;
635
636 xmc_device.DeviceEvent_cb(XMC_USBD_EVENT_CONNECT);
637
638 /* Set Trim */
639 gusbcfg.d32 = xmc_device.global_register->gusbcfg;
640 gusbcfg.b.usbtrdtim = 9U; /* default value for LS/FS */
641 xmc_device.global_register->gusbcfg = gusbcfg.d32;
642
643 /* clear interrupt */
644 XMC_USBD_ClearEvent(XMC_USBD_EVENT_ENUMDONE);
645 }
646
647
648 /**
649 * @brief Handles all interrupts for all out endpoints
650 *
651 * The interrupt handler first checks, which endpoint has caused the interrupt and then
652 * determines, which interrupt should be handled.
653 */
XMC_USBD_lHandleOEPInt(const XMC_USBD_t * const obj)654 static void XMC_USBD_lHandleOEPInt(const XMC_USBD_t *const obj)
655 {
656 daint_data_t daint;
657 daint_data_t daintmsk;
658 doepmsk_data_t doepmsk;
659 doepint_data_t doepint;
660 deptsiz_data_t doeptsiz;
661 XMC_USBD_EP_t *ep;
662 uint16_t temp;
663 uint16_t temp1;
664 uint16_t mask;
665 uint8_t ep_num;
666
667 daint.d32 = xmc_device.device_register->daint;
668
669 daintmsk.d32 = xmc_device.device_register->daintmsk;
670
671 doepmsk.d32 = xmc_device.device_register->doepmsk;
672
673 mask = daint.ep.out & daintmsk.ep.out;
674 ep_num = 0U;
675 doeptsiz.d32 = 0U;
676
677 while ((uint16_t)mask >> ep_num)
678 {
679 temp1 = (mask >> (uint16_t)ep_num);
680 temp = temp1 & 0x1U;
681 if (temp)
682 {
683 /* load register data for endpoint */
684 ep = &xmc_device.ep[ep_num];
685 doepint.d32 = xmc_device.endpoint_out_register[ep_num]->doepint & doepmsk.d32;
686 if(obj->usbd_transfer_mode == XMC_USBD_USE_DMA)
687 {
688 doeptsiz.d32 = xmc_device.endpoint_out_register[ep_num]->doeptsiz;
689 }
690 /* Setup Phase Complete */
691 if (doepint.b.setup)
692 {
693 /* ep0 not stalled any more */
694 ep->isStalled = 0U;
695 if(obj->usbd_transfer_mode == XMC_USBD_USE_DMA)
696 {
697 /* calculate size for setup packet */
698 ep->outBytesAvailable = (uint32_t)(((uint32_t)XMC_USBD_SETUP_COUNT -
699 (uint32_t)((deptsiz0_data_t*)&doeptsiz)->b.supcnt)*(uint32_t)XMC_USBD_SETUP_SIZE);
700 }
701 if(obj->usbd_transfer_mode == XMC_USBD_USE_FIFO)
702 {
703 ep->outBytesAvailable += ep->xferCount;
704 }
705 ep->outInUse = 0U;
706 xmc_device.EndpointEvent_cb(0U,XMC_USBD_EP_EVENT_SETUP); /* signal endpoint event */
707 /* clear the interrupt */
708 XMC_USBD_ClearEventOUTEP((uint32_t)XMC_USBD_EVENT_OUT_EP_SETUP,ep_num);
709 }
710 if (doepint.b.xfercompl)
711 {
712 if(obj->usbd_transfer_mode == XMC_USBD_USE_DMA)
713 {
714 uint32_t bytes = (ep->xferLength - ep->xferCount) - doeptsiz.b.xfersize;
715 ep->xferCount += bytes;
716 ep->xferBuffer += bytes;
717 }
718 if (ep->xferTotal == ep->xferLength)
719 {
720 ep->outBytesAvailable = ep->xferCount;
721 ep->outInUse = 0U;
722 xmc_device.EndpointEvent_cb(ep_num,XMC_USBD_EP_EVENT_OUT);
723 }
724 else
725 {
726 XMC_USBD_lStartReadXfer(ep);
727 }
728
729 }
730
731 XMC_USBD_ClearEventOUTEP(doepint.d32,ep_num);
732 }
733 ep_num++;
734 }
735
736 /* clear interrupt */
737 XMC_USBD_ClearEvent(XMC_USBD_EVENT_OUTEP);
738 }
739
740 /**
741 * @brief Handles all interrupts for all in endpoints
742 *
743 * The interrupt handler first checks, which endpoint has caused the interrupt and then
744 * determines, which interrupt should be handled.
745 */
XMC_USBD_lHandleIEPInt(const XMC_USBD_t * const obj)746 static void XMC_USBD_lHandleIEPInt(const XMC_USBD_t *const obj)
747 {
748 XMC_USBD_EP_t *ep;
749 daint_data_t daint;
750 diepmsk_data_t diepmsk;
751 diepint_data_t diepint;
752 deptsiz_data_t dieptsiz;
753 uint16_t temp;
754 uint16_t temp1;
755 uint16_t mask;
756 uint8_t ep_num;
757 uint32_t inepint;
758
759 daint.d32 = xmc_device.device_register->daint;
760
761 diepmsk.d32 = xmc_device.device_register->diepmsk;
762
763 dieptsiz.d32 = 0U;
764 mask = daint.ep.in;
765 ep_num = 0U;
766
767 while ((uint16_t)mask >> ep_num)
768 {
769 temp1 = ((uint16_t)mask >> (uint16_t)ep_num);
770 temp = (uint16_t)temp1 & (uint16_t)0x1U;
771 if ((uint16_t)temp)
772 {
773 ep = &xmc_device.ep[ep_num];
774 inepint = (uint32_t)xmc_device.endpoint_in_register[ep_num]->diepint;
775 diepint.d32 = inepint &
776 ((((uint32_t)((uint32_t)xmc_device.device_register->dtknqr4_fifoemptymsk >> ep->address_u.address_st.number) &
777 0x1U) << 7U) | (uint32_t)diepmsk.d32);
778 if(obj->usbd_transfer_mode == XMC_USBD_USE_DMA)
779 {
780 dieptsiz.d32 = xmc_device.endpoint_in_register[ep_num]->dieptsiz;
781 }
782 if(obj->usbd_transfer_mode == XMC_USBD_USE_FIFO)
783 {
784 if (diepint.b.emptyintr)
785 {
786 uint32_t bytes;
787 bytes = XMC_USBD_lWriteFifo(ep);
788 ep->xferCount += bytes;
789 ep->xferBuffer += bytes;
790 }
791 }
792 if (diepint.b.xfercompl)
793 {
794 if(obj->usbd_transfer_mode == XMC_USBD_USE_DMA)
795 {
796 /* update xfer values */
797 if ((dieptsiz.b.pktcnt == 0U) && (dieptsiz.b.xfersize == 0U))
798 {
799 uint32_t Bytes = ep->xferLength - ep->xferCount;
800 ep->xferCount += Bytes;
801 ep->xferBuffer += Bytes;
802 }
803 }
804 if (ep->xferTotal==ep->xferLength)
805 {
806 ep->inInUse = 0U;
807 if(obj->usbd_transfer_mode == XMC_USBD_USE_FIFO)
808 {
809 /* mask fifo empty interrupt */
810 xmc_device.device_register->dtknqr4_fifoemptymsk =
811 (uint32_t)(xmc_device.device_register->dtknqr4_fifoemptymsk & ~(((uint32_t)1U << ep_num)));
812 }
813 xmc_device.EndpointEvent_cb(0x80U | ep_num,XMC_USBD_EP_EVENT_IN);
814 }
815 else
816 {
817 /* start next step of transfer */
818 XMC_USBD_lStartWriteXfer(ep);
819 }
820
821 }
822
823 XMC_USBD_ClearEventINEP((uint32_t)diepint.d32,ep_num);
824 }
825 ep_num++;
826 }
827 XMC_USBD_ClearEvent(XMC_USBD_EVENT_INEP);
828 }
829
830 /**
831 * @brief RX Fifo interrupt handler
832 *
833 * This function handles the interrupt, when the rx fifo is not empty anymore.
834 */
XMC_USBD_lHandleRxFLvl(void)835 static void XMC_USBD_lHandleRxFLvl(void)
836 {
837 device_grxsts_data_t data;
838 data.d32 = xmc_device.global_register->grxstsp;
839
840 switch (data.b.pktsts)
841 {
842 case XMC_USBD_GRXSTS_PKTSTS_GOUTNAK:
843 break;
844 case XMC_USBD_GRXSTS_PKTSTS_OUTCMPL:
845 break;
846 case XMC_USBD_GRXSTS_PKTSTS_OUTDATA:
847 XMC_USBD_lReadFifo((uint32_t)data.b.epnum,(uint32_t)data.b.bcnt);
848 break;
849 case XMC_USBD_GRXSTS_PKTSTS_SETUP:
850 XMC_USBD_lReadFifo((uint32_t)data.b.epnum,(uint32_t)data.b.bcnt);
851 break;
852 case XMC_USBD_GRXSTS_PKTSTS_SETUPCMPL:
853 break;
854 default:
855 break;
856 }
857 /* no need to clear */
858 }
859
860 /**
861 * @brief Global interrupt handler
862 *
863 * The handler first checks, which global interrupt has caused the interrupt
864 * and then dispatches interrupt to the corresponding sub-handler.
865 */
XMC_USBD_IRQHandler(const XMC_USBD_t * const obj)866 void XMC_USBD_IRQHandler(const XMC_USBD_t *const obj)
867 {
868 gintmsk_data_t gintmsk;
869 gintsts_data_t data;
870
871 gintmsk.d32 = xmc_device.global_register->gintmsk;
872 data.d32 = xmc_device.global_register->gintsts & gintmsk.d32;
873
874 if (data.b.sofintr)
875 {
876 xmc_device.DeviceEvent_cb(XMC_USBD_EVENT_SOF);
877 XMC_USBD_ClearEvent(XMC_USBD_EVENT_SOF);
878 }
879 if(obj->usbd_transfer_mode == XMC_USBD_USE_FIFO)
880 {
881 if (data.b.rxstsqlvl)
882 {
883 /* Masked that interrupt so its only done once */
884 gintmsk.b.rxstsqlvl = 0U;
885 xmc_device.global_register->gintmsk = gintmsk.d32;
886 XMC_USBD_lHandleRxFLvl(); /* handle the interrupt */
887 gintmsk.b.rxstsqlvl = 1U;
888 xmc_device.global_register->gintmsk = gintmsk.d32;
889 }
890 }
891 if (data.b.erlysuspend)
892 {
893 XMC_USBD_ClearEvent(XMC_USBD_EVENT_EARLYSUSPEND);
894 }
895 if (data.b.usbsuspend)
896 {
897 xmc_device.DeviceEvent_cb(XMC_USBD_EVENT_SUSPEND);
898 XMC_USBD_ClearEvent(XMC_USBD_EVENT_SUSPEND);
899 }
900 if (data.b.wkupintr)
901 {
902 xmc_device.DeviceEvent_cb(XMC_USBD_EVENT_REMOTE_WAKEUP);
903 XMC_USBD_ClearEvent(XMC_USBD_EVENT_REMOTE_WAKEUP);
904 }
905 if (data.b.sessreqintr)
906 {
907 xmc_device.IsPowered = 1U;
908 xmc_device.DeviceEvent_cb(XMC_USBD_EVENT_POWER_ON);
909 XMC_USBD_ClearEvent(XMC_USBD_EVENT_POWER_ON);
910 }
911 if (data.b.usbreset)
912 {
913 XMC_USBD_lHandleUSBReset(obj);
914 }
915 if (data.b.enumdone)
916 {
917 XMC_USBD_lHandleEnumDone();
918 }
919 if (data.b.inepint)
920 {
921 XMC_USBD_lHandleIEPInt(obj);
922 }
923 if (data.b.outepintr)
924 {
925 XMC_USBD_lHandleOEPInt(obj);
926 }
927 if (data.b.otgintr)
928 {
929 XMC_USBD_lHandleOTGInt();
930 }
931
932 }
933
934
935 /*******************************************************************************
936 * API IMPLEMENTATION
937 *******************************************************************************/
938 /**
939 * Enables the USB0 module
940 **/
XMC_USBD_Enable(void)941 void XMC_USBD_Enable(void)
942 {
943 #if defined(CLOCK_GATING_SUPPORTED)
944 XMC_SCU_CLOCK_UngatePeripheralClock(XMC_SCU_PERIPHERAL_CLOCK_USB0);
945 #endif
946 /* Reset and power up */
947 XMC_SCU_RESET_DeassertPeripheralReset(XMC_SCU_PERIPHERAL_RESET_USB0);
948 XMC_SCU_POWER_EnableUsb();
949 }
950
951 /**
952 * Disables the USB0 module
953 **/
XMC_USBD_Disable(void)954 void XMC_USBD_Disable(void)
955 {
956 /* Clear Reset and power up */
957 XMC_SCU_RESET_AssertPeripheralReset(XMC_SCU_PERIPHERAL_RESET_USB0);
958 #if defined(CLOCK_GATING_SUPPORTED)
959 XMC_SCU_CLOCK_GatePeripheralClock(XMC_SCU_PERIPHERAL_CLOCK_USB0);
960 #endif
961 XMC_SCU_POWER_DisableUsb();
962 }
963
964 /**
965 * Clear the USB device event
966 **/
XMC_USBD_ClearEvent(const XMC_USBD_EVENT_t event)967 void XMC_USBD_ClearEvent(const XMC_USBD_EVENT_t event)
968 {
969 gintsts_data_t clear;
970 clear.d32 = 0U;
971 switch(event)
972 {
973 case (XMC_USBD_EVENT_POWER_ON):
974 clear.b.sessreqintr = 1U;
975 break;
976 case (XMC_USBD_EVENT_RESET):
977 clear.b.usbreset = 1U;
978 break;
979 case (XMC_USBD_EVENT_SUSPEND):
980 clear.b.usbsuspend = 1U;
981 break;
982 case (XMC_USBD_EVENT_RESUME):
983 clear.b.wkupintr = 1U;
984 break;
985 case (XMC_USBD_EVENT_REMOTE_WAKEUP):
986 clear.b.wkupintr = 1U;
987 break;
988 case (XMC_USBD_EVENT_SOF):
989 clear.b.sofintr = 1U;
990 break;
991 case (XMC_USBD_EVENT_EARLYSUSPEND):
992 clear.b.erlysuspend = 1U;
993 break;
994 case (XMC_USBD_EVENT_ENUMDONE):
995 clear.b.enumdone = 1U;
996 break;
997 case (XMC_USBD_EVENT_OUTEP):
998 clear.b.outepintr = 1U;
999 break;
1000 default:
1001 break;
1002 }
1003 xmc_device.global_register->gintsts = clear.d32;
1004 }
1005
1006 /**
1007 * Clear the USB OTG events
1008 **/
XMC_USBD_lClearEventOTG(uint32_t event)1009 static void XMC_USBD_lClearEventOTG(uint32_t event)
1010 {
1011 gotgint_data_t clear = { .d32 = 0U};
1012 clear.d32 = event;
1013 xmc_device.global_register->gotgint = clear.d32;
1014 }
1015
1016 /**
1017 * Clear the USB IN EP events
1018 **/
XMC_USBD_ClearEventINEP(uint32_t event,const uint8_t ep_num)1019 void XMC_USBD_ClearEventINEP(uint32_t event,const uint8_t ep_num)
1020 {
1021 diepint_data_t clear;
1022 clear.d32 = event;
1023 xmc_device.endpoint_in_register[ep_num]->diepint = clear.d32;
1024 }
1025
1026 /**
1027 * Clear the USB OUT EP events
1028 **/
XMC_USBD_ClearEventOUTEP(uint32_t event,const uint8_t ep_num)1029 void XMC_USBD_ClearEventOUTEP(uint32_t event,const uint8_t ep_num)
1030 {
1031 doepint_data_t clear;
1032 clear.d32 = event;
1033 xmc_device.endpoint_out_register[ep_num]->doepint = clear.d32;
1034 }
1035
1036 /**
1037 * Enable the USB OUT EP events
1038 **/
XMC_USBD_EnableEventOUTEP(uint32_t event)1039 void XMC_USBD_EnableEventOUTEP(uint32_t event)
1040 {
1041 doepint_data_t doepint;
1042 doepint.d32 = event;
1043 xmc_device.device_register->doepmsk |= doepint.d32;
1044 }
1045
1046 /**
1047 * Enable the USB IN EP events
1048 **/
XMC_USBD_EnableEventINEP(uint32_t event)1049 void XMC_USBD_EnableEventINEP(uint32_t event)
1050 {
1051 diepint_data_t diepint;
1052 diepint.d32 = event;
1053 xmc_device.device_register->diepmsk |= diepint.d32;
1054 }
1055
1056 /**
1057 * Gets the USB device capabilities
1058 **/
XMC_USBD_GetCapabilities()1059 XMC_USBD_CAPABILITIES_t XMC_USBD_GetCapabilities()
1060 {
1061 XMC_USBD_CAPABILITIES_t cap={0U};
1062 cap.event_connect = 1U;
1063 cap.event_disconnect = 1U;
1064 #if UC_SERIES == 45
1065 cap.event_power_off = 1U;
1066 cap.event_power_on = 1U;
1067 #else
1068 cap.event_power_off = 0U;
1069 cap.event_power_on = 0U;
1070 #endif
1071 cap.event_high_speed = 0U;
1072 cap.event_remote_wakeup = 1U;
1073 cap.event_reset = 1U;
1074 cap.event_resume = 1U;
1075 cap.event_suspend = 1U;
1076 cap.reserved = 0U;
1077 return cap;
1078 }
1079
1080 /**
1081 * Initializes the USB device
1082 **/
XMC_USBD_Init(XMC_USBD_t * obj)1083 XMC_USBD_STATUS_t XMC_USBD_Init(XMC_USBD_t *obj)
1084 {
1085 uint8_t *XMC_USBD_BASE_ADDRESS;
1086 uint32_t i;
1087 gahbcfg_data_t gahbcfg;
1088 gusbcfg_data_t gusbcfg;
1089 dcfg_data_t dcfg;
1090 dctl_data_t dctl;
1091 gintmsk_data_t gintmsk;
1092
1093 XMC_ASSERT("XMC_USBD_Init: obj.usbd_max_num_eps not of type XMC_USBD_MAX_NUM_EPS_t",
1094 XMC_USBD_CHECK_INPUT_MAX_NUM_EPS(obj->usbd_max_num_eps))
1095
1096 XMC_USBD_Enable();
1097
1098 usbd_init = obj;
1099
1100 /* Filling out buffer size */
1101 for(i = 0U;i < (uint32_t)XMC_USBD_NUM_EPS;i++)
1102 {
1103 XMC_USBD_EP_OUT_BUFFERSIZE[i] = XMC_USBD_EP0_BUFFER_SIZE;
1104 XMC_USBD_EP_IN_BUFFERSIZE[i] = XMC_USBD_EP0_BUFFER_SIZE;
1105 }
1106
1107 /* clear device status */
1108 memset((void*)&xmc_device,0x0U,sizeof(XMC_USBD_DEVICE_t));
1109
1110 /* assign callbacks */
1111 xmc_device.DeviceEvent_cb = obj->cb_xmc_device_event;
1112 xmc_device.EndpointEvent_cb = obj->cb_endpoint_event;
1113 XMC_USBD_BASE_ADDRESS = (uint8_t *)(obj->usbd);
1114 /* assign register address */
1115 xmc_device.global_register = (dwc_otg_core_global_regs_t*)(obj->usbd);
1116 xmc_device.device_register = ((dwc_otg_device_global_regs_t*)(XMC_USBD_BASE_ADDRESS + DWC_DEV_GLOBAL_REG_OFFSET));
1117 for (i = 0U;i < (uint32_t)XMC_USBD_NUM_EPS;i++)
1118 {
1119 xmc_device.endpoint_in_register[i] = (dwc_otg_dev_in_ep_regs_t*)(XMC_USBD_BASE_ADDRESS + DWC_DEV_IN_EP_REG_OFFSET +
1120 ((uint32_t)DWC_EP_REG_OFFSET*i));
1121 }
1122 for (i = 0U;i < (uint32_t)XMC_USBD_NUM_EPS;i++)
1123 {
1124 xmc_device.endpoint_out_register[i] = (dwc_otg_dev_out_ep_regs_t*)(XMC_USBD_BASE_ADDRESS +
1125 DWC_DEV_OUT_EP_REG_OFFSET +
1126 ((uint32_t)DWC_EP_REG_OFFSET*i));
1127 }
1128 for (i = 0U;i < (uint32_t)XMC_USBD_NUM_TX_FIFOS;i++)
1129 {
1130 xmc_device.fifo[i] = (uint32_t*)(XMC_USBD_BASE_ADDRESS +
1131 XMC_USBD_TX_FIFO_REG_OFFSET +
1132 (i * XMC_USBD_TX_FIFO_OFFSET));
1133 }
1134 /* obj data structure for endpoint 0 */
1135 /* Done by driver core */
1136 /* configure ahb details */
1137 gahbcfg.d32 = xmc_device.global_register->gahbcfg;
1138 gahbcfg.b.glblintrmsk = 1U; /* enable interrupts ( global mask ) */
1139 gahbcfg.b.nptxfemplvl_txfemplvl = 1U;
1140 if(obj->usbd_transfer_mode == XMC_USBD_USE_DMA)
1141 {
1142 /* Enable dma if needed */
1143 gahbcfg.b.dmaenable = 1U; /* enable dma if needed */
1144 }
1145 else
1146 {
1147 gahbcfg.b.dmaenable = 0U;
1148 }
1149 xmc_device.global_register->gahbcfg = gahbcfg.d32;
1150 /* configure usb details */
1151 gusbcfg.d32= xmc_device.global_register->gusbcfg;
1152 gusbcfg.b.force_dev_mode = 1U; /* force us into device mode */
1153 gusbcfg.b.srpcap = 1U; /* enable session request protocoll */
1154 xmc_device.global_register->gusbcfg = gusbcfg.d32;
1155
1156 /* Device init */
1157 /* configure device speed */
1158 dcfg.d32 = xmc_device.device_register->dcfg;
1159 dcfg.b.devspd = XMC_USBD_DCFG_DEVSPD_FS;
1160 dcfg.b.descdma = 0U;
1161 xmc_device.device_register->dcfg = dcfg.d32;
1162 /* configure device functions */
1163 dctl.d32 = xmc_device.device_register->dctl;
1164 dctl.b.sftdiscon = 1U; /* disconnect the device until its connected by the user */
1165 /* all other config is done by default register value */
1166 xmc_device.device_register->dctl = dctl.d32;
1167 /* flush the fifos for proper operation */
1168 XMC_USBD_lFlushTXFifo((uint8_t)0x10U); /* 0x10 == all fifos, see doc */
1169 XMC_USBD_lFlushRXFifo();
1170 /* Enable Global Interrupts */
1171 /* clear interrupt status bits prior to unmasking */
1172 xmc_device.global_register->gintmsk = 0U; /* disable all interrupts */
1173 xmc_device.global_register->gintsts = 0xFFFFFFFFU; /* clear all interrupts */
1174
1175 gintmsk.d32 = 0U;
1176 /* enable common interrupts */
1177 gintmsk.b.modemismatch = 1U;
1178 gintmsk.b.otgintr = 1U;
1179 gintmsk.b.sessreqintr = 1U;
1180 /* enable device interrupts */
1181 gintmsk.b.usbreset = 1U;
1182 gintmsk.b.enumdone = 1U;
1183 gintmsk.b.erlysuspend = 1U;
1184 gintmsk.b.usbsuspend = 1U;
1185 gintmsk.b.wkupintr = 1U;
1186 gintmsk.b.sofintr = 1U;
1187 if(obj->usbd_transfer_mode == XMC_USBD_USE_FIFO)
1188 {
1189 gintmsk.b.rxstsqlvl = 1U;
1190 }
1191 gintmsk.b.outepintr = 1U;
1192 gintmsk.b.inepintr = 1U;
1193 xmc_device.global_register->gintmsk = gintmsk.d32;
1194 return XMC_USBD_STATUS_OK;
1195 }
1196
1197 /**
1198 * Uninitializes the USB device
1199 **/
XMC_USBD_Uninitialize()1200 XMC_USBD_STATUS_t XMC_USBD_Uninitialize()
1201 {
1202 /* Disconnect the device */
1203 dctl_data_t dctl;
1204 dctl.d32 = xmc_device.device_register->dctl;
1205 dctl.b.sftdiscon = 1U;
1206 xmc_device.device_register->dctl = dctl.d32;
1207 /* clean up */
1208 memset((void*)&xmc_device,0U,sizeof(xmc_device));
1209 return XMC_USBD_STATUS_OK;
1210 }
1211
1212 /**
1213 * Connects the USB device to host
1214 **/
XMC_USBD_DeviceConnect()1215 XMC_USBD_STATUS_t XMC_USBD_DeviceConnect()
1216 {
1217 /* Just disable softdisconnect */
1218 dctl_data_t dctl;
1219 dctl.d32 = xmc_device.device_register->dctl;
1220 dctl.b.sftdiscon = 0U;
1221 xmc_device.device_register->dctl = dctl.d32;
1222 return XMC_USBD_STATUS_OK;
1223 }
1224
1225 /**
1226 * Disconnects the USB device from host
1227 **/
XMC_USBD_DeviceDisconnect()1228 XMC_USBD_STATUS_t XMC_USBD_DeviceDisconnect()
1229 {
1230 dctl_data_t dctl;
1231 dctl.d32 = xmc_device.device_register->dctl;
1232 dctl.b.sftdiscon = 1U;
1233 xmc_device.device_register->dctl = dctl.d32;
1234 return XMC_USBD_STATUS_OK;
1235 }
1236
1237 /**
1238 * Gets the USB device state.
1239 **/
XMC_USBD_DeviceGetState(const XMC_USBD_t * const obj)1240 XMC_USBD_STATE_t XMC_USBD_DeviceGetState(const XMC_USBD_t *const obj)
1241 {
1242 XMC_USBD_STATE_t state={0U};
1243 state.speed = XMC_USBD_SPEED_FULL;
1244 state.connected = xmc_device.IsConnected;
1245 state.active = XMC_USBD_lDeviceActive(obj);
1246 state.powered = xmc_device.IsPowered;
1247 return state;
1248 }
1249
1250 /**
1251 * Prepares the endpoint to read next OUT packet
1252 **/
XMC_USBD_EndpointReadStart(const uint8_t ep_addr,uint32_t size)1253 XMC_USBD_STATUS_t XMC_USBD_EndpointReadStart(const uint8_t ep_addr, uint32_t size)
1254 {
1255 XMC_USBD_EP_t *ep = &xmc_device.ep[ep_addr & (uint8_t)XMC_USBD_EP_NUM_MASK];
1256 XMC_USBD_STATUS_t result;
1257
1258 if (ep->outInUse || !ep->isConfigured)
1259 {
1260 result = XMC_USBD_STATUS_ERROR;
1261 }
1262 else
1263 {
1264 /* short the length to buffer size if needed */
1265 if (size > ep->outBufferSize)
1266 {
1267 size = ep->outBufferSize;
1268 }
1269 /* set ep values */
1270 ep->xferTotal = size;
1271 ep->xferCount = 0U;
1272 ep->xferLength = 0U;
1273 ep->xferBuffer = ep->outBuffer;
1274 ep->outBytesAvailable = 0U;
1275 XMC_USBD_lStartReadXfer(ep);
1276 result= XMC_USBD_STATUS_OK;
1277 }
1278 return result;
1279 }
1280
1281 /**
1282 * Reads the number of bytes from the USB OUT endpoint
1283 **/
XMC_USBD_EndpointRead(const uint8_t ep_num,uint8_t * buffer,uint32_t length)1284 int32_t XMC_USBD_EndpointRead(const uint8_t ep_num,uint8_t * buffer,uint32_t length)
1285 {
1286 XMC_USBD_EP_t *ep = &xmc_device.ep[ep_num];
1287 if (length > ep->outBytesAvailable)
1288 {
1289 length = ep->outBytesAvailable;
1290 }
1291 memcpy(buffer,&ep->outBuffer[ep->outOffset],length);
1292 ep->outBytesAvailable -= length;
1293 if (ep->outBytesAvailable)
1294 {
1295 ep->outOffset += length;
1296 }
1297 else
1298 {
1299 ep->outOffset = 0U;
1300 }
1301 return (int32_t)length;
1302 }
1303
1304 /**
1305 * Writes number of bytes in to the USB IN endpoint.
1306 **/
XMC_USBD_EndpointWrite(const uint8_t ep_num,const uint8_t * buffer,uint32_t length)1307 int32_t XMC_USBD_EndpointWrite(const uint8_t ep_num,const uint8_t * buffer,uint32_t length)
1308 {
1309 XMC_USBD_EP_t * ep = &xmc_device.ep[ep_num & (uint8_t)XMC_USBD_EP_NUM_MASK];
1310 int32_t result;
1311 if (!ep->isConfigured)
1312 {
1313 result = (int32_t)XMC_USBD_STATUS_ERROR;
1314 }
1315 else if (ep->inInUse == 1U)
1316 {
1317 result=(int32_t)0;
1318 }
1319 else
1320 {
1321 if (length > ep->inBufferSize)
1322 {
1323 length = ep->inBufferSize;
1324 }
1325 /* copy data into input buffer for DMA and FIFO mode */
1326 memcpy(ep->inBuffer,(const void *)buffer,length);
1327 ep->xferBuffer = ep->inBuffer;
1328 ep->xferTotal = length;
1329 /* set transfer values */
1330 ep->xferLength = 0U;
1331 ep->xferCount = 0U;
1332 ep->inInUse = 1U;
1333 /* start the transfer */
1334 XMC_USBD_lStartWriteXfer(ep);
1335 result=(int32_t)ep->xferTotal;
1336 }
1337 return result;
1338 }
1339
1340 /**
1341 * Sets the USB device address.
1342 **/
XMC_USBD_DeviceSetAddress(const uint8_t address,const XMC_USBD_SET_ADDRESS_STAGE_t stage)1343 XMC_USBD_STATUS_t XMC_USBD_DeviceSetAddress(const uint8_t address,const XMC_USBD_SET_ADDRESS_STAGE_t stage)
1344 {
1345 dcfg_data_t data;
1346 data.d32 = xmc_device.device_register->dcfg;
1347 if (stage == XMC_USBD_SET_ADDRESS_STAGE_SETUP)
1348 {
1349 data.b.devaddr = address;
1350 xmc_device.device_register->dcfg = data.d32;
1351 }
1352 return XMC_USBD_STATUS_OK;
1353 }
1354
1355 /**
1356 * Set/clear stall on the selected endpoint.
1357 **/
XMC_USBD_EndpointStall(const uint8_t ep_addr,const bool stall)1358 XMC_USBD_STATUS_t XMC_USBD_EndpointStall(const uint8_t ep_addr, const bool stall)
1359 {
1360 depctl_data_t data;
1361 XMC_USBD_EP_t *ep = &xmc_device.ep[(ep_addr & (uint8_t)XMC_USBD_EP_NUM_MASK)];
1362 if (stall)
1363 {
1364 if (ep_addr & (uint8_t)XMC_USBD_ENDPOINT_DIRECTION_MASK)
1365 {
1366 /*set stall bit */
1367 data.d32 = xmc_device.endpoint_in_register[ep->address_u.address_st.number]->diepctl;
1368 data.b.stall = 1U;
1369 xmc_device.endpoint_in_register[ep->address_u.address_st.number]->diepctl = data.d32;
1370 }
1371 else
1372 {
1373 /*set stall bit */
1374 data.d32 = xmc_device.endpoint_out_register[ep->address_u.address_st.number]->doepctl;
1375 data.b.stall = 1U;
1376 xmc_device.endpoint_out_register[ep->address_u.address_st.number]->doepctl = data.d32;
1377 }
1378 ep->isStalled = 1U;
1379 }
1380 else
1381 {
1382 /* just clear stall bit */
1383 if (ep_addr & (uint8_t)XMC_USBD_ENDPOINT_DIRECTION_MASK)
1384 {
1385 data.d32 = xmc_device.endpoint_in_register[ep->address_u.address_st.number]->diepctl;
1386 data.b.stall = 0U;
1387 data.b.setd0pid = 1U; /* reset pid to 0 */
1388 xmc_device.endpoint_in_register[ep->address_u.address_st.number]->diepctl = data.d32;
1389 }
1390 else
1391 {
1392 data.d32 = xmc_device.endpoint_out_register[ep->address_u.address_st.number]->doepctl;
1393 data.b.stall = 0U;
1394 data.b.setd0pid = 1U; /* reset pid to 0 */
1395 xmc_device.endpoint_out_register[ep->address_u.address_st.number]->doepctl = data.d32;
1396 }
1397 ep->isStalled = 0U;
1398 }
1399 return XMC_USBD_STATUS_OK;
1400 }
1401
1402 /**
1403 * Aborts the data transfer on the selected endpoint
1404 **/
XMC_USBD_EndpointAbort(const uint8_t ep_addr)1405 XMC_USBD_STATUS_t XMC_USBD_EndpointAbort(const uint8_t ep_addr) {
1406 XMC_USBD_EP_t *ep = &xmc_device.ep[ep_addr & (uint8_t)XMC_USBD_ENDPOINT_NUMBER_MASK];
1407 if (ep->address_u.address_st.direction)
1408 {
1409 ep->inInUse = 0U;
1410 }
1411 if (!ep->address_u.address_st.direction)
1412 {
1413 ep->outInUse = 0U;
1414 }
1415 ep->isStalled = 0U;
1416 ep->outBytesAvailable = 0U;
1417 ep->outOffset = 0U;
1418 ep->xferLength = 0U;
1419 ep->xferCount = 0U;
1420 ep->xferTotal = 0U;
1421
1422 return XMC_USBD_STATUS_OK;
1423 }
1424
1425 /**
1426 * Configures the given endpoint
1427 **/
XMC_USBD_EndpointConfigure(const uint8_t ep_addr,const XMC_USBD_ENDPOINT_TYPE_t ep_type,const uint16_t ep_max_packet_size)1428 XMC_USBD_STATUS_t XMC_USBD_EndpointConfigure(const uint8_t ep_addr,
1429 const XMC_USBD_ENDPOINT_TYPE_t ep_type,
1430 const uint16_t ep_max_packet_size)
1431 {
1432 daint_data_t daintmsk;
1433 XMC_USBD_EP_t *ep;
1434 daintmsk.d32 = xmc_device.device_register->daintmsk;
1435 ep =&xmc_device.ep[ep_addr & (uint32_t)XMC_USBD_ENDPOINT_NUMBER_MASK];
1436 memset((void*)ep,0x0U,sizeof(XMC_USBD_EP_t)); /* clear endpoint structure */
1437 /* do ep configuration */
1438 ep->address_u.address = ep_addr;
1439 ep->isConfigured = 1U;
1440 ep->maxPacketSize = (uint8_t)ep_max_packet_size;
1441 if (ep->address_u.address != 0U)
1442 {
1443 ep->maxTransferSize = (uint32_t)XMC_USBD_MAX_TRANSFER_SIZE;
1444 }
1445 else
1446 {
1447 ep->maxTransferSize = (uint32_t)XMC_USBD_MAX_TRANSFER_SIZE_EP0;
1448 }
1449 /* transfer buffer */
1450 ep->inBuffer = XMC_USBD_EP_IN_BUFFER[ep->address_u.address_st.number];
1451 ep->outBuffer = XMC_USBD_EP_OUT_BUFFER[ep->address_u.address_st.number];
1452 /* buffer size*/
1453 ep->inBufferSize = XMC_USBD_EP_IN_BUFFERSIZE[ep->address_u.address_st.number];
1454 ep->outBufferSize = XMC_USBD_EP_OUT_BUFFERSIZE[ep->address_u.address_st.number];
1455 /* is in */
1456 if ((ep->address_u.address_st.direction == 1U) || (ep_type == XMC_USBD_ENDPOINT_TYPE_CONTROL))
1457 {
1458 depctl_data_t data;
1459 data.d32 = xmc_device.endpoint_in_register[ep->address_u.address_st.number]->diepctl;
1460 /*enable endpoint */
1461 data.b.usbactep = 1U;
1462 /* set ep type */
1463 data.b.eptype = (uint8_t)ep_type;
1464 /* set mps */
1465 if (ep_type == XMC_USBD_ENDPOINT_TYPE_CONTROL)
1466 {
1467 switch(ep_max_packet_size)
1468 {
1469 case (64U):
1470 data.b.mps = 0x0U;
1471 break;
1472 case (32U):
1473 data.b.mps = 0x1U;
1474 break;
1475 case (16U):
1476 data.b.mps = 0x2U;
1477 break;
1478 case (8U):
1479 data.b.mps = 0x3U;
1480 break;
1481 default:
1482 break;
1483 }
1484 }
1485 else
1486 {
1487 data.b.mps = ep_max_packet_size;
1488 }
1489 /* set first data0 pid */
1490 data.b.setd0pid = 1U;
1491 /* clear stall */
1492 data.b.stall = 0U;
1493 /* set tx fifo */
1494 ep->txFifoNum = XMC_USBD_lAssignTXFifo(); /* get tx fifo */
1495 data.b.txfnum = ep->txFifoNum;
1496 xmc_device.endpoint_in_register[ep->address_u.address_st.number]->diepctl = data.d32; /* configure endpoint */
1497 daintmsk.ep.in |= (uint16_t)((uint16_t)1U << (uint8_t)ep->address_u.address_st.number); /* enable interrupts for endpoint */
1498 }
1499 if ((ep->address_u.address_st.direction == 0U) || (ep_type == XMC_USBD_ENDPOINT_TYPE_CONTROL))
1500 {
1501 /* is out */
1502 depctl_data_t data;
1503 data.d32 = xmc_device.endpoint_out_register[ep->address_u.address_st.number]->doepctl;
1504 /*enable endpoint */
1505 data.b.usbactep = 1U;
1506 /* set ep type */
1507 data.b.eptype = (uint8_t)ep_type;
1508 /* set mps */
1509 if (ep_type == XMC_USBD_ENDPOINT_TYPE_CONTROL)
1510 {
1511 switch(ep_max_packet_size)
1512 {
1513 case (64U):
1514 data.b.mps = 0x0U;
1515 break;
1516 case (32U):
1517 data.b.mps = 0x1U;
1518 break;
1519 case (16U):
1520 data.b.mps = 0x2U;
1521 break;
1522 case (8U):
1523 data.b.mps = 0x3U;
1524 break;
1525 default:
1526 break;
1527 }
1528 }
1529 else
1530 {
1531 data.b.mps = ep_max_packet_size;
1532 }
1533 /* set first data0 pid */
1534 data.b.setd0pid = 1U;
1535 /* clear stall */
1536 data.b.stall =(uint8_t) 0U;
1537 xmc_device.endpoint_out_register[ep->address_u.address_st.number]->doepctl = data.d32; /* configure endpoint */
1538 daintmsk.ep.out |=(uint16_t) ((uint16_t)1U << (uint8_t)ep->address_u.address_st.number); /* enable interrupts */
1539 }
1540 xmc_device.device_register->daintmsk = daintmsk.d32;
1541 return XMC_USBD_STATUS_OK;
1542 }
1543
1544 /**
1545 * Unconfigure the selected endpoint.
1546 **/
XMC_USBD_EndpointUnconfigure(const uint8_t ep_addr)1547 XMC_USBD_STATUS_t XMC_USBD_EndpointUnconfigure(const uint8_t ep_addr)
1548 {
1549 XMC_USBD_EP_t *ep = &xmc_device.ep[ep_addr & (uint8_t)XMC_USBD_ENDPOINT_NUMBER_MASK];
1550 depctl_data_t data;
1551 daint_data_t daintmsk;
1552 XMC_USBD_STATUS_t result;
1553 uint32_t number_temp;
1554 data.d32 = 0U;
1555 daintmsk.d32 = xmc_device.device_register->daintmsk;
1556 number_temp = (uint32_t)((uint32_t)1U << (uint8_t)ep->address_u.address_st.number);
1557 /* if not configured return an error */
1558 if (!ep->isConfigured)
1559 {
1560 result = XMC_USBD_STATUS_ERROR;
1561 }
1562 else
1563 {
1564 /* disable the endpoint, deactivate it and only send naks */
1565 data.b.usbactep = 0U;
1566 data.b.epdis = 1U;
1567 data.b.snak = 1U;
1568 data.b.stall = 0U;
1569 ep->isConfigured = 0U;
1570 ep->isStalled = 0U;
1571 ep->outInUse = 0U;
1572 ep->inInUse = 0U;
1573 /* chose register based on the direction. Control Endpoint need both */
1574 if ((ep->address_u.address_st.direction == 1U) || (ep->type == (uint8_t)XMC_USBD_ENDPOINT_TYPE_CONTROL))
1575 {
1576 /* disable endpoint configuration */
1577 xmc_device.endpoint_in_register[ep->address_u.address_st.number]->diepctl = data.d32;
1578 /* disable interrupts */
1579 daintmsk.ep.in = (uint16_t)((uint32_t)daintmsk.ep.in & (~(uint32_t)number_temp));
1580 }
1581 if ((ep->address_u.address_st.direction == 0U) || (ep->type == (uint8_t)XMC_USBD_ENDPOINT_TYPE_CONTROL))
1582 {
1583 xmc_device.endpoint_out_register[ep->address_u.address_st.number]->doepctl = data.d32;
1584 daintmsk.ep.out = (uint16_t)((uint32_t)daintmsk.ep.out & (~(uint32_t)number_temp));
1585 if(usbd_init->usbd_transfer_mode == XMC_USBD_USE_FIFO)
1586 {
1587 xmc_device.device_register->dtknqr4_fifoemptymsk &= ~number_temp;
1588 }
1589 }
1590 xmc_device.device_register->daintmsk = daintmsk.d32;
1591 XMC_USBD_lUnassignFifo(ep->txFifoNum); /* free fifo */
1592 result = XMC_USBD_STATUS_OK;
1593 }
1594 return result;
1595 }
1596
1597 /**
1598 * Gets the current USB frame number
1599 **/
XMC_USBD_GetFrameNumber(void)1600 uint16_t XMC_USBD_GetFrameNumber(void)
1601 {
1602 uint16_t result;
1603 dsts_data_t dsts;
1604 dsts.d32 = xmc_device.device_register->dsts;
1605 result = (uint16_t)dsts.b.soffn;
1606 return result;
1607 }
1608
1609 /**
1610 * Gets the USB speed enumeration completion status.
1611 * This should not be used for the actual USB enumeration completion status. For the actual USB enumeration status,
1612 * the application layer should check for the completion of USB standard request Set configuration.
1613 **/
XMC_USBD_IsEnumDone(void)1614 uint32_t XMC_USBD_IsEnumDone(void)
1615 {
1616 return (uint32_t)((uint8_t)xmc_device.IsConnected && (uint8_t)xmc_device.IsPowered);
1617 }
1618
1619 /***
1620 * MISRA C 2004 Deviations
1621 *
1622 * 1. cast from pointer to pointer [MISRA 2004 Rule 11.4]
1623 * 2. cast from pointer to unsigned int [Encompasses MISRA 2004 Rule 11.1], [MISRA 2004 Rule 11.3]
1624 * 3. call to function 'memset()' not made in the presence of a prototype [MISRA 2004 Rule 8.1]
1625 * 4. No explicit type for symbol '_Bool', int assumed
1626 */
1627 #endif /* defined(USB0) */
1628