mirror of https://github.com/ARMmbed/mbed-os.git
Added workaround for "unloading" IN endpoints after unstalling. Disable and then reenable when USBPhyHw::endpoint_unhalt() is called.
parent
0f614124c1
commit
4b4364fedf
|
@ -21,6 +21,27 @@
|
||||||
|
|
||||||
#include "nrf_clock.h"
|
#include "nrf_clock.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO list for nRF52840 USBD driver
|
||||||
|
*
|
||||||
|
* 1.) Properly enable/disable start-of-frame interrupt.
|
||||||
|
*
|
||||||
|
* Description: Currently, start-of-frame interrupts are masked by a flag at this layer
|
||||||
|
* but still cause the processor to be interrupted for no purpose.
|
||||||
|
*
|
||||||
|
* The Nordic driver requires you to call nrf_drv_start(bool)
|
||||||
|
* with a boolean flag indicating whether it should enable start-of-frame
|
||||||
|
* interrupts or not. From the datasheet it seems to be possible to
|
||||||
|
* enable/disable SoF interrupts on the fly, but the fact that they
|
||||||
|
* force you to make the SoF decision during "start" makes me suspicious
|
||||||
|
* the underlying driver may manage/use the SoF flag in other ways.
|
||||||
|
*
|
||||||
|
* Next steps: Investigate how the SoF flag is used during "nrf_drv_start" and
|
||||||
|
* determine if enabling/disabling this interrupt would cause internal problems
|
||||||
|
* with the Nordic USBD driver
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
#define MAX_PACKET_SIZE_SETUP NRF_DRV_USBD_EPSIZE
|
#define MAX_PACKET_SIZE_SETUP NRF_DRV_USBD_EPSIZE
|
||||||
#define MAX_PACKET_NON_ISO NRF_DRV_USBD_EPSIZE
|
#define MAX_PACKET_NON_ISO NRF_DRV_USBD_EPSIZE
|
||||||
#define MAX_PACKET_ISO NRF_DRV_USBD_ISOSIZE
|
#define MAX_PACKET_ISO NRF_DRV_USBD_ISOSIZE
|
||||||
|
@ -46,10 +67,19 @@ void USBD_HAL_IRQHandler(void);
|
||||||
static USBPhyHw *instance = 0;
|
static USBPhyHw *instance = 0;
|
||||||
|
|
||||||
static volatile bool virtual_status_xfer_event;
|
static volatile bool virtual_status_xfer_event;
|
||||||
|
static volatile bool irq_already_pending;
|
||||||
|
|
||||||
static void usbd_event_handler(nrf_drv_usbd_evt_t const * const p_event);
|
static void usbd_event_handler(nrf_drv_usbd_evt_t const * const p_event);
|
||||||
static void power_usb_event_handler(nrf_drv_power_usb_evt_t event);
|
static void power_usb_event_handler(nrf_drv_power_usb_evt_t event);
|
||||||
|
|
||||||
|
#if USBD_DEBUG
|
||||||
|
|
||||||
|
// Static array of saved events to track what happens
|
||||||
|
static nrf_drv_usbd_evt_t debug_events[32];
|
||||||
|
static uint8_t debug_evt_index = 0;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
USBPhy *get_usb_phy() {
|
USBPhy *get_usb_phy() {
|
||||||
static USBPhyHw usbphy;
|
static USBPhyHw usbphy;
|
||||||
return &usbphy;
|
return &usbphy;
|
||||||
|
@ -97,15 +127,22 @@ void USBPhyHw::init(USBPhyEvents *events) {
|
||||||
instance = this;
|
instance = this;
|
||||||
|
|
||||||
virtual_status_xfer_event = false;
|
virtual_status_xfer_event = false;
|
||||||
|
irq_already_pending = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Configure ISOIN endpoint to respond with ZLP when
|
* TODO - Configure ISOIN endpoint to respond with ZLP when
|
||||||
* no data is ready to be sent
|
* no data is ready to be sent
|
||||||
|
*
|
||||||
|
* This is a feature available in the Nordic SDK15.2
|
||||||
|
* For now we just configure the appropriate register on initialization
|
||||||
*/
|
*/
|
||||||
NRF_USBD->ISOINCONFIG |= 0x01; // set RESPONSE to 1 (respond with ZLP)
|
NRF_USBD->ISOINCONFIG |= 0x01; // set RESPONSE to 1 (respond with ZLP)
|
||||||
|
|
||||||
// Enable IRQ
|
// Enable IRQ
|
||||||
|
//NVIC_SetVector(USBD_IRQn, (uint32_t)USBD_IRQHandler);
|
||||||
NVIC_SetVector(USBD_IRQn, (uint32_t)USBD_HAL_IRQHandler);
|
NVIC_SetVector(USBD_IRQn, (uint32_t)USBD_HAL_IRQHandler);
|
||||||
|
//NVIC_SetPriority(USBD_IRQn, 7);
|
||||||
|
//NVIC_EnableIRQ(USBD_IRQn); // This is handled by the Nordic driver
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBPhyHw::deinit() {
|
void USBPhyHw::deinit() {
|
||||||
|
@ -177,7 +214,6 @@ void USBPhyHw::sof_enable() {
|
||||||
// TODO - Enable SOF interrupt
|
// TODO - Enable SOF interrupt
|
||||||
// Can this safely be done if
|
// Can this safely be done if
|
||||||
// nrf_drv_usbd_start is called with SoF enabled?
|
// nrf_drv_usbd_start is called with SoF enabled?
|
||||||
// For now just mask the interrupt with a boolean flag
|
|
||||||
sof_enabled = true;
|
sof_enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,6 +304,8 @@ void USBPhyHw::ep0_read(uint8_t *data, uint32_t size) {
|
||||||
|
|
||||||
virtual_status_xfer_event = true;
|
virtual_status_xfer_event = true;
|
||||||
|
|
||||||
|
irq_already_pending = NVIC_GetPendingIRQ(USBD_IRQn);
|
||||||
|
|
||||||
// Trigger an interrupt to process the virtual status event
|
// Trigger an interrupt to process the virtual status event
|
||||||
NVIC_SetPendingIRQ(USBD_IRQn);
|
NVIC_SetPendingIRQ(USBD_IRQn);
|
||||||
|
|
||||||
|
@ -311,6 +349,8 @@ void USBPhyHw::ep0_write(uint8_t *buffer, uint32_t size) {
|
||||||
|
|
||||||
virtual_status_xfer_event = true;
|
virtual_status_xfer_event = true;
|
||||||
|
|
||||||
|
irq_already_pending = NVIC_GetPendingIRQ(USBD_IRQn);
|
||||||
|
|
||||||
// Trigger an interrupt to process the virtual status event
|
// Trigger an interrupt to process the virtual status event
|
||||||
NVIC_SetPendingIRQ(USBD_IRQn);
|
NVIC_SetPendingIRQ(USBD_IRQn);
|
||||||
|
|
||||||
|
@ -356,7 +396,10 @@ void USBPhyHw::endpoint_stall(usb_ep_t endpoint) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBPhyHw::endpoint_unstall(usb_ep_t endpoint) {
|
void USBPhyHw::endpoint_unstall(usb_ep_t endpoint) {
|
||||||
nrf_drv_usbd_ep_stall_clear(get_nordic_endpoint(endpoint));
|
nrf_drv_usbd_ep_t ep = get_nordic_endpoint(endpoint);
|
||||||
|
nrf_drv_usbd_ep_stall_clear(ep);
|
||||||
|
nrf_drv_usbd_ep_disable(ep);
|
||||||
|
nrf_drv_usbd_ep_enable(ep);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool USBPhyHw::endpoint_read(usb_ep_t endpoint, uint8_t *data, uint32_t size) {
|
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) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBPhyHw::endpoint_abort(usb_ep_t endpoint) {
|
void USBPhyHw::endpoint_abort(usb_ep_t endpoint) {
|
||||||
nrf_drv_usbd_ep_abort(get_nordic_endpoint(endpoint));
|
nrf_drv_usbd_ep_t nrf_ep = get_nordic_endpoint(endpoint);
|
||||||
|
nrf_drv_usbd_ep_abort(nrf_ep);
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBPhyHw::process() {
|
void USBPhyHw::process() {
|
||||||
|
@ -561,9 +605,7 @@ void USBPhyHw::_reset(void)
|
||||||
|
|
||||||
usb_event_type = USB_HW_EVENT_NONE;
|
usb_event_type = USB_HW_EVENT_NONE;
|
||||||
|
|
||||||
// Clear all endpoint interrupts
|
// TODO - Clear all endpoint interrupts?
|
||||||
NVIC_ClearPendingIRQ(USBD_IRQn);
|
|
||||||
nrf_usbd_event_clear((nrf_usbd_event_t)0x01FFFFFF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBPhyHw::enable_usb_interrupts(void) {
|
void USBPhyHw::enable_usb_interrupts(void) {
|
||||||
|
@ -602,15 +644,15 @@ void USBD_HAL_IRQHandler(void)
|
||||||
if(virtual_status_xfer_event)
|
if(virtual_status_xfer_event)
|
||||||
{
|
{
|
||||||
if(instance) {
|
if(instance) {
|
||||||
//if(!irq_already_pending)
|
|
||||||
// return;
|
|
||||||
|
|
||||||
//irq_already_pending = false;
|
|
||||||
instance->_usb_virtual_status_event_handler();
|
instance->_usb_virtual_status_event_handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual_status_xfer_event = false;
|
virtual_status_xfer_event = false;
|
||||||
|
|
||||||
|
if(!irq_already_pending)
|
||||||
|
return;
|
||||||
|
|
||||||
|
irq_already_pending = false;
|
||||||
}
|
}
|
||||||
// Call Nordic driver IRQ handler
|
// Call Nordic driver IRQ handler
|
||||||
USBD_IRQHandler();
|
USBD_IRQHandler();
|
||||||
|
|
Loading…
Reference in New Issue