forked from LonelyWolf/stm32
-
Notifications
You must be signed in to change notification settings - Fork 0
/
usb_ll.c
656 lines (579 loc) · 21.4 KB
/
usb_ll.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
#include "usb_ll.h"
USB_HandleTypeDef husb; // USB device handle
// Initialize the low level USB device
// input:
// husb - pointer to the USB device handle
void HAL_USB_Init(USB_HandleTypeDef *husb) {
// USB state
husb->State = USB_BUSY;
// ---- Initialize the low level hardware: GPIO, CLOCK, NVIC...
// For the STM32L products there is no need to configure the PA12/PA11 (USB DM/DP) pins couple as Alternate Function
// Enable the USB peripheral clock
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
// Enable the SYSCFG peripheral clock
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
// Set USB interrupt priority
NVIC_SetPriority(USB_LP_IRQn,7);
// Enable USB interrupt
NVIC_EnableIRQ(USB_LP_IRQn);
// ---- End of low level hardware initialization
}
// Stop the low level USB device
// input:
// husb - pointer to the USB device handle
void HAL_USB_DeInit(USB_HandleTypeDef *husb) {
// disable all interrupts and force USB reset
husb->Instance->CNTR = USB_CNTR_FRES;
// clear interrupt status register
husb->Instance->ISTR = 0;
// switch-off the USB device
husb->Instance->CNTR = (USB_CNTR_FRES | USB_CNTR_PDWN);
// Disable the USB peripheral clock
RCC->APB1ENR &= RCC_APB1ENR_USBEN;
// Disable the USB interrupt
NVIC_DisableIRQ(USB_LP_IRQn);
// Change state
husb->State = USB_READY;
}
// Stop the USB device
// input:
// husb - pointer to the USB device handle
void HAL_USB_Stop(USB_HandleTypeDef *husb) {
// Disable all interrupts and force the USB reset
husb->Instance->CNTR = USB_CNTR_FRES;
// Clear the interrupt status register
husb->Instance->ISTR = 0;
// Switch-off the USB device
husb->Instance->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN;
}
// Set the USB device address
// input:
// husb - pointer to the USB device handle
// address - new device address
void HAL_USB_SetAddress(USB_HandleTypeDef *husb, uint8_t address) {
if (address == 0) {
// Set device address and enable function
husb->Instance->DADDR = USB_DADDR_EF;
} else {
// USB Address will be applied later
husb->USB_Address = address;
}
}
// Copy a data from the user memory area to the USB packet memory area (PMA)
// USBx - pointer to the USB peripheral handle
// pbUsrBuf - pointer to the user buffer
// wPMABufAddr - address in PMA
// wNBytes - number of bytes to be copied
static void USB_WritePMA(USB_TypeDef *USBx, uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes) {
uint16_t *pdwVal = (uint16_t *)((wPMABufAddr << 1) + (uint32_t)USBx + 0x400);
uint32_t i,temp1,temp2;
for (i = (wNBytes + 1) >> 1; i--; ) {
temp1 = (uint16_t) * pbUsrBuf;
pbUsrBuf++;
temp2 = temp1 | (uint16_t) * pbUsrBuf << 8;
*pdwVal++ = temp2;
pdwVal++;
pbUsrBuf++;
}
}
// Copy a data from the USB packet memory area to the user memory area
// input:
// USBx - pointer to the USB peripheral handle
// pbUsrBuf - pointer to the user buffer
// wPMABufAddr - address in PMA
// wNBytes - number of bytes to be copied
static void USB_ReadPMA(USB_TypeDef *USBx, uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes) {
uint32_t *pdwVal = (uint32_t *)((wPMABufAddr << 1) + (uint32_t)USBx + 0x400);
uint32_t i;
for (i = (wNBytes + 1) >> 1; i--; ) {
*(uint16_t*)pbUsrBuf++ = *pdwVal++;
pbUsrBuf++;
}
}
// Receive an amount of data
// input:
// husb - pointer to the USB device handle
// ep_addr - endpoint address
// pBuf - pointer to the reception buffer
// len - amount of data to be received
void HAL_USB_EP_Receive(USB_HandleTypeDef *husb, uint8_t ep_addr, uint8_t *pBuf, uint32_t len) {
USB_EPTypeDef *ep = &husb->OUT_ep[ep_addr & 0x7F];
// Setup and start the reception
ep->xfer_buff = pBuf;
ep->xfer_len = len;
ep->xfer_count = 0;
ep->is_in = 0;
ep->num = ep_addr & 0x7F;
// Multiple packet transfer
if (ep->xfer_len > ep->maxpacket) {
len = ep->maxpacket;
ep->xfer_len -= len;
} else {
len = ep->xfer_len;
ep->xfer_len = 0;
}
// Configure and validate the RX endpoint
if (ep->doublebuffer) {
// Set the Double buffer counter
USB_SET_EP_DBUF1_CNT(husb->Instance,ep->num,ep->is_in,len);
} else {
// Set the RX buffer count
USB_SET_EP_RX_CNT(husb->Instance,ep->num,len);
}
// Validate transfer
USB_SET_EP_RX_STATUS(husb->Instance,ep->num,USB_EP_RX_VALID);
}
// Transmit an amount of data
// input:
// husb - pointer to the USB device handle
// ep_addr - endpoint address
// pBuf - pointer to the transmission buffer
// len - amount of data to be received
void HAL_USB_EP_Transmit(USB_HandleTypeDef *husb, uint8_t ep_addr, uint8_t *pBuf, uint32_t len) {
USB_EPTypeDef *ep = &husb->IN_ep[ep_addr & 0x7F];
uint16_t pmabuffer = 0;
// Setup and start the transmission
ep->xfer_buff = pBuf;
ep->xfer_len = len;
ep->xfer_count = 0;
ep->is_in = 1;
ep->num = ep_addr & 0x7F;
// Multiple packet transfer
if (ep->xfer_len > ep->maxpacket) {
len = ep->maxpacket;
ep->xfer_len -= len;
} else {
len = ep->xfer_len;
ep->xfer_len = 0;
}
// Configure and validate the TX endpoint
if (ep->doublebuffer) {
// Set the Double buffer counter
USB_SET_EP_DBUF1_CNT(husb->Instance,ep->num,ep->is_in,len);
// Write the data to the USB endpoint
pmabuffer = (USB_GET_ENDPOINT(husb->Instance,ep->num) & USB_EP_DTOG_TX) ? ep->pmaaddr1 : ep->pmaaddr0;
USB_WritePMA(husb->Instance,ep->xfer_buff,pmabuffer,len);
USB_FreeUserBuffer(husb->Instance,ep->num,ep->is_in);
} else {
// Single buffer
USB_WritePMA(husb->Instance,ep->xfer_buff,ep->pmaadress,len);
USB_SET_EP_TX_CNT(husb->Instance,ep->num, len);
}
// Validate transfer
USB_SET_EP_TX_STATUS(husb->Instance,ep->num,USB_EP_TX_VALID);
}
// Set a STALL condition for an endpoint
// input:
// husb - pointer to the USB device handle
// ep_addr - endpoint address
void HAL_USB_EP_SetStall(USB_HandleTypeDef *husb, uint8_t ep_addr) {
USB_EPTypeDef *ep;
ep = ((0x80 & ep_addr) == 0x80) ? &husb->IN_ep[ep_addr & 0x7F] : &husb->OUT_ep[ep_addr];
ep->is_stall = 1;
ep->num = ep_addr & 0x7F;
ep->is_in = ((ep_addr & 0x80) == 0x80);
if (ep->num) {
if (ep->is_in) {
// Set STALL status for TX
USB_SET_EP_TX_STATUS(husb->Instance,ep->num,USB_EP_TX_STALL);
} else {
// Set STALL status for RX
USB_SET_EP_RX_STATUS(husb->Instance,ep->num,USB_EP_RX_STALL);
}
} else {
// Set STALL status for both RX and TX
USB_SET_EP_TXRX_STATUS(husb->Instance,ep->num,USB_EP_RX_STALL,USB_EP_TX_STALL);
}
}
// Open and configure an endpoint
// input:
// husb - pointer to the USB device handle
// ep_addr - endpoint address
// ep_mps - endpoint maximum packet size
// ep_type - endpoint type
void HAL_USB_EP_Open(USB_HandleTypeDef *husb, uint8_t ep_addr, uint16_t ep_mps, uint8_t ep_type) {
USB_EPTypeDef *ep;
ep = ((0x80 & ep_addr) == 0x80) ? &husb->IN_ep[ep_addr & 0x7F] : &husb->OUT_ep[ep_addr & 0x7F];
ep->num = ep_addr & 0x7F;
ep->is_in = ((0x80 & ep_addr) != 0);
ep->maxpacket = ep_mps;
ep->type = ep_type;
// Set type of endpoint
switch (ep->type) {
case USB_EP_TYPE_CTRL:
USB_SET_EPTYPE(husb->Instance,ep->num,USB_EP_CONTROL);
break;
case USB_EP_TYPE_BULK:
USB_SET_EPTYPE(husb->Instance,ep->num,USB_EP_BULK);
break;
case USB_EP_TYPE_INTR:
USB_SET_EPTYPE(husb->Instance, ep->num, USB_EP_INTERRUPT);
break;
case USB_EP_TYPE_ISOC:
USB_SET_EPTYPE(husb->Instance, ep->num, USB_EP_ISOCHRONOUS);
break;
default:
break;
}
// Set endpoint address
USB_SET_EP_ADDRESS(husb->Instance,ep->num,ep->num);
if (ep->doublebuffer) {
// Double buffered
USB_SET_EP_DBUF(husb->Instance,ep->num);
// Set buffer address for double buffered mode
USB_SET_EP_DBUF_ADDR(husb->Instance,ep->num,ep->pmaaddr0,ep->pmaaddr1);
if (ep->is_in==0) {
// Clear the data toggle bits for both IN and OUT endpoints
USB_CLEAR_RX_DTOG(husb->Instance,ep->num);
USB_CLEAR_TX_DTOG(husb->Instance,ep->num);
// Reset value of the data toggle bits for the endpoint out
USB_TX_DTOG(husb->Instance, ep->num);
// Set VALID status for the RX endpoint
USB_SET_EP_RX_STATUS(husb->Instance,ep->num,USB_EP_RX_VALID);
// Set DISABLED status for the TX endpoint
USB_SET_EP_TX_STATUS(husb->Instance,ep->num,USB_EP_TX_DIS);
} else {
// Clear the data toggle bits for the both IN and OUT endpoints
USB_CLEAR_RX_DTOG(husb->Instance,ep->num);
USB_CLEAR_TX_DTOG(husb->Instance,ep->num);
USB_RX_DTOG(husb->Instance,ep->num);
// Configure DISABLE status for both IN and OUT endpoints
USB_SET_EP_TX_STATUS(husb->Instance,ep->num,USB_EP_TX_DIS);
USB_SET_EP_RX_STATUS(husb->Instance,ep->num,USB_EP_RX_DIS);
}
} else {
// Single buffered
if (ep->is_in) {
// Set the endpoint TX buffer address
USB_SET_EP_TX_ADDRESS(husb->Instance, ep->num, ep->pmaadress);
USB_CLEAR_TX_DTOG(husb->Instance, ep->num);
// Configure NAK status for the endpoint
USB_SET_EP_TX_STATUS(husb->Instance, ep->num, USB_EP_TX_NAK);
} else {
// Set the endpoint RX buffer address
USB_SET_EP_RX_ADDRESS(husb->Instance,ep->num,ep->pmaadress);
// Set the endpoint TX buffer counter
USB_SET_EP_RX_CNT(husb->Instance,ep->num,ep->maxpacket);
USB_CLEAR_RX_DTOG(husb->Instance,ep->num);
// Configure VALID status for the endpoint
USB_SET_EP_RX_STATUS(husb->Instance,ep->num,USB_EP_RX_VALID);
}
}
}
// Deactivate an endpoint
// input:
// husb - pointer to the USB device handle
// ep_addr - endpoint address
void HAL_USB_EP_Close(USB_HandleTypeDef *husb, uint8_t ep_addr) {
USB_EPTypeDef *ep;
ep = ((ep_addr & 0x80) == 0x80) ? &husb->IN_ep[ep_addr & 0x7F] : &husb->OUT_ep[ep_addr & 0x7F];
ep->num = ep_addr & 0x7F;
ep->is_in = ((0x80 & ep_addr) != 0);
if (ep->doublebuffer == 0) {
// Double buffer
if (ep->is_in==0) {
// Clear the data toggle bits for the both IN and OUT endpoints
USB_CLEAR_RX_DTOG(husb->Instance,ep->num);
USB_CLEAR_TX_DTOG(husb->Instance,ep->num);
// Reset value of the data toggle bits for the endpoint OUT
USB_TX_DTOG(husb->Instance,ep->num);
USB_SET_EP_RX_STATUS(husb->Instance,ep->num,USB_EP_RX_DIS);
USB_SET_EP_TX_STATUS(husb->Instance,ep->num,USB_EP_TX_DIS);
} else {
// Clear the data toggle bits for the both IN and OUT endpoints
USB_CLEAR_RX_DTOG(husb->Instance,ep->num);
USB_CLEAR_TX_DTOG(husb->Instance,ep->num);
USB_RX_DTOG(husb->Instance,ep->num);
// Configure DISABLE status for the both IN and OUT endpoints
USB_SET_EP_TX_STATUS(husb->Instance,ep->num,USB_EP_TX_DIS);
USB_SET_EP_RX_STATUS(husb->Instance,ep->num,USB_EP_RX_DIS);
}
} else {
// Single buffer
if (ep->is_in) {
// Clear TX DTOG bit and configure DISABLE status for the endpoint
USB_CLEAR_TX_DTOG(husb->Instance,ep->num);
USB_SET_EP_TX_STATUS(husb->Instance,ep->num,USB_EP_TX_DIS);
} else {
// Clear RX DTOG bit and configure DISABLE status for the endpoint
USB_CLEAR_RX_DTOG(husb->Instance,ep->num);
USB_SET_EP_RX_STATUS(husb->Instance,ep->num,USB_EP_RX_DIS);
}
}
}
// Clear a STALL condition for an endpoint
// input:
// husb - pointer to the USB device handle
// ep_addr - endpoint address
void HAL_USB_EP_ClrStall(USB_HandleTypeDef *husb, uint8_t ep_addr) {
USB_EPTypeDef *ep;
ep = ((ep_addr & 0x80) == 0x80) ? &husb->IN_ep[ep_addr & 0x7F] : &husb->OUT_ep[ep_addr];
ep->is_stall = 0;
ep->num = ep_addr & 0x7F;
ep->is_in = ((ep_addr & 0x80) == 0x80);
if (ep->is_in) {
USB_CLEAR_TX_DTOG(husb->Instance,ep->num);
USB_SET_EP_TX_STATUS(husb->Instance,ep->num,USB_EP_TX_VALID);
} else {
USB_CLEAR_RX_DTOG(husb->Instance,ep->num);
USB_SET_EP_RX_STATUS(husb->Instance,ep->num,USB_EP_RX_VALID);
}
}
// Flush an endpoint
// input:
// husb - pointer to the USB device handle
// ep_addr - endpoint address
void HAL_USB_EP_Flush(USB_HandleTypeDef *husb, uint8_t ep_addr) {
// Does nothing?
}
// Connect/Disconnect the USB device
// input:
// husb - pointer to the USB device handle
// state - new state of the connection (0 = disconnected, any number = connected)
void HAL_USB_SetConnectionState(USB_HandleTypeDef *husb, uint8_t state) {
if (state) {
// Connect internal pull-up on USB DP line
SYSCFG->PMC |= (uint32_t)SYSCFG_PMC_USB_PU;
} else {
// Disconnect internal pull-up on USB DP line
SYSCFG->PMC &= (uint32_t)(~SYSCFG_PMC_USB_PU);
}
}
// Configure PMA for endpoint
// input:
// husb - pointer to the USB device handle
// ep_addr - endpoint address
// ep_kind - endpoint Kind
// USB_SNG_BUF: Single Buffer used
// USB_DBL_BUF: Double Buffer used
// pmaadress - EP address in The PMA:
// In case of single buffer endpoint this parameter is 16-bit value providing the address in PMA allocated to endpoint
// In case of double buffer endpoint this parameter is a 32-bit value providing the endpoint buffer 0 address
// in the LSB part of 32-bit value and endpoint buffer 1 address in the MSB part of 32-bit value
void HAL_USB_PMAConfig(USB_HandleTypeDef *husb, uint16_t ep_addr, uint16_t ep_kind, uint32_t pmaadress) {
USB_EPTypeDef *ep;
ep = ((ep_addr & 0x80) == 0x80) ? &husb->IN_ep[ep_addr & 0x7F] : &husb->OUT_ep[ep_addr];
// Check if the endpoint is single or double Buffer
if (ep_kind == USB_SNG_BUF) {
// Single Buffer
ep->doublebuffer = 0;
// Configure the PMA
ep->pmaadress = (uint16_t)pmaadress;
} else {
// Double Buffer Endpoint
ep->doublebuffer = 1;
// Configure the PMA
ep->pmaaddr0 = pmaadress & 0xFFFF;
ep->pmaaddr1 = (pmaadress & 0xFFFF0000) >> 16;
}
}
// Get received data size
// input:
// husb - pointer to the USB device handle
// ep_addr - endpoint address
// return: received data size
inline uint16_t HAL_USB_EP_GetRxCount(USB_HandleTypeDef *husb, uint8_t ep_addr) {
return husb->OUT_ep[ep_addr & 0x7F].xfer_count;
}
// Handle USB Endpoint interrupt request
// input:
// husb - pointer to the USB handle
static void USB_EP_ISR_Handler(USB_HandleTypeDef *husb) {
USB_EPTypeDef *ep;
uint16_t count = 0;
uint8_t EPindex;
__IO uint16_t wIstr;
__IO uint16_t wEPVal = 0;
// Stay in loop while pending interrupts present
while ((wIstr = husb->Instance->ISTR) & USB_ISTR_CTR) {
// Extract highest priority endpoint number
EPindex = (uint8_t)(wIstr & USB_ISTR_EP_ID);
if (EPindex == 0) {
// Process the control endpoint
// The DIR bit indicates direction of transaction
if (wIstr & USB_ISTR_DIR) {
// The DIR bit is set (OUT transaction: from host to the USB peripheral)
// CTR_RX bit set indicates SETUP or OUT interrupt
// CTR_TX or CTR_RX bits set indicates 2 interrupts pending
ep = &husb->OUT_ep[0];
wEPVal = USB_GET_ENDPOINT(husb->Instance,USB_ENDP0);
if (wEPVal & USB_EP_SETUP) {
// Get SETUP packet
ep->xfer_count = USB_GET_EP_RX_CNT(husb->Instance,ep->num);
USB_ReadPMA(husb->Instance,(uint8_t*)husb->Setup,ep->pmaadress,ep->xfer_count);
// SETUP bit kept frozen while CTR_RX = 1
USB_CLEAR_RX_EP_CTR(husb->Instance,USB_ENDP0);
// Process SETUP packet
HAL_USB_SetupStageCallback(husb);
} else if (wEPVal & USB_EP_CTR_RX) {
USB_CLEAR_RX_EP_CTR(husb->Instance,USB_ENDP0);
// Get control data OUT packet
ep->xfer_count = USB_GET_EP_RX_CNT(husb->Instance,ep->num);
if (ep->xfer_count) {
USB_ReadPMA(husb->Instance,ep->xfer_buff,ep->pmaadress,ep->xfer_count);
ep->xfer_buff += ep->xfer_count;
}
// Process control data OUT packet
HAL_USB_DataOutStageCallback(husb,0);
USB_SET_EP_RX_CNT(husb->Instance,USB_ENDP0,ep->maxpacket);
USB_SET_EP_RX_STATUS(husb->Instance,USB_ENDP0,USB_EP_RX_VALID);
}
} else {
// The DIR bit is cleared (IN transaction: from USB peripheral to the host)
// DIR = 0 implies that (EP_CTR_TX = 1) always
USB_CLEAR_TX_EP_CTR(husb->Instance,USB_ENDP0);
ep = &husb->IN_ep[0];
ep->xfer_count = USB_GET_EP_TX_CNT(husb->Instance,ep->num);
ep->xfer_buff += ep->xfer_count;
// TX complete
HAL_USB_DataInStageCallback(husb,0);
if ((husb->USB_Address > 0) && (ep->xfer_len == 0)) {
husb->Instance->DADDR = (husb->USB_Address | USB_DADDR_EF);
husb->USB_Address = 0;
}
}
} else {
// A non control endpoint interrupt
// Process related endpoint register
wEPVal = USB_GET_ENDPOINT(husb->Instance,EPindex);
if (wEPVal & USB_EP_CTR_RX) {
// Clear the interrupt flag
USB_CLEAR_RX_EP_CTR(husb->Instance,EPindex);
ep = &husb->OUT_ep[EPindex];
// OUT
if (ep->doublebuffer) {
// Double buffer
if (USB_GET_ENDPOINT(husb->Instance,ep->num) & USB_EP_DTOG_RX) {
// Read from endpoint BUF0Addr buffer
count = USB_GET_EP_DBUF0_CNT(husb->Instance,ep->num);
if (count) USB_ReadPMA(husb->Instance,ep->xfer_buff,ep->pmaaddr0,count);
} else {
// Read from endpoint BUF1Addr buffer
count = USB_GET_EP_DBUF1_CNT(husb->Instance,ep->num);
if (count) USB_ReadPMA(husb->Instance,ep->xfer_buff,ep->pmaaddr1,count);
}
USB_FreeUserBuffer(husb->Instance,ep->num,USB_EP_DBUF_OUT);
} else {
// Single buffer
count = USB_GET_EP_RX_CNT(husb->Instance,ep->num);
if (count) USB_ReadPMA(husb->Instance,ep->xfer_buff,ep->pmaadress,count);
}
// Multiple packet on the NON control OUT endpoint
ep->xfer_count += count;
ep->xfer_buff += count;
if ((ep->xfer_len == 0) || (count < ep->maxpacket)) {
// RX complete
HAL_USB_DataOutStageCallback(husb,ep->num);
} else {
HAL_USB_EP_Receive(husb, ep->num, ep->xfer_buff, ep->xfer_len);
}
} // if ((wEPVal & EP_CTR_RX)
if (wEPVal & USB_EP_CTR_TX) {
ep = &husb->IN_ep[EPindex];
// Clear the intterrupt flag
USB_CLEAR_TX_EP_CTR(husb->Instance,EPindex);
// IN
if (ep->doublebuffer) {
// Double buffer
if (USB_GET_ENDPOINT(husb->Instance,ep->num) & USB_EP_DTOG_TX) {
// Read from endpoint BUF0Addr buffer
ep->xfer_count = USB_GET_EP_DBUF0_CNT(husb->Instance,ep->num);
if (ep->xfer_count) USB_WritePMA(husb->Instance,ep->xfer_buff,ep->pmaaddr0,ep->xfer_count);
} else {
// Read from endpoint BUF1Addr buffer
ep->xfer_count = USB_GET_EP_DBUF1_CNT(husb->Instance,ep->num);
if (ep->xfer_count) USB_WritePMA(husb->Instance,ep->xfer_buff,ep->pmaaddr1,ep->xfer_count);
}
USB_FreeUserBuffer(husb->Instance,ep->num,USB_EP_DBUF_IN);
} else {
// Single buffer
ep->xfer_count = USB_GET_EP_TX_CNT(husb->Instance,ep->num);
if (ep->xfer_count) USB_WritePMA(husb->Instance,ep->xfer_buff,ep->pmaadress,ep->xfer_count);
}
// Multiple packet on the NON control IN endpoint
ep->xfer_count = USB_GET_EP_TX_CNT(husb->Instance,ep->num);
ep->xfer_buff += ep->xfer_count;
// Is this ZLP (zero length packet)?
if (ep->xfer_len) {
// Pending transfer
HAL_USB_EP_Transmit(husb,ep->num,ep->xfer_buff,ep->xfer_len);
} else {
// ZLP --> TX complete
HAL_USB_DataInStageCallback(husb,ep->num);
}
}
}
}
}
// Handle USB low priority interrupts
void USB_LP_IRQHandler(void) {
uint32_t wInterrupt_Mask = 0;
// USB correct transfer (endpoint has successfully completed a transaction)
if (husb.Instance->ISTR & USB_ISTR_CTR) {
// Servicing of the endpoint correct transfer interrupt clear of the CTR flag into the sub
USB_EP_ISR_Handler(&husb);
}
// USB peripheral has detected an active USB RESET signal
if (husb.Instance->ISTR & USB_ISTR_RESET) {
// Clear the RESET flag
husb.Instance->ISTR &= ~USB_ISTR_RESET;
// Call the USB reset procedure
HAL_USB_ResetCallback(&husb);
// Clear the USB address
HAL_USB_SetAddress(&husb,0);
}
// The MCU has not been able to respond in time to an USB memory request
if (husb.Instance->ISTR & USB_ISTR_PMAOVR) {
// Clear the overrun/underrun flag
husb.Instance->ISTR &= ~USB_ISTR_PMAOVR;
}
// USB error
// NANS: no answer
// CRC: wrong CRC received
// BST: bit stuffing error detected in data
// FVIO: framing format violation (non-standard frame received)
if (husb.Instance->ISTR & USB_ISTR_ERR) {
// Usually it is safely to ignore this
// Clear the ERR flag
husb.Instance->ISTR &= ~USB_ISTR_ERR;
}
// In the suspend mode was detected an activity that wakes up the USB peripheral
if (husb.Instance->ISTR & USB_ISTR_WKUP) {
// Clear the LP_MODE flag (no low-power mode)
husb.Instance->CNTR &= ~USB_CNTR_LP_MODE;
// Set wInterrupt_Mask global variable
wInterrupt_Mask = USB_CNTR_CTRM | USB_CNTR_WKUPM | USB_CNTR_SUSPM | USB_CNTR_ERRM | USB_CNTR_ESOFM | USB_CNTR_RESETM;
// Set interrupt mask
husb.Instance->CNTR = wInterrupt_Mask;
// Call USB resume procedure
HAL_USB_ResumeCallback(&husb);
// Clear the WKUP flag
husb.Instance->ISTR &= ~USB_ISTR_WKUP;
}
// No traffic has been received for 3ms, that indicates a suspend mode request from the USB bus
if (husb.Instance->ISTR & USB_ISTR_SUSP) {
// clear of the ISTR bit must be done after setting of CNTR_FSUSP
husb.Instance->ISTR &= ~USB_ISTR_SUSP;
// Force low-power mode in the macrocell
husb.Instance->CNTR |= USB_CNTR_FSUSP;
husb.Instance->CNTR |= USB_CNTR_LP_MODE;
if (husb.Instance->ISTR & USB_ISTR_WKUP) {
// Call the suspend procedure
HAL_USB_SuspendCallback(&husb);
}
}
// A SOF (start of frame) packet arrives through the USB bus (beginning a new USB frame)
if (husb.Instance->ISTR & USB_ISTR_SOF) {
// Clear the SOF flag
husb.Instance->ISTR &= ~USB_ISTR_SOF;
// Call SOF procedure
HAL_USB_SOFCallback(&husb);
}
// An SOF packet is expected but not received
if (husb.Instance->ISTR & USB_ISTR_ESOF) {
// After a three consecutive ESOF interrupts without any traffic occurring in between,
// a suspend interrupt will be generated. Therefore just clear flag.
// Clear the ESOF flag
husb.Instance->ISTR &= ~USB_ISTR_ESOF;
}
}