M471M/R1/S BSP V3.01.000
The Board Support Package for M4521
usbd.c
Go to the documentation of this file.
1/**************************************************************************/
9#include <string.h>
10#include "NuMicro.h"
11
12
13#if 0
14#define DBG_PRINTF printf
15#else
16#define DBG_PRINTF(...)
17#endif
18
19#ifdef __cplusplus
20extern "C"
21{
22#endif
23
37/* Global variables for Control Pipe */
38uint8_t g_usbd_SetupPacket[8] = {0};
39volatile uint8_t g_usbd_RemoteWakeupEn = 0;
44static volatile uint8_t *g_usbd_CtrlInPointer = 0;
45static volatile uint32_t g_usbd_CtrlInSize = 0;
46static volatile uint8_t *g_usbd_CtrlOutPointer = 0;
47static volatile uint32_t g_usbd_CtrlOutSize = 0;
48static volatile uint32_t g_usbd_CtrlOutSizeLimit = 0;
49static volatile uint32_t g_usbd_UsbAddr = 0;
50static volatile uint32_t g_usbd_UsbConfig = 0;
51static volatile uint32_t g_usbd_CtrlMaxPktSize = 8;
52static volatile uint32_t g_usbd_UsbAltInterface = 0;
53static volatile uint32_t g_usbd_CtrlOutToggle = 0;
54static volatile uint8_t g_usbd_CtrlInZeroFlag = 0ul;
65uint32_t g_u32EpStallLock = 0;
78void USBD_Open(const S_USBD_INFO_T *param, CLASS_REQ pfnClassReq, SET_INTERFACE_REQ pfnSetInterface)
79{
80 g_usbd_sInfo = param;
81 g_usbd_pfnClassRequest = pfnClassReq;
82 g_usbd_pfnSetInterface = pfnSetInterface;
83
84 /* get EP0 maximum packet size */
85 g_usbd_CtrlMaxPktSize = g_usbd_sInfo->gu8DevDesc[7];
86
87 /* Initial USB engine */
88 USBD->ATTR = 0x7D0;
89 /* Force SE0 */
91}
92
102void USBD_Start(void)
103{
104 CLK_SysTickDelay(100000);
105 /* Disable software-disconnect function */
106 USBD_CLR_SE0();
107
108 /* Clear USB-related interrupts before enable interrupt */
110
111 /* Enable USB-related interrupts. */
113}
114
125void USBD_GetSetupPacket(uint8_t *buf)
126{
128}
129
141{
142 g_usbd_CtrlOutToggle = 0;
143 /* Get SETUP packet from USB buffer */
145 /* Check the request type */
146 switch(g_usbd_SetupPacket[0] & 0x60)
147 {
148 case REQ_STANDARD: // Standard
149 {
151 break;
152 }
153 case REQ_CLASS: // Class
154 {
156 {
158 }
159 break;
160 }
161 case REQ_VENDOR: // Vendor
162 {
164 {
166 }
167 break;
168 }
169 default: // reserved
170 {
171 /* Setup error, stall the device */
174 break;
175 }
176 }
177}
178
190{
191 uint32_t u32Len;
192
193 g_usbd_CtrlInZeroFlag = (uint8_t)0ul;
194 u32Len = 0;
195 u32Len = g_usbd_SetupPacket[7];
196 u32Len <<= 8;
197 u32Len += g_usbd_SetupPacket[6];
198
199 switch(g_usbd_SetupPacket[3])
200 {
201 // Get Device Descriptor
202 case DESC_DEVICE:
203 {
204 u32Len = Minimum(u32Len, LEN_DEVICE);
205 DBG_PRINTF("Get device desc, %d\n", u32Len);
206
207 USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8DevDesc, u32Len);
208
209 break;
210 }
211 // Get Configuration Descriptor
212 case DESC_CONFIG:
213 {
214 uint32_t u32TotalLen;
215
216 u32TotalLen = g_usbd_sInfo->gu8ConfigDesc[3];
217 u32TotalLen = g_usbd_sInfo->gu8ConfigDesc[2] + (u32TotalLen << 8);
218
219 if (u32Len > u32TotalLen)
220 {
221 u32Len = u32TotalLen;
222 if ((u32Len % g_usbd_CtrlMaxPktSize) == 0ul)
223 {
224 g_usbd_CtrlInZeroFlag = (uint8_t)1ul;
225 }
226 }
227 USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8ConfigDesc, u32Len);
228
229 break;
230 }
231 // Get HID Descriptor
232 case DESC_HID:
233 {
234 /* CV3.0 HID Class Descriptor Test,
235 Need to indicate index of the HID Descriptor within gu8ConfigDescriptor, specifically HID Composite device. */
236 uint32_t u32ConfigDescOffset; // u32ConfigDescOffset is configuration descriptor offset (HID descriptor start index)
237 u32Len = Minimum(u32Len, LEN_HID);
238 DBG_PRINTF("Get HID desc, %d\n", u32Len);
239
240 u32ConfigDescOffset = g_usbd_sInfo->gu32ConfigHidDescIdx[g_usbd_SetupPacket[4]];
241 USBD_PrepareCtrlIn((uint8_t *)&g_usbd_sInfo->gu8ConfigDesc[u32ConfigDescOffset], u32Len);
242
243 break;
244 }
245 // Get Report Descriptor
246 case DESC_HID_RPT:
247 {
249 {
251 if ((u32Len % g_usbd_CtrlMaxPktSize) == 0ul)
252 {
253 g_usbd_CtrlInZeroFlag = (uint8_t)1ul;
254 }
255 }
257 break;
258 }
259 // Get String Descriptor
260 case DESC_STRING:
261 {
262 // Get String Descriptor
263 if(g_usbd_SetupPacket[2] < 4)
264 {
265 if (u32Len > g_usbd_sInfo->gu8StringDesc[g_usbd_SetupPacket[2]][0])
266 {
268 if ((u32Len % g_usbd_CtrlMaxPktSize) == 0ul)
269 {
270 g_usbd_CtrlInZeroFlag = (uint8_t)1ul;
271 }
272 }
274
275
276 break;
277 }
278 else
279 {
280 // Not support. Reply STALL.
283
284 DBG_PRINTF("Unsupported string desc (%d). Stall ctrl pipe.\n", g_usbd_SetupPacket[2]);
285
286 break;
287 }
288 }
289 default:
290 // Not support. Reply STALL.
293
294 DBG_PRINTF("Unsupported get desc type. stall ctrl pipe\n");
295
296 break;
297 }
298}
299
311{
312
313 /* clear global variables for new request */
314 g_usbd_CtrlInPointer = 0;
315 g_usbd_CtrlInSize = 0;
316
317 if(g_usbd_SetupPacket[0] & 0x80) /* request data transfer direction */
318 {
319 // Device to host
320 switch(g_usbd_SetupPacket[1])
321 {
323 {
324 // Return current configuration setting
325 /* Data stage */
326 M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0)) = g_usbd_UsbConfig;
329 /* Status stage */
331
332 DBG_PRINTF("Get configuration\n");
333
334 break;
335 }
336 case GET_DESCRIPTOR:
337 {
339 USBD_PrepareCtrlOut(0, 0); /* For status stage */
340 break;
341 }
342 case GET_INTERFACE:
343 {
344 // Return current interface setting
345 /* Data stage */
346 M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0)) = g_usbd_UsbAltInterface;
349 /* Status stage */
351
352 DBG_PRINTF("Get interface\n");
353
354 break;
355 }
356 case GET_STATUS:
357 {
358 // Device
359 if(g_usbd_SetupPacket[0] == 0x80)
360 {
361 uint8_t u8Tmp;
362
363 u8Tmp = 0;
364 if(g_usbd_sInfo->gu8ConfigDesc[7] & 0x40) u8Tmp |= 1; // Self-Powered/Bus-Powered.
365 if(g_usbd_sInfo->gu8ConfigDesc[7] & 0x20) u8Tmp |= (g_usbd_RemoteWakeupEn << 1); // Remote wake up
366
368
369 }
370 // Interface
371 else if(g_usbd_SetupPacket[0] == 0x81)
373 // Endpoint
374 else if(g_usbd_SetupPacket[0] == 0x82)
375 {
376 uint8_t ep = g_usbd_SetupPacket[4] & 0xF;
378 }
379
381 /* Data stage */
384 /* Status stage */
386
387 DBG_PRINTF("Get status\n");
388
389 break;
390 }
391 default:
392 {
393 /* Setup error, stall the device */
396
397 DBG_PRINTF("Unknown request. stall ctrl pipe.\n");
398
399 break;
400 }
401 }
402 }
403 else
404 {
405 // Host to device
406 switch(g_usbd_SetupPacket[1])
407 {
408 case CLEAR_FEATURE:
409 {
411 {
412 int32_t epNum, i;
413
414 /* EP number stall is not allow to be clear in MSC class "Error Recovery Test".
415 a flag: g_u32EpStallLock is added to support it */
416 epNum = g_usbd_SetupPacket[4] & 0xF;
417 for(i = 0; i < USBD_MAX_EP; i++)
418 {
419 if(((USBD->EP[i].CFG & 0xF) == epNum) && ((g_u32EpStallLock & (1 << i)) == 0))
420 {
421 USBD->EP[i].CFGP &= ~USBD_CFGP_SSTALL_Msk;
422 USBD->EP[i].CFG &= ~USBD_CFG_DSQSYNC_Msk;
423 DBG_PRINTF("Clr stall ep%d %x\n", i, USBD->EP[i].CFGP);
424 }
425 }
426 }
429
430 /* Status stage */
433
434 DBG_PRINTF("Clear feature op %d\n", g_usbd_SetupPacket[2]);
435
436 break;
437 }
438 case SET_ADDRESS:
439 {
440 g_usbd_UsbAddr = g_usbd_SetupPacket[2];
441 DBG_PRINTF("Set addr to %d\n", g_usbd_UsbAddr);
442
443 // DATA IN for end of setup
444 /* Status Stage */
447
448 break;
449 }
451 {
452 g_usbd_UsbConfig = g_usbd_SetupPacket[2];
453
456
457 // DATA IN for end of setup
458 /* Status stage */
461
462 DBG_PRINTF("Set config to %d\n", g_usbd_UsbConfig);
463
464 break;
465 }
466 case SET_FEATURE:
467 {
469 {
471 DBG_PRINTF("Set feature. stall ep %d\n", g_usbd_SetupPacket[4] & 0xF);
472 }
474 {
476 DBG_PRINTF("Set feature. enable remote wakeup\n");
477 }
478
479 /* Status stage */
482
483
484
485 break;
486 }
487 case SET_INTERFACE:
488 {
489 g_usbd_UsbAltInterface = g_usbd_SetupPacket[2];
492 /* Status stage */
495
496 DBG_PRINTF("Set interface to %d\n", g_usbd_UsbAltInterface);
497
498 break;
499 }
500 default:
501 {
502 /* Setup error, stall the device */
505
506 DBG_PRINTF("Unsupported request. stall ctrl pipe.\n");
507
508 break;
509 }
510 }
511 }
512}
513
525void USBD_PrepareCtrlIn(uint8_t *pu8Buf, uint32_t u32Size)
526{
527 DBG_PRINTF("Prepare Ctrl In %d\n", u32Size);
528 if(u32Size > g_usbd_CtrlMaxPktSize)
529 {
530 // Data size > MXPLD
531 g_usbd_CtrlInPointer = pu8Buf + g_usbd_CtrlMaxPktSize;
532 g_usbd_CtrlInSize = u32Size - g_usbd_CtrlMaxPktSize;
534 USBD_MemCopy((uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0), pu8Buf, g_usbd_CtrlMaxPktSize);
535 USBD_SET_PAYLOAD_LEN(EP0, g_usbd_CtrlMaxPktSize);
536 }
537 else
538 {
539 // Data size <= MXPLD
540 g_usbd_CtrlInPointer = 0;
541 g_usbd_CtrlInSize = 0;
543 USBD_MemCopy((uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0), pu8Buf, u32Size);
544 USBD_SET_PAYLOAD_LEN(EP0, u32Size);
545 }
546}
547
558void USBD_CtrlIn(void)
559{
560 DBG_PRINTF("Ctrl In Ack. residue %d\n", g_usbd_CtrlInSize);
561 if(g_usbd_CtrlInSize)
562 {
563 // Process remained data
564 if(g_usbd_CtrlInSize > g_usbd_CtrlMaxPktSize)
565 {
566 // Data size > MXPLD
567 USBD_MemCopy((uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0), (uint8_t *)g_usbd_CtrlInPointer, g_usbd_CtrlMaxPktSize);
568 USBD_SET_PAYLOAD_LEN(EP0, g_usbd_CtrlMaxPktSize);
569 g_usbd_CtrlInPointer += g_usbd_CtrlMaxPktSize;
570 g_usbd_CtrlInSize -= g_usbd_CtrlMaxPktSize;
571 }
572 else
573 {
574 // Data size <= MXPLD
575 USBD_MemCopy((uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0), (uint8_t *)g_usbd_CtrlInPointer, g_usbd_CtrlInSize);
576 USBD_SET_PAYLOAD_LEN(EP0, g_usbd_CtrlInSize);
577 g_usbd_CtrlInPointer = 0;
578 g_usbd_CtrlInSize = 0;
579 }
580 }
581 else // No more data for IN token
582 {
583 // In ACK for Set address
585 {
586 if((USBD_GET_ADDR() != g_usbd_UsbAddr) && (USBD_GET_ADDR() == 0))
587 {
588 USBD_SET_ADDR(g_usbd_UsbAddr);
589 }
590 }
591
592 /* For the case of data size is integral times maximum packet size */
593 if(g_usbd_CtrlInZeroFlag)
594 {
596 g_usbd_CtrlInZeroFlag = (uint8_t)0ul;
597 }
598
599 DBG_PRINTF("Ctrl In done.\n");
600
601 }
602}
603
615void USBD_PrepareCtrlOut(uint8_t *pu8Buf, uint32_t u32Size)
616{
617 g_usbd_CtrlOutPointer = pu8Buf;
618 g_usbd_CtrlOutSize = 0;
619 g_usbd_CtrlOutSizeLimit = u32Size;
620 USBD_SET_PAYLOAD_LEN(EP1, g_usbd_CtrlMaxPktSize);
621}
622
633void USBD_CtrlOut(void)
634{
635 uint32_t u32Size;
636
637 DBG_PRINTF("Ctrl Out Ack %d\n", g_usbd_CtrlOutSize);
638
639 if (g_usbd_CtrlOutToggle != (USBD->EPSTS & USBD_EPSTS_EPSTS1_Msk))
640 {
641 g_usbd_CtrlOutToggle = USBD->EPSTS & USBD_EPSTS_EPSTS1_Msk;
642 if(g_usbd_CtrlOutSize < g_usbd_CtrlOutSizeLimit)
643 {
644 u32Size = USBD_GET_PAYLOAD_LEN(EP1);
645 USBD_MemCopy((uint8_t *)g_usbd_CtrlOutPointer, (uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP1), u32Size);
646 g_usbd_CtrlOutPointer += u32Size;
647 g_usbd_CtrlOutSize += u32Size;
648
649 if(g_usbd_CtrlOutSize < g_usbd_CtrlOutSizeLimit)
650 USBD_SET_PAYLOAD_LEN(EP1, g_usbd_CtrlMaxPktSize);
651 }
652 }
653 else
654 {
655 USBD_SET_PAYLOAD_LEN(EP1, g_usbd_CtrlMaxPktSize);
656 }
657}
658
669void USBD_SwReset(void)
670{
671 int i;
672
673 // Reset all variables for protocol
674 g_usbd_CtrlInPointer = 0;
675 g_usbd_CtrlInSize = 0;
676 g_usbd_CtrlOutPointer = 0;
677 g_usbd_CtrlOutSize = 0;
678 g_usbd_CtrlOutSizeLimit = 0;
680 memset(g_usbd_SetupPacket, 0, 8);
681
682 /* Reset PID DATA0 */
683 for(i=0; i<USBD_MAX_EP; i++)
684 USBD->EP[i].CFG &= ~USBD_CFG_DSQSYNC_Msk;
685
686 // Reset USB device address
687 USBD_SET_ADDR(0);
688}
689
700{
701 g_usbd_pfnVendorRequest = pfnVendorReq;
702}
703
713void USBD_SetConfigCallback(SET_CONFIG_CB pfnSetConfigCallback)
714{
715 g_usbd_pfnSetConfigCallback = pfnSetConfigCallback;
716}
717
718
729void USBD_LockEpStall(uint32_t u32EpBitmap)
730{
731 g_u32EpStallLock = u32EpBitmap;
732}
733
734
735
736
737 /* end of group USBD_EXPORTED_FUNCTIONS */
739 /* end of group USBD_Driver */
741 /* end of group Standard_Driver */
743
744#ifdef __cplusplus
745}
746#endif
747
#define USBD_EPSTS_EPSTS1_Msk
Definition: M471M_R1_S.h:12600
#define USBD_CFG_DSQSYNC_Msk
Definition: M471M_R1_S.h:12675
NuMicro peripheral access layer header file.
__STATIC_INLINE uint32_t CLK_SysTickDelay(uint32_t us)
This function execute delay function.
Definition: clk.h:366
#define NULL
Definition: M471M_R1_S.h:13908
#define M8(adr)
Definition: M471M_R1_S.h:13935
#define USBD
Definition: M471M_R1_S.h:13837
#define GET_DESCRIPTOR
Definition: usbd.h:67
#define LEN_HID
Definition: usbd.h:93
#define GET_INTERFACE
Definition: usbd.h:71
#define CLEAR_FEATURE
Definition: usbd.h:64
#define LEN_DEVICE
Definition: usbd.h:89
#define REQ_STANDARD
Definition: usbd.h:58
#define USBD_INT_FLDET
Definition: usbd.h:122
#define DESC_HID
Definition: usbd.h:85
#define REQ_CLASS
Definition: usbd.h:59
#define USBD_INT_WAKEUP
Definition: usbd.h:123
#define SET_CONFIGURATION
Definition: usbd.h:70
#define DESC_HID_RPT
Definition: usbd.h:86
#define DESC_DEVICE
Definition: usbd.h:76
#define USBD_MAX_EP
Definition: usbd.h:45
#define USBD_BUF_BASE
Definition: usbd.h:44
#define REQ_VENDOR
Definition: usbd.h:60
#define USBD_INT_BUS
Definition: usbd.h:120
#define SET_INTERFACE
Definition: usbd.h:72
#define EP1
Definition: usbd.h:48
#define FEATURE_DEVICE_REMOTE_WAKEUP
Definition: usbd.h:105
#define DESC_CONFIG
Definition: usbd.h:77
#define USBD_INT_USB
Definition: usbd.h:121
#define GET_CONFIGURATION
Definition: usbd.h:69
#define SET_ADDRESS
Definition: usbd.h:66
#define FEATURE_ENDPOINT_HALT
Definition: usbd.h:106
#define EP0
Definition: usbd.h:47
#define DESC_STRING
Definition: usbd.h:78
#define GET_STATUS
Definition: usbd.h:63
#define SET_FEATURE
Definition: usbd.h:65
void USBD_Open(const S_USBD_INFO_T *param, CLASS_REQ pfnClassReq, SET_INTERFACE_REQ pfnSetInterface)
This function makes USBD module to be ready to use.
Definition: usbd.c:78
#define USBD_GET_EP_BUF_ADDR(ep)
Get the offset of the specified USB endpoint buffer.
Definition: usbd.h:468
void USBD_LockEpStall(uint32_t u32EpBitmap)
EP stall lock function to avoid stall clear by USB SET FEATURE request.
Definition: usbd.c:729
void USBD_StandardRequest(void)
Process standard request.
Definition: usbd.c:310
const uint32_t * gu32ConfigHidDescIdx
Definition: usbd.h:30
#define USBD_SET_SE0()
Enable SE0. Force USB PHY transceiver to drive SE0.
Definition: usbd.h:245
#define USBD_GET_PAYLOAD_LEN(ep)
Get USB payload size (OUT data)
Definition: usbd.h:428
void(* VENDOR_REQ)(void)
Definition: usbd.h:625
#define USBD_SET_DATA1(ep)
Set USB DATA1 PID for the specified endpoint ID.
Definition: usbd.h:389
CLASS_REQ g_usbd_pfnClassRequest
Definition: usbd.c:62
volatile uint8_t g_usbd_RemoteWakeupEn
Definition: usbd.c:39
void USBD_PrepareCtrlOut(uint8_t *pu8Buf, uint32_t u32Size)
Prepare the first Control OUT pipe.
Definition: usbd.c:615
static __INLINE void USBD_SetStall(uint8_t epnum)
Set USB endpoint stall state.
Definition: usbd.h:536
#define USBD_GET_ADDR()
Get USB device address.
Definition: usbd.h:281
static __INLINE uint32_t USBD_GetStall(uint8_t epnum)
Get USB endpoint stall state.
Definition: usbd.h:600
void USBD_GetDescriptor(void)
Process GetDescriptor request.
Definition: usbd.c:189
#define USBD_SET_ADDR(addr)
Set USB device address.
Definition: usbd.h:269
void USBD_GetSetupPacket(uint8_t *buf)
Get the received SETUP packet.
Definition: usbd.c:125
void(* CLASS_REQ)(void)
Definition: usbd.h:626
SET_INTERFACE_REQ g_usbd_pfnSetInterface
Definition: usbd.c:63
#define USBD_CLR_SE0()
Disable SE0.
Definition: usbd.h:257
void USBD_Start(void)
This function makes USB host to recognize the device.
Definition: usbd.c:102
void USBD_SwReset(void)
Reset software flags.
Definition: usbd.c:669
void USBD_PrepareCtrlIn(uint8_t *pu8Buf, uint32_t u32Size)
Prepare the first Control IN pipe.
Definition: usbd.c:525
void USBD_CtrlIn(void)
Repeat Control IN pipe.
Definition: usbd.c:558
uint32_t g_u32EpStallLock
Definition: usbd.c:65
uint8_t g_usbd_SetupPacket[8]
Definition: usbd.c:38
#define Minimum(a, b)
Compare two input numbers and return minimum one.
Definition: usbd.h:184
void USBD_SetConfigCallback(SET_CONFIG_CB pfnSetConfigCallback)
The callback function which called when get SET CONFIGURATION request.
Definition: usbd.c:713
static __INLINE void USBD_MemCopy(uint8_t *dest, uint8_t *src, int32_t size)
To support byte access between USB SRAM and system SRAM.
Definition: usbd.h:520
const S_USBD_INFO_T * g_usbd_sInfo
Definition: usbd.c:59
#define USBD_SET_EP_STALL(ep)
Set USB endpoint stall state.
Definition: usbd.h:480
void USBD_SetVendorRequest(VENDOR_REQ pfnVendorReq)
USBD Set Vendor Request.
Definition: usbd.c:699
void USBD_ProcessSetupPacket(void)
Process SETUP packet.
Definition: usbd.c:140
#define USBD_CLR_INT_FLAG(flag)
Clear USB interrupt flag.
Definition: usbd.h:323
SET_CONFIG_CB g_usbd_pfnSetConfigCallback
Definition: usbd.c:64
void(* SET_INTERFACE_REQ)(void)
Definition: usbd.h:627
const uint8_t * gu8ConfigDesc
Definition: usbd.h:26
const uint8_t * gu8DevDesc
Definition: usbd.h:25
const uint32_t * gu32HidReportSize
Definition: usbd.h:29
void(* SET_CONFIG_CB)(void)
Definition: usbd.h:628
const uint8_t ** gu8HidReportDesc
Definition: usbd.h:28
void USBD_CtrlOut(void)
Repeat Control OUT pipe.
Definition: usbd.c:633
const uint8_t ** gu8StringDesc
Definition: usbd.h:27
#define USBD_ENABLE_INT(intr)
Enable USB interrupt function.
Definition: usbd.h:296
VENDOR_REQ g_usbd_pfnVendorRequest
Definition: usbd.c:61
#define USBD_SET_PAYLOAD_LEN(ep, size)
Set USB payload size (IN data)
Definition: usbd.h:416
#define DBG_PRINTF(...)
Definition: usbd.c:16