diff --git a/tinyusb/osal/osal_none.h b/tinyusb/osal/osal_none.h index 8500638fc..f8a0ace19 100644 --- a/tinyusb/osal/osal_none.h +++ b/tinyusb/osal/osal_none.h @@ -74,27 +74,27 @@ static inline osal_task_t osal_task_create(osal_func_t code, const char* name, u return (osal_task_t) 1; } -#define TASK_RESTART \ +#define TASK_RESTART \ _state = 0 -#define OSAL_TASK_BEGIN \ - static uint16_t _state = 0; \ - ATTR_UNUSED static uint32_t _timeout = 0; \ - (void) _timeout; \ - switch(_state) { \ +#define OSAL_TASK_BEGIN \ + static uint16_t _state = 0; \ + ATTR_UNUSED static uint32_t _timeout = 0; \ + (void) _timeout; \ + switch(_state) { \ case 0: { -#define OSAL_TASK_END \ - default: TASK_RESTART; break; \ - }}\ +#define OSAL_TASK_END \ + default: TASK_RESTART; break; \ + }} \ return; -#define osal_task_delay(msec) \ - do {\ - _timeout = tusb_hal_millis();\ - _state = __LINE__; case __LINE__:\ +#define osal_task_delay(msec) \ + do { \ + _timeout = tusb_hal_millis(); \ + _state = __LINE__; case __LINE__: \ if ( _timeout + msec > tusb_hal_millis() ) \ - return TUSB_ERROR_OSAL_WAITING;\ + return TUSB_ERROR_OSAL_WAITING; \ }while(0) //--------------------------------------------------------------------+ @@ -156,23 +156,21 @@ static inline void osal_queue_flush(osal_queue_t const queue_hdl) queue_hdl->count = queue_hdl->rd_idx = queue_hdl->wr_idx = 0; } -#define osal_queue_receive(queue_hdl, p_data, msec, p_error) \ - do {\ - _timeout = tusb_hal_millis();\ - _state = __LINE__; case __LINE__:\ - if( queue_hdl->count == 0 ) {\ - if ( (msec != OSAL_TIMEOUT_WAIT_FOREVER) && ( _timeout + msec <= tusb_hal_millis()) ) /* time out */ \ - *(p_error) = TUSB_ERROR_OSAL_TIMEOUT;\ - else\ - return TUSB_ERROR_OSAL_WAITING;\ - } else{\ - /*TODO mutex lock tusb_hal_int_disable */\ - memcpy(p_data, queue_hdl->buffer + (queue_hdl->rd_idx * queue_hdl->item_size), queue_hdl->item_size);\ - queue_hdl->rd_idx = (queue_hdl->rd_idx + 1) % queue_hdl->depth;\ - queue_hdl->count--;\ - /*TODO mutex unlock tusb_hal_int_enable */\ - *(p_error) = TUSB_ERROR_NONE;\ - }\ +#define osal_queue_receive(queue_hdl, p_data, msec, p_error) \ + do { \ + _timeout = tusb_hal_millis(); \ + _state = __LINE__; case __LINE__: \ + if( queue_hdl->count == 0 ) { \ + if ( (msec != OSAL_TIMEOUT_WAIT_FOREVER) && ( _timeout + msec <= tusb_hal_millis()) ) \ + *(p_error) = TUSB_ERROR_OSAL_TIMEOUT; \ + else \ + return TUSB_ERROR_OSAL_WAITING; \ + } else{ \ + /*tusb_hal_int_disable_all();*/ \ + fifo_read(queue_hdl, p_data); \ + /*tusb_hal_int_enable_all();*/ \ + *(p_error) = TUSB_ERROR_NONE; \ + } \ }while(0) @@ -210,19 +208,21 @@ static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl) sem_hdl->count = 0; } -#define osal_semaphore_wait(sem_hdl, msec, p_error) \ - do {\ - _timeout = tusb_hal_millis();\ - _state = __LINE__; case __LINE__:\ - if( sem_hdl->count == 0 ) {\ - if ( (msec != OSAL_TIMEOUT_WAIT_FOREVER) && (_timeout + msec <= tusb_hal_millis()) ) /* time out */ \ - *(p_error) = TUSB_ERROR_OSAL_TIMEOUT;\ - else\ - return TUSB_ERROR_OSAL_WAITING;\ - } else{\ - if (sem_hdl->count) sem_hdl->count--; /*TODO mutex tusb_hal_int_disable consideration*/\ - *(p_error) = TUSB_ERROR_NONE;\ - }\ +#define osal_semaphore_wait(sem_hdl, msec, p_error) \ + do { \ + _timeout = tusb_hal_millis(); \ + _state = __LINE__; case __LINE__: \ + if( sem_hdl->count == 0 ) { \ + if ( (msec != OSAL_TIMEOUT_WAIT_FOREVER) && (_timeout + msec <= tusb_hal_millis()) ) \ + *(p_error) = TUSB_ERROR_OSAL_TIMEOUT; \ + else \ + return TUSB_ERROR_OSAL_WAITING; \ + } else{ \ + /*tusb_hal_int_disable_all();*/ \ + sem_hdl->count--; \ + /*tusb_hal_int_enable_all();*/ \ + *(p_error) = TUSB_ERROR_NONE; \ + } \ }while(0) //--------------------------------------------------------------------+ diff --git a/tinyusb/portable/nordic/nrf5x/dcd_nrf5x.c b/tinyusb/portable/nordic/nrf5x/dcd_nrf5x.c index f3346b231..082fc40e3 100644 --- a/tinyusb/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/tinyusb/portable/nordic/nrf5x/dcd_nrf5x.c @@ -64,10 +64,14 @@ enum typedef struct { uint8_t* buffer; + uint16_t total_len; uint16_t actual_len; uint8_t mps; // max packet size + + // FIXME Errata 104 walkaround + uint16_t frame_num; } nom_xfer_t; /*static*/ struct @@ -80,7 +84,7 @@ typedef struct }control; // Non control: 7 endpoints IN & OUT (offset 1) - nom_xfer_t xfer[2][7]; + nom_xfer_t xfer[7][2]; volatile bool dma_running; }_dcd; @@ -227,14 +231,14 @@ bool dcd_control_xfer (uint8_t rhport, tusb_dir_t dir, uint8_t * buffer, uint16_ *------------------------------------------------------------------*/ static void normal_xact_start(uint8_t epnum, uint8_t dir) { - nom_xfer_t* xfer = &_dcd.xfer[dir][epnum-1]; + nom_xfer_t* xfer = &_dcd.xfer[epnum-1][dir]; // Each transaction is up to Max Packet Size uint8_t const xact_len = min16_of(xfer->total_len - xfer->actual_len, xfer->mps); if ( dir == TUSB_DIR_OUT ) { - // HW issue on nrf5284 sample, SIZE.EPOUT won't trigger ACK as spec + // Errata 135: HW issue on nrf5284 sample, SIZE.EPOUT won't trigger ACK as spec // use the back door interface as sdk for walk around if ( nrf_drv_usbd_errata_sizeepout_rw() ) { @@ -266,7 +270,7 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) uint8_t const epnum = edpt_number(desc_edpt->bEndpointAddress); uint8_t const dir = edpt_dir(desc_edpt->bEndpointAddress); - _dcd.xfer[dir][epnum-1].mps = desc_edpt->wMaxPacketSize.size; + _dcd.xfer[epnum-1][dir].mps = desc_edpt->wMaxPacketSize.size; if ( dir == TUSB_DIR_OUT ) { @@ -289,9 +293,17 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t uint8_t const epnum = edpt_number(ep_addr); uint8_t const dir = edpt_dir(ep_addr); - _dcd.xfer[dir][epnum-1].buffer = buffer; - _dcd.xfer[dir][epnum-1].total_len = total_bytes; - _dcd.xfer[dir][epnum-1].actual_len = 0; + nom_xfer_t* xfer = &_dcd.xfer[epnum-1][dir]; + + xfer->buffer = buffer; + xfer->total_len = total_bytes; + xfer->actual_len = 0; + + // FIXME Errata 104 walkaround + if ( nrf_drv_usbd_errata_104() ) + { + xfer->frame_num = (uint16_t) NRF_USBD->FRAMECNTR; + } normal_xact_start(epnum, dir); @@ -340,7 +352,7 @@ bool dcd_edpt_busy (uint8_t rhport, uint8_t ep_addr) uint8_t const epnum = edpt_number(ep_addr); uint8_t const dir = edpt_dir(ep_addr); - nom_xfer_t* xfer = &_dcd.xfer[dir][epnum-1]; + nom_xfer_t* xfer = &_dcd.xfer[epnum-1][dir]; return xfer->actual_len < xfer->total_len; } @@ -376,11 +388,6 @@ void USBD_IRQHandler(void) dcd_bus_event(0, USBD_BUS_EVENT_RESET); } - if ( int_status & USBD_INTEN_SOF_Msk ) - { - dcd_bus_event(0, USBD_BUS_EVENT_SOF); - } - if ( int_status & EDPT_END_ALL_MASK ) { // DMA complete move data from SRAM -> Endpoint @@ -444,7 +451,7 @@ void USBD_IRQHandler(void) { if ( BIT_TEST_(data_status, epnum ) ) { - nom_xfer_t* xfer = &_dcd.xfer[TUSB_DIR_IN][epnum-1]; + nom_xfer_t* xfer = &_dcd.xfer[epnum-1][TUSB_DIR_IN]; xfer->actual_len += NRF_USBD->EPIN[epnum].MAXCNT; @@ -465,7 +472,7 @@ void USBD_IRQHandler(void) { if ( BIT_TEST_(data_status, 16+epnum ) ) { - nom_xfer_t* xfer = &_dcd.xfer[TUSB_DIR_OUT][epnum-1]; + nom_xfer_t* xfer = &_dcd.xfer[epnum-1][TUSB_DIR_OUT]; uint8_t const xact_len = NRF_USBD->SIZE.EPOUT[epnum]; @@ -486,7 +493,7 @@ void USBD_IRQHandler(void) { if ( BIT_TEST_(int_status, USBD_INTEN_ENDEPOUT0_Pos+epnum) ) { - nom_xfer_t* xfer = &_dcd.xfer[TUSB_DIR_OUT][epnum-1]; + nom_xfer_t* xfer = &_dcd.xfer[epnum-1][TUSB_DIR_OUT]; // Transfer complete if transaction len < Max Packet Size or total len is transferred if ( (NRF_USBD->EPOUT[epnum].AMOUNT == xfer->mps) && (xfer->actual_len < xfer->total_len) ) @@ -517,6 +524,46 @@ void USBD_IRQHandler(void) } } + + // SOF interrupt + if ( int_status & USBD_INTEN_SOF_Msk ) + { + // FIXME Errata 104 The EPDATA event might not be generated, and the related update of EPDATASTATUS does not occur. + // There is no way for software to tell if a xfer is complete or not. + // Walkaround: we will asssume an non-control IN transfer is always complete after 10 frames + if ( nrf_drv_usbd_errata_104() ) + { + // Check all the queued IN transfer, retire all transfer if 10 frames has passed + for (int i=0; i<7; i++) + { + nom_xfer_t* xfer = &_dcd.xfer[i][TUSB_DIR_IN]; + + if (xfer->actual_len < xfer->total_len) + { + uint16_t diff = (uint16_t) NRF_USBD->FRAMECNTR; + + if ( diff > xfer->frame_num ) + { + diff -= xfer->frame_num; + }else + { + diff = (diff + 1024) - xfer->frame_num; // Frame counter cap at 1024 + } + + // Walkaround, mark this transfer as complete + if (diff > 10) + { + xfer->actual_len = xfer->total_len; + dcd_xfer_complete(0, (i+1) | TUSB_DIR_IN_MASK, xfer->actual_len, true); + } + } + } + } + + dcd_bus_event(0, USBD_BUS_EVENT_SOF); + } + + } #endif diff --git a/tinyusb/portable/nordic/nrf5x/hal_nrf5x.c b/tinyusb/portable/nordic/nrf5x/hal_nrf5x.c index 97fdccac1..473ebf138 100644 --- a/tinyusb/portable/nordic/nrf5x/hal_nrf5x.c +++ b/tinyusb/portable/nordic/nrf5x/hal_nrf5x.c @@ -199,6 +199,40 @@ void power_usb_event_handler(uint32_t event) nrf_usbd_eventcause_clear(NRF_USBD_EVENTCAUSE_READY_MASK); /* Enable the peripheral */ + // ERRATA 171, 187 + + if (nrf_drv_usbd_errata_187()) + { +// CRITICAL_REGION_ENTER(); + if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000) + { + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + *((volatile uint32_t *)(0x4006ED14)) = 0x00000003; + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + } + else + { + *((volatile uint32_t *)(0x4006ED14)) = 0x00000003; + } +// CRITICAL_REGION_EXIT(); + } + + if (nrf_drv_usbd_errata_171()) + { +// CRITICAL_REGION_ENTER(); + if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000) + { + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0; + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + } + else + { + *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0; + } +// CRITICAL_REGION_EXIT(); + } + nrf_usbd_enable(); // Enable HFCLK @@ -212,6 +246,39 @@ void power_usb_event_handler(uint32_t event) nrf_usbd_eventcause_clear(NRF_USBD_EVENTCAUSE_READY_MASK); nrf_usbd_event_clear(NRF_USBD_EVENT_USBEVENT); + if (nrf_drv_usbd_errata_171()) + { +// CRITICAL_REGION_ENTER(); + if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000) + { + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + *((volatile uint32_t *)(0x4006EC14)) = 0x00000000; + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + } + else + { + *((volatile uint32_t *)(0x4006EC14)) = 0x00000000; + } + +// CRITICAL_REGION_EXIT(); + } + + if (nrf_drv_usbd_errata_187()) + { +// CRITICAL_REGION_ENTER(); + if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000) + { + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + *((volatile uint32_t *)(0x4006ED14)) = 0x00000000; + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + } + else + { + *((volatile uint32_t *)(0x4006ED14)) = 0x00000000; + } +// CRITICAL_REGION_EXIT(); + } + if ( nrf_drv_usbd_errata_166() ) { *((volatile uint32_t *) (NRF_USBD_BASE + 0x800)) = 0x7E3; @@ -227,10 +294,9 @@ void power_usb_event_handler(uint32_t event) USBD_INTEN_EP0SETUP_Msk | USBD_INTEN_EP0DATADONE_Msk | USBD_INTEN_ENDEPIN0_Msk | USBD_INTEN_ENDEPOUT0_Msk | USBD_INTEN_EPDATA_Msk | USBD_INTEN_SOF_Msk; - // if (enable_sof || nrf_drv_usbd_errata_104()) - // { - // ints_to_enable |= NRF_USBD_INT_SOF_MASK; - // } + // FIXME Errata 104: USB complete event is not generated (happedn randomly). + // Requires to enable SOF to perform clean up task. + // nrf_drv_usbd_errata_104() // Enable interrupt, Priorities 0,1,4,5 (nRF52) are reserved for SoftDevice NVIC_SetPriority(USBD_IRQn, 7); diff --git a/tinyusb/tusb_hal.h b/tinyusb/tusb_hal.h index f09ba0f7d..84871f7b7 100644 --- a/tinyusb/tusb_hal.h +++ b/tinyusb/tusb_hal.h @@ -78,6 +78,33 @@ void tusb_hal_int_disable(uint8_t rhport); // Only required to implement if using No RTOS (osal_none) uint32_t tusb_hal_millis(void); + +// Enable all ports' interrupt +static inline void tusb_hal_int_enable_all(void) +{ +#ifdef TUSB_CFG_CONTROLLER_0_MODE + tusb_hal_int_enable(0); +#endif + +#ifdef TUSB_CFG_CONTROLLER_0_MODE + tusb_hal_int_enable(1); +#endif +} + +// Disable all ports' interrupt +static inline void tusb_hal_int_disable_all(void) +{ +#ifdef TUSB_CFG_CONTROLLER_0_MODE + tusb_hal_int_disable(0); +#endif + +#ifdef TUSB_CFG_CONTROLLER_0_MODE + tusb_hal_int_disable(1); +#endif +} + + + #ifdef __cplusplus } #endif diff --git a/tinyusb/tusb_option.h b/tinyusb/tusb_option.h index 4ddc288a4..d17487ba8 100644 --- a/tinyusb/tusb_option.h +++ b/tinyusb/tusb_option.h @@ -45,6 +45,7 @@ #define TUSB_VERSION_NAME "alpha" #define TUSB_VERSION XSTRING_(TUSB_VERSION_YEAR) "." XSTRING_(TUSB_VERSION_MONTH) +// TODO remove, use vendor specific flag /** \defgroup group_mcu Supported MCU * \ref TUSB_CFG_MCU must be defined to one of these * @{ */ @@ -57,6 +58,7 @@ #define MCU_LPC43XX 7 ///< NXP LPC43xx family /** @} */ +// Allow to use command line to change the config name/location #ifndef TUSB_CFG_CONFIG_FILE #define TUSB_CFG_CONFIG_FILE "tusb_config.h" #endif