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
|
run: python3 tools/get_deps.py $BUILD_ARGS
|
||||||
|
|
||||||
- name: Build
|
- 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)
|
- name: Test on actual hardware (hardware in the loop)
|
||||||
run: python3 test/hil/hil_test.py hfp.json
|
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 TUP_DCD_ENDPOINT_MAX 7 // only 5 TX FIFO for endpoint IN
|
||||||
#define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/
|
#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
|
// Disable slave if DMA is enabled
|
||||||
#define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE
|
#define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE
|
||||||
#define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_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 CFG_TUSB_OS_INC_PATH_DEFAULT freertos/
|
||||||
|
|
||||||
|
#define TUP_MCU_MULTIPLE_CORE 1
|
||||||
|
|
||||||
// Disable slave if DMA is enabled
|
// Disable slave if DMA is enabled
|
||||||
#define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE
|
#define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE
|
||||||
#define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_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)
|
#elif TU_CHECK_MCU(OPT_MCU_RP2040)
|
||||||
#define TUP_DCD_EDPT_ISO_ALLOC
|
#define TUP_DCD_EDPT_ISO_ALLOC
|
||||||
#define TUP_DCD_ENDPOINT_MAX 16
|
#define TUP_DCD_ENDPOINT_MAX 16
|
||||||
|
#define TUP_MCU_MULTIPLE_CORE 1
|
||||||
|
|
||||||
#define TU_ATTR_FAST_FUNC __attribute__((section(".time_critical.tinyusb")))
|
#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 };
|
enum { RHPORT_INVALID = 0xFFu };
|
||||||
tu_static uint8_t _usbd_rhport = RHPORT_INVALID;
|
tu_static uint8_t _usbd_rhport = RHPORT_INVALID;
|
||||||
|
|
||||||
// Event queue
|
static OSAL_SPINLOCK_DEF(_usbd_spin, usbd_int_set);
|
||||||
// usbd_int_set() is used as mutex in OS NONE config
|
|
||||||
|
// 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);
|
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
|
// Mutex for claiming endpoint
|
||||||
#if OSAL_MUTEX_REQUIRED
|
#if OSAL_MUTEX_REQUIRED
|
||||||
tu_static osal_mutex_def_t _ubsd_mutexdef;
|
static osal_mutex_def_t _ubsd_mutexdef;
|
||||||
tu_static osal_mutex_t _usbd_mutex;
|
static osal_mutex_t _usbd_mutex;
|
||||||
#else
|
#else
|
||||||
#define _usbd_mutex NULL
|
#define _usbd_mutex NULL
|
||||||
#endif
|
#endif
|
||||||
@@ -466,7 +467,7 @@ bool tud_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
|
|||||||
TU_ASSERT(rh_init);
|
TU_ASSERT(rh_init);
|
||||||
|
|
||||||
TU_LOG_USBD("USBD init on controller %u, speed = %s\r\n", rhport,
|
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(usbd_device_t));
|
||||||
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(dcd_event_t));
|
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(dcd_event_t));
|
||||||
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_fifo_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);
|
tu_varclr(&_usbd_dev);
|
||||||
_usbd_queued_setup = 0;
|
_usbd_queued_setup = 0;
|
||||||
|
|
||||||
|
osal_spin_init(&_usbd_spin);
|
||||||
|
|
||||||
#if OSAL_MUTEX_REQUIRED
|
#if OSAL_MUTEX_REQUIRED
|
||||||
// Init device mutex
|
// Init device mutex
|
||||||
_usbd_mutex = osal_mutex_create(&_ubsd_mutexdef);
|
_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
|
// USBD API For Class Driver
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
void usbd_int_set(bool enabled)
|
void usbd_int_set(bool enabled) {
|
||||||
{
|
if (enabled) {
|
||||||
if (enabled)
|
|
||||||
{
|
|
||||||
dcd_int_enable(_usbd_rhport);
|
dcd_int_enable(_usbd_rhport);
|
||||||
}else
|
} else {
|
||||||
{
|
|
||||||
dcd_int_disable(_usbd_rhport);
|
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)
|
// 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)
|
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);
|
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_int_set(bool enabled);
|
||||||
|
void usbd_spin_lock(bool in_isr);
|
||||||
|
void usbd_spin_unlock(bool in_isr);
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// USBD Endpoint API
|
// USBD Endpoint API
|
||||||
|
@@ -75,6 +75,10 @@ typedef void (*osal_task_func_t)( void * );
|
|||||||
// OSAL Porting API
|
// OSAL Porting API
|
||||||
// Should be implemented as static inline function in osal_port.h header
|
// 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);
|
osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef);
|
||||||
bool osal_semaphore_delete(osal_semaphore_t semd_hdl);
|
bool osal_semaphore_delete(osal_semaphore_t semd_hdl);
|
||||||
bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr);
|
bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr);
|
||||||
|
@@ -42,20 +42,20 @@ extern "C" {
|
|||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
#if configSUPPORT_STATIC_ALLOCATION
|
#if configSUPPORT_STATIC_ALLOCATION
|
||||||
typedef StaticSemaphore_t osal_semaphore_def_t;
|
typedef StaticSemaphore_t osal_semaphore_def_t;
|
||||||
typedef StaticSemaphore_t osal_mutex_def_t;
|
typedef StaticSemaphore_t osal_mutex_def_t;
|
||||||
#else
|
#else
|
||||||
// not used therefore defined to smallest possible type to save space
|
|
||||||
typedef uint8_t osal_semaphore_def_t;
|
// not used therefore defined to the smallest possible type to save space
|
||||||
typedef uint8_t osal_mutex_def_t;
|
typedef uint8_t osal_semaphore_def_t;
|
||||||
|
typedef uint8_t osal_mutex_def_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef SemaphoreHandle_t osal_semaphore_t;
|
typedef SemaphoreHandle_t osal_semaphore_t;
|
||||||
typedef SemaphoreHandle_t osal_mutex_t;
|
typedef SemaphoreHandle_t osal_mutex_t;
|
||||||
typedef QueueHandle_t osal_queue_t;
|
typedef QueueHandle_t osal_queue_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
|
||||||
uint16_t depth;
|
uint16_t depth;
|
||||||
uint16_t item_sz;
|
uint16_t item_sz;
|
||||||
void* buf;
|
void* buf;
|
||||||
@@ -83,16 +83,14 @@ typedef struct
|
|||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// TASK API
|
// TASK API
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t _osal_ms2tick(uint32_t msec) {
|
TU_ATTR_ALWAYS_INLINE static inline uint32_t _osal_ms2tick(uint32_t msec) {
|
||||||
if ( msec == OSAL_TIMEOUT_WAIT_FOREVER ) return portMAX_DELAY;
|
if (msec == OSAL_TIMEOUT_WAIT_FOREVER) { return portMAX_DELAY; }
|
||||||
if ( msec == 0 ) return 0;
|
if (msec == 0) { return 0; }
|
||||||
|
|
||||||
uint32_t ticks = pdMS_TO_TICKS(msec);
|
uint32_t ticks = pdMS_TO_TICKS(msec);
|
||||||
|
|
||||||
// configTICK_RATE_HZ is less than 1000 and 1 tick > 1 ms
|
// If configTICK_RATE_HZ is less than 1000 and 1 tick > 1 ms, we still need to delay at least 1 tick
|
||||||
// we still need to delay at least 1 tick
|
if (ticks == 0) { ticks = 1; }
|
||||||
if ( ticks == 0 ) ticks = 1;
|
|
||||||
|
|
||||||
return ticks;
|
return ticks;
|
||||||
}
|
}
|
||||||
@@ -101,10 +99,71 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
|
|||||||
vTaskDelay(pdMS_TO_TICKS(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
|
// Semaphore API
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t *semdef) {
|
TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t *semdef) {
|
||||||
#if configSUPPORT_STATIC_ALLOCATION
|
#if configSUPPORT_STATIC_ALLOCATION
|
||||||
return xSemaphoreCreateBinaryStatic(semdef);
|
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) {
|
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;
|
return xSemaphoreGive(sem_hdl) != 0;
|
||||||
} else {
|
} else {
|
||||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
BaseType_t res = xSemaphoreGiveFromISR(sem_hdl, &xHigherPriorityTaskWoken);
|
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);
|
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||||
#endif
|
|
||||||
|
|
||||||
return res != 0;
|
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)
|
// MUTEX API (priority inheritance)
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t *mdef) {
|
TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t *mdef) {
|
||||||
#if configSUPPORT_STATIC_ALLOCATION
|
#if configSUPPORT_STATIC_ALLOCATION
|
||||||
return xSemaphoreCreateMutexStatic(mdef);
|
return xSemaphoreCreateMutexStatic(mdef);
|
||||||
@@ -174,7 +225,6 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd
|
|||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// QUEUE API
|
// QUEUE API
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) {
|
TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) {
|
||||||
osal_queue_t q;
|
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) {
|
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;
|
return xQueueSendToBack(qhdl, data, OSAL_TIMEOUT_WAIT_FOREVER) != 0;
|
||||||
} else {
|
} else {
|
||||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
BaseType_t res = xQueueSendToBackFromISR(qhdl, data, &xHigherPriorityTaskWoken);
|
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);
|
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||||
#endif
|
|
||||||
|
|
||||||
return res != 0;
|
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) );
|
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
|
// Semaphore API
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
@@ -40,6 +40,33 @@ extern "C" {
|
|||||||
TU_ATTR_WEAK void osal_task_delay(uint32_t msec);
|
TU_ATTR_WEAK void osal_task_delay(uint32_t msec);
|
||||||
#endif
|
#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
|
// Binary Semaphore API
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
@@ -43,6 +43,27 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
|
|||||||
sleep_ms(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
|
// Binary Semaphore API
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
@@ -42,6 +42,32 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
|
|||||||
rt_thread_mdelay(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
|
// 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
|
// Semaphore API
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
@@ -35,6 +35,35 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
|
|||||||
k_msleep(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
|
// Binary Semaphore API
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
@@ -39,6 +39,7 @@
|
|||||||
#define DWC2_DEBUG 2
|
#define DWC2_DEBUG 2
|
||||||
|
|
||||||
#include "device/dcd.h"
|
#include "device/dcd.h"
|
||||||
|
#include "device/usbd_pvt.h"
|
||||||
#include "dwc2_common.h"
|
#include "dwc2_common.h"
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
@@ -52,6 +53,7 @@ typedef struct {
|
|||||||
uint8_t interval;
|
uint8_t interval;
|
||||||
} xfer_ctl_t;
|
} 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];
|
static xfer_ctl_t xfer_status[DWC2_EP_MAX][2];
|
||||||
#define XFER_CTL_BASE(_ep, _dir) (&xfer_status[_ep][_dir])
|
#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) {
|
static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uint8_t dir) {
|
||||||
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
|
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
|
||||||
xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, dir);
|
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);
|
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
|
||||||
uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
|
uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
|
||||||
|
|
||||||
|
usbd_spin_lock(false);
|
||||||
|
|
||||||
_dcd_data.allocated_epin_count = 0;
|
_dcd_data.allocated_epin_count = 0;
|
||||||
|
|
||||||
// Disable non-control interrupt
|
// 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_tx(dwc2, 0x10); // all tx fifo
|
||||||
dfifo_flush_rx(dwc2);
|
dfifo_flush_rx(dwc2);
|
||||||
|
|
||||||
dfifo_device_init(rhport); // re-init dfifo
|
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) {
|
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) {
|
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 epnum = tu_edpt_number(ep_addr);
|
||||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||||
|
|
||||||
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir);
|
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir);
|
||||||
xfer->buffer = buffer;
|
bool ret;
|
||||||
xfer->ff = NULL;
|
|
||||||
xfer->total_len = total_bytes;
|
|
||||||
|
|
||||||
// EP0 can only handle one packet
|
usbd_spin_lock(false);
|
||||||
if (epnum == 0) {
|
|
||||||
_dcd_data.ep0_pending[dir] = total_bytes;
|
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
|
usbd_spin_unlock(false);
|
||||||
edpt_schedule_packets(rhport, epnum, dir);
|
|
||||||
|
|
||||||
return true;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The number of bytes has to be given explicitly to allow more flexible control of how many
|
// 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 epnum = tu_edpt_number(ep_addr);
|
||||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||||
|
|
||||||
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir);
|
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir);
|
||||||
xfer->buffer = NULL;
|
bool ret;
|
||||||
xfer->ff = ff;
|
|
||||||
xfer->total_len = total_bytes;
|
|
||||||
|
|
||||||
// Schedule packets to be sent within interrupt
|
usbd_spin_lock(false);
|
||||||
// TODO xfer fifo may only available for slave mode
|
|
||||||
edpt_schedule_packets(rhport, epnum, dir);
|
|
||||||
|
|
||||||
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) {
|
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
|
// 7.4.1 Initialization on USB Reset
|
||||||
|
// Must be called from critical section
|
||||||
static void handle_bus_reset(uint8_t rhport) {
|
static void handle_bus_reset(uint8_t rhport) {
|
||||||
dwc2_regs_t *dwc2 = DWC2_REG(rhport);
|
dwc2_regs_t *dwc2 = DWC2_REG(rhport);
|
||||||
const uint8_t ep_count = dwc2_ep_count(dwc2);
|
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) {
|
void dcd_int_handler(uint8_t rhport) {
|
||||||
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
|
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
|
||||||
|
|
||||||
const uint32_t gintmask = dwc2->gintmsk;
|
const uint32_t gintmask = dwc2->gintmsk;
|
||||||
const uint32_t gintsts = dwc2->gintsts & gintmask;
|
const uint32_t gintsts = dwc2->gintsts & gintmask;
|
||||||
|
|
||||||
if (gintsts & GINTSTS_USBRST) {
|
if (gintsts & GINTSTS_USBRST) {
|
||||||
// USBRST is start of reset.
|
// USBRST is start of reset.
|
||||||
dwc2->gintsts = GINTSTS_USBRST;
|
dwc2->gintsts = GINTSTS_USBRST;
|
||||||
|
|
||||||
|
usbd_spin_lock(true);
|
||||||
handle_bus_reset(rhport);
|
handle_bus_reset(rhport);
|
||||||
|
usbd_spin_unlock(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gintsts & GINTSTS_ENUMDNE) {
|
if (gintsts & GINTSTS_ENUMDNE) {
|
||||||
|
@@ -55,8 +55,8 @@ static const dwc2_controller_t _dwc2_controller[] = {
|
|||||||
// On ESP32 for consistency we associate
|
// On ESP32 for consistency we associate
|
||||||
// - Port0 to OTG_FS, and Port1 to OTG_HS
|
// - Port0 to OTG_FS, and Port1 to OTG_HS
|
||||||
static const dwc2_controller_t _dwc2_controller[] = {
|
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_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_HS_REG_BASE, .irqnum = ETS_USB_OTG_INTR_SOURCE, .ep_count = 16, .ep_in_count = 8, .ep_fifo_size = 4096 }
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -23,6 +23,7 @@ build_separator = '-' * 95
|
|||||||
build_status = [STATUS_OK, STATUS_FAILED, STATUS_SKIPPED]
|
build_status = [STATUS_OK, STATUS_FAILED, STATUS_SKIPPED]
|
||||||
|
|
||||||
verbose = False
|
verbose = False
|
||||||
|
parallel_jobs = os.cpu_count()
|
||||||
|
|
||||||
# -----------------------------
|
# -----------------------------
|
||||||
# Helper
|
# Helper
|
||||||
@@ -110,13 +111,17 @@ def cmake_board(board, toolchain, build_flags_on):
|
|||||||
f'-DTOOLCHAIN={toolchain} {build_flags}')
|
f'-DTOOLCHAIN={toolchain} {build_flags}')
|
||||||
if rcmd.returncode == 0:
|
if rcmd.returncode == 0:
|
||||||
cmd = f"cmake --build {build_dir}"
|
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'):
|
if os.getenv('CIRCLECI'):
|
||||||
resource_class = { 'small': 1, 'medium': 2, 'medium+': 3, 'large': 4 }
|
resource_class = { 'small': 1, 'medium': 2, 'medium+': 3, 'large': 4 }
|
||||||
for rc in resource_class:
|
for rc in resource_class:
|
||||||
if rc in os.getenv('CIRCLE_JOB'):
|
if rc in os.getenv('CIRCLE_JOB'):
|
||||||
cmd += f' --parallel {resource_class[rc]}'
|
njobs = resource_class[rc]
|
||||||
break
|
break
|
||||||
|
cmd += f' --parallel {njobs}'
|
||||||
rcmd = run_cmd(cmd)
|
rcmd = run_cmd(cmd)
|
||||||
ret[0 if rcmd.returncode == 0 else 1] += 1
|
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():
|
def main():
|
||||||
global verbose
|
global verbose
|
||||||
|
global parallel_jobs
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('families', nargs='*', default=[], help='Families to build')
|
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('-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('-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('-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')
|
parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
@@ -229,6 +236,7 @@ def main():
|
|||||||
build_flags_on = args.build_flags_on
|
build_flags_on = args.build_flags_on
|
||||||
one_per_family = args.one_per_family
|
one_per_family = args.one_per_family
|
||||||
verbose = args.verbose
|
verbose = args.verbose
|
||||||
|
parallel_jobs = args.jobs
|
||||||
|
|
||||||
if len(families) == 0 and len(boards) == 0:
|
if len(families) == 0 and len(boards) == 0:
|
||||||
print("Please specify families or board to build")
|
print("Please specify families or board to build")
|
||||||
|
Reference in New Issue
Block a user