mirror of
https://github.com/hathach/tinyusb.git
synced 2026-03-10 17:44:48 +00:00
16
.github/workflows/claude-code-review.yml
vendored
16
.github/workflows/claude-code-review.yml
vendored
@ -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
|
||||
|
||||
|
||||
57
AGENTS.md
57
AGENTS.md
@ -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
|
||||
|
||||
|
||||
@ -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?**
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
201
src/osal/osal_threadx.h
Normal 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
|
||||
@ -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
|
||||
|
||||
@ -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'],
|
||||
|
||||
Reference in New Issue
Block a user