Merge pull request #3127 from hathach/fix/dcd_race_condition
add osal spinlock API, Fix/dcd dwc2 race condition
This commit is contained in:
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -266,7 +266,7 @@ jobs:
|
||||
run: python3 tools/get_deps.py $BUILD_ARGS
|
||||
|
||||
- name: Build
|
||||
run: python3 tools/build.py --toolchain iar $BUILD_ARGS
|
||||
run: python3 tools/build.py -j 4 --toolchain iar $BUILD_ARGS
|
||||
|
||||
- name: Test on actual hardware (hardware in the loop)
|
||||
run: python3 test/hil/hil_test.py hfp.json
|
||||
|
@@ -369,6 +369,10 @@
|
||||
#define TUP_DCD_ENDPOINT_MAX 7 // only 5 TX FIFO for endpoint IN
|
||||
#define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/
|
||||
|
||||
#if CFG_TUSB_MCU == OPT_MCU_ESP32S3
|
||||
#define TUP_MCU_MULTIPLE_CORE 1
|
||||
#endif
|
||||
|
||||
// Disable slave if DMA is enabled
|
||||
#define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE
|
||||
#define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE
|
||||
@@ -381,6 +385,8 @@
|
||||
|
||||
#define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/
|
||||
|
||||
#define TUP_MCU_MULTIPLE_CORE 1
|
||||
|
||||
// Disable slave if DMA is enabled
|
||||
#define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE
|
||||
#define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE
|
||||
@@ -410,6 +416,7 @@
|
||||
#elif TU_CHECK_MCU(OPT_MCU_RP2040)
|
||||
#define TUP_DCD_EDPT_ISO_ALLOC
|
||||
#define TUP_DCD_ENDPOINT_MAX 16
|
||||
#define TUP_MCU_MULTIPLE_CORE 1
|
||||
|
||||
#define TU_ATTR_FAST_FUNC __attribute__((section(".time_critical.tinyusb")))
|
||||
|
||||
|
@@ -340,15 +340,16 @@ TU_ATTR_ALWAYS_INLINE static inline usbd_class_driver_t const * get_driver(uint8
|
||||
enum { RHPORT_INVALID = 0xFFu };
|
||||
tu_static uint8_t _usbd_rhport = RHPORT_INVALID;
|
||||
|
||||
// Event queue
|
||||
// usbd_int_set() is used as mutex in OS NONE config
|
||||
static OSAL_SPINLOCK_DEF(_usbd_spin, usbd_int_set);
|
||||
|
||||
// Event queue: usbd_int_set() is used as mutex in OS NONE config
|
||||
OSAL_QUEUE_DEF(usbd_int_set, _usbd_qdef, CFG_TUD_TASK_QUEUE_SZ, dcd_event_t);
|
||||
tu_static osal_queue_t _usbd_q;
|
||||
static osal_queue_t _usbd_q;
|
||||
|
||||
// Mutex for claiming endpoint
|
||||
#if OSAL_MUTEX_REQUIRED
|
||||
tu_static osal_mutex_def_t _ubsd_mutexdef;
|
||||
tu_static osal_mutex_t _usbd_mutex;
|
||||
static osal_mutex_def_t _ubsd_mutexdef;
|
||||
static osal_mutex_t _usbd_mutex;
|
||||
#else
|
||||
#define _usbd_mutex NULL
|
||||
#endif
|
||||
@@ -466,7 +467,7 @@ bool tud_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
|
||||
TU_ASSERT(rh_init);
|
||||
|
||||
TU_LOG_USBD("USBD init on controller %u, speed = %s\r\n", rhport,
|
||||
rh_init->speed == TUSB_SPEED_HIGH ? "High" : "Full");
|
||||
rh_init->speed == TUSB_SPEED_HIGH ? "High" : "Full");
|
||||
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(usbd_device_t));
|
||||
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(dcd_event_t));
|
||||
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_fifo_t));
|
||||
@@ -475,6 +476,8 @@ bool tud_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
|
||||
tu_varclr(&_usbd_dev);
|
||||
_usbd_queued_setup = 0;
|
||||
|
||||
osal_spin_init(&_usbd_spin);
|
||||
|
||||
#if OSAL_MUTEX_REQUIRED
|
||||
// Init device mutex
|
||||
_usbd_mutex = osal_mutex_create(&_ubsd_mutexdef);
|
||||
@@ -1242,17 +1245,21 @@ TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const* event, bool in_isr)
|
||||
// USBD API For Class Driver
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void usbd_int_set(bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
void usbd_int_set(bool enabled) {
|
||||
if (enabled) {
|
||||
dcd_int_enable(_usbd_rhport);
|
||||
}else
|
||||
{
|
||||
} else {
|
||||
dcd_int_disable(_usbd_rhport);
|
||||
}
|
||||
}
|
||||
|
||||
void usbd_spin_lock(bool in_isr) {
|
||||
osal_spin_lock(&_usbd_spin, in_isr);
|
||||
}
|
||||
void usbd_spin_unlock(bool in_isr) {
|
||||
osal_spin_unlock(&_usbd_spin, in_isr);
|
||||
}
|
||||
|
||||
// Parse consecutive endpoint descriptors (IN & OUT)
|
||||
bool usbd_open_edpt_pair(uint8_t rhport, uint8_t const* p_desc, uint8_t ep_count, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in)
|
||||
{
|
||||
|
@@ -68,6 +68,8 @@ usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count) TU_ATTR
|
||||
typedef bool (*usbd_control_xfer_cb_t)(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
|
||||
|
||||
void usbd_int_set(bool enabled);
|
||||
void usbd_spin_lock(bool in_isr);
|
||||
void usbd_spin_unlock(bool in_isr);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBD Endpoint API
|
||||
|
@@ -75,6 +75,10 @@ typedef void (*osal_task_func_t)( void * );
|
||||
// OSAL Porting API
|
||||
// Should be implemented as static inline function in osal_port.h header
|
||||
/*
|
||||
void osal_spin_init(osal_spinlock_t *ctx);
|
||||
void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr)
|
||||
void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr);
|
||||
|
||||
osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef);
|
||||
bool osal_semaphore_delete(osal_semaphore_t semd_hdl);
|
||||
bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr);
|
||||
|
@@ -42,20 +42,20 @@ extern "C" {
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
#if configSUPPORT_STATIC_ALLOCATION
|
||||
typedef StaticSemaphore_t osal_semaphore_def_t;
|
||||
typedef StaticSemaphore_t osal_mutex_def_t;
|
||||
typedef StaticSemaphore_t osal_semaphore_def_t;
|
||||
typedef StaticSemaphore_t osal_mutex_def_t;
|
||||
#else
|
||||
// not used therefore defined to smallest possible type to save space
|
||||
typedef uint8_t osal_semaphore_def_t;
|
||||
typedef uint8_t osal_mutex_def_t;
|
||||
|
||||
// not used therefore defined to the smallest possible type to save space
|
||||
typedef uint8_t osal_semaphore_def_t;
|
||||
typedef uint8_t osal_mutex_def_t;
|
||||
#endif
|
||||
|
||||
typedef SemaphoreHandle_t osal_semaphore_t;
|
||||
typedef SemaphoreHandle_t osal_mutex_t;
|
||||
typedef QueueHandle_t osal_queue_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
uint16_t depth;
|
||||
uint16_t item_sz;
|
||||
void* buf;
|
||||
@@ -83,16 +83,14 @@ typedef struct
|
||||
//--------------------------------------------------------------------+
|
||||
// TASK API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t _osal_ms2tick(uint32_t msec) {
|
||||
if ( msec == OSAL_TIMEOUT_WAIT_FOREVER ) return portMAX_DELAY;
|
||||
if ( msec == 0 ) return 0;
|
||||
if (msec == OSAL_TIMEOUT_WAIT_FOREVER) { return portMAX_DELAY; }
|
||||
if (msec == 0) { return 0; }
|
||||
|
||||
uint32_t ticks = pdMS_TO_TICKS(msec);
|
||||
|
||||
// configTICK_RATE_HZ is less than 1000 and 1 tick > 1 ms
|
||||
// we still need to delay at least 1 tick
|
||||
if ( ticks == 0 ) ticks = 1;
|
||||
// If configTICK_RATE_HZ is less than 1000 and 1 tick > 1 ms, we still need to delay at least 1 tick
|
||||
if (ticks == 0) { ticks = 1; }
|
||||
|
||||
return ticks;
|
||||
}
|
||||
@@ -101,10 +99,71 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
|
||||
vTaskDelay(pdMS_TO_TICKS(msec));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Spinlock API
|
||||
//--------------------------------------------------------------------+
|
||||
#define OSAL_SPINLOCK_DEF(_name, _int_set) \
|
||||
osal_spinlock_t _name
|
||||
|
||||
#if TUSB_MCU_VENDOR_ESPRESSIF
|
||||
// Espressif critical take spinlock as argument and does not use in_isr
|
||||
typedef portMUX_TYPE osal_spinlock_t;
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) {
|
||||
spinlock_initialize(ctx);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
|
||||
if (!TUP_MCU_MULTIPLE_CORE && in_isr) {
|
||||
return; // single core MCU does not need to lock in ISR
|
||||
}
|
||||
portENTER_CRITICAL(ctx);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
|
||||
if (!TUP_MCU_MULTIPLE_CORE && in_isr) {
|
||||
return; // single core MCU does not need to lock in ISR
|
||||
}
|
||||
portEXIT_CRITICAL(ctx);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
typedef UBaseType_t osal_spinlock_t;
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) {
|
||||
(void) ctx;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
|
||||
if (in_isr) {
|
||||
if (!TUP_MCU_MULTIPLE_CORE) {
|
||||
(void) ctx;
|
||||
return; // single core MCU does not need to lock in ISR
|
||||
}
|
||||
*ctx = taskENTER_CRITICAL_FROM_ISR();
|
||||
} else {
|
||||
taskENTER_CRITICAL();
|
||||
}
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
|
||||
if (in_isr) {
|
||||
if (!TUP_MCU_MULTIPLE_CORE) {
|
||||
(void) ctx;
|
||||
return; // single core MCU does not need to lock in ISR
|
||||
}
|
||||
taskEXIT_CRITICAL_FROM_ISR(*ctx);
|
||||
} else {
|
||||
taskEXIT_CRITICAL();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Semaphore API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t *semdef) {
|
||||
#if configSUPPORT_STATIC_ALLOCATION
|
||||
return xSemaphoreCreateBinaryStatic(semdef);
|
||||
@@ -120,19 +179,12 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_delete(osal_semaphore_t
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) {
|
||||
if ( !in_isr ) {
|
||||
if (!in_isr) {
|
||||
return xSemaphoreGive(sem_hdl) != 0;
|
||||
} else {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
BaseType_t res = xSemaphoreGiveFromISR(sem_hdl, &xHigherPriorityTaskWoken);
|
||||
|
||||
#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3
|
||||
// not needed after https://github.com/espressif/esp-idf/commit/c5fd79547ac9b7bae06fa660e9f814d18d3390b7
|
||||
if ( xHigherPriorityTaskWoken ) portYIELD_FROM_ISR();
|
||||
#else
|
||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||
#endif
|
||||
|
||||
return res != 0;
|
||||
}
|
||||
}
|
||||
@@ -148,7 +200,6 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t c
|
||||
//--------------------------------------------------------------------+
|
||||
// MUTEX API (priority inheritance)
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t *mdef) {
|
||||
#if configSUPPORT_STATIC_ALLOCATION
|
||||
return xSemaphoreCreateMutexStatic(mdef);
|
||||
@@ -174,7 +225,6 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd
|
||||
//--------------------------------------------------------------------+
|
||||
// QUEUE API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) {
|
||||
osal_queue_t q;
|
||||
|
||||
@@ -201,19 +251,12 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, v
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const *data, bool in_isr) {
|
||||
if ( !in_isr ) {
|
||||
if (!in_isr) {
|
||||
return xQueueSendToBack(qhdl, data, OSAL_TIMEOUT_WAIT_FOREVER) != 0;
|
||||
} else {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
BaseType_t res = xQueueSendToBackFromISR(qhdl, data, &xHigherPriorityTaskWoken);
|
||||
|
||||
#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3
|
||||
// not needed after https://github.com/espressif/esp-idf/commit/c5fd79547ac9b7bae06fa660e9f814d18d3390b7 (IDF v5)
|
||||
if ( xHigherPriorityTaskWoken ) portYIELD_FROM_ISR();
|
||||
#else
|
||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||
#endif
|
||||
|
||||
return res != 0;
|
||||
}
|
||||
}
|
||||
|
@@ -40,6 +40,32 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
|
||||
os_time_delay( os_time_ms_to_ticks32(msec) );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Spinlock API
|
||||
//--------------------------------------------------------------------+
|
||||
typedef os_sr_t osal_spinlock_t;
|
||||
|
||||
#define OSAL_SPINLOCK_DEF(_name, _int_set) \
|
||||
osal_spinlock_t _name
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) {
|
||||
(void) ctx;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
|
||||
if (!TUP_MCU_MULTIPLE_CORE && in_isr) {
|
||||
return; // single core MCU does not need to lock in ISR
|
||||
}
|
||||
OS_ENTER_CRITICAL(*ctx);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
|
||||
if (!TUP_MCU_MULTIPLE_CORE && in_isr) {
|
||||
return; // single core MCU does not need to lock in ISR
|
||||
}
|
||||
OS_ENTER_CRITICAL(*ctx);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Semaphore API
|
||||
//--------------------------------------------------------------------+
|
||||
|
@@ -40,6 +40,33 @@ extern "C" {
|
||||
TU_ATTR_WEAK void osal_task_delay(uint32_t msec);
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Spinlock API
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct {
|
||||
void (* interrupt_set)(bool);
|
||||
} osal_spinlock_t;
|
||||
|
||||
// For SMP, spinlock must be locked by hardware, cannot just use interrupt
|
||||
#define OSAL_SPINLOCK_DEF(_name, _int_set) \
|
||||
osal_spinlock_t _name = { .interrupt_set = _int_set }
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) {
|
||||
(void) ctx;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
|
||||
if (!in_isr) {
|
||||
ctx->interrupt_set(false);
|
||||
}
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
|
||||
if (!in_isr) {
|
||||
ctx->interrupt_set(true);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Binary Semaphore API
|
||||
//--------------------------------------------------------------------+
|
||||
|
@@ -43,6 +43,27 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
|
||||
sleep_ms(msec);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Spinlock API
|
||||
//--------------------------------------------------------------------+
|
||||
typedef critical_section_t osal_spinlock_t; // pico implement critical section with spinlock
|
||||
#define OSAL_SPINLOCK_DEF(_name, _int_set) \
|
||||
osal_spinlock_t _name
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) {
|
||||
critical_section_init(ctx);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
|
||||
(void) in_isr;
|
||||
critical_section_enter_blocking(ctx);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
|
||||
(void) in_isr;
|
||||
critical_section_exit(ctx);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Binary Semaphore API
|
||||
//--------------------------------------------------------------------+
|
||||
|
@@ -42,6 +42,32 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
|
||||
rt_thread_mdelay(msec);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Spinlock API
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct rt_spinlock osal_spinlock_t;
|
||||
|
||||
#define OSAL_SPINLOCK_DEF(_name, _int_set) \
|
||||
osal_spinlock_t _name
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) {
|
||||
rt_spin_lock_init(ctx);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
|
||||
if (!TUP_MCU_MULTIPLE_CORE && in_isr) {
|
||||
return; // single core MCU does not need to lock in ISR
|
||||
}
|
||||
rt_spin_lock(ctx);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
|
||||
if (!TUP_MCU_MULTIPLE_CORE && in_isr) {
|
||||
return; // single core MCU does not need to lock in ISR
|
||||
}
|
||||
rt_spin_unlock(ctx);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Semaphore API
|
||||
//--------------------------------------------------------------------+
|
||||
|
@@ -56,6 +56,25 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t msec2wait(uint32_t msec) {
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Spinlock API, stub not implemented
|
||||
//--------------------------------------------------------------------+
|
||||
typedef uint8_t osal_spinlock_t;
|
||||
#define OSAL_SPINLOCK_DEF(_name, _int_set) \
|
||||
osal_spinlock_t _name
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) {
|
||||
(void) ctx;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
|
||||
(void) ctx; (void) in_isr;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
|
||||
(void) ctx; (void) in_isr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Semaphore API
|
||||
//--------------------------------------------------------------------+
|
||||
|
@@ -35,6 +35,35 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
|
||||
k_msleep(msec);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Spinlock API
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct {
|
||||
struct k_spinlock lock;
|
||||
k_spinlock_key_t key;
|
||||
} osal_spinlock_t;
|
||||
|
||||
#define OSAL_SPINLOCK_DEF(_name, _int_set) \
|
||||
osal_spinlock_t _name
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) {
|
||||
(void) ctx;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
|
||||
if (!TUP_MCU_MULTIPLE_CORE && in_isr) {
|
||||
return; // single core MCU does not need to lock in ISR
|
||||
}
|
||||
ctx->key = k_spin_lock(&ctx->lock);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
|
||||
if (!TUP_MCU_MULTIPLE_CORE && in_isr) {
|
||||
return; // single core MCU does not need to lock in ISR
|
||||
}
|
||||
k_spin_unlock(&ctx->lock, ctx->key);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Binary Semaphore API
|
||||
//--------------------------------------------------------------------+
|
||||
|
@@ -39,6 +39,7 @@
|
||||
#define DWC2_DEBUG 2
|
||||
|
||||
#include "device/dcd.h"
|
||||
#include "device/usbd_pvt.h"
|
||||
#include "dwc2_common.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
@@ -52,6 +53,7 @@ typedef struct {
|
||||
uint8_t interval;
|
||||
} xfer_ctl_t;
|
||||
|
||||
// This variable is modified from ISR context, so it must be protected by critical section
|
||||
static xfer_ctl_t xfer_status[DWC2_EP_MAX][2];
|
||||
#define XFER_CTL_BASE(_ep, _dir) (&xfer_status[_ep][_dir])
|
||||
|
||||
@@ -321,6 +323,9 @@ static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) {
|
||||
}
|
||||
}
|
||||
|
||||
// Since this function returns void, it is not possible to return a boolean success message
|
||||
// We must make sure that this function is not called when the EP is disabled
|
||||
// Must be called from critical section
|
||||
static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uint8_t dir) {
|
||||
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
|
||||
xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, dir);
|
||||
@@ -531,6 +536,8 @@ void dcd_edpt_close_all(uint8_t rhport) {
|
||||
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
|
||||
uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
|
||||
|
||||
usbd_spin_lock(false);
|
||||
|
||||
_dcd_data.allocated_epin_count = 0;
|
||||
|
||||
// Disable non-control interrupt
|
||||
@@ -548,8 +555,9 @@ void dcd_edpt_close_all(uint8_t rhport) {
|
||||
|
||||
dfifo_flush_tx(dwc2, 0x10); // all tx fifo
|
||||
dfifo_flush_rx(dwc2);
|
||||
|
||||
dfifo_device_init(rhport); // re-init dfifo
|
||||
|
||||
usbd_spin_unlock(false);
|
||||
}
|
||||
|
||||
bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) {
|
||||
@@ -567,21 +575,31 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpo
|
||||
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir);
|
||||
xfer->buffer = buffer;
|
||||
xfer->ff = NULL;
|
||||
xfer->total_len = total_bytes;
|
||||
bool ret;
|
||||
|
||||
// EP0 can only handle one packet
|
||||
if (epnum == 0) {
|
||||
_dcd_data.ep0_pending[dir] = total_bytes;
|
||||
usbd_spin_lock(false);
|
||||
|
||||
if (xfer->max_size == 0) {
|
||||
ret = false; // Endpoint is closed
|
||||
} else {
|
||||
xfer->buffer = buffer;
|
||||
xfer->ff = NULL;
|
||||
xfer->total_len = total_bytes;
|
||||
|
||||
// EP0 can only handle one packet
|
||||
if (epnum == 0) {
|
||||
_dcd_data.ep0_pending[dir] = total_bytes;
|
||||
}
|
||||
|
||||
// Schedule packets to be sent within interrupt
|
||||
edpt_schedule_packets(rhport, epnum, dir);
|
||||
ret = true;
|
||||
}
|
||||
|
||||
// Schedule packets to be sent within interrupt
|
||||
edpt_schedule_packets(rhport, epnum, dir);
|
||||
usbd_spin_unlock(false);
|
||||
|
||||
return true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// The number of bytes has to be given explicitly to allow more flexible control of how many
|
||||
@@ -594,17 +612,27 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t
|
||||
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir);
|
||||
xfer->buffer = NULL;
|
||||
xfer->ff = ff;
|
||||
xfer->total_len = total_bytes;
|
||||
bool ret;
|
||||
|
||||
// Schedule packets to be sent within interrupt
|
||||
// TODO xfer fifo may only available for slave mode
|
||||
edpt_schedule_packets(rhport, epnum, dir);
|
||||
usbd_spin_lock(false);
|
||||
|
||||
return true;
|
||||
if (xfer->max_size == 0) {
|
||||
ret = false; // Endpoint is closed
|
||||
} else {
|
||||
xfer->buffer = NULL;
|
||||
xfer->ff = ff;
|
||||
xfer->total_len = total_bytes;
|
||||
|
||||
// Schedule packets to be sent within interrupt
|
||||
// TODO xfer fifo may only available for slave mode
|
||||
edpt_schedule_packets(rhport, epnum, dir);
|
||||
ret = true;
|
||||
}
|
||||
|
||||
usbd_spin_unlock(false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
|
||||
@@ -631,6 +659,7 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// 7.4.1 Initialization on USB Reset
|
||||
// Must be called from critical section
|
||||
static void handle_bus_reset(uint8_t rhport) {
|
||||
dwc2_regs_t *dwc2 = DWC2_REG(rhport);
|
||||
const uint8_t ep_count = dwc2_ep_count(dwc2);
|
||||
@@ -983,14 +1012,16 @@ static void handle_ep_irq(uint8_t rhport, uint8_t dir) {
|
||||
*/
|
||||
void dcd_int_handler(uint8_t rhport) {
|
||||
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
|
||||
|
||||
const uint32_t gintmask = dwc2->gintmsk;
|
||||
const uint32_t gintsts = dwc2->gintsts & gintmask;
|
||||
|
||||
if (gintsts & GINTSTS_USBRST) {
|
||||
// USBRST is start of reset.
|
||||
dwc2->gintsts = GINTSTS_USBRST;
|
||||
|
||||
usbd_spin_lock(true);
|
||||
handle_bus_reset(rhport);
|
||||
usbd_spin_unlock(true);
|
||||
}
|
||||
|
||||
if (gintsts & GINTSTS_ENUMDNE) {
|
||||
|
@@ -55,8 +55,8 @@ static const dwc2_controller_t _dwc2_controller[] = {
|
||||
// On ESP32 for consistency we associate
|
||||
// - Port0 to OTG_FS, and Port1 to OTG_HS
|
||||
static const dwc2_controller_t _dwc2_controller[] = {
|
||||
{ .reg_base = DWC2_FS_REG_BASE, .irqnum = ETS_USB_OTG11_CH0_INTR_SOURCE, .ep_count = 7, .ep_in_count = 5, .ep_fifo_size = 1024 },
|
||||
{ .reg_base = DWC2_HS_REG_BASE, .irqnum = ETS_USB_OTG_INTR_SOURCE, .ep_count = 16, .ep_in_count = 8, .ep_fifo_size = 4096 }
|
||||
{ .reg_base = DWC2_FS_REG_BASE, .irqnum = ETS_USB_OTG11_CH0_INTR_SOURCE, .ep_count = 7, .ep_in_count = 5, .ep_fifo_size = 1024 },
|
||||
{ .reg_base = DWC2_HS_REG_BASE, .irqnum = ETS_USB_OTG_INTR_SOURCE, .ep_count = 16, .ep_in_count = 8, .ep_fifo_size = 4096 }
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@@ -23,6 +23,7 @@ build_separator = '-' * 95
|
||||
build_status = [STATUS_OK, STATUS_FAILED, STATUS_SKIPPED]
|
||||
|
||||
verbose = False
|
||||
parallel_jobs = os.cpu_count()
|
||||
|
||||
# -----------------------------
|
||||
# Helper
|
||||
@@ -110,13 +111,17 @@ def cmake_board(board, toolchain, build_flags_on):
|
||||
f'-DTOOLCHAIN={toolchain} {build_flags}')
|
||||
if rcmd.returncode == 0:
|
||||
cmd = f"cmake --build {build_dir}"
|
||||
# circleci docker return $nproc as 36 core, limit parallel according to resource class. Required for IAR, also prevent crashed/killed by docker
|
||||
njobs = parallel_jobs
|
||||
|
||||
# circleci docker return $nproc as 36 core, limit parallel according to resource class.
|
||||
# Required for IAR, also prevent crashed/killed by docker
|
||||
if os.getenv('CIRCLECI'):
|
||||
resource_class = { 'small': 1, 'medium': 2, 'medium+': 3, 'large': 4 }
|
||||
for rc in resource_class:
|
||||
if rc in os.getenv('CIRCLE_JOB'):
|
||||
cmd += f' --parallel {resource_class[rc]}'
|
||||
njobs = resource_class[rc]
|
||||
break
|
||||
cmd += f' --parallel {njobs}'
|
||||
rcmd = run_cmd(cmd)
|
||||
ret[0 if rcmd.returncode == 0 else 1] += 1
|
||||
|
||||
@@ -211,6 +216,7 @@ def build_family(family, toolchain, build_system, build_flags_on, one_per_family
|
||||
# -----------------------------
|
||||
def main():
|
||||
global verbose
|
||||
global parallel_jobs
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('families', nargs='*', default=[], help='Families to build')
|
||||
@@ -219,6 +225,7 @@ def main():
|
||||
parser.add_argument('-s', '--build-system', default='cmake', help='Build system to use, default is cmake')
|
||||
parser.add_argument('-f1', '--build-flags-on', action='append', default=[], help='Build flag to pass to build system')
|
||||
parser.add_argument('-1', '--one-per-family', action='store_true', default=False, help='Build only one random board inside a family')
|
||||
parser.add_argument('-j', '--jobs', type=int, default=os.cpu_count(), help='Number of jobs to run in parallel')
|
||||
parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
|
||||
args = parser.parse_args()
|
||||
|
||||
@@ -229,6 +236,7 @@ def main():
|
||||
build_flags_on = args.build_flags_on
|
||||
one_per_family = args.one_per_family
|
||||
verbose = args.verbose
|
||||
parallel_jobs = args.jobs
|
||||
|
||||
if len(families) == 0 and len(boards) == 0:
|
||||
print("Please specify families or board to build")
|
||||
|
Reference in New Issue
Block a user