mirror of https://github.com/ARMmbed/mbed-os.git
working on making the mbed and nordic drivers compatible
parent
cd6892d0f0
commit
24d8c86007
|
@ -68,6 +68,7 @@ private:
|
||||||
USBPhyEvents *events;
|
USBPhyEvents *events;
|
||||||
|
|
||||||
bool sof_enabled;
|
bool sof_enabled;
|
||||||
|
bool connect_enabled;
|
||||||
|
|
||||||
typedef enum usb_hw_event_type_t {
|
typedef enum usb_hw_event_type_t {
|
||||||
USB_HW_EVENT_NONE = 0,
|
USB_HW_EVENT_NONE = 0,
|
||||||
|
@ -96,6 +97,11 @@ private:
|
||||||
// Returns the corresponding enumeration given an mbed endpoint number
|
// Returns the corresponding enumeration given an mbed endpoint number
|
||||||
static nrf_drv_usbd_ep_t get_nordic_endpoint(usb_ep_t endpoint);
|
static nrf_drv_usbd_ep_t get_nordic_endpoint(usb_ep_t endpoint);
|
||||||
|
|
||||||
|
void _reset(void);
|
||||||
|
|
||||||
|
static void enable_usb_interrupts(void);
|
||||||
|
static void disable_usb_interrupts(void);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -26,21 +26,32 @@
|
||||||
#define IS_IN_EP(ep) (ep & 0x80) // Checks if the given endpoint is an IN endpoint (MSB set)
|
#define IS_IN_EP(ep) (ep & 0x80) // Checks if the given endpoint is an IN endpoint (MSB set)
|
||||||
#define IS_OUT_EP(ep) (ep & ~0x80) // Checks if the given endpoint is an OUT endpoint (MSB clear)
|
#define IS_OUT_EP(ep) (ep & ~0x80) // Checks if the given endpoint is an OUT endpoint (MSB clear)
|
||||||
|
|
||||||
|
// Debugging flag for tracking USB events
|
||||||
|
#define USBD_DEBUG 1
|
||||||
|
|
||||||
// Nordic USBD driver IRQ handler
|
// Nordic USBD driver IRQ handler
|
||||||
extern "C" void USBD_IRQHandler(void);
|
extern "C" void USBD_IRQHandler(void);
|
||||||
|
|
||||||
static USBPhyHw *instance;
|
static USBPhyHw *instance = 0;
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
USBPhyHw::USBPhyHw() :
|
USBPhyHw::USBPhyHw() :
|
||||||
events(NULL), sof_enabled(false),
|
events(NULL), sof_enabled(false), connect_enabled(false),
|
||||||
usb_event_type(USB_HW_EVENT_NONE),
|
usb_event_type(USB_HW_EVENT_NONE),
|
||||||
usb_power_event(NRF_DRV_POWER_USB_EVT_REMOVED) {
|
usb_power_event(NRF_DRV_POWER_USB_EVT_REMOVED) {
|
||||||
|
|
||||||
|
@ -77,11 +88,12 @@ void USBPhyHw::init(USBPhyEvents *events) {
|
||||||
ret = nrf_drv_usbd_init(usbd_event_handler);
|
ret = nrf_drv_usbd_init(usbd_event_handler);
|
||||||
APP_ERROR_CHECK(ret);
|
APP_ERROR_CHECK(ret);
|
||||||
|
|
||||||
|
// Store a reference to this instance
|
||||||
instance = this;
|
instance = this;
|
||||||
|
|
||||||
// Enable IRQ
|
// Enable IRQ
|
||||||
NVIC_SetVector(USBD_IRQn, (uint32_t)USBD_IRQHandler);
|
NVIC_SetVector(USBD_IRQn, (uint32_t)USBD_IRQHandler);
|
||||||
NVIC_SetPriority(USBD_IRQn, 6);
|
NVIC_SetPriority(USBD_IRQn, 7);
|
||||||
NVIC_EnableIRQ(USBD_IRQn);
|
NVIC_EnableIRQ(USBD_IRQn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +103,10 @@ void USBPhyHw::deinit() {
|
||||||
// Disable the USB Device driver
|
// Disable the USB Device driver
|
||||||
ret_code_t ret = nrf_drv_usbd_uninit();
|
ret_code_t ret = nrf_drv_usbd_uninit();
|
||||||
APP_ERROR_CHECK(ret);
|
APP_ERROR_CHECK(ret);
|
||||||
//NVIC_DisableIRQ(USBD_IRQn);
|
NVIC_DisableIRQ(USBD_IRQn);
|
||||||
|
|
||||||
|
// Clear the instance pointer?
|
||||||
|
//instance = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool USBPhyHw::powered() {
|
bool USBPhyHw::powered() {
|
||||||
|
@ -104,13 +119,27 @@ bool USBPhyHw::powered() {
|
||||||
|
|
||||||
void USBPhyHw::connect() {
|
void USBPhyHw::connect() {
|
||||||
|
|
||||||
/*if(!nrf_drv_usbd_is_enabled())
|
// To save power, we only enable the USBD peripheral
|
||||||
|
// when there's actually VBUS detected
|
||||||
|
|
||||||
|
// So flag that the USB stack is ready to connect
|
||||||
|
this->connect_enabled = true;
|
||||||
|
|
||||||
|
// If VBUS is already available, enable immediately
|
||||||
|
if(nrf_drv_power_usbstatus_get() == NRF_DRV_POWER_USB_STATE_CONNECTED)
|
||||||
|
{
|
||||||
|
// Enabling USB will cause NRF_DRV_POWER_USB_EVT_READY
|
||||||
|
// to occur, which will start the USBD peripheral
|
||||||
|
// when the internal regulator has settled
|
||||||
|
if(!nrf_drv_usbd_is_enabled())
|
||||||
nrf_drv_usbd_enable();
|
nrf_drv_usbd_enable();
|
||||||
if(!nrf_drv_usbd_is_started())
|
}
|
||||||
nrf_drv_usbd_start(true);*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBPhyHw::disconnect() {
|
void USBPhyHw::disconnect() {
|
||||||
|
|
||||||
|
this->connect_enabled = false;
|
||||||
|
|
||||||
if(nrf_drv_usbd_is_started())
|
if(nrf_drv_usbd_is_started())
|
||||||
nrf_drv_usbd_stop();
|
nrf_drv_usbd_stop();
|
||||||
if(nrf_drv_usbd_is_enabled())
|
if(nrf_drv_usbd_is_enabled())
|
||||||
|
@ -268,6 +297,15 @@ void USBPhyHw::process() {
|
||||||
if (usb_event_type == USB_HW_EVENT_NONE)
|
if (usb_event_type == USB_HW_EVENT_NONE)
|
||||||
return;
|
return;
|
||||||
else if (usb_event_type == USB_HW_EVENT_USBD) {
|
else if (usb_event_type == USB_HW_EVENT_USBD) {
|
||||||
|
|
||||||
|
#ifdef USBD_DEBUG
|
||||||
|
// Save this event to the static log
|
||||||
|
memcpy(&debug_events[debug_evt_index++], &usb_event, sizeof(nrf_drv_usbd_evt_t));
|
||||||
|
// Reset index if we overflow the buffer
|
||||||
|
if(debug_evt_index >= 32)
|
||||||
|
debug_evt_index = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Process regular USBD events
|
// Process regular USBD events
|
||||||
switch (usb_event.type) {
|
switch (usb_event.type) {
|
||||||
case NRF_DRV_USBD_EVT_SUSPEND:
|
case NRF_DRV_USBD_EVT_SUSPEND:
|
||||||
|
@ -279,6 +317,7 @@ void USBPhyHw::process() {
|
||||||
case NRF_DRV_USBD_EVT_WUREQ:
|
case NRF_DRV_USBD_EVT_WUREQ:
|
||||||
break;
|
break;
|
||||||
case NRF_DRV_USBD_EVT_RESET:
|
case NRF_DRV_USBD_EVT_RESET:
|
||||||
|
this->_reset();
|
||||||
events->reset();
|
events->reset();
|
||||||
break;
|
break;
|
||||||
case NRF_DRV_USBD_EVT_SOF:
|
case NRF_DRV_USBD_EVT_SOF:
|
||||||
|
@ -298,13 +337,29 @@ void USBPhyHw::process() {
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if((usb_event.data.eptransfer.ep & 0x7F) == 0)
|
if((usb_event.data.eptransfer.ep & 0x7F) == 0)
|
||||||
|
{
|
||||||
|
/* NOTE: Data values or size may be tested here to decide if clear or stall.
|
||||||
|
* If errata 154 is present the data transfer is acknowledged by the hardware. */
|
||||||
|
if (!nrf_drv_usbd_errata_154()) {
|
||||||
|
/* Transfer ok - allow status stage */
|
||||||
|
nrf_drv_usbd_setup_clear();
|
||||||
|
}
|
||||||
|
|
||||||
events->ep0_out();
|
events->ep0_out();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
events->out((usb_ep_t) usb_event.data.eptransfer.ep);
|
events->out((usb_ep_t) usb_event.data.eptransfer.ep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NRF_DRV_USBD_EVT_SETUP: {
|
case NRF_DRV_USBD_EVT_SETUP: {
|
||||||
|
|
||||||
|
// Clear endpoint 0 stalls on setup packet receive
|
||||||
|
if(nrf_drv_usbd_ep_stall_check(NRF_DRV_USBD_EPOUT0))
|
||||||
|
nrf_drv_usbd_ep_stall_clear(NRF_DRV_USBD_EPOUT0);
|
||||||
|
if(nrf_drv_usbd_ep_stall_check(NRF_DRV_USBD_EPIN0))
|
||||||
|
nrf_drv_usbd_ep_stall_clear(NRF_DRV_USBD_EPIN0);
|
||||||
|
|
||||||
// Copy the setup packet into the internal buffer
|
// Copy the setup packet into the internal buffer
|
||||||
nrf_drv_usbd_setup_get(&setup_buf);
|
nrf_drv_usbd_setup_get(&setup_buf);
|
||||||
events->ep0_setup();
|
events->ep0_setup();
|
||||||
|
@ -313,9 +368,6 @@ void USBPhyHw::process() {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Re-enable interrupt
|
|
||||||
//NVIC_ClearPendingIRQ(USB_IRQn);
|
|
||||||
//NVIC_EnableIRQ(USB_IRQn);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (usb_event_type == USB_HW_EVENT_POWER)
|
else if (usb_event_type == USB_HW_EVENT_POWER)
|
||||||
|
@ -323,16 +375,20 @@ void USBPhyHw::process() {
|
||||||
// Process USB power-related events
|
// Process USB power-related events
|
||||||
switch (usb_power_event) {
|
switch (usb_power_event) {
|
||||||
case NRF_DRV_POWER_USB_EVT_DETECTED:
|
case NRF_DRV_POWER_USB_EVT_DETECTED:
|
||||||
|
if(this->connect_enabled) {
|
||||||
if(!nrf_drv_usbd_is_enabled())
|
if(!nrf_drv_usbd_is_enabled())
|
||||||
nrf_drv_usbd_enable();
|
nrf_drv_usbd_enable();
|
||||||
events->power(true);
|
events->power(true);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case NRF_DRV_POWER_USB_EVT_REMOVED:
|
case NRF_DRV_POWER_USB_EVT_REMOVED:
|
||||||
events->power(false);
|
events->power(false);
|
||||||
break;
|
break;
|
||||||
case NRF_DRV_POWER_USB_EVT_READY:
|
case NRF_DRV_POWER_USB_EVT_READY:
|
||||||
|
if(this->connect_enabled) {
|
||||||
if(!nrf_drv_usbd_is_started())
|
if(!nrf_drv_usbd_is_started())
|
||||||
nrf_drv_usbd_start(true);
|
nrf_drv_usbd_start(false);//nrf_drv_usbd_start(true);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
|
@ -342,10 +398,14 @@ void USBPhyHw::process() {
|
||||||
// Unflag the event type
|
// Unflag the event type
|
||||||
usb_event_type = USB_HW_EVENT_NONE;
|
usb_event_type = USB_HW_EVENT_NONE;
|
||||||
|
|
||||||
|
// Re-enable interrupt
|
||||||
|
NVIC_ClearPendingIRQ(USBD_IRQn);
|
||||||
|
enable_usb_interrupts();
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBPhyHw::_usb_event_handler(
|
void USBPhyHw::_usb_event_handler(
|
||||||
nrf_drv_usbd_evt_t const * const p_event) {
|
nrf_drv_usbd_evt_t const * const p_event) {
|
||||||
|
disable_usb_interrupts();
|
||||||
// Copy the event data into internal memory
|
// Copy the event data into internal memory
|
||||||
memcpy(&instance->usb_event, p_event, sizeof(instance->usb_event));
|
memcpy(&instance->usb_event, p_event, sizeof(instance->usb_event));
|
||||||
// Tell the upper layers of the stack to process the event
|
// Tell the upper layers of the stack to process the event
|
||||||
|
@ -354,6 +414,7 @@ void USBPhyHw::_usb_event_handler(
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBPhyHw::_usb_power_event_handler(nrf_drv_power_usb_evt_t event) {
|
void USBPhyHw::_usb_power_event_handler(nrf_drv_power_usb_evt_t event) {
|
||||||
|
disable_usb_interrupts();
|
||||||
// Copy the event data into internal memory
|
// Copy the event data into internal memory
|
||||||
instance->usb_power_event = event;
|
instance->usb_power_event = event;
|
||||||
// Tell the upper layers of the stack to process the event
|
// Tell the upper layers of the stack to process the event
|
||||||
|
@ -374,16 +435,70 @@ nrf_drv_usbd_ep_t USBPhyHw::get_nordic_endpoint(usb_ep_t endpoint) {
|
||||||
return (nrf_drv_usbd_ep_t) endpoint;
|
return (nrf_drv_usbd_ep_t) endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void USBPhyHw::_reset(void)
|
||||||
|
{
|
||||||
|
// Disable all endpoints except for control endpoints
|
||||||
|
nrf_drv_usbd_ep_default_config();
|
||||||
|
|
||||||
|
// TODO - Clear all endpoint interrupts?
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBPhyHw::enable_usb_interrupts(void) {
|
||||||
|
// Enable USB and USB-related power interrupts
|
||||||
|
NVIC_EnableIRQ(USBD_IRQn);
|
||||||
|
nrf_power_int_enable(NRF_POWER_INT_USBDETECTED_MASK |
|
||||||
|
NRF_POWER_INT_USBREMOVED_MASK |
|
||||||
|
NRF_POWER_INT_USBPWRRDY_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBPhyHw::disable_usb_interrupts(void) {
|
||||||
|
// Disable USB and USB-related power interrupts
|
||||||
|
NVIC_DisableIRQ(USBD_IRQn);
|
||||||
|
nrf_power_int_disable(NRF_POWER_INT_USBDETECTED_MASK |
|
||||||
|
NRF_POWER_INT_USBREMOVED_MASK |
|
||||||
|
NRF_POWER_INT_USBPWRRDY_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
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(instance) {
|
||||||
// Pass the event on to the USBPhyHW instance
|
// Pass the event on to the USBPhyHW instance
|
||||||
instance->_usb_power_event_handler(event);
|
instance->_usb_power_event_handler(event);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
|
if(instance) {
|
||||||
|
NVIC_DisableIRQ(USBD_IRQn);
|
||||||
// Pass the event on to the USBPhyHW instance
|
// Pass the event on to the USBPhyHW instance
|
||||||
instance->_usb_event_handler(p_event);
|
instance->_usb_event_handler(p_event);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
void USBD_IRQHandler_v(void) { }
|
|
||||||
|
/**
|
||||||
|
* @brief Feeder passing data between mbed and nordic USB stacks
|
||||||
|
*
|
||||||
|
* @param[out] p_next See @ref nrf_drv_usbd_feeder_t documentation.
|
||||||
|
* @param[in,out] p_context See @ref nrf_drv_usbd_feeder_t documentation.
|
||||||
|
* @param[in] ep_size See @ref nrf_drv_usbd_feeder_t documentation.
|
||||||
|
*
|
||||||
|
* @retval true Continue transfer.
|
||||||
|
* @retval false This was the last transfer.
|
||||||
|
*/
|
||||||
|
bool mbed_nrf_feeder(nrf_drv_usbd_ep_transfer_t * p_next,
|
||||||
|
void * p_context,
|
||||||
|
size_t ep_size)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
// We don't know if this is the last transfer or not at this level -- mbed doesn't tell us...
|
||||||
|
// So just tell the nordic layer that the transfer isn't over yet (so don't NAK/STALL)
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//extern "C" {
|
||||||
|
//void USBD_IRQHandler_v(void) { }
|
||||||
|
//}
|
||||||
|
|
Loading…
Reference in New Issue