Skip to content

Commit 4b4364f

Browse files
AGlass0fMilkArto Kinnunen
authored andcommitted
Added workaround for "unloading" IN endpoints after unstalling. Disable and then reenable when USBPhyHw::endpoint_unhalt() is called.
1 parent 0f61412 commit 4b4364f

File tree

1 file changed

+53
-11
lines changed

1 file changed

+53
-11
lines changed

usb/device/targets/TARGET_NORDIC/TARGET_MCU_NRF52840/USBPhy_Nordic.cpp

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,27 @@
2121

2222
#include "nrf_clock.h"
2323

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+
*/
2445
#define MAX_PACKET_SIZE_SETUP NRF_DRV_USBD_EPSIZE
2546
#define MAX_PACKET_NON_ISO NRF_DRV_USBD_EPSIZE
2647
#define MAX_PACKET_ISO NRF_DRV_USBD_ISOSIZE
@@ -46,10 +67,19 @@ void USBD_HAL_IRQHandler(void);
4667
static USBPhyHw *instance = 0;
4768

4869
static volatile bool virtual_status_xfer_event;
70+
static volatile bool irq_already_pending;
4971

5072
static void usbd_event_handler(nrf_drv_usbd_evt_t const * const p_event);
5173
static void power_usb_event_handler(nrf_drv_power_usb_evt_t event);
5274

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+
5383
USBPhy *get_usb_phy() {
5484
static USBPhyHw usbphy;
5585
return &usbphy;
@@ -97,15 +127,22 @@ void USBPhyHw::init(USBPhyEvents *events) {
97127
instance = this;
98128

99129
virtual_status_xfer_event = false;
130+
irq_already_pending = false;
100131

101132
/*
102-
* Configure ISOIN endpoint to respond with ZLP when
133+
* TODO - Configure ISOIN endpoint to respond with ZLP when
103134
* 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
104138
*/
105139
NRF_USBD->ISOINCONFIG |= 0x01; // set RESPONSE to 1 (respond with ZLP)
106140

107141
// Enable IRQ
142+
//NVIC_SetVector(USBD_IRQn, (uint32_t)USBD_IRQHandler);
108143
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
109146
}
110147

111148
void USBPhyHw::deinit() {
@@ -177,7 +214,6 @@ void USBPhyHw::sof_enable() {
177214
// TODO - Enable SOF interrupt
178215
// Can this safely be done if
179216
// nrf_drv_usbd_start is called with SoF enabled?
180-
// For now just mask the interrupt with a boolean flag
181217
sof_enabled = true;
182218
}
183219

@@ -268,6 +304,8 @@ void USBPhyHw::ep0_read(uint8_t *data, uint32_t size) {
268304

269305
virtual_status_xfer_event = true;
270306

307+
irq_already_pending = NVIC_GetPendingIRQ(USBD_IRQn);
308+
271309
// Trigger an interrupt to process the virtual status event
272310
NVIC_SetPendingIRQ(USBD_IRQn);
273311

@@ -311,6 +349,8 @@ void USBPhyHw::ep0_write(uint8_t *buffer, uint32_t size) {
311349

312350
virtual_status_xfer_event = true;
313351

352+
irq_already_pending = NVIC_GetPendingIRQ(USBD_IRQn);
353+
314354
// Trigger an interrupt to process the virtual status event
315355
NVIC_SetPendingIRQ(USBD_IRQn);
316356

@@ -356,7 +396,10 @@ void USBPhyHw::endpoint_stall(usb_ep_t endpoint) {
356396
}
357397

358398
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);
360403
}
361404

362405
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) {
389432
}
390433

391434
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);
393437
}
394438

395439
void USBPhyHw::process() {
@@ -561,9 +605,7 @@ void USBPhyHw::_reset(void)
561605

562606
usb_event_type = USB_HW_EVENT_NONE;
563607

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?
567609
}
568610

569611
void USBPhyHw::enable_usb_interrupts(void) {
@@ -602,15 +644,15 @@ void USBD_HAL_IRQHandler(void)
602644
if(virtual_status_xfer_event)
603645
{
604646
if(instance) {
605-
//if(!irq_already_pending)
606-
// return;
607-
608-
//irq_already_pending = false;
609647
instance->_usb_virtual_status_event_handler();
610648
}
611649

612650
virtual_status_xfer_event = false;
613651

652+
if(!irq_already_pending)
653+
return;
654+
655+
irq_already_pending = false;
614656
}
615657
// Call Nordic driver IRQ handler
616658
USBD_IRQHandler();

0 commit comments

Comments
 (0)