summaryrefslogtreecommitdiff
path: root/tinyusb
diff options
context:
space:
mode:
authorhathach <[email protected]>2018-04-07 15:03:56 +0700
committerhathach <[email protected]>2018-04-07 15:03:56 +0700
commit9be8e7bef6d8d8cada684f1f46334bceded7479f (patch)
tree7c92f4e4d92f9fc50e2ddcaa2c99edcaf7fd8f8e /tinyusb
parentb9fc708e41a8e2cc3135aa2ff07567e6daa61097 (diff)
add nrf52 walkaround for errata 104, 171, 187.
clean up osal_none
Diffstat (limited to 'tinyusb')
-rw-r--r--tinyusb/osal/osal_none.h88
-rw-r--r--tinyusb/portable/nordic/nrf5x/dcd_nrf5x.c79
-rw-r--r--tinyusb/portable/nordic/nrf5x/hal_nrf5x.c74
-rw-r--r--tinyusb/tusb_hal.h27
-rw-r--r--tinyusb/tusb_option.h2
5 files changed, 206 insertions, 64 deletions
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