21
21
22
22
#include " nrf_clock.h"
23
23
24
+ /*
25
+ * TODO list for nRF52840 USBD driver
26
+ *
27
+ * 1.) Properly enable/disable start-of-frame interrupt.
28
+ *
29
+ * Description: Currently, start-of-frame interrupts are masked by a flag at this layer
30
+ * but still cause the processor to be interrupted for no purpose.
31
+ *
32
+ * The Nordic driver requires you to call nrf_drv_start(bool)
33
+ * with a boolean flag indicating whether it should enable start-of-frame
34
+ * interrupts or not. From the datasheet it seems to be possible to
35
+ * enable/disable SoF interrupts on the fly, but the fact that they
36
+ * force you to make the SoF decision during "start" makes me suspicious
37
+ * the underlying driver may manage/use the SoF flag in other ways.
38
+ *
39
+ * Next steps: Investigate how the SoF flag is used during "nrf_drv_start" and
40
+ * determine if enabling/disabling this interrupt would cause internal problems
41
+ * with the Nordic USBD driver
42
+ *
43
+ *
44
+ */
24
45
#define MAX_PACKET_SIZE_SETUP NRF_DRV_USBD_EPSIZE
25
46
#define MAX_PACKET_NON_ISO NRF_DRV_USBD_EPSIZE
26
47
#define MAX_PACKET_ISO NRF_DRV_USBD_ISOSIZE
@@ -46,10 +67,19 @@ void USBD_HAL_IRQHandler(void);
46
67
static USBPhyHw *instance = 0 ;
47
68
48
69
static volatile bool virtual_status_xfer_event;
70
+ static volatile bool irq_already_pending;
49
71
50
72
static void usbd_event_handler (nrf_drv_usbd_evt_t const * const p_event);
51
73
static void power_usb_event_handler (nrf_drv_power_usb_evt_t event);
52
74
75
+ #if USBD_DEBUG
76
+
77
+ // Static array of saved events to track what happens
78
+ static nrf_drv_usbd_evt_t debug_events[32 ];
79
+ static uint8_t debug_evt_index = 0 ;
80
+
81
+ #endif
82
+
53
83
USBPhy *get_usb_phy () {
54
84
static USBPhyHw usbphy;
55
85
return &usbphy;
@@ -97,15 +127,22 @@ void USBPhyHw::init(USBPhyEvents *events) {
97
127
instance = this ;
98
128
99
129
virtual_status_xfer_event = false ;
130
+ irq_already_pending = false ;
100
131
101
132
/*
102
- * Configure ISOIN endpoint to respond with ZLP when
133
+ * TODO - Configure ISOIN endpoint to respond with ZLP when
103
134
* no data is ready to be sent
135
+ *
136
+ * This is a feature available in the Nordic SDK15.2
137
+ * For now we just configure the appropriate register on initialization
104
138
*/
105
139
NRF_USBD->ISOINCONFIG |= 0x01 ; // set RESPONSE to 1 (respond with ZLP)
106
140
107
141
// Enable IRQ
142
+ // NVIC_SetVector(USBD_IRQn, (uint32_t)USBD_IRQHandler);
108
143
NVIC_SetVector (USBD_IRQn, (uint32_t )USBD_HAL_IRQHandler);
144
+ // NVIC_SetPriority(USBD_IRQn, 7);
145
+ // NVIC_EnableIRQ(USBD_IRQn); // This is handled by the Nordic driver
109
146
}
110
147
111
148
void USBPhyHw::deinit () {
@@ -177,7 +214,6 @@ void USBPhyHw::sof_enable() {
177
214
// TODO - Enable SOF interrupt
178
215
// Can this safely be done if
179
216
// nrf_drv_usbd_start is called with SoF enabled?
180
- // For now just mask the interrupt with a boolean flag
181
217
sof_enabled = true ;
182
218
}
183
219
@@ -268,6 +304,8 @@ void USBPhyHw::ep0_read(uint8_t *data, uint32_t size) {
268
304
269
305
virtual_status_xfer_event = true ;
270
306
307
+ irq_already_pending = NVIC_GetPendingIRQ (USBD_IRQn);
308
+
271
309
// Trigger an interrupt to process the virtual status event
272
310
NVIC_SetPendingIRQ (USBD_IRQn);
273
311
@@ -311,6 +349,8 @@ void USBPhyHw::ep0_write(uint8_t *buffer, uint32_t size) {
311
349
312
350
virtual_status_xfer_event = true ;
313
351
352
+ irq_already_pending = NVIC_GetPendingIRQ (USBD_IRQn);
353
+
314
354
// Trigger an interrupt to process the virtual status event
315
355
NVIC_SetPendingIRQ (USBD_IRQn);
316
356
@@ -356,7 +396,10 @@ void USBPhyHw::endpoint_stall(usb_ep_t endpoint) {
356
396
}
357
397
358
398
void USBPhyHw::endpoint_unstall (usb_ep_t endpoint) {
359
- nrf_drv_usbd_ep_stall_clear (get_nordic_endpoint (endpoint));
399
+ nrf_drv_usbd_ep_t ep = get_nordic_endpoint (endpoint);
400
+ nrf_drv_usbd_ep_stall_clear (ep);
401
+ nrf_drv_usbd_ep_disable (ep);
402
+ nrf_drv_usbd_ep_enable (ep);
360
403
}
361
404
362
405
bool USBPhyHw::endpoint_read (usb_ep_t endpoint, uint8_t *data, uint32_t size) {
@@ -389,7 +432,8 @@ bool USBPhyHw::endpoint_write(usb_ep_t endpoint, uint8_t *data, uint32_t size) {
389
432
}
390
433
391
434
void USBPhyHw::endpoint_abort (usb_ep_t endpoint) {
392
- nrf_drv_usbd_ep_abort (get_nordic_endpoint (endpoint));
435
+ nrf_drv_usbd_ep_t nrf_ep = get_nordic_endpoint (endpoint);
436
+ nrf_drv_usbd_ep_abort (nrf_ep);
393
437
}
394
438
395
439
void USBPhyHw::process () {
@@ -561,9 +605,7 @@ void USBPhyHw::_reset(void)
561
605
562
606
usb_event_type = USB_HW_EVENT_NONE;
563
607
564
- // Clear all endpoint interrupts
565
- NVIC_ClearPendingIRQ (USBD_IRQn);
566
- nrf_usbd_event_clear ((nrf_usbd_event_t )0x01FFFFFF );
608
+ // TODO - Clear all endpoint interrupts?
567
609
}
568
610
569
611
void USBPhyHw::enable_usb_interrupts (void ) {
@@ -602,15 +644,15 @@ void USBD_HAL_IRQHandler(void)
602
644
if (virtual_status_xfer_event)
603
645
{
604
646
if (instance) {
605
- // if(!irq_already_pending)
606
- // return;
607
-
608
- // irq_already_pending = false;
609
647
instance->_usb_virtual_status_event_handler ();
610
648
}
611
649
612
650
virtual_status_xfer_event = false ;
613
651
652
+ if (!irq_already_pending)
653
+ return ;
654
+
655
+ irq_already_pending = false ;
614
656
}
615
657
// Call Nordic driver IRQ handler
616
658
USBD_IRQHandler ();
0 commit comments