working on making the mbed and nordic drivers compatible

pull/11023/head
George Beckstein 2018-11-29 00:17:05 -05:00 committed by Evelyne Donnaes
parent cd6892d0f0
commit 24d8c86007
2 changed files with 142 additions and 21 deletions

View File

@ -68,6 +68,7 @@ private:
USBPhyEvents *events;
bool sof_enabled;
bool connect_enabled;
typedef enum usb_hw_event_type_t {
USB_HW_EVENT_NONE = 0,
@ -96,6 +97,11 @@ private:
// Returns the corresponding enumeration given an mbed endpoint number
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

View File

@ -26,21 +26,32 @@
#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)
// Debugging flag for tracking USB events
#define USBD_DEBUG 1
// Nordic USBD driver IRQ handler
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 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() {
static USBPhyHw usbphy;
return &usbphy;
}
USBPhyHw::USBPhyHw() :
events(NULL), sof_enabled(false),
events(NULL), sof_enabled(false), connect_enabled(false),
usb_event_type(USB_HW_EVENT_NONE),
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);
APP_ERROR_CHECK(ret);
// Store a reference to this instance
instance = this;
// Enable IRQ
NVIC_SetVector(USBD_IRQn, (uint32_t)USBD_IRQHandler);
NVIC_SetPriority(USBD_IRQn, 6);
NVIC_SetPriority(USBD_IRQn, 7);
NVIC_EnableIRQ(USBD_IRQn);
}
@ -91,7 +103,10 @@ void USBPhyHw::deinit() {
// Disable the USB Device driver
ret_code_t ret = nrf_drv_usbd_uninit();
APP_ERROR_CHECK(ret);
//NVIC_DisableIRQ(USBD_IRQn);
NVIC_DisableIRQ(USBD_IRQn);
// Clear the instance pointer?
//instance = 0;
}
bool USBPhyHw::powered() {
@ -104,13 +119,27 @@ bool USBPhyHw::powered() {
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();
if(!nrf_drv_usbd_is_started())
nrf_drv_usbd_start(true);*/
}
}
void USBPhyHw::disconnect() {
this->connect_enabled = false;
if(nrf_drv_usbd_is_started())
nrf_drv_usbd_stop();
if(nrf_drv_usbd_is_enabled())
@ -268,6 +297,15 @@ void USBPhyHw::process() {
if (usb_event_type == USB_HW_EVENT_NONE)
return;
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
switch (usb_event.type) {
case NRF_DRV_USBD_EVT_SUSPEND:
@ -279,6 +317,7 @@ void USBPhyHw::process() {
case NRF_DRV_USBD_EVT_WUREQ:
break;
case NRF_DRV_USBD_EVT_RESET:
this->_reset();
events->reset();
break;
case NRF_DRV_USBD_EVT_SOF:
@ -298,13 +337,29 @@ void USBPhyHw::process() {
else
{
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();
}
else
events->out((usb_ep_t) usb_event.data.eptransfer.ep);
}
}
break;
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
nrf_drv_usbd_setup_get(&setup_buf);
events->ep0_setup();
@ -313,9 +368,6 @@ void USBPhyHw::process() {
default:
break;
// Re-enable interrupt
//NVIC_ClearPendingIRQ(USB_IRQn);
//NVIC_EnableIRQ(USB_IRQn);
}
}
else if (usb_event_type == USB_HW_EVENT_POWER)
@ -323,16 +375,20 @@ void USBPhyHw::process() {
// Process USB power-related events
switch (usb_power_event) {
case NRF_DRV_POWER_USB_EVT_DETECTED:
if(this->connect_enabled) {
if(!nrf_drv_usbd_is_enabled())
nrf_drv_usbd_enable();
events->power(true);
}
break;
case NRF_DRV_POWER_USB_EVT_REMOVED:
events->power(false);
break;
case NRF_DRV_POWER_USB_EVT_READY:
if(this->connect_enabled) {
if(!nrf_drv_usbd_is_started())
nrf_drv_usbd_start(true);
nrf_drv_usbd_start(false);//nrf_drv_usbd_start(true);
}
break;
default:
ASSERT(false);
@ -342,10 +398,14 @@ void USBPhyHw::process() {
// Unflag the event type
usb_event_type = USB_HW_EVENT_NONE;
// Re-enable interrupt
NVIC_ClearPendingIRQ(USBD_IRQn);
enable_usb_interrupts();
}
void USBPhyHw::_usb_event_handler(
nrf_drv_usbd_evt_t const * const p_event) {
disable_usb_interrupts();
// Copy the event data into internal memory
memcpy(&instance->usb_event, p_event, sizeof(instance->usb_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) {
disable_usb_interrupts();
// Copy the event data into internal memory
instance->usb_power_event = 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;
}
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) {
if(instance) {
// Pass the event on to the USBPhyHW instance
instance->_usb_power_event_handler(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
instance->_usb_event_handler(p_event);
}
}
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) { }
//}