Merge pull request #3423 from armusin/threadx_osal

ThreadX OSAL header
This commit is contained in:
Ha Thach
2026-03-05 21:25:58 +07:00
committed by GitHub
14 changed files with 586 additions and 84 deletions

View File

@ -1,27 +1,15 @@
name: Claude Code Review
on:
pull_request:
pull_request_target:
types: [opened, synchronize, ready_for_review, reopened]
# Optional: Only run on specific file changes
# paths:
# - "src/**/*.ts"
# - "src/**/*.tsx"
# - "src/**/*.js"
# - "src/**/*.jsx"
jobs:
claude-review:
# Optional: Filter by PR author
# if: |
# github.event.pull_request.user.login == 'external-contributor' ||
# github.event.pull_request.user.login == 'new-developer' ||
# github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
pull-requests: write
issues: read
id-token: write

View File

@ -114,13 +114,65 @@ Use `-DBOARD=...` with any supported board under `hw/bsp/espressif/boards/`. NEV
- `cd examples/device/cdc_msc_freertos`
- `idf.py -DBOARD=espressif_s3_devkitc monitor`
## J-Link GDB Server + RTT Logging
## GDB Debugging
Look up the board's `JLINK_DEVICE` and `OPENOCD_OPTION` from `hw/bsp/*/boards/*/board.cmake` (or `board.mk`).
### JLinkGDBServer
**Terminal 1 start the GDB server:**
```bash
JLinkGDBServer -device stm32h743xi -if SWD -speed 4000 \
-port 2331 -swoport 2332 -telnetport 2333 -nogui
```
**Terminal 2 connect GDB:**
```bash
arm-none-eabi-gdb /tmp/build/firmware.elf
(gdb) target remote :2331
(gdb) monitor reset halt
(gdb) load
(gdb) continue
```
To break on entry instead of running immediately:
```bash
(gdb) monitor reset halt
(gdb) load
(gdb) break main
(gdb) continue
```
### OpenOCD
**Terminal 1 start the GDB server:**
```bash
openocd -f interface/stlink.cfg -f target/stm32h7x.cfg
# or with J-Link probe:
openocd -f interface/jlink.cfg -f target/stm32h7x.cfg
```
For boards that define `OPENOCD_OPTION` in `board.cmake`, use those options directly:
```bash
openocd $(cat hw/bsp/FAMILY/boards/BOARD/board.cmake | grep OPENOCD_OPTION | ...)
```
**Terminal 2 connect GDB (OpenOCD default port is 3333):**
```bash
arm-none-eabi-gdb /tmp/build/firmware.elf
(gdb) target remote :3333
(gdb) monitor reset halt
(gdb) load
(gdb) continue
```
### RTT Logging with JLinkGDBServer
- Build with RTT logging enabled (example):
`cd examples/device/cdc_msc && make BOARD=stm32h743eval LOG=2 LOGGER=rtt all`
- Flash with J-Link:
`cd examples/device/cdc_msc && make BOARD=stm32h743eval LOG=2 LOGGER=rtt flash-jlink`
- Launch GDB server (keep this running in terminal 1):
- Launch GDB server with RTT port (keep this running in terminal 1):
`JLinkGDBServer -device stm32h743xi -if SWD -speed 4000 -port 2331 -swoport 2332 -telnetport 2333 -RTTTelnetPort 19021 -nogui`
- Read RTT output (terminal 2):
`JLinkRTTClient`
@ -128,7 +180,6 @@ Use `-DBOARD=...` with any supported board under `hw/bsp/espressif/boards/`. NEV
`JLinkRTTClient | tee rtt.log`
- For non-interactive capture:
`timeout 20s JLinkRTTClient > rtt.log`
- Use the board-specific `JLINK_DEVICE` from `hw/bsp/*/boards/*/board.mk` if you are not using `stm32h743eval`.
## Unit Testing

View File

@ -15,7 +15,7 @@ Yes, TinyUSB is released under the MIT license, allowing commercial use with min
**Q: Does TinyUSB require an RTOS?**
No, TinyUSB works in bare metal environments. It also supports FreeRTOS, RT-Thread, and Mynewt.
No, TinyUSB works in bare metal environments. It also supports FreeRTOS, RT-Thread, ThreadX, and Mynewt.
**Q: How much memory does TinyUSB use?**

View File

@ -39,11 +39,35 @@ enum {
#define HELLO_STR "Hello from TinyUSB\r\n"
int main(void) {
board_init();
board_led_write(true);
// board test example does not use both device and host stack
#if CFG_TUSB_OS != OPT_OS_NONE
uint32_t tusb_time_millis_api(void) {
return osal_time_millis();
}
void tusb_time_delay_ms_api(uint32_t ms) {
osal_task_delay(ms);
}
#endif
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
// Task parameter type: ULONG for ThreadX, void* for FreeRTOS and noos
#if CFG_TUSB_OS == OPT_OS_THREADX
#define RTOS_PARAM ULONG
#elif CFG_TUSB_OS == OPT_OS_FREERTOS
#define RTOS_PARAM void*
static void freertos_init(void);
#else
#define RTOS_PARAM void*
#endif
static void board_test_loop(RTOS_PARAM param) {
(void) param;
uint32_t start_ms = 0;
(void) start_ms;
bool led_state = false;
while (1) {
@ -58,26 +82,94 @@ int main(void) {
}
// Blink and print every interval ms
if (!(tusb_time_millis_api() - start_ms < interval_ms)) {
start_ms = tusb_time_millis_api();
if (ch < 0) {
// skip if echoing
printf(HELLO_STR);
#ifndef LOGGER_UART
board_uart_write(HELLO_STR, sizeof(HELLO_STR)-1);
#endif
}
board_led_write(led_state);
led_state = !led_state; // toggle
#if CFG_TUSB_OS == OPT_OS_FREERTOS
vTaskDelay(interval_ms / portTICK_PERIOD_MS);
#elif CFG_TUSB_OS == OPT_OS_THREADX
tx_thread_sleep(_osal_ms2tick(interval_ms));
#else
if (tusb_time_millis_api() - start_ms < interval_ms) {
continue; // not enough time
}
#endif
start_ms = tusb_time_millis_api();
if (ch < 0) {
// skip if echoing
printf(HELLO_STR);
#ifndef LOGGER_UART
board_uart_write(HELLO_STR, sizeof(HELLO_STR)-1);
#endif
}
board_led_write(led_state);
led_state = !led_state; // toggle
}
}
int main(void) {
board_init();
board_led_write(true);
#if CFG_TUSB_OS == OPT_OS_FREERTOS
freertos_init();
#elif CFG_TUSB_OS == OPT_OS_THREADX
tx_kernel_enter();
#else
board_test_loop(NULL);
#endif
return 0;
}
#ifdef ESP_PLATFORM
void app_main(void) {
main();
}
#endif
//--------------------------------------------------------------------+
// FreeRTOS
//--------------------------------------------------------------------+
#if CFG_TUSB_OS == OPT_OS_FREERTOS
#ifdef ESP_PLATFORM
#define MAIN_STACK_SIZE 4096
#else
#define MAIN_STACK_SIZE 512
#endif
#if configSUPPORT_STATIC_ALLOCATION
static StackType_t _main_stack[MAIN_STACK_SIZE];
static StaticTask_t _main_taskdef;
#endif
static void freertos_init(void) {
#if configSUPPORT_STATIC_ALLOCATION
xTaskCreateStatic(board_test_loop, "main", MAIN_STACK_SIZE, NULL, 1, _main_stack, &_main_taskdef);
#else
xTaskCreate(board_test_loop, "main", MAIN_STACK_SIZE, NULL, 1, NULL);
#endif
#ifndef ESP_PLATFORM
vTaskStartScheduler();
#endif
}
//--------------------------------------------------------------------+
// ThreadX
//--------------------------------------------------------------------+
#elif CFG_TUSB_OS == OPT_OS_THREADX
#define MAIN_TASK_STACK_SIZE 1024
static TX_THREAD _main_thread;
static ULONG _main_thread_stack[MAIN_TASK_STACK_SIZE / sizeof(ULONG)];
void tx_application_define(void *first_unused_memory) {
(void) first_unused_memory;
static CHAR main_thread_name[] = "main";
tx_thread_create(&_main_thread, main_thread_name, board_test_loop, 0,
_main_thread_stack, MAIN_TASK_STACK_SIZE,
1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);
}
#endif

View File

@ -31,7 +31,7 @@
#include "tusb.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTYPES
// MACRO CONSTANT TYPEDEF PROTOTYPES
//--------------------------------------------------------------------+
/* Blink pattern
@ -41,71 +41,179 @@
*/
enum {
BLINK_NOT_MOUNTED = 250,
BLINK_MOUNTED = 1000,
BLINK_SUSPENDED = 2500,
BLINK_MOUNTED = 1000,
BLINK_SUSPENDED = 2500,
};
static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
void led_blinking_task(void);
// Task parameter type: ULONG for ThreadX, void* for FreeRTOS and noos
#if CFG_TUSB_OS == OPT_OS_THREADX
#define RTOS_PARAM ULONG
#elif CFG_TUSB_OS == OPT_OS_FREERTOS
#define RTOS_PARAM void*
static void freertos_init(void);
#else
#define RTOS_PARAM void*
#endif
/*------------- MAIN -------------*/
int main(void) {
board_init();
void led_blinking_task(RTOS_PARAM param);
// init device stack on configured roothub port
//--------------------------------------------------------------------+
// USB Device Task
//--------------------------------------------------------------------+
static void usb_device_init(void) {
tusb_rhport_init_t dev_init = {
.role = TUSB_ROLE_DEVICE,
.role = TUSB_ROLE_DEVICE,
.speed = TUSB_SPEED_AUTO
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
board_init_after_tusb();
}
#if CFG_TUSB_OS != OPT_OS_NONE && CFG_TUSB_OS != OPT_OS_PICO
static void usb_device_task(RTOS_PARAM param) {
(void) param;
usb_device_init();
while (1) {
tud_task(); // tinyusb device task
led_blinking_task();
tud_task();
}
}
#endif
//--------------------------------------------------------------------+
// Main
//--------------------------------------------------------------------+
int main(void) {
board_init();
#if CFG_TUSB_OS == OPT_OS_FREERTOS
freertos_init();
#elif CFG_TUSB_OS == OPT_OS_THREADX
tx_kernel_enter();
#else
// noos + pico-sdk: init USB then run polling loop
usb_device_init();
while (1) {
tud_task();
led_blinking_task(NULL);
}
#endif
return 0;
}
#ifdef ESP_PLATFORM
void app_main(void) {
main();
}
#endif
//--------------------------------------------------------------------+
// Device callbacks
//--------------------------------------------------------------------+
// Invoked when device is mounted
void tud_mount_cb(void) {
blink_interval_ms = BLINK_MOUNTED;
}
// Invoked when device is unmounted
void tud_umount_cb(void) {
blink_interval_ms = BLINK_NOT_MOUNTED;
}
// Invoked when usb bus is suspended
// remote_wakeup_en : if host allow us to perform remote wakeup
// Within 7ms, device must draw an average of current less than 2.5 mA from bus
void tud_suspend_cb(bool remote_wakeup_en) {
(void) remote_wakeup_en;
blink_interval_ms = BLINK_SUSPENDED;
}
// Invoked when usb bus is resumed
void tud_resume_cb(void) {
blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
}
//--------------------------------------------------------------------+
// BLINKING TASK
// Blinking Task
//--------------------------------------------------------------------+
void led_blinking_task(void) {
void led_blinking_task(RTOS_PARAM param) {
(void) param;
static uint32_t start_ms = 0;
static bool led_state = false;
// Blink every interval ms
if (tusb_time_millis_api() - start_ms < blink_interval_ms) return; // not enough time
start_ms += blink_interval_ms;
while (1) {
#if CFG_TUSB_OS == OPT_OS_FREERTOS
vTaskDelay(blink_interval_ms / portTICK_PERIOD_MS);
#elif CFG_TUSB_OS == OPT_OS_THREADX
tx_thread_sleep(_osal_ms2tick(blink_interval_ms));
#else
if (tusb_time_millis_api() - start_ms < blink_interval_ms) {
return; // not enough time
}
#endif
board_led_write(led_state);
led_state = 1 - led_state; // toggle
start_ms += blink_interval_ms;
board_led_write(led_state);
led_state = 1 - led_state; // toggle
}
}
//--------------------------------------------------------------------+
// FreeRTOS
//--------------------------------------------------------------------+
#if CFG_TUSB_OS == OPT_OS_FREERTOS
#ifdef ESP_PLATFORM
#define USBD_STACK_SIZE 4096
#else
#define USBD_STACK_SIZE (3*configMINIMAL_STACK_SIZE/2 * (CFG_TUSB_DEBUG ? 2 : 1))
#endif
#define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE
#if configSUPPORT_STATIC_ALLOCATION
static StackType_t _usb_device_stack[USBD_STACK_SIZE];
static StaticTask_t _usb_device_taskdef;
static StackType_t _blinky_stack[BLINKY_STACK_SIZE];
static StaticTask_t _blinky_taskdef;
#endif
static void freertos_init(void) {
#if configSUPPORT_STATIC_ALLOCATION
xTaskCreateStatic(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, _usb_device_stack, &_usb_device_taskdef);
xTaskCreateStatic(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, _blinky_stack, &_blinky_taskdef);
#else
xTaskCreate(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL);
xTaskCreate(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, NULL);
#endif
#ifndef ESP_PLATFORM
vTaskStartScheduler();
#endif
}
//--------------------------------------------------------------------+
// ThreadX
//--------------------------------------------------------------------+
#elif CFG_TUSB_OS == OPT_OS_THREADX
#define USBD_STACK_SIZE 4096
#define BLINKY_STACK_SIZE 512
static TX_THREAD _usb_device_thread;
static ULONG _usb_device_stack[USBD_STACK_SIZE / sizeof(ULONG)];
static TX_THREAD _blinky_thread;
static ULONG _blinky_stack[BLINKY_STACK_SIZE / sizeof(ULONG)];
void tx_application_define(void *first_unused_memory) {
(void) first_unused_memory;
static CHAR usbd_name[] = "usbd";
static CHAR blinky_name[] = "blinky";
tx_thread_create(&_usb_device_thread, usbd_name, usb_device_task, 0,
_usb_device_stack, USBD_STACK_SIZE,
0, 0, TX_NO_TIME_SLICE, TX_AUTO_START);
tx_thread_create(&_blinky_thread, blinky_name, led_blinking_task, 0,
_blinky_stack, BLINKY_STACK_SIZE,
1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);
}
#endif

View File

@ -251,3 +251,53 @@ void vApplicationSetupTimerInterrupt(void) {
#endif
#endif
//--------------------------------------------------------------------
// ThreadX hooks for ARM Cortex-M
//--------------------------------------------------------------------
#if CFG_TUSB_OS == OPT_OS_THREADX && defined(__ARM_ARCH)
#include "tx_api.h"
#include "tx_initialize.h"
// Newlib linker symbol: end of statically allocated RAM (start of heap)
extern ULONG _end;
// CMSIS standard variable for system clock frequency
extern uint32_t SystemCoreClock;
// Cortex-M SysTick registers (fixed addresses on all Cortex-M)
#define _TX_SYST_CSR (*((volatile uint32_t *)0xE000E010U))
#define _TX_SYST_RVR (*((volatile uint32_t *)0xE000E014U))
#define _TX_SYST_CVR (*((volatile uint32_t *)0xE000E018U))
// SCB->SHP[10] = PendSV priority, [11] = SysTick priority (byte access at SCB base + 0xD22)
#define _TX_SCB_SHPR3 (*((volatile uint32_t *)0xE000ED20U))
VOID _tx_initialize_low_level(VOID) {
// Set the first available memory address for tx_application_define
_tx_initialize_unused_memory = (VOID *)(&_end);
// Configure SysTick for ThreadX tick rate: enable with processor clock + interrupt
_TX_SYST_RVR = (SystemCoreClock / TX_TIMER_TICKS_PER_SECOND) - 1u;
_TX_SYST_CVR = 0u;
_TX_SYST_CSR = 0x07u; // CLKSOURCE=1, TICKINT=1, ENABLE=1
// SHPR3 bits[31:24] = SysTick priority, bits[23:16] = PendSV priority
// PendSV must be lowest priority (0xFF). SysTick must be higher than PendSV (0x40)
// so SysTick can preempt the PendSV scheduler idle loop (__tx_ts_wait) to tick the timer.
_TX_SCB_SHPR3 = (_TX_SCB_SHPR3 & 0x0000FFFFU) | 0x40FF0000U;
}
// Weak callback for board-specific SysTick work (e.g. HAL_IncTick on STM32)
void osal_threadx_tick_cb(void);
TU_ATTR_WEAK void osal_threadx_tick_cb(void) { }
// SysTick drives the ThreadX timer tick
extern void _tx_timer_interrupt(void);
void SysTick_Handler(void);
void SysTick_Handler(void) {
osal_threadx_tick_cb();
_tx_timer_interrupt();
}
#endif

View File

@ -364,14 +364,3 @@ bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const* tx_buf, uint8_t* rx
return true;
}
#endif
// board test example does not use both device and host stack
#if !CFG_TUD_ENABLED && !CFG_TUH_ENABLED
TU_ATTR_WEAK uint32_t tusb_time_millis_api(void) {
return osal_time_millis();
}
TU_ATTR_WEAK void tusb_time_delay_ms_api(uint32_t ms) {
osal_task_delay(ms);
}
#endif

View File

@ -380,6 +380,26 @@ function(family_add_rtos TARGET RTOS)
target_link_libraries(${TARGET} PUBLIC freertos_kernel)
target_compile_definitions(${TARGET} PUBLIC CFG_TUSB_OS=OPT_OS_FREERTOS)
elseif (RTOS STREQUAL "threadx")
if (NOT TARGET threadx)
# Derive THREADX_ARCH from CMAKE_SYSTEM_CPU if not explicitly set
if (NOT DEFINED THREADX_ARCH)
string(REPLACE "-" "_" THREADX_ARCH ${CMAKE_SYSTEM_CPU})
endif ()
# Derive THREADX_TOOLCHAIN from TOOLCHAIN if not explicitly set
if (NOT DEFINED THREADX_TOOLCHAIN)
if (TOOLCHAIN STREQUAL "iar")
set(THREADX_TOOLCHAIN "iar")
elseif (TOOLCHAIN STREQUAL "clang")
set(THREADX_TOOLCHAIN "ac6")
else ()
set(THREADX_TOOLCHAIN "gnu")
endif ()
endif ()
add_subdirectory(${TOP}/lib/threadx ${CMAKE_BINARY_DIR}/lib/threadx)
endif ()
target_link_libraries(${TARGET} PUBLIC threadx)
target_compile_definitions(${TARGET} PUBLIC CFG_TUSB_OS=OPT_OS_THREADX)
elseif (RTOS STREQUAL "zephyr")
target_compile_definitions(${TARGET} PUBLIC CFG_TUSB_OS=OPT_OS_ZEPHYR)
target_include_directories(${TARGET} PUBLIC ${ZEPHYR_BASE}/include)

View File

@ -377,15 +377,3 @@ bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const* tx_buf, uint8_t* rx
}
#endif
// board test example does not use both device and host stack
#if !CFG_TUD_ENABLED && !CFG_TUH_ENABLED
TU_ATTR_WEAK uint32_t tusb_time_millis_api(void) {
return osal_time_millis();
}
TU_ATTR_WEAK void tusb_time_delay_ms_api(uint32_t ms) {
osal_task_delay(ms);
}
#endif

View File

@ -139,6 +139,10 @@ void board_init(void) {
#endif
NVIC_SetPriority(OTG_HS_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
#elif CFG_TUSB_OS == OPT_OS_THREADX
// Disable SysTick before kernel entry; _tx_initialize_low_level() will re-configure it
SysTick->CTRL &= ~1UL;
#endif
GPIO_InitTypeDef GPIO_InitStruct;
@ -299,6 +303,11 @@ uint32_t tusb_time_millis_api(void) {
return system_ticks;
}
#elif CFG_TUSB_OS == OPT_OS_THREADX
// Keep HAL_GetTick() working for HAL functions called from board_init()
void osal_threadx_tick_cb(void) {
HAL_IncTick();
}
#endif
void HardFault_Handler(void) {

View File

@ -65,6 +65,8 @@ typedef void (*osal_task_func_t)(void* param);
#include "osal_rtx4.h"
#elif CFG_TUSB_OS == OPT_OS_ZEPHYR
#include "osal_zephyr.h"
#elif CFG_TUSB_OS == OPT_OS_THREADX
#include "osal_threadx.h"
#elif CFG_TUSB_OS == OPT_OS_CUSTOM
#include "tusb_os_custom.h" // implemented by application
#else

201
src/osal/osal_threadx.h Normal file
View File

@ -0,0 +1,201 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* This file is part of the TinyUSB stack.
*/
#ifndef TUSB_OSAL_THREADX_H_
#define TUSB_OSAL_THREADX_H_
// ThreadX Headers
#include "tx_api.h"
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------+
// TASK API
//--------------------------------------------------------------------+
TU_ATTR_ALWAYS_INLINE static inline uint32_t _osal_ms2tick(uint32_t msec) {
if ( msec == TX_WAIT_FOREVER ) {
return TX_WAIT_FOREVER;
}
if ( msec == 0 ) {
return 0;
}
uint32_t ticks = msec * TX_TIMER_TICKS_PER_SECOND / 1000;
// TX_TIMER_TICKS_PER_SECOND 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;
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t osal_time_millis(void) {
return (uint32_t)((uint64_t) tx_time_get() * 1000u / TX_TIMER_TICKS_PER_SECOND);
}
TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
tx_thread_sleep(_osal_ms2tick(msec));
}
//--------------------------------------------------------------------+
// Spinlock API
//--------------------------------------------------------------------+
//--------------------------------------------------------------------+
// 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 (act)
//--------------------------------------------------------------------+
// Note: semaphores are not used in tinyusb for now, and their API has not been tested
typedef TX_SEMAPHORE osal_semaphore_def_t, * osal_semaphore_t;
TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t *semdef) {
tx_semaphore_create(semdef, TX_NULL, 0);
return semdef;
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_delete(osal_semaphore_t sem_hdl) {
(void) sem_hdl;
return TX_SUCCESS == tx_semaphore_delete(sem_hdl);
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) {
(void) in_isr;
return TX_SUCCESS == tx_semaphore_put(sem_hdl);
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) {
return TX_SUCCESS == tx_semaphore_get(sem_hdl, _osal_ms2tick(msec));
}
TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl) {
(void) sem_hdl;
}
//--------------------------------------------------------------------+
// MUTEX API
//--------------------------------------------------------------------+
typedef TX_MUTEX osal_mutex_def_t, *osal_mutex_t;
TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t *mdef) {
if (TX_SUCCESS == tx_mutex_create(mdef, mdef->tx_mutex_name, TX_NO_INHERIT)) {
return mdef;
} else {
return NULL;
}
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_delete(osal_mutex_t mutex_hdl) {
(void) mutex_hdl;
return true; // nothing to do
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec) {
return TX_SUCCESS == tx_mutex_get(mutex_hdl, _osal_ms2tick(msec));
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) {
return TX_SUCCESS == tx_mutex_put(mutex_hdl);
}
//--------------------------------------------------------------------+
// QUEUE API
//--------------------------------------------------------------------+
typedef TX_QUEUE osal_queue_def_t, * osal_queue_t;
// _int_set is not used with an RTOS _usbd_qdef
#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
static _type _name##_buf[_depth]; \
osal_queue_def_t _name = { \
.tx_queue_name = (CHAR*)(uintptr_t)#_name, \
.tx_queue_message_size = (sizeof(_type) + 3) / 4, \
.tx_queue_capacity = _depth, \
.tx_queue_start = (ULONG *) _name##_buf }
TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) {
return TX_SUCCESS ==
tx_queue_create(qdef, qdef->tx_queue_name, qdef->tx_queue_message_size, qdef->tx_queue_start, qdef->tx_queue_capacity * qdef->tx_queue_message_size * 4)
? qdef : 0;
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_delete(osal_queue_t qhdl) {
(void) qhdl;
return true;
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) {
return 0 == tx_queue_receive(qhdl, data, _osal_ms2tick(msec));
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const *data, bool in_isr) {
return 0 == tx_queue_send(qhdl, (VOID *)(uintptr_t) data, in_isr ? TX_NO_WAIT : TX_WAIT_FOREVER);
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) {
ULONG enqueued;
tx_queue_info_get(qhdl, 0, &enqueued, 0, 0, 0, 0);
return enqueued == 0;
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -238,6 +238,7 @@
#define OPT_OS_RTTHREAD 6 ///< RT-Thread
#define OPT_OS_RTX4 7 ///< Keil RTX 4
#define OPT_OS_ZEPHYR 8 ///< Zephyr
#define OPT_OS_THREADX 9 ///< ThreadX
//--------------------------------------------------------------------+
// Mode and Speed

View File

@ -14,6 +14,9 @@ deps_mandatory = {
'lib/lwip': ['https://github.com/lwip-tcpip/lwip.git',
'159e31b689577dbf69cf0683bbaffbd71fa5ee10',
'all'],
'lib/threadx': ['https://github.com/eclipse-threadx/threadx.git',
'4b6e8100d932a3a67b34c6eb17f84f3bffb9e2ae',
'all'],
'tools/linkermap': ['https://github.com/hathach/linkermap.git',
'8e1f440fa15c567aceb5aa0d14f6d18c329cc67f',
'all'],