add nrf52 walkaround for errata 104, 171, 187.

clean up osal_none
This commit is contained in:
hathach 2018-04-07 15:03:56 +07:00
parent b9fc708e41
commit 9be8e7bef6
5 changed files with 206 additions and 64 deletions

View File

@ -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)
//--------------------------------------------------------------------+

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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