diff --git a/examples/device/CMakeLists.txt b/examples/device/CMakeLists.txt index 02fcc0b87..a2f73bb0d 100644 --- a/examples/device/CMakeLists.txt +++ b/examples/device/CMakeLists.txt @@ -8,14 +8,11 @@ family_initialize_project(tinyusb_device_examples ${CMAKE_CURRENT_LIST_DIR}) # family_add_subdirectory will filter what to actually add based on selected FAMILY set(EXAMPLE_LIST audio_4_channel_mic - audio_4_channel_mic_freertos audio_test - audio_test_freertos audio_test_multi_rate board_test cdc_dual_ports cdc_msc - cdc_msc_freertos cdc_msc_throughput cdc_uac2 dfu @@ -23,11 +20,9 @@ set(EXAMPLE_LIST dynamic_configuration hid_boot_interface hid_composite - hid_composite_freertos hid_generic_inout hid_multiple_interface midi_test - midi_test_freertos midi2_device msc_dual_lun mtp diff --git a/examples/device/audio_4_channel_mic/CMakeLists.txt b/examples/device/audio_4_channel_mic/CMakeLists.txt index 5d7ffa4fc..8c27e900d 100644 --- a/examples/device/audio_4_channel_mic/CMakeLists.txt +++ b/examples/device/audio_4_channel_mic/CMakeLists.txt @@ -2,6 +2,11 @@ cmake_minimum_required(VERSION 3.20) include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake) +# Need to set Espressif defaults before project() is called +if(FAMILY STREQUAL "espressif") + list(APPEND SDKCONFIG_DEFAULTS "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults") +endif() + project(audio_4_channel_mic C CXX ASM) # Checks this example is valid for the family and initializes the project @@ -30,6 +35,6 @@ if (CMAKE_C_COMPILER_ID STREQUAL "GNU") target_link_libraries(${PROJECT_NAME} PUBLIC m) endif() -# Configure compilation flags and libraries for the example without RTOS. +# Configure compilation flags and libraries for the selected RTOS. # See the corresponding function in hw/bsp/FAMILY/family.cmake for details. -family_configure_device_example(${PROJECT_NAME} noos) +family_configure_device_example(${PROJECT_NAME} ${RTOS}) diff --git a/examples/device/audio_4_channel_mic_freertos/sdkconfig.defaults b/examples/device/audio_4_channel_mic/sdkconfig.defaults similarity index 100% rename from examples/device/audio_4_channel_mic_freertos/sdkconfig.defaults rename to examples/device/audio_4_channel_mic/sdkconfig.defaults diff --git a/examples/device/audio_4_channel_mic/skip.txt b/examples/device/audio_4_channel_mic/skip.txt index 3ca433c08..70a1a872b 100644 --- a/examples/device/audio_4_channel_mic/skip.txt +++ b/examples/device/audio_4_channel_mic/skip.txt @@ -1,6 +1,29 @@ -mcu:SAMD11 -mcu:SAME5X -mcu:SAMG -family:broadcom_64bit -family:espressif -mcu:CH583 +rtos:noos mcu:SAMD11 +rtos:noos mcu:SAME5X +rtos:noos mcu:SAMG +rtos:noos family:broadcom_64bit +rtos:noos family:espressif +rtos:noos mcu:CH583 + +rtos:freertos mcu:CH32F20X +rtos:freertos mcu:CH32V103 +rtos:freertos mcu:CH32V20X +rtos:freertos mcu:CH32V307 +rtos:freertos mcu:CH583 +rtos:freertos mcu:CXD56 +rtos:freertos mcu:F1C100S +rtos:freertos mcu:GD32VF103 +rtos:freertos mcu:MCXA15 +rtos:freertos mcu:MKL25ZXX +rtos:freertos mcu:MSP430x5xx +rtos:freertos mcu:FT90X +rtos:freertos mcu:SAMD11 +rtos:freertos mcu:VALENTYUSB_EPTRI +rtos:freertos mcu:RAXXX +rtos:freertos mcu:STM32L0 +rtos:freertos board:lpcxpresso11u37 +rtos:freertos board:lpcxpresso1347 +rtos:freertos family:broadcom_32bit +rtos:freertos family:broadcom_64bit +rtos:freertos family:nuc121_125 +rtos:freertos family:hpmicro diff --git a/examples/device/audio_4_channel_mic_freertos/src/CMakeLists.txt b/examples/device/audio_4_channel_mic/src/CMakeLists.txt similarity index 100% rename from examples/device/audio_4_channel_mic_freertos/src/CMakeLists.txt rename to examples/device/audio_4_channel_mic/src/CMakeLists.txt diff --git a/examples/device/audio_4_channel_mic/src/main.c b/examples/device/audio_4_channel_mic/src/main.c index c9c6dd46c..38f42d11f 100644 --- a/examples/device/audio_4_channel_mic/src/main.c +++ b/examples/device/audio_4_channel_mic/src/main.c @@ -72,21 +72,18 @@ audio20_control_range_4_n_t(1) sampleFreqRng; // Audio test data, 4 channels muxed together, buffer[0] for CH0, buffer[1] for CH1, buffer[2] for CH2, buffer[3] for CH3 uint16_t i2s_dummy_buffer[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX * CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE / 1000]; -void led_blinking_task(void); -void audio_task(void); +void led_blinking_task(void *param); +void audio_task(void *param); + +#if CFG_TUSB_OS == OPT_OS_FREERTOS +static void usb_device_task(void *param); +static void freertos_init(void); +#endif /*------------- MAIN -------------*/ int main(void) { board_init(); - // init device stack on configured roothub port - tusb_rhport_init_t dev_init = { - .role = TUSB_ROLE_DEVICE, - .speed = TUSB_SPEED_AUTO}; - tusb_init(BOARD_TUD_RHPORT, &dev_init); - - board_init_after_tusb(); - // Init values sampFreq = AUDIO_SAMPLE_RATE; clkValid = 1; @@ -112,11 +109,25 @@ int main(void) { *p_buff++ = (uint16_t) ((int16_t) (sinf(t) * 750) + 6000); } +#if CFG_TUSB_OS == OPT_OS_FREERTOS + freertos_init(); +#else + // init device stack on configured roothub port + tusb_rhport_init_t dev_init = { + .role = TUSB_ROLE_DEVICE, + .speed = TUSB_SPEED_AUTO}; + tusb_init(BOARD_TUD_RHPORT, &dev_init); + + board_init_after_tusb(); + while (1) { tud_task();// tinyusb device task - led_blinking_task(); - audio_task(); + led_blinking_task(NULL); + audio_task(NULL); } +#endif + + return 0; } //--------------------------------------------------------------------+ @@ -153,14 +164,23 @@ void tud_resume_cb(void) { // This task simulates an audio receive callback, one frame is received every 1ms. // We assume that the audio data is read from an I2S buffer. // In a real application, this would be replaced with actual I2S receive callback. -void audio_task(void) { +void audio_task(void *param) { + (void) param; static uint32_t start_ms = 0; - uint32_t curr_ms = tusb_time_millis_api(); - if (start_ms == curr_ms) { - return; // not enough time + + while (1) { + uint32_t curr_ms = tusb_time_millis_api(); + if (start_ms != curr_ms) { + start_ms = curr_ms; + tud_audio_write(i2s_dummy_buffer, AUDIO_SAMPLE_RATE / 1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX); + } + +#if CFG_TUSB_OS == OPT_OS_FREERTOS + vTaskDelay(1); +#else + return; +#endif } - start_ms = curr_ms; - tud_audio_write(i2s_dummy_buffer, AUDIO_SAMPLE_RATE / 1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX); } //--------------------------------------------------------------------+ @@ -403,16 +423,91 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p //--------------------------------------------------------------------+ // BLINKING TASK //--------------------------------------------------------------------+ -void led_blinking_task(void) { - static uint32_t start_ms = 0; +void led_blinking_task(void *param) { + (void) param; 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); +#else + static uint32_t start_ms = 0; + // Blink every interval ms + if (tusb_time_millis_api() - start_ms < blink_interval_ms) { + return; // not enough time + } + start_ms += blink_interval_ms; +#endif - board_led_write(led_state); - led_state = 1 - led_state;// toggle + 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 + +void app_main(void) { + main(); +} +#else + #define USBD_STACK_SIZE ((4 * configMINIMAL_STACK_SIZE / 2) * (CFG_TUSB_DEBUG ? 2 : 1)) +#endif + +#define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE +#define AUDIO_STACK_SIZE configMINIMAL_STACK_SIZE + +#if configSUPPORT_STATIC_ALLOCATION +StackType_t blinky_stack[BLINKY_STACK_SIZE]; +StaticTask_t blinky_taskdef; + +StackType_t usb_device_stack[USBD_STACK_SIZE]; +StaticTask_t usb_device_taskdef; + +StackType_t audio_stack[AUDIO_STACK_SIZE]; +StaticTask_t audio_taskdef; +#endif + +// USB Device Driver task +// This top level thread processes all USB events and invokes callbacks. +static void usb_device_task(void *param) { + (void) param; + + // init device stack on configured roothub port. + // This should be called after scheduler/kernel is started. + // Otherwise, it could cause kernel issue since USB IRQ handler uses RTOS queue API. + tusb_rhport_init_t dev_init = { + .role = TUSB_ROLE_DEVICE, + .speed = TUSB_SPEED_AUTO + }; + tusb_init(BOARD_TUD_RHPORT, &dev_init); + + board_init_after_tusb(); + + while (1) { + tud_task();// tinyusb device task + } +} + +static void freertos_init(void) { +#if configSUPPORT_STATIC_ALLOCATION + xTaskCreateStatic(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, blinky_stack, &blinky_taskdef); + xTaskCreateStatic(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, usb_device_stack, &usb_device_taskdef); + xTaskCreateStatic(audio_task, "audio", AUDIO_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, audio_stack, &audio_taskdef); +#else + xTaskCreate(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, NULL); + xTaskCreate(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, NULL); + xTaskCreate(audio_task, "audio", AUDIO_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL); +#endif + +#ifndef ESP_PLATFORM + vTaskStartScheduler(); +#endif +} + +#endif diff --git a/examples/device/audio_4_channel_mic/src/tusb_config.h b/examples/device/audio_4_channel_mic/src/tusb_config.h index 085f9d168..0da1b9c00 100644 --- a/examples/device/audio_4_channel_mic/src/tusb_config.h +++ b/examples/device/audio_4_channel_mic/src/tusb_config.h @@ -57,6 +57,11 @@ extern "C" { #define CFG_TUSB_OS OPT_OS_NONE #endif +// Espressif IDF requires "freertos/" prefix in include path +#ifdef ESP_PLATFORM +#define CFG_TUSB_OS_INC_PATH freertos/ +#endif + #ifndef CFG_TUSB_DEBUG #define CFG_TUSB_DEBUG 0 #endif diff --git a/examples/device/audio_4_channel_mic_freertos/CMakeLists.txt b/examples/device/audio_4_channel_mic_freertos/CMakeLists.txt deleted file mode 100644 index 66ef19fbc..000000000 --- a/examples/device/audio_4_channel_mic_freertos/CMakeLists.txt +++ /dev/null @@ -1,40 +0,0 @@ -cmake_minimum_required(VERSION 3.20) - -include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake) - -# Need to set Espressif defaults before project() is called -if(FAMILY STREQUAL "espressif") - list(APPEND SDKCONFIG_DEFAULTS "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults") -endif() - -project(audio_4_channel_mic_freertos C CXX ASM) - -# Checks this example is valid for the family and initializes the project -family_initialize_project(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}) - -# Espressif has its own cmake build system -if(FAMILY STREQUAL "espressif") - return() -endif() - -add_executable(${PROJECT_NAME}) - -# Example source -target_sources(${PROJECT_NAME} PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c - ) - -# Example include -target_include_directories(${PROJECT_NAME} PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/src - ) - -# Add libm for GCC -if (CMAKE_C_COMPILER_ID STREQUAL "GNU") - target_link_libraries(${PROJECT_NAME} PUBLIC m) -endif() - -# Configure compilation flags and libraries for the example with FreeRTOS. -# See the corresponding function in hw/bsp/FAMILY/family.cmake for details. -family_configure_device_example(${PROJECT_NAME} freertos) diff --git a/examples/device/audio_4_channel_mic_freertos/CMakePresets.json b/examples/device/audio_4_channel_mic_freertos/CMakePresets.json deleted file mode 100644 index 5cd8971e9..000000000 --- a/examples/device/audio_4_channel_mic_freertos/CMakePresets.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "version": 6, - "include": [ - "../../../hw/bsp/BoardPresets.json" - ] -} diff --git a/examples/device/audio_4_channel_mic_freertos/Makefile b/examples/device/audio_4_channel_mic_freertos/Makefile deleted file mode 100644 index 3c421af74..000000000 --- a/examples/device/audio_4_channel_mic_freertos/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -RTOS = freertos -include ../../../hw/bsp/family_support.mk - -INC += \ - src \ - - -# Example source -EXAMPLE_SOURCE = \ - src/main.c \ - src/usb_descriptors.c - -SRC_C += $(addprefix $(EXAMPLE_PATH)/, $(EXAMPLE_SOURCE)) - -include ../../../hw/bsp/family_rules.mk diff --git a/examples/device/audio_4_channel_mic_freertos/skip.txt b/examples/device/audio_4_channel_mic_freertos/skip.txt deleted file mode 100644 index 1fd6b4b8a..000000000 --- a/examples/device/audio_4_channel_mic_freertos/skip.txt +++ /dev/null @@ -1,22 +0,0 @@ -mcu:CH32F20X -mcu:CH32V103 -mcu:CH32V20X -mcu:CH32V307 -mcu:CH583 -mcu:CXD56 -mcu:F1C100S -mcu:GD32VF103 -mcu:MCXA15 -mcu:MKL25ZXX -mcu:MSP430x5xx -mcu:FT90X -mcu:SAMD11 -mcu:VALENTYUSB_EPTRI -mcu:RAXXX -mcu:STM32L0 -board:lpcxpresso11u37 -board:lpcxpresso1347 -family:broadcom_32bit -family:broadcom_64bit -family:nuc121_125 -family:hpmicro diff --git a/examples/device/audio_4_channel_mic_freertos/src/main.c b/examples/device/audio_4_channel_mic_freertos/src/main.c deleted file mode 100644 index eac66a4ef..000000000 --- a/examples/device/audio_4_channel_mic_freertos/src/main.c +++ /dev/null @@ -1,486 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020 Reinhard Panhuber - * - * 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. - * - */ - -/* plot_audio_samples.py requires following modules: - * $ sudo apt install libportaudio - * $ pip3 install sounddevice matplotlib - * - * Then run - * $ python3 plot_audio_samples.py - */ - -#include -#include -#include -#include - -#include "bsp/board_api.h" -#include "tusb.h" - -#ifdef ESP_PLATFORM - // ESP-IDF need "freertos/" prefix in include path. - // CFG_TUSB_OS_INC_PATH should be defined accordingly. - #include "freertos/FreeRTOS.h" - #include "freertos/queue.h" - #include "freertos/semphr.h" - #include "freertos/task.h" - #include "freertos/timers.h" - - #define USBD_STACK_SIZE 4096 -#else - - #include "FreeRTOS.h" - #include "queue.h" - #include "semphr.h" - #include "task.h" - #include "timers.h" - - // Increase stack size when debug log is enabled - #define USBD_STACK_SIZE (4 * configMINIMAL_STACK_SIZE / 2) * (CFG_TUSB_DEBUG ? 2 : 1) -#endif - -#define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE -#define AUDIO_STACK_SIZE configMINIMAL_STACK_SIZE - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF PROTYPES -//--------------------------------------------------------------------+ -#define AUDIO_SAMPLE_RATE CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE - -/* Blink pattern - * - 250 ms : device not mounted - * - 1000 ms : device mounted - * - 2500 ms : device is suspended - */ -enum { - BLINK_NOT_MOUNTED = 250, - BLINK_MOUNTED = 1000, - BLINK_SUSPENDED = 2500, -}; - -// static task -#if configSUPPORT_STATIC_ALLOCATION -StackType_t blinky_stack[BLINKY_STACK_SIZE]; -StaticTask_t blinky_taskdef; - -StackType_t usb_device_stack[USBD_STACK_SIZE]; -StaticTask_t usb_device_taskdef; - -StackType_t audio_stack[AUDIO_STACK_SIZE]; -StaticTask_t audio_taskdef; -#endif - -static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; - -// Audio controls -// Current states -bool mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0 -uint16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1];// +1 for master channel 0 -uint32_t sampFreq; -uint8_t clkValid; - -// Range states -audio20_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1];// Volume range state -audio20_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state - -// Audio test data, 4 channels muxed together, buffer[0] for CH0, buffer[1] for CH1, buffer[2] for CH2, buffer[3] for CH3 -uint16_t i2s_dummy_buffer[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX * CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE / 1000]; - -void led_blinking_task(void *param); -void usb_device_task(void *param); -void audio_isr_task(void *param); - -/*------------- MAIN -------------*/ -int main(void) { - board_init(); - - // Init values - sampFreq = AUDIO_SAMPLE_RATE; - clkValid = 1; - - sampleFreqRng.wNumSubRanges = 1; - sampleFreqRng.subrange[0].bMin = AUDIO_SAMPLE_RATE; - sampleFreqRng.subrange[0].bMax = AUDIO_SAMPLE_RATE; - sampleFreqRng.subrange[0].bRes = 0; - - // Generate dummy data - uint16_t *p_buff = i2s_dummy_buffer; - uint16_t dataVal = 0; - for (uint16_t cnt = 0; cnt < AUDIO_SAMPLE_RATE / 1000; cnt++) { - // CH0 saw wave - *p_buff++ = dataVal; - // CH1 inverted saw wave - *p_buff++ = 3200 + AUDIO_SAMPLE_RATE / 1000 - dataVal; - dataVal += 32; - // CH3 square wave - *p_buff++ = cnt < (AUDIO_SAMPLE_RATE / 1000 / 2) ? 3400 : 5000; - // CH4 sinus wave - float t = 2 * 3.1415f * cnt / (AUDIO_SAMPLE_RATE / 1000); - *p_buff++ = (uint16_t) ((int16_t) (sinf(t) * 750) + 6000); - } - -#if configSUPPORT_STATIC_ALLOCATION - // blinky task - xTaskCreateStatic(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, blinky_stack, &blinky_taskdef); - - // Create a task for tinyusb device stack - xTaskCreateStatic(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, usb_device_stack, &usb_device_taskdef); - - // Audio receive (I2S) ISR simulation - // To simulate a ISR the priority is set to the highest - xTaskCreateStatic(audio_isr_task, "audio", AUDIO_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, audio_stack, &audio_taskdef); -#else - xTaskCreate(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, NULL); - xTaskCreate(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, NULL); - xTaskCreate(audio_isr_task, "audio", AUDIO_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL); -#endif - - // only start scheduler for non-espressif mcu - #ifndef ESP_PLATFORM - vTaskStartScheduler(); - #endif - - return 0; -} - -#ifdef ESP_PLATFORM -void app_main(void) { - main(); -} -#endif - -// USB Device Driver task -// This top level thread process all usb events and invoke callbacks -void usb_device_task(void *param) { - (void) param; - - // init device stack on configured roothub port - // This should be called after scheduler/kernel is started. - // Otherwise it could cause kernel issue since USB IRQ handler does use RTOS queue API. - tusb_rhport_init_t dev_init = { - .role = TUSB_ROLE_DEVICE, - .speed = TUSB_SPEED_AUTO}; - tusb_init(BOARD_TUD_RHPORT, &dev_init); - - board_init_after_tusb(); - - // RTOS forever loop - while (1) { - // tinyusb device task - tud_task(); - } -} - -//--------------------------------------------------------------------+ -// 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; -} - -//--------------------------------------------------------------------+ -// AUDIO Task -//--------------------------------------------------------------------+ - -// This task simulates an audio receive ISR, one frame is received every 1ms. -// We assume that the audio data is read from an I2S buffer. -// In a real application, this would be replaced with actual I2S receive callback. -void audio_isr_task(void *param) { - (void) param; - while (1) { - vTaskDelay(1); - tud_audio_write(i2s_dummy_buffer, AUDIO_SAMPLE_RATE / 1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX); - } -} - -//--------------------------------------------------------------------+ -// Application Callback API Implementations -//--------------------------------------------------------------------+ - -// Invoked when audio class specific set request received for an EP -bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *pBuff) { - (void) rhport; - (void) pBuff; - - // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); - - // Page 91 in UAC2 specification - uint8_t channelNum = TU_U16_LOW(p_request->wValue); - uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); - uint8_t ep = TU_U16_LOW(p_request->wIndex); - - (void) channelNum; - (void) ctrlSel; - (void) ep; - - return false;// Yet not implemented -} - -// Invoked when audio class specific set request received for an interface -bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *pBuff) { - (void) rhport; - (void) pBuff; - - // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); - - // Page 91 in UAC2 specification - uint8_t channelNum = TU_U16_LOW(p_request->wValue); - uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); - uint8_t itf = TU_U16_LOW(p_request->wIndex); - - (void) channelNum; - (void) ctrlSel; - (void) itf; - - return false;// Yet not implemented -} - -// Invoked when audio class specific set request received for an entity -bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *pBuff) { - (void) rhport; - - // Page 91 in UAC2 specification - uint8_t channelNum = TU_U16_LOW(p_request->wValue); - uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); - uint8_t itf = TU_U16_LOW(p_request->wIndex); - uint8_t entityID = TU_U16_HIGH(p_request->wIndex); - - (void) itf; - - // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); - - // If request is for our feature unit - if (entityID == 2) { - switch (ctrlSel) { - case AUDIO20_FU_CTRL_MUTE: - // Request uses format layout 1 - TU_VERIFY(p_request->wLength == sizeof(audio20_control_cur_1_t)); - - mute[channelNum] = ((audio20_control_cur_1_t *) pBuff)->bCur; - - TU_LOG1(" Set Mute: %d of channel: %u\r\n", mute[channelNum], channelNum); - return true; - - case AUDIO20_FU_CTRL_VOLUME: - // Request uses format layout 2 - TU_VERIFY(p_request->wLength == sizeof(audio20_control_cur_2_t)); - - volume[channelNum] = (uint16_t) ((audio20_control_cur_2_t *) pBuff)->bCur; - TU_LOG1(" Set Volume: %d dB of channel: %u\r\n", volume[channelNum], channelNum); - return true; - - // Unknown/Unsupported control - default: - TU_BREAKPOINT(); - return false; - } - } - return false;// Yet not implemented -} - -// Invoked when audio class specific get request received for an EP -bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request) { - (void) rhport; - - // Page 91 in UAC2 specification - uint8_t channelNum = TU_U16_LOW(p_request->wValue); - uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); - uint8_t ep = TU_U16_LOW(p_request->wIndex); - - (void) channelNum; - (void) ctrlSel; - (void) ep; - - return false;// Yet not implemented -} - -// Invoked when audio class specific get request received for an interface -bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const *p_request) { - (void) rhport; - - // Page 91 in UAC2 specification - uint8_t channelNum = TU_U16_LOW(p_request->wValue); - uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); - uint8_t itf = TU_U16_LOW(p_request->wIndex); - - (void) channelNum; - (void) ctrlSel; - (void) itf; - - return false;// Yet not implemented -} - -// Invoked when audio class specific get request received for an entity -bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request) { - (void) rhport; - - // Page 91 in UAC2 specification - uint8_t channelNum = TU_U16_LOW(p_request->wValue); - uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); - // uint8_t itf = TU_U16_LOW(p_request->wIndex); // Since we have only one audio function implemented, we do not need the itf value - uint8_t entityID = TU_U16_HIGH(p_request->wIndex); - - // Input terminal (Microphone input) - if (entityID == 1) { - switch (ctrlSel) { - case AUDIO20_TE_CTRL_CONNECTOR: { - // The terminal connector control only has a get request with only the CUR attribute. - audio20_desc_channel_cluster_t ret; - - // Those are dummy values for now - ret.bNrChannels = 1; - ret.bmChannelConfig = 0; - ret.iChannelNames = 0; - - TU_LOG1(" Get terminal connector\r\n"); - - return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void *) &ret, sizeof(ret)); - } break; - - // Unknown/Unsupported control selector - default: - TU_BREAKPOINT(); - return false; - } - } - - // Feature unit - if (entityID == 2) { - switch (ctrlSel) { - case AUDIO20_FU_CTRL_MUTE: - // Audio control mute cur parameter block consists of only one byte - we thus can send it right away - // There does not exist a range parameter block for mute - TU_LOG1(" Get Mute of channel: %u\r\n", channelNum); - return tud_control_xfer(rhport, p_request, &mute[channelNum], 1); - - case AUDIO20_FU_CTRL_VOLUME: - switch (p_request->bRequest) { - case AUDIO20_CS_REQ_CUR: - TU_LOG1(" Get Volume of channel: %u\r\n", channelNum); - return tud_control_xfer(rhport, p_request, &volume[channelNum], sizeof(volume[channelNum])); - - case AUDIO20_CS_REQ_RANGE: - TU_LOG1(" Get Volume range of channel: %u\r\n", channelNum); - - // Copy values - only for testing - better is version below - audio20_control_range_2_n_t(1) ret; - - ret.wNumSubRanges = 1; - ret.subrange[0].bMin = -90;// -90 dB - ret.subrange[0].bMax = 90; // +90 dB - ret.subrange[0].bRes = 1; // 1 dB steps - - return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void *) &ret, sizeof(ret)); - - // Unknown/Unsupported control - default: - TU_BREAKPOINT(); - return false; - } - break; - - // Unknown/Unsupported control - default: - TU_BREAKPOINT(); - return false; - } - } - - // Clock Source unit - if (entityID == 4) { - switch (ctrlSel) { - case AUDIO20_CS_CTRL_SAM_FREQ: - // channelNum is always zero in this case - switch (p_request->bRequest) { - case AUDIO20_CS_REQ_CUR: - TU_LOG1(" Get Sample Freq.\r\n"); - // Buffered control transfer is needed for IN flow control to work - return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq)); - - case AUDIO20_CS_REQ_RANGE: - TU_LOG1(" Get Sample Freq. range\r\n"); - return tud_control_xfer(rhport, p_request, &sampleFreqRng, sizeof(sampleFreqRng)); - - // Unknown/Unsupported control - default: - TU_BREAKPOINT(); - return false; - } - break; - - case AUDIO20_CS_CTRL_CLK_VALID: - // Only cur attribute exists for this request - TU_LOG1(" Get Sample Freq. valid\r\n"); - return tud_control_xfer(rhport, p_request, &clkValid, sizeof(clkValid)); - - // Unknown/Unsupported control - default: - TU_BREAKPOINT(); - return false; - } - } - - TU_LOG1(" Unsupported entity: %d\r\n", entityID); - return false;// Yet not implemented -} - -///--------------------------------------------------------------------+ -// BLINKING TASK -//--------------------------------------------------------------------+ -void led_blinking_task(void *param) { - (void) param; - static bool led_state = false; - - while (1) { - // Blink every interval ms - vTaskDelay(blink_interval_ms / portTICK_PERIOD_MS); - - board_led_write(led_state); - led_state = 1 - led_state;// toggle - } -} diff --git a/examples/device/audio_4_channel_mic_freertos/src/plot_audio_samples.py b/examples/device/audio_4_channel_mic_freertos/src/plot_audio_samples.py deleted file mode 100755 index 3b3cd0d83..000000000 --- a/examples/device/audio_4_channel_mic_freertos/src/plot_audio_samples.py +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env python3 -import sounddevice as sd -import matplotlib.pyplot as plt -import numpy as np -import platform - - -def find_windows_input_device(name_hint, channels, preferred_apis=None): - """Pick a Windows input device index from query_devices() output.""" - preferred_apis = preferred_apis or [] - name_hint = name_hint.lower() - candidates = [] - - for index in range(len(sd.query_devices())): - device_info = sd.query_devices(index) - max_input_channels = int(device_info.get('max_input_channels', 0)) - - if max_input_channels < channels: - continue - - device_name = str(device_info.get('name', '')).lower() - if name_hint not in device_name: - continue - - score = 0 - - # Prefer exact channel matches to avoid selecting a different stream layout. - if max_input_channels == channels: - score += 100 - else: - score += 10 - - hostapi_index = int(device_info.get('hostapi', -1)) - api_name = '' - if hostapi_index >= 0: - hostapi_info = sd.query_hostapis(hostapi_index) - api_name = str(hostapi_info.get('name', '')).lower() - - for priority, api_hint in enumerate(preferred_apis): - if api_hint in api_name: - score += 50 - priority - break - - candidates.append((score, index)) - - if not candidates: - raise ValueError( - 'No input device matching hint="{}" with at least {} channels'.format(name_hint, channels) - ) - - return max(candidates, key=lambda item: item[0])[1] - -if __name__ == '__main__': - - # If you got "ValueError: No input device matching", that is because your PC name example device - # differently from tested list below. Uncomment the next line to see full list and try to pick correct one - # print(sd.query_devices()) - - fs = 48000 # Sample rate - duration = 100e-3 # Duration of recording - - if platform.system() == 'Windows': - # Match by substring to support names like "Microphone (2- MicNode_4_Ch)". - device = find_windows_input_device('micnode_4_ch', channels=4, preferred_apis=['wdm-ks', 'wasapi', 'mme']) - elif platform.system() == 'Darwin': - device = 'MicNode_4_Ch' - else: - device ='default' - - myrecording = sd.rec(int(duration * fs), samplerate=fs, channels=4, dtype='int16', device=device) - print('Waiting...') - sd.wait() # Wait until recording is finished - print('Done!') - - time = np.arange(0, duration, 1 / fs) # time vector - plt.plot(time, myrecording) - plt.xlabel('Time [s]') - plt.ylabel('Amplitude') - plt.title('MicNode 4 Channel') - plt.show() diff --git a/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h b/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h deleted file mode 100644 index 74729695f..000000000 --- a/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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. - * - */ - -#ifndef TUSB_CONFIG_H_ -#define TUSB_CONFIG_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Board Specific Configuration -//--------------------------------------------------------------------+ - -// RHPort number used for device can be defined by board.mk, default to port 0 -#ifndef BOARD_TUD_RHPORT -#define BOARD_TUD_RHPORT 0 -#endif - -// RHPort max operational speed can defined by board.mk -#ifndef BOARD_TUD_MAX_SPEED -#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED -#endif - -//-------------------------------------------------------------------- -// COMMON CONFIGURATION -//-------------------------------------------------------------------- - -// defined by compiler flags for flexibility -#ifndef CFG_TUSB_MCU -#error CFG_TUSB_MCU must be defined -#endif - -// This examples use FreeRTOS -#ifndef CFG_TUSB_OS -#define CFG_TUSB_OS OPT_OS_FREERTOS -#endif - -// Espressif IDF requires "freertos/" prefix in include path -#ifdef ESP_PLATFORM -#define CFG_TUSB_OS_INC_PATH freertos/ -#endif - -#ifndef CFG_TUSB_DEBUG -#define CFG_TUSB_DEBUG 0 -#endif - -// Enable Device stack -#define CFG_TUD_ENABLED 1 - -// Default is max speed that hardware controller could support with on-chip PHY -#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED - -/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. - * Tinyusb use follows macros to declare transferring memory so that they can be put - * into those specific section. - * e.g - * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) - * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) - */ -#ifndef CFG_TUSB_MEM_SECTION -#define CFG_TUSB_MEM_SECTION -#endif - -#ifndef CFG_TUSB_MEM_ALIGN -#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) -#endif - -//-------------------------------------------------------------------- -// DEVICE CONFIGURATION -//-------------------------------------------------------------------- - -#ifndef CFG_TUD_ENDPOINT0_SIZE -#define CFG_TUD_ENDPOINT0_SIZE 64 -#endif - -//------------- CLASS -------------// -#define CFG_TUD_AUDIO 1 -#define CFG_TUD_CDC 0 -#define CFG_TUD_MSC 0 -#define CFG_TUD_HID 0 -#define CFG_TUD_MIDI 0 -#define CFG_TUD_VENDOR 0 - -//-------------------------------------------------------------------- -// AUDIO CLASS DRIVER CONFIGURATION -//-------------------------------------------------------------------- - -// Have a look into audio_device.h for all configurations -#define CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE 48000 - -#define CFG_TUD_AUDIO_ENABLE_EP_IN 1 -#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup -#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 4 // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup -#define CFG_TUD_AUDIO_EP_SZ_IN TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) - -#define CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL 1 - -#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN -#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_EP_SZ_IN // Example write FIFO every 1ms, so it should be 8 times larger for HS device - -#ifdef __cplusplus -} -#endif - -#endif /* TUSB_CONFIG_H_ */ diff --git a/examples/device/audio_4_channel_mic_freertos/src/usb_descriptors.c b/examples/device/audio_4_channel_mic_freertos/src/usb_descriptors.c deleted file mode 100644 index 0afb3df0a..000000000 --- a/examples/device/audio_4_channel_mic_freertos/src/usb_descriptors.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * 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. - * - */ - -#include "bsp/board_api.h" -#include "tusb.h" - -// Unique PID per example: guarantees re-enumeration on re-flash and a fresh host driver match. -#define USB_PID 0x4002 - -//--------------------------------------------------------------------+ -// Device Descriptors -//--------------------------------------------------------------------+ -static tusb_desc_device_t const desc_device = -{ - .bLength = sizeof(tusb_desc_device_t), - .bDescriptorType = TUSB_DESC_DEVICE, - .bcdUSB = 0x0200, - - // Use Interface Association Descriptor (IAD) for Audio - // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) - .bDeviceClass = TUSB_CLASS_MISC, - .bDeviceSubClass = MISC_SUBCLASS_COMMON, - .bDeviceProtocol = MISC_PROTOCOL_IAD, - .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, - - .idVendor = 0xCafe, - .idProduct = USB_PID, - .bcdDevice = 0x0100, - - .iManufacturer = 0x01, - .iProduct = 0x02, - .iSerialNumber = 0x03, - - .bNumConfigurations = 0x01 -}; - -// Invoked when received GET DEVICE DESCRIPTOR -// Application return pointer to descriptor -uint8_t const * tud_descriptor_device_cb(void) -{ - return (uint8_t const *) &desc_device; -} - -//--------------------------------------------------------------------+ -// Configuration Descriptor -//--------------------------------------------------------------------+ -enum -{ - ITF_NUM_AUDIO_CONTROL = 0, - ITF_NUM_AUDIO_STREAMING, - ITF_NUM_TOTAL -}; - -#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO20_MIC_FOUR_CH_DESC_LEN) - -#if TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX) - // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number - // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ... - #define EPNUM_AUDIO 0x03 - -#elif TU_CHECK_MCU(OPT_MCU_NRF5X) - // nRF5x ISO can only be endpoint 8 - #define EPNUM_AUDIO 0x08 - -#elif TU_CHECK_MCU(OPT_MCU_MAX32650, OPT_MCU_MAX32666, OPT_MCU_MAX32690, OPT_MCU_MAX78002) - // Put audio iso on EP>=8 so the 2048/4096-byte FIFOs can back double packet buffering - #define EPNUM_AUDIO 0x0A - -#else - #define EPNUM_AUDIO 0x01 -#endif - -uint8_t const desc_configuration[] = -{ - // Config number, interface count, string index, total length, attribute, power in mA - TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), - - // Interface number, string index, EP Out & EP In address, EP size - TUD_AUDIO20_MIC_FOUR_CH_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, /*_nBitsUsedPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX*8, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO_EP_SZ_IN) -}; - -// Invoked when received GET CONFIGURATION DESCRIPTOR -// Application return pointer to descriptor -// Descriptor contents must exist long enough for transfer to complete -uint8_t const * tud_descriptor_configuration_cb(uint8_t index) -{ - (void) index; // for multiple configurations - return desc_configuration; -} - -//--------------------------------------------------------------------+ -// String Descriptors -//--------------------------------------------------------------------+ - -// String Descriptor Index -enum { - STRID_LANGID = 0, - STRID_MANUFACTURER, - STRID_PRODUCT, - STRID_SERIAL, -}; - -// array of pointer to string descriptors -char const* string_desc_arr [] = { - (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) - "PaniRCorp", // 1: Manufacturer - "MicNode_4_Ch", // 2: Product - NULL, // 3: Serials will use unique ID if possible - "UAC2", // 4: Audio Interface -}; - -static uint16_t _desc_str[32 + 1]; - -// Invoked when received GET STRING DESCRIPTOR request -// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete -uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { - (void) langid; - size_t chr_count; - - switch ( index ) { - case STRID_LANGID: - memcpy(&_desc_str[1], string_desc_arr[0], 2); - chr_count = 1; - break; - - case STRID_SERIAL: - chr_count = board_usb_get_serial(_desc_str + 1, 32); - break; - - default: - // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. - // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors - - if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0]))) { - return NULL; - } - - const char *str = string_desc_arr[index]; - - // Cap at max char - chr_count = strlen(str); - size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type - if ( chr_count > max_count ) { - chr_count = max_count; - } - - // Convert ASCII string into UTF-16 - for ( size_t i = 0; i < chr_count; i++ ) { - _desc_str[1 + i] = str[i]; - } - break; - } - - // first byte is length (including header), second byte is string type - _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2)); - - return _desc_str; -} diff --git a/examples/device/audio_test/CMakeLists.txt b/examples/device/audio_test/CMakeLists.txt index 3382530c6..9dd74a62c 100644 --- a/examples/device/audio_test/CMakeLists.txt +++ b/examples/device/audio_test/CMakeLists.txt @@ -2,6 +2,11 @@ cmake_minimum_required(VERSION 3.20) include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake) +# Need to set Espressif defaults before project() is called +if(FAMILY STREQUAL "espressif") + list(APPEND SDKCONFIG_DEFAULTS "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults") +endif() + project(audio_test C CXX ASM) # Checks this example is valid for the family and initializes the project @@ -25,6 +30,6 @@ target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src ) -# Configure compilation flags and libraries for the example without RTOS. +# Configure compilation flags and libraries for the selected RTOS. # See the corresponding function in hw/bsp/FAMILY/family.cmake for details. -family_configure_device_example(${PROJECT_NAME} noos) +family_configure_device_example(${PROJECT_NAME} ${RTOS}) diff --git a/examples/device/audio_test_freertos/sdkconfig.defaults b/examples/device/audio_test/sdkconfig.defaults similarity index 100% rename from examples/device/audio_test_freertos/sdkconfig.defaults rename to examples/device/audio_test/sdkconfig.defaults diff --git a/examples/device/audio_test/skip.txt b/examples/device/audio_test/skip.txt index 42394bb11..86f089274 100644 --- a/examples/device/audio_test/skip.txt +++ b/examples/device/audio_test/skip.txt @@ -1,5 +1,26 @@ -mcu:SAMD11 -mcu:SAME5X -mcu:SAMG -family:espressif -mcu:CH583 +rtos:noos mcu:SAMD11 +rtos:noos mcu:SAME5X +rtos:noos mcu:SAMG +rtos:noos family:espressif +rtos:noos mcu:CH583 + +rtos:freertos mcu:CH32F20X +rtos:freertos mcu:CH32V103 +rtos:freertos mcu:CH32V20X +rtos:freertos mcu:CH32V307 +rtos:freertos mcu:CH583 +rtos:freertos mcu:CXD56 +rtos:freertos mcu:F1C100S +rtos:freertos mcu:GD32VF103 +rtos:freertos mcu:MCXA15 +rtos:freertos mcu:MKL25ZXX +rtos:freertos mcu:MSP430x5xx +rtos:freertos mcu:FT90X +rtos:freertos mcu:SAMD11 +rtos:freertos mcu:VALENTYUSB_EPTRI +rtos:freertos mcu:RAXXX +rtos:freertos family:broadcom_32bit +rtos:freertos family:broadcom_64bit +rtos:freertos board:stm32l0538disco +rtos:freertos family:nuc121_125 +rtos:freertos family:hpmicro diff --git a/examples/device/audio_test_freertos/src/CMakeLists.txt b/examples/device/audio_test/src/CMakeLists.txt similarity index 100% rename from examples/device/audio_test_freertos/src/CMakeLists.txt rename to examples/device/audio_test/src/CMakeLists.txt diff --git a/examples/device/audio_test/src/main.c b/examples/device/audio_test/src/main.c index 876a41d06..4f0fa3040 100644 --- a/examples/device/audio_test/src/main.c +++ b/examples/device/audio_test/src/main.c @@ -70,21 +70,18 @@ audio20_control_range_4_n_t(1) sampleFreqRng; uint16_t test_buffer_audio[CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE / 1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX / 2]; uint16_t startVal = 0; -void led_blinking_task(void); -void audio_task(void); +void led_blinking_task(void *param); +void audio_task(void *param); + +#if CFG_TUSB_OS == OPT_OS_FREERTOS +static void usb_device_task(void *param); +static void freertos_init(void); +#endif /*------------- MAIN -------------*/ int main(void) { board_init(); - // init device stack on configured roothub port - tusb_rhport_init_t dev_init = { - .role = TUSB_ROLE_DEVICE, - .speed = TUSB_SPEED_AUTO}; - tusb_init(BOARD_TUD_RHPORT, &dev_init); - - board_init_after_tusb(); - // Init values sampFreq = CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE; clkValid = 1; @@ -94,11 +91,25 @@ int main(void) { sampleFreqRng.subrange[0].bMax = CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE; sampleFreqRng.subrange[0].bRes = 0; +#if CFG_TUSB_OS == OPT_OS_FREERTOS + freertos_init(); +#else + // init device stack on configured roothub port + tusb_rhport_init_t dev_init = { + .role = TUSB_ROLE_DEVICE, + .speed = TUSB_SPEED_AUTO}; + tusb_init(BOARD_TUD_RHPORT, &dev_init); + + board_init_after_tusb(); + while (1) { tud_task();// tinyusb device task - led_blinking_task(); - audio_task(); + led_blinking_task(NULL); + audio_task(NULL); } +#endif + + return 0; } //--------------------------------------------------------------------+ @@ -136,17 +147,26 @@ void tud_resume_cb(void) { // This task simulates an audio receive callback, one frame is received every 1ms. // We assume that the audio data is read from an I2S buffer. // In a real application, this would be replaced with actual I2S receive callback. -void audio_task(void) { +void audio_task(void *param) { + (void) param; static uint32_t start_ms = 0; - uint32_t curr_ms = tusb_time_millis_api(); - if (start_ms == curr_ms) { - return; // not enough time + + while (1) { + uint32_t curr_ms = tusb_time_millis_api(); + if (start_ms != curr_ms) { + start_ms = curr_ms; + for (size_t cnt = 0; cnt < sizeof(test_buffer_audio) / 2; cnt++) { + test_buffer_audio[cnt] = startVal++; + } + tud_audio_write((uint8_t *) test_buffer_audio, sizeof(test_buffer_audio)); + } + +#if CFG_TUSB_OS == OPT_OS_FREERTOS + vTaskDelay(1); +#else + return; +#endif } - start_ms = curr_ms; - for (size_t cnt = 0; cnt < sizeof(test_buffer_audio) / 2; cnt++) { - test_buffer_audio[cnt] = startVal++; - } - tud_audio_write((uint8_t *) test_buffer_audio, sizeof(test_buffer_audio)); } //--------------------------------------------------------------------+ @@ -397,16 +417,91 @@ bool tud_audio_set_itf_close_ep_cb(uint8_t rhport, tusb_control_request_t const //--------------------------------------------------------------------+ // BLINKING TASK //--------------------------------------------------------------------+ -void led_blinking_task(void) { - static uint32_t start_ms = 0; +void led_blinking_task(void *param) { + (void) param; 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); +#else + static uint32_t start_ms = 0; + // Blink every interval ms + if (tusb_time_millis_api() - start_ms < blink_interval_ms) { + return; // not enough time + } + start_ms += blink_interval_ms; +#endif - board_led_write(led_state); - led_state = 1 - led_state;// toggle + 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 + +void app_main(void) { + main(); +} +#else + #define USBD_STACK_SIZE ((4 * configMINIMAL_STACK_SIZE / 2) * (CFG_TUSB_DEBUG ? 2 : 1)) +#endif + +#define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE +#define AUDIO_STACK_SIZE configMINIMAL_STACK_SIZE + +#if configSUPPORT_STATIC_ALLOCATION +StackType_t blinky_stack[BLINKY_STACK_SIZE]; +StaticTask_t blinky_taskdef; + +StackType_t usb_device_stack[USBD_STACK_SIZE]; +StaticTask_t usb_device_taskdef; + +StackType_t audio_stack[AUDIO_STACK_SIZE]; +StaticTask_t audio_taskdef; +#endif + +// USB Device Driver task +// This top level thread processes all USB events and invokes callbacks. +static void usb_device_task(void *param) { + (void) param; + + // init device stack on configured roothub port. + // This should be called after scheduler/kernel is started. + // Otherwise, it could cause kernel issue since USB IRQ handler uses RTOS queue API. + tusb_rhport_init_t dev_init = { + .role = TUSB_ROLE_DEVICE, + .speed = TUSB_SPEED_AUTO + }; + tusb_init(BOARD_TUD_RHPORT, &dev_init); + + board_init_after_tusb(); + + while (1) { + tud_task();// tinyusb device task + } +} + +static void freertos_init(void) { +#if configSUPPORT_STATIC_ALLOCATION + xTaskCreateStatic(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, blinky_stack, &blinky_taskdef); + xTaskCreateStatic(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, usb_device_stack, &usb_device_taskdef); + xTaskCreateStatic(audio_task, "audio", AUDIO_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, audio_stack, &audio_taskdef); +#else + xTaskCreate(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, NULL); + xTaskCreate(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL); + xTaskCreate(audio_task, "audio", AUDIO_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL); +#endif + +#ifndef ESP_PLATFORM + vTaskStartScheduler(); +#endif +} + +#endif diff --git a/examples/device/audio_test/src/tusb_config.h b/examples/device/audio_test/src/tusb_config.h index e311d892f..ffdb2d5c9 100644 --- a/examples/device/audio_test/src/tusb_config.h +++ b/examples/device/audio_test/src/tusb_config.h @@ -57,6 +57,11 @@ extern "C" { #define CFG_TUSB_OS OPT_OS_NONE #endif +// Espressif IDF requires "freertos/" prefix in include path +#ifdef ESP_PLATFORM +#define CFG_TUSB_OS_INC_PATH freertos/ +#endif + #ifndef CFG_TUSB_DEBUG #define CFG_TUSB_DEBUG 0 #endif diff --git a/examples/device/audio_test_freertos/CMakeLists.txt b/examples/device/audio_test_freertos/CMakeLists.txt deleted file mode 100644 index a39e56822..000000000 --- a/examples/device/audio_test_freertos/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -cmake_minimum_required(VERSION 3.20) - -include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake) - -# Need to set Espressif defaults before project() is called -if(FAMILY STREQUAL "espressif") - list(APPEND SDKCONFIG_DEFAULTS "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults") -endif() - -project(audio_test_freertos C CXX ASM) - -# Checks this example is valid for the family and initializes the project -family_initialize_project(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}) - -# Espressif has its own cmake build system -if(FAMILY STREQUAL "espressif") - return() -endif() - -add_executable(${PROJECT_NAME}) - -# Example source -target_sources(${PROJECT_NAME} PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c - ) - -# Example include -target_include_directories(${PROJECT_NAME} PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/src - ) - -# Configure compilation flags and libraries for the example with FreeRTOS. -# See the corresponding function in hw/bsp/FAMILY/family.cmake for details. -family_configure_device_example(${PROJECT_NAME} freertos) diff --git a/examples/device/audio_test_freertos/CMakePresets.json b/examples/device/audio_test_freertos/CMakePresets.json deleted file mode 100644 index 5cd8971e9..000000000 --- a/examples/device/audio_test_freertos/CMakePresets.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "version": 6, - "include": [ - "../../../hw/bsp/BoardPresets.json" - ] -} diff --git a/examples/device/audio_test_freertos/Makefile b/examples/device/audio_test_freertos/Makefile deleted file mode 100644 index 3c421af74..000000000 --- a/examples/device/audio_test_freertos/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -RTOS = freertos -include ../../../hw/bsp/family_support.mk - -INC += \ - src \ - - -# Example source -EXAMPLE_SOURCE = \ - src/main.c \ - src/usb_descriptors.c - -SRC_C += $(addprefix $(EXAMPLE_PATH)/, $(EXAMPLE_SOURCE)) - -include ../../../hw/bsp/family_rules.mk diff --git a/examples/device/audio_test_freertos/skip.txt b/examples/device/audio_test_freertos/skip.txt deleted file mode 100644 index 660bacd25..000000000 --- a/examples/device/audio_test_freertos/skip.txt +++ /dev/null @@ -1,20 +0,0 @@ -mcu:CH32F20X -mcu:CH32V103 -mcu:CH32V20X -mcu:CH32V307 -mcu:CH583 -mcu:CXD56 -mcu:F1C100S -mcu:GD32VF103 -mcu:MCXA15 -mcu:MKL25ZXX -mcu:MSP430x5xx -mcu:FT90X -mcu:SAMD11 -mcu:VALENTYUSB_EPTRI -mcu:RAXXX -family:broadcom_32bit -family:broadcom_64bit -board:stm32l0538disco -family:nuc121_125 -family:hpmicro diff --git a/examples/device/audio_test_freertos/src/main.c b/examples/device/audio_test_freertos/src/main.c deleted file mode 100644 index cf2fb74d1..000000000 --- a/examples/device/audio_test_freertos/src/main.c +++ /dev/null @@ -1,480 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020 Reinhard Panhuber - * - * 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. - * - */ - -/* plot_audio_samples.py requires following modules: - * $ sudo apt install libportaudio - * $ pip3 install sounddevice matplotlib - * - * Then run - * $ python3 plot_audio_samples.py - */ - -#include -#include -#include - -#include "bsp/board_api.h" -#include "tusb.h" - -#ifdef ESP_PLATFORM - // ESP-IDF need "freertos/" prefix in include path. - // CFG_TUSB_OS_INC_PATH should be defined accordingly. - #include "freertos/FreeRTOS.h" - #include "freertos/queue.h" - #include "freertos/semphr.h" - #include "freertos/task.h" - #include "freertos/timers.h" - - #define USBD_STACK_SIZE 4096 -#else - - #include "FreeRTOS.h" - #include "queue.h" - #include "semphr.h" - #include "task.h" - #include "timers.h" - - // Increase stack size when debug log is enabled - #define USBD_STACK_SIZE (4 * configMINIMAL_STACK_SIZE / 2) * (CFG_TUSB_DEBUG ? 2 : 1) -#endif - -#define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE -#define AUDIO_STACK_SIZE configMINIMAL_STACK_SIZE - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF PROTYPES -//--------------------------------------------------------------------+ - -/* Blink pattern - * - 250 ms : device not mounted - * - 1000 ms : device mounted - * - 2500 ms : device is suspended - */ -enum { - BLINK_NOT_MOUNTED = 250, - BLINK_MOUNTED = 1000, - BLINK_SUSPENDED = 2500, -}; - -// static task -#if configSUPPORT_STATIC_ALLOCATION -StackType_t blinky_stack[BLINKY_STACK_SIZE]; -StaticTask_t blinky_taskdef; - -StackType_t usb_device_stack[USBD_STACK_SIZE]; -StaticTask_t usb_device_taskdef; - -StackType_t audio_stack[AUDIO_STACK_SIZE]; -StaticTask_t audio_taskdef; -#endif - -static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; - -// Audio controls -// Current states -bool mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0 -uint16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1];// +1 for master channel 0 -uint32_t sampFreq; -uint8_t clkValid; - -// Range states -audio20_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1];// Volume range state -audio20_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state - -// Audio test data -uint16_t test_buffer_audio[CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE / 1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX / 2]; -uint16_t startVal = 0; - -void led_blinking_task(void *param); -void usb_device_task(void *param); -void audio_isr_task(void *param); - -/*------------- MAIN -------------*/ -int main(void) { - board_init(); - - // Init values - sampFreq = CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE; - clkValid = 1; - - sampleFreqRng.wNumSubRanges = 1; - sampleFreqRng.subrange[0].bMin = CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE; - sampleFreqRng.subrange[0].bMax = CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE; - sampleFreqRng.subrange[0].bRes = 0; - -#if configSUPPORT_STATIC_ALLOCATION - // blinky task - xTaskCreateStatic(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, blinky_stack, &blinky_taskdef); - - // Create a task for tinyusb device stack - xTaskCreateStatic(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, usb_device_stack, &usb_device_taskdef); - - // Audio receive (I2S) ISR simulation - // To simulate a ISR the priority is set to the highest - xTaskCreateStatic(audio_isr_task, "audio", AUDIO_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, audio_stack, &audio_taskdef); -#else - xTaskCreate(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, NULL); - xTaskCreate(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL); - xTaskCreate(audio_isr_task, "audio", AUDIO_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL); -#endif - - // only start scheduler for non-espressif mcu - #ifndef ESP_PLATFORM - vTaskStartScheduler(); - #endif - - return 0; -} - -#ifdef ESP_PLATFORM -void app_main(void) { - main(); -} -#endif - -// USB Device Driver task -// This top level thread process all usb events and invoke callbacks -void usb_device_task(void *param) { - (void) param; - - // init device stack on configured roothub port - // This should be called after scheduler/kernel is started. - // Otherwise it could cause kernel issue since USB IRQ handler does use RTOS queue API. - tusb_rhport_init_t dev_init = { - .role = TUSB_ROLE_DEVICE, - .speed = TUSB_SPEED_AUTO}; - tusb_init(BOARD_TUD_RHPORT, &dev_init); - - board_init_after_tusb(); - - // RTOS forever loop - while (1) { - // tinyusb device task - tud_task(); - } -} - -//--------------------------------------------------------------------+ -// 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; -} - -//--------------------------------------------------------------------+ -// AUDIO Task -//--------------------------------------------------------------------+ - -// This task simulates an audio receive ISR, one frame is received every 1ms. -// We assume that the audio data is read from an I2S buffer. -// In a real application, this would be replaced with actual I2S receive callback. -void audio_isr_task(void *param) { - (void) param; - while (1) { - vTaskDelay(1); - for (size_t cnt = 0; cnt < sizeof(test_buffer_audio) / 2; cnt++) { - test_buffer_audio[cnt] = startVal++; - } - tud_audio_write((uint8_t *) test_buffer_audio, sizeof(test_buffer_audio)); - } -} - -//--------------------------------------------------------------------+ -// Application Callback API Implementations -//--------------------------------------------------------------------+ - -// Invoked when audio class specific set request received for an EP -bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *pBuff) { - (void) rhport; - (void) pBuff; - - // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); - - // Page 91 in UAC2 specification - uint8_t channelNum = TU_U16_LOW(p_request->wValue); - uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); - uint8_t ep = TU_U16_LOW(p_request->wIndex); - - (void) channelNum; - (void) ctrlSel; - (void) ep; - - return false;// Yet not implemented -} - -// Invoked when audio class specific set request received for an interface -bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *pBuff) { - (void) rhport; - (void) pBuff; - - // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); - - // Page 91 in UAC2 specification - uint8_t channelNum = TU_U16_LOW(p_request->wValue); - uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); - uint8_t itf = TU_U16_LOW(p_request->wIndex); - - (void) channelNum; - (void) ctrlSel; - (void) itf; - - return false;// Yet not implemented -} - -// Invoked when audio class specific set request received for an entity -bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *pBuff) { - (void) rhport; - - // Page 91 in UAC2 specification - uint8_t channelNum = TU_U16_LOW(p_request->wValue); - uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); - uint8_t itf = TU_U16_LOW(p_request->wIndex); - uint8_t entityID = TU_U16_HIGH(p_request->wIndex); - - (void) itf; - - // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); - - // If request is for our feature unit - if (entityID == 2) { - switch (ctrlSel) { - case AUDIO20_FU_CTRL_MUTE: - // Request uses format layout 1 - TU_VERIFY(p_request->wLength == sizeof(audio20_control_cur_1_t)); - - mute[channelNum] = ((audio20_control_cur_1_t *) pBuff)->bCur; - - TU_LOG1(" Set Mute: %d of channel: %u\r\n", mute[channelNum], channelNum); - return true; - - case AUDIO20_FU_CTRL_VOLUME: - // Request uses format layout 2 - TU_VERIFY(p_request->wLength == sizeof(audio20_control_cur_2_t)); - - volume[channelNum] = (uint16_t) ((audio20_control_cur_2_t *) pBuff)->bCur; - TU_LOG1(" Set Volume: %d dB of channel: %u\r\n", volume[channelNum], channelNum); - return true; - - // Unknown/Unsupported control - default: - TU_BREAKPOINT(); - return false; - } - } - return false;// Yet not implemented -} - -// Invoked when audio class specific get request received for an EP -bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request) { - (void) rhport; - - // Page 91 in UAC2 specification - uint8_t channelNum = TU_U16_LOW(p_request->wValue); - uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); - uint8_t ep = TU_U16_LOW(p_request->wIndex); - - (void) channelNum; - (void) ctrlSel; - (void) ep; - - return false;// Yet not implemented -} - -// Invoked when audio class specific get request received for an interface -bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const *p_request) { - (void) rhport; - - // Page 91 in UAC2 specification - uint8_t channelNum = TU_U16_LOW(p_request->wValue); - uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); - uint8_t itf = TU_U16_LOW(p_request->wIndex); - - (void) channelNum; - (void) ctrlSel; - (void) itf; - - return false;// Yet not implemented -} - -// Invoked when audio class specific get request received for an entity -bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request) { - (void) rhport; - - // Page 91 in UAC2 specification - uint8_t channelNum = TU_U16_LOW(p_request->wValue); - uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); - // uint8_t itf = TU_U16_LOW(p_request->wIndex); // Since we have only one audio function implemented, we do not need the itf value - uint8_t entityID = TU_U16_HIGH(p_request->wIndex); - - // Input terminal (Microphone input) - if (entityID == 1) { - switch (ctrlSel) { - case AUDIO20_TE_CTRL_CONNECTOR: { - // The terminal connector control only has a get request with only the CUR attribute. - audio20_desc_channel_cluster_t ret; - - // Those are dummy values for now - ret.bNrChannels = 1; - ret.bmChannelConfig = (audio20_channel_config_t) 0; - ret.iChannelNames = 0; - - TU_LOG1(" Get terminal connector\r\n"); - - return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void *) &ret, sizeof(ret)); - } break; - - // Unknown/Unsupported control selector - default: - TU_BREAKPOINT(); - return false; - } - } - - // Feature unit - if (entityID == 2) { - switch (ctrlSel) { - case AUDIO20_FU_CTRL_MUTE: - // Audio control mute cur parameter block consists of only one byte - we thus can send it right away - // There does not exist a range parameter block for mute - TU_LOG1(" Get Mute of channel: %u\r\n", channelNum); - return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &mute[channelNum], 1); - - case AUDIO20_FU_CTRL_VOLUME: - switch (p_request->bRequest) { - case AUDIO20_CS_REQ_CUR: - TU_LOG1(" Get Volume of channel: %u\r\n", channelNum); - return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &volume[channelNum], sizeof(volume[channelNum])); - - case AUDIO20_CS_REQ_RANGE: - TU_LOG1(" Get Volume range of channel: %u\r\n", channelNum); - - // Copy values - only for testing - better is version below - audio20_control_range_2_n_t(1) - ret; - - ret.wNumSubRanges = 1; - ret.subrange[0].bMin = -90;// -90 dB - ret.subrange[0].bMax = 90; // +90 dB - ret.subrange[0].bRes = 1; // 1 dB steps - - return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void *) &ret, sizeof(ret)); - - // Unknown/Unsupported control - default: - TU_BREAKPOINT(); - return false; - } - break; - - // Unknown/Unsupported control - default: - TU_BREAKPOINT(); - return false; - } - } - - // Clock Source unit - if (entityID == 4) { - switch (ctrlSel) { - case AUDIO20_CS_CTRL_SAM_FREQ: - // channelNum is always zero in this case - switch (p_request->bRequest) { - case AUDIO20_CS_REQ_CUR: - TU_LOG1(" Get Sample Freq.\r\n"); - return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq)); - - case AUDIO20_CS_REQ_RANGE: - TU_LOG1(" Get Sample Freq. range\r\n"); - return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &sampleFreqRng, sizeof(sampleFreqRng)); - - // Unknown/Unsupported control - default: - TU_BREAKPOINT(); - return false; - } - break; - - case AUDIO20_CS_CTRL_CLK_VALID: - // Only cur attribute exists for this request - TU_LOG1(" Get Sample Freq. valid\r\n"); - return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &clkValid, sizeof(clkValid)); - - // Unknown/Unsupported control - default: - TU_BREAKPOINT(); - return false; - } - } - - TU_LOG1(" Unsupported entity: %d\r\n", entityID); - return false;// Yet not implemented -} - -bool tud_audio_set_itf_close_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request) { - (void) rhport; - (void) p_request; - startVal = 0; - - return true; -} - -//--------------------------------------------------------------------+ -// BLINKING TASK -//--------------------------------------------------------------------+ -void led_blinking_task(void *param) { - (void) param; - static bool led_state = false; - - while (1) { - // Blink every interval ms - vTaskDelay(blink_interval_ms / portTICK_PERIOD_MS); - - board_led_write(led_state); - led_state = 1 - led_state;// toggle - } -} diff --git a/examples/device/audio_test_freertos/src/plot_audio_samples.py b/examples/device/audio_test_freertos/src/plot_audio_samples.py deleted file mode 100755 index b6a916be4..000000000 --- a/examples/device/audio_test_freertos/src/plot_audio_samples.py +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env python3 -import sounddevice as sd -import matplotlib.pyplot as plt -import numpy as np -import platform - - -def find_windows_input_device(name_hint, channels, preferred_apis=None): - """Pick a Windows input device index from query_devices() output.""" - preferred_apis = preferred_apis or [] - name_hint = name_hint.lower() - candidates = [] - - for index in range(len(sd.query_devices())): - device_info = sd.query_devices(index) - max_input_channels = int(device_info.get('max_input_channels', 0)) - - if max_input_channels < channels: - continue - - device_name = str(device_info.get('name', '')).lower() - if name_hint not in device_name: - continue - - score = 0 - - # Prefer exact channel matches (for example 1ch source over a 4ch source). - if max_input_channels == channels: - score += 100 - else: - score += 10 - - hostapi_index = int(device_info.get('hostapi', -1)) - api_name = '' - if hostapi_index >= 0: - hostapi_info = sd.query_hostapis(hostapi_index) - api_name = str(hostapi_info.get('name', '')).lower() - - for priority, api_hint in enumerate(preferred_apis): - if api_hint in api_name: - score += 50 - priority - break - - candidates.append((score, index)) - - if not candidates: - raise ValueError( - 'No input device matching hint="{}" with at least {} channels'.format(name_hint, channels) - ) - - return max(candidates, key=lambda item: item[0])[1] - -if __name__ == '__main__': - - # If you got "ValueError: No input device matching", that is because your PC name example device - # differently from tested list below. Uncomment the next line to see full list and try to pick correct one - # print(sd.query_devices()) - - fs = 48000 # Sample rate - duration = 3 # Duration of recording - - if platform.system() == 'Windows': - # Match by substring to support names like "Microphone (2- MicNode)". - device = find_windows_input_device('micnode', channels=1, preferred_apis=['wasapi', 'mme', 'wdm-ks']) - elif platform.system() == 'Darwin': - device = 'MicNode' - else: - device ='default' - - myrecording = sd.rec(int(duration * fs), samplerate=fs, channels=1, dtype='int16', device=device) - print('Waiting...') - sd.wait() # Wait until recording is finished - print('Done!') - - time = np.arange(0, duration, 1 / fs) # time vector - plt.plot(time, myrecording) - plt.xlabel('Time [s]') - plt.ylabel('Amplitude') - plt.title('MicNode') - plt.show() diff --git a/examples/device/audio_test_freertos/src/tusb_config.h b/examples/device/audio_test_freertos/src/tusb_config.h deleted file mode 100644 index 81f0c11f4..000000000 --- a/examples/device/audio_test_freertos/src/tusb_config.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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. - * - */ - -#ifndef TUSB_CONFIG_H_ -#define TUSB_CONFIG_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Board Specific Configuration -//--------------------------------------------------------------------+ - -// RHPort number used for device can be defined by board.mk, default to port 0 -#ifndef BOARD_TUD_RHPORT -#define BOARD_TUD_RHPORT 0 -#endif - -// RHPort max operational speed can defined by board.mk -#ifndef BOARD_TUD_MAX_SPEED -#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED -#endif - -//-------------------------------------------------------------------- -// COMMON CONFIGURATION -//-------------------------------------------------------------------- - -// defined by compiler flags for flexibility -#ifndef CFG_TUSB_MCU -#error CFG_TUSB_MCU must be defined -#endif - -// This examples use FreeRTOS -#ifndef CFG_TUSB_OS -#define CFG_TUSB_OS OPT_OS_FREERTOS -#endif - -// Espressif IDF requires "freertos/" prefix in include path -#ifdef ESP_PLATFORM -#define CFG_TUSB_OS_INC_PATH freertos/ -#endif - -#ifndef CFG_TUSB_DEBUG -#define CFG_TUSB_DEBUG 0 -#endif - -// Enable Device stack -#define CFG_TUD_ENABLED 1 - -// Default is max speed that hardware controller could support with on-chip PHY -#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED - -// CFG_TUSB_DEBUG is defined by compiler in DEBUG build -// #define CFG_TUSB_DEBUG 0 - -/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. - * Tinyusb use follows macros to declare transferring memory so that they can be put - * into those specific section. - * e.g - * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) - * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) - */ -#ifndef CFG_TUSB_MEM_SECTION -#define CFG_TUSB_MEM_SECTION -#endif - -#ifndef CFG_TUSB_MEM_ALIGN -#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) -#endif - -//-------------------------------------------------------------------- -// DEVICE CONFIGURATION -//-------------------------------------------------------------------- - -#ifndef CFG_TUD_ENDPOINT0_SIZE -#define CFG_TUD_ENDPOINT0_SIZE 64 -#endif - -//------------- CLASS -------------// -#define CFG_TUD_AUDIO 1 -#define CFG_TUD_CDC 0 -#define CFG_TUD_MSC 0 -#define CFG_TUD_HID 0 -#define CFG_TUD_MIDI 0 -#define CFG_TUD_VENDOR 0 - -//-------------------------------------------------------------------- -// AUDIO CLASS DRIVER CONFIGURATION -//-------------------------------------------------------------------- - -// Have a look into audio_device.h for all configurations -#define CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE 48000 - -#define CFG_TUD_AUDIO_ENABLE_EP_IN 1 -#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below -#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below - be aware: for different number of channels you need another descriptor! -#define CFG_TUD_AUDIO_EP_SZ_IN TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) -#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN -#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_EP_SZ_IN // Example write FIFO every 1ms, so it should be 8 times larger for HS device - -#ifdef __cplusplus -} -#endif - -#endif /* TUSB_CONFIG_H_ */ diff --git a/examples/device/audio_test_freertos/src/usb_descriptors.c b/examples/device/audio_test_freertos/src/usb_descriptors.c deleted file mode 100644 index 709425c49..000000000 --- a/examples/device/audio_test_freertos/src/usb_descriptors.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * 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. - * - */ - -#include "bsp/board_api.h" -#include "tusb.h" - -// Unique PID per example: guarantees re-enumeration on re-flash and a fresh host driver match. -#define USB_PID 0x4004 - -//--------------------------------------------------------------------+ -// Device Descriptors -//--------------------------------------------------------------------+ -static tusb_desc_device_t const desc_device = -{ - .bLength = sizeof(tusb_desc_device_t), - .bDescriptorType = TUSB_DESC_DEVICE, - .bcdUSB = 0x0200, - - // Use Interface Association Descriptor (IAD) for Audio - // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) - .bDeviceClass = TUSB_CLASS_MISC, - .bDeviceSubClass = MISC_SUBCLASS_COMMON, - .bDeviceProtocol = MISC_PROTOCOL_IAD, - .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, - - .idVendor = 0xCafe, - .idProduct = USB_PID, - .bcdDevice = 0x0100, - - .iManufacturer = 0x01, - .iProduct = 0x02, - .iSerialNumber = 0x03, - - .bNumConfigurations = 0x01 -}; - -// Invoked when received GET DEVICE DESCRIPTOR -// Application return pointer to descriptor -uint8_t const * tud_descriptor_device_cb(void) -{ - return (uint8_t const *) &desc_device; -} - -//--------------------------------------------------------------------+ -// Configuration Descriptor -//--------------------------------------------------------------------+ -enum -{ - ITF_NUM_AUDIO_CONTROL = 0, - ITF_NUM_AUDIO_STREAMING, - ITF_NUM_TOTAL -}; - -#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO20_MIC_ONE_CH_DESC_LEN) - -#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX - // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number - // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ... - #define EPNUM_AUDIO 0x03 - -#elif TU_CHECK_MCU(OPT_MCU_NRF5X) - // nRF5x ISO can only be endpoint 8 - #define EPNUM_AUDIO 0x08 - -#elif TU_CHECK_MCU(OPT_MCU_MAX32650, OPT_MCU_MAX32666, OPT_MCU_MAX32690, OPT_MCU_MAX78002) - // Put audio iso on EP>=8 so the 2048/4096-byte FIFOs can back double packet buffering - #define EPNUM_AUDIO 0x0A - -#else - #define EPNUM_AUDIO 0x01 -#endif - -uint8_t const desc_configuration[] = -{ - // Config number, interface count, string index, total length, attribute, power in mA - TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), - - // Interface number, string index, EP Out & EP In address, EP size - TUD_AUDIO20_MIC_ONE_CH_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, /*_nBitsUsedPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX*8, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO_EP_SZ_IN) -}; - -// Invoked when received GET CONFIGURATION DESCRIPTOR -// Application return pointer to descriptor -// Descriptor contents must exist long enough for transfer to complete -uint8_t const * tud_descriptor_configuration_cb(uint8_t index) -{ - (void) index; // for multiple configurations - return desc_configuration; -} - -//--------------------------------------------------------------------+ -// String Descriptors -//--------------------------------------------------------------------+ - -// String Descriptor Index -enum { - STRID_LANGID = 0, - STRID_MANUFACTURER, - STRID_PRODUCT, - STRID_SERIAL, -}; - -// array of pointer to string descriptors -char const* string_desc_arr [] = -{ - (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) - "PaniRCorp", // 1: Manufacturer - "MicNode", // 2: Product - NULL, // 3: Serials will use unique ID if possible - "UAC2", // 4: Audio Interface - -}; - -static uint16_t _desc_str[32 + 1]; - -// Invoked when received GET STRING DESCRIPTOR request -// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete -uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { - (void) langid; - size_t chr_count; - - switch ( index ) { - case STRID_LANGID: - memcpy(&_desc_str[1], string_desc_arr[0], 2); - chr_count = 1; - break; - - case STRID_SERIAL: - chr_count = board_usb_get_serial(_desc_str + 1, 32); - break; - - default: - // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. - // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors - - if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0]))) { - return NULL; - } - - const char *str = string_desc_arr[index]; - - // Cap at max char - chr_count = strlen(str); - size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type - if (chr_count > max_count) { - chr_count = max_count; - } - - // Convert ASCII string into UTF-16 - for ( size_t i = 0; i < chr_count; i++ ) { - _desc_str[1 + i] = str[i]; - } - break; - } - - // first byte is length (including header), second byte is string type - _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2)); - - return _desc_str; -} diff --git a/examples/device/cdc_msc/CMakeLists.txt b/examples/device/cdc_msc/CMakeLists.txt index 293b497a7..b862b33b7 100644 --- a/examples/device/cdc_msc/CMakeLists.txt +++ b/examples/device/cdc_msc/CMakeLists.txt @@ -2,6 +2,11 @@ cmake_minimum_required(VERSION 3.20) include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake) +# Need to set Espressif defaults before project() is called +if(FAMILY STREQUAL "espressif") + list(APPEND SDKCONFIG_DEFAULTS "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults") +endif() + project(cdc_msc C CXX ASM) # Checks this example is valid for the family and initializes the project @@ -31,6 +36,6 @@ target_include_directories(${EXE_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src ) -# Configure compilation flags and libraries for the example without RTOS. +# Configure compilation flags and libraries for the selected RTOS. # See the corresponding function in hw/bsp/FAMILY/family.cmake for details. family_configure_device_example(${EXE_NAME} ${RTOS}) diff --git a/examples/device/cdc_msc_freertos/sdkconfig.defaults b/examples/device/cdc_msc/sdkconfig.defaults similarity index 100% rename from examples/device/cdc_msc_freertos/sdkconfig.defaults rename to examples/device/cdc_msc/sdkconfig.defaults diff --git a/examples/device/cdc_msc/skip.txt b/examples/device/cdc_msc/skip.txt index b6252e405..72118c8db 100644 --- a/examples/device/cdc_msc/skip.txt +++ b/examples/device/cdc_msc/skip.txt @@ -1,3 +1,24 @@ -mcu:SAMD11 -family:espressif -board:ch32v203g_r0_1v0 +rtos:noos mcu:SAMD11 +rtos:noos family:espressif +rtos:noos board:ch32v203g_r0_1v0 + +rtos:freertos mcu:CH32F20X +rtos:freertos mcu:CH32V103 +rtos:freertos mcu:CH32V20X +rtos:freertos mcu:CH32V307 +rtos:freertos mcu:CH583 +rtos:freertos mcu:CXD56 +rtos:freertos mcu:F1C100S +rtos:freertos mcu:GD32VF103 +rtos:freertos mcu:MCXA15 +rtos:freertos mcu:MKL25ZXX +rtos:freertos mcu:MSP430x5xx +rtos:freertos mcu:FT90X +rtos:freertos mcu:SAMD11 +rtos:freertos mcu:VALENTYUSB_EPTRI +rtos:freertos mcu:RAXXX +rtos:freertos mcu:STM32L0 +rtos:freertos family:broadcom_32bit +rtos:freertos family:broadcom_64bit +rtos:freertos family:nuc121_125 +rtos:freertos family:hpmicro diff --git a/examples/device/cdc_msc_freertos/src/CMakeLists.txt b/examples/device/cdc_msc/src/CMakeLists.txt similarity index 100% rename from examples/device/cdc_msc_freertos/src/CMakeLists.txt rename to examples/device/cdc_msc/src/CMakeLists.txt diff --git a/examples/device/cdc_msc/src/main.c b/examples/device/cdc_msc/src/main.c index b00a0e3a9..1318f6f32 100644 --- a/examples/device/cdc_msc/src/main.c +++ b/examples/device/cdc_msc/src/main.c @@ -44,25 +44,38 @@ enum { static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; static bool blink_enable = true; -void led_blinking_task(void); -void cdc_task(void); +void led_blinking_task(void *param); +void cdc_task(void *param); +extern void msc_disk_init(void); + +#if CFG_TUSB_OS == OPT_OS_FREERTOS +static void usb_device_task(void *param); +static void freertos_init(void); +#endif /*------------- MAIN -------------*/ int main(void) { board_init(); +#if CFG_TUSB_OS == OPT_OS_FREERTOS + freertos_init(); +#else // init device stack on configured roothub port tusb_rhport_init_t dev_init = {.role = TUSB_ROLE_DEVICE, .speed = TUSB_SPEED_AUTO}; tusb_init(BOARD_TUD_RHPORT, &dev_init); board_init_after_tusb(); + msc_disk_init(); while (1) { tud_task(); // tinyusb device task - led_blinking_task(); + led_blinking_task(NULL); - cdc_task(); + cdc_task(NULL); } +#endif + + return 0; } //--------------------------------------------------------------------+ @@ -96,38 +109,49 @@ void tud_resume_cb(void) { //--------------------------------------------------------------------+ // USB CDC //--------------------------------------------------------------------+ -void cdc_task(void) { - // connected() check for DTR bit - // Most but not all terminal client set this when making connection - // if ( tud_cdc_connected() ) - { - // connected and there are data available - if (tud_cdc_available()) { - // read data - char buf[64]; - uint32_t count = tud_cdc_read(buf, sizeof(buf)); - (void)count; +void cdc_task(void *param) { + (void) param; + + while (1) { + // connected() check for DTR bit + // Most but not all terminal client set this when making connection + // if ( tud_cdc_connected() ) + { + // connected and there are data available + while (tud_cdc_available()) { + // read data + char buf[64]; + uint32_t count = tud_cdc_read(buf, sizeof(buf)); + (void)count; + + // Echo back + // Note: Skip echo by commenting out write() and write_flush() + // for throughput test e.g + // $ dd if=/dev/zero of=/dev/ttyACM0 count=10000 + tud_cdc_write(buf, count); + } - // Echo back - // Note: Skip echo by commenting out write() and write_flush() - // for throughput test e.g - // $ dd if=/dev/zero of=/dev/ttyACM0 count=10000 - tud_cdc_write(buf, count); tud_cdc_write_flush(); + + // Press on-board button to send Uart status notification + static cdc_notify_uart_state_t uart_state = {.value = 0}; + + static uint32_t btn_prev = 0; + const uint32_t btn = board_button_read(); + + if ((btn_prev == 0u) && (btn != 0u)) { + uart_state.dsr ^= 1; + uart_state.dcd ^= 1; + tud_cdc_notify_uart_state(&uart_state); + } + btn_prev = btn; } - // Press on-board button to send Uart status notification - static cdc_notify_uart_state_t uart_state = {.value = 0}; - - static uint32_t btn_prev = 0; - const uint32_t btn = board_button_read(); - - if ((btn_prev == 0u) && (btn != 0u)) { - uart_state.dsr ^= 1; - uart_state.dcd ^= 1; - tud_cdc_notify_uart_state(&uart_state); - } - btn_prev = btn; +#if CFG_TUSB_OS == OPT_OS_FREERTOS + vTaskDelay(1); +#else + break; +#endif } } @@ -154,18 +178,109 @@ void tud_cdc_rx_cb(uint8_t itf) { //--------------------------------------------------------------------+ // BLINKING TASK //--------------------------------------------------------------------+ -void led_blinking_task(void) { - static uint32_t start_ms = 0; +void led_blinking_task(void *param) { + (void) param; static bool led_state = false; +#if CFG_TUSB_OS != OPT_OS_FREERTOS + static uint32_t start_ms = 0; +#endif - if (blink_enable) { + while (1) { + if (!blink_enable) { +#if CFG_TUSB_OS == OPT_OS_FREERTOS + vTaskDelay(1); + continue; +#else + return; +#endif + } + +#if CFG_TUSB_OS == OPT_OS_FREERTOS + vTaskDelay(blink_interval_ms / portTICK_PERIOD_MS); +#else // Blink every interval ms if (tusb_time_millis_api() - start_ms < blink_interval_ms) { return; // not enough time } start_ms += blink_interval_ms; +#endif board_led_write(led_state); led_state = !led_state; + +#if CFG_TUSB_OS != OPT_OS_FREERTOS + break; +#endif } } + +//--------------------------------------------------------------------+ +// FreeRTOS +//--------------------------------------------------------------------+ +#if CFG_TUSB_OS == OPT_OS_FREERTOS + +#ifdef ESP_PLATFORM + #define USBD_STACK_SIZE 4096 + +void app_main(void) { + main(); +} +#else + // Increase stack size when debug log is enabled + #define USBD_STACK_SIZE (configMINIMAL_STACK_SIZE * (CFG_TUSB_DEBUG ? 4 : 2)) +#endif + +#define CDC_STACK_SIZE (configMINIMAL_STACK_SIZE * (CFG_TUSB_DEBUG ? 3 : 2)) +#define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE + +#if configSUPPORT_STATIC_ALLOCATION +StackType_t blinky_stack[BLINKY_STACK_SIZE]; +StaticTask_t blinky_taskdef; + +StackType_t usb_device_stack[USBD_STACK_SIZE]; +StaticTask_t usb_device_taskdef; + +StackType_t cdc_stack[CDC_STACK_SIZE]; +StaticTask_t cdc_taskdef; +#endif + +// USB Device Driver task +// This top level thread processes all USB events and invokes callbacks. +static void usb_device_task(void *param) { + (void) param; + + // init device stack on configured roothub port. + // This should be called after scheduler/kernel is started. + // Otherwise, it could cause kernel issue since USB IRQ handler uses RTOS queue API. + tusb_rhport_init_t dev_init = { + .role = TUSB_ROLE_DEVICE, + .speed = TUSB_SPEED_AUTO + }; + tusb_init(BOARD_TUD_RHPORT, &dev_init); + + board_init_after_tusb(); + msc_disk_init(); + + while (1) { + tud_task();// tinyusb device task + tud_cdc_write_flush(); + } +} + +static void freertos_init(void) { +#if configSUPPORT_STATIC_ALLOCATION + xTaskCreateStatic(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, blinky_stack, &blinky_taskdef); + xTaskCreateStatic(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, usb_device_stack, &usb_device_taskdef); + xTaskCreateStatic(cdc_task, "cdc", CDC_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, cdc_stack, &cdc_taskdef); +#else + xTaskCreate(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, NULL); + xTaskCreate(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL); + xTaskCreate(cdc_task, "cdc", CDC_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, NULL); +#endif + +#ifndef ESP_PLATFORM + vTaskStartScheduler(); +#endif +} + +#endif diff --git a/examples/device/cdc_msc/src/msc_disk.c b/examples/device/cdc_msc/src/msc_disk.c index 017acd039..2684eec8e 100644 --- a/examples/device/cdc_msc/src/msc_disk.c +++ b/examples/device/cdc_msc/src/msc_disk.c @@ -28,6 +28,40 @@ #if CFG_TUD_MSC +#if CFG_TUSB_OS == OPT_OS_FREERTOS +#define CFG_EXAMPLE_MSC_ASYNC_IO 1 +#else +#define CFG_EXAMPLE_MSC_ASYNC_IO 0 +#endif + +// Simulate read/write operation delay +#define CFG_EXAMPLE_MSC_IO_DELAY_MS 0 + +#if CFG_EXAMPLE_MSC_ASYNC_IO +#define IO_STACK_SIZE configMINIMAL_STACK_SIZE + +typedef struct { + uint8_t lun; + bool is_read; + uint32_t lba; + uint32_t offset; + void *buffer; + uint32_t bufsize; +} io_ops_t; + +QueueHandle_t io_queue; +#if configSUPPORT_STATIC_ALLOCATION +uint8_t io_queue_buf[sizeof(io_ops_t)]; +StaticQueue_t io_queue_static; +StackType_t io_stack[IO_STACK_SIZE]; +StaticTask_t io_taskdef; +#endif + +static void io_task(void *params); +#endif + +void msc_disk_init(void); + // whether host does safe-eject static bool ejected = false; @@ -118,6 +152,45 @@ uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = { {README_CONTENTS} }; +void msc_disk_init(void) { +#if CFG_EXAMPLE_MSC_ASYNC_IO +#if configSUPPORT_STATIC_ALLOCATION + io_queue = xQueueCreateStatic(1, sizeof(io_ops_t), io_queue_buf, &io_queue_static); + xTaskCreateStatic(io_task, "io", IO_STACK_SIZE, NULL, 2, io_stack, &io_taskdef); +#else + io_queue = xQueueCreate(1, sizeof(io_ops_t)); + xTaskCreate(io_task, "io", IO_STACK_SIZE, NULL, 2, NULL); +#endif +#endif +} + +#if CFG_EXAMPLE_MSC_ASYNC_IO +static void io_task(void *params) { + (void) params; + io_ops_t io_ops; + + while (1) { + if (xQueueReceive(io_queue, &io_ops, portMAX_DELAY)) { + uint8_t *addr = (uint8_t *) (uintptr_t) (msc_disk[io_ops.lba] + io_ops.offset); + int32_t nbytes = (int32_t) io_ops.bufsize; + + if (io_ops.is_read) { + memcpy(io_ops.buffer, addr, io_ops.bufsize); + } else { +#ifndef CFG_EXAMPLE_MSC_READONLY + memcpy(addr, io_ops.buffer, io_ops.bufsize); +#else + nbytes = -1; +#endif + } + + tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS); + tud_msc_async_io_done(nbytes, false); + } + } +} +#endif + // Invoked when received SCSI_CMD_INQUIRY, v2 with full inquiry response // Some inquiry_resp's fields are already filled with default values, application can update them // Return length of inquiry response, typically sizeof(scsi_inquiry_resp_t) (36 bytes), can be longer if included vendor data. @@ -183,18 +256,27 @@ int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buff // out of ramdisk if (lba >= DISK_BLOCK_NUM) { - return -1; + return TUD_MSC_RET_ERROR; } // Check for overflow of offset + bufsize if (lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE) { - return -1; + return TUD_MSC_RET_ERROR; } +#if CFG_EXAMPLE_MSC_ASYNC_IO + io_ops_t io_ops = {.is_read = true, .lun = lun, .lba = lba, .offset = offset, .buffer = buffer, .bufsize = bufsize}; + + // Send IO operation to IO task + TU_ASSERT(xQueueSend(io_queue, &io_ops, 0) == pdPASS); + + return TUD_MSC_RET_ASYNC; +#else uint8_t const *addr = msc_disk[lba] + offset; (void) memcpy(buffer, addr, bufsize); return (int32_t) bufsize; +#endif } bool tud_msc_is_writable_cb(uint8_t lun) { @@ -214,12 +296,27 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t * // out of ramdisk if (lba >= DISK_BLOCK_NUM) { - return -1; + return TUD_MSC_RET_ERROR; + } + + // Check for overflow of offset + bufsize + if (lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE) { + return TUD_MSC_RET_ERROR; } #ifndef CFG_EXAMPLE_MSC_READONLY +#if CFG_EXAMPLE_MSC_ASYNC_IO + io_ops_t io_ops = {.is_read = false, .lun = lun, .lba = lba, .offset = offset, .buffer = buffer, .bufsize = bufsize}; + + // Send IO operation to IO task + TU_ASSERT(xQueueSend(io_queue, &io_ops, 0) == pdPASS); + + return TUD_MSC_RET_ASYNC; +#else uint8_t *addr = msc_disk[lba] + offset; (void) memcpy(addr, buffer, bufsize); + tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS); +#endif #else (void) lba; (void) offset; diff --git a/examples/device/cdc_msc/src/tusb_config.h b/examples/device/cdc_msc/src/tusb_config.h index f0709d8fb..13e270175 100644 --- a/examples/device/cdc_msc/src/tusb_config.h +++ b/examples/device/cdc_msc/src/tusb_config.h @@ -57,6 +57,11 @@ #define CFG_TUSB_OS OPT_OS_NONE #endif +// Espressif IDF requires "freertos/" prefix in include path +#ifdef ESP_PLATFORM +#define CFG_TUSB_OS_INC_PATH freertos/ +#endif + #ifndef CFG_TUSB_DEBUG #define CFG_TUSB_DEBUG 0 #endif diff --git a/examples/device/cdc_msc_freertos/CMakeLists.txt b/examples/device/cdc_msc_freertos/CMakeLists.txt deleted file mode 100644 index 1eafd529a..000000000 --- a/examples/device/cdc_msc_freertos/CMakeLists.txt +++ /dev/null @@ -1,36 +0,0 @@ -cmake_minimum_required(VERSION 3.20) - -include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake) - -# Need to set Espressif defaults before project() is called -if(FAMILY STREQUAL "espressif") - list(APPEND SDKCONFIG_DEFAULTS "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults") -endif() - -project(cdc_msc_freertos C CXX ASM) - -# Checks this example is valid for the family and initializes the project -family_initialize_project(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}) - -# Espressif has its own cmake build system -if(FAMILY STREQUAL "espressif") - return() -endif() - -add_executable(${PROJECT_NAME}) - -# Example source -target_sources(${PROJECT_NAME} PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_disk.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c - ) - -# Example include -target_include_directories(${PROJECT_NAME} PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/src - ) - -# Configure compilation flags and libraries for the example with FreeRTOS. -# See the corresponding function in hw/bsp/FAMILY/family.cmake for details. -family_configure_device_example(${PROJECT_NAME} freertos) diff --git a/examples/device/cdc_msc_freertos/CMakePresets.json b/examples/device/cdc_msc_freertos/CMakePresets.json deleted file mode 100644 index 5cd8971e9..000000000 --- a/examples/device/cdc_msc_freertos/CMakePresets.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "version": 6, - "include": [ - "../../../hw/bsp/BoardPresets.json" - ] -} diff --git a/examples/device/cdc_msc_freertos/Makefile b/examples/device/cdc_msc_freertos/Makefile deleted file mode 100644 index dbab13395..000000000 --- a/examples/device/cdc_msc_freertos/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -RTOS = freertos -include ../../../hw/bsp/family_support.mk - -INC += \ - src \ - - -# Example source -EXAMPLE_SOURCE = \ - src/main.c \ - src/msc_disk.c \ - src/usb_descriptors.c - -SRC_C += $(addprefix $(EXAMPLE_PATH)/, $(EXAMPLE_SOURCE)) - -include ../../../hw/bsp/family_rules.mk diff --git a/examples/device/cdc_msc_freertos/skip.txt b/examples/device/cdc_msc_freertos/skip.txt deleted file mode 100644 index 48781de84..000000000 --- a/examples/device/cdc_msc_freertos/skip.txt +++ /dev/null @@ -1,20 +0,0 @@ -mcu:CH32F20X -mcu:CH32V103 -mcu:CH32V20X -mcu:CH32V307 -mcu:CH583 -mcu:CXD56 -mcu:F1C100S -mcu:GD32VF103 -mcu:MCXA15 -mcu:MKL25ZXX -mcu:MSP430x5xx -mcu:FT90X -mcu:SAMD11 -mcu:VALENTYUSB_EPTRI -mcu:RAXXX -mcu:STM32L0 -family:broadcom_32bit -family:broadcom_64bit -family:nuc121_125 -family:hpmicro diff --git a/examples/device/cdc_msc_freertos/src/main.c b/examples/device/cdc_msc_freertos/src/main.c deleted file mode 100644 index 4a920c90b..000000000 --- a/examples/device/cdc_msc_freertos/src/main.c +++ /dev/null @@ -1,239 +0,0 @@ -/* - * 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. - * - */ - -#include -#include -#include - -#include "bsp/board_api.h" -#include "tusb.h" - -#ifdef ESP_PLATFORM - #define USBD_STACK_SIZE 4096 -#else - // Increase stack size when debug log is enabled - #define USBD_STACK_SIZE (configMINIMAL_STACK_SIZE * (CFG_TUSB_DEBUG ? 4 : 2)) -#endif - -#define CDC_STACK_SIZE (configMINIMAL_STACK_SIZE * (CFG_TUSB_DEBUG ? 3 : 2)) -#define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF PROTOTYPES -//--------------------------------------------------------------------+ - -/* Blink pattern - * - 250 ms : device not mounted - * - 1000 ms : device mounted - * - 2500 ms : device is suspended - */ -enum { - BLINK_NOT_MOUNTED = 250, - BLINK_MOUNTED = 1000, - BLINK_SUSPENDED = 2500, -}; - -// static task -#if configSUPPORT_STATIC_ALLOCATION -StackType_t blinky_stack[BLINKY_STACK_SIZE]; -StaticTask_t blinky_taskdef; - -StackType_t usb_device_stack[USBD_STACK_SIZE]; -StaticTask_t usb_device_taskdef; - -StackType_t cdc_stack[CDC_STACK_SIZE]; -StaticTask_t cdc_taskdef; -#endif - -static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; - -static void usb_device_task(void *param); -void led_blinking_task(void* param); -void cdc_task(void *params); -extern void msc_disk_init(void); -//--------------------------------------------------------------------+ -// Main -//--------------------------------------------------------------------+ - -int main(void) { - board_init(); - - // Create task for: tinyusb, blinky, cdc -#if configSUPPORT_STATIC_ALLOCATION - xTaskCreateStatic(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, blinky_stack, &blinky_taskdef); - xTaskCreateStatic(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES-1, usb_device_stack, &usb_device_taskdef); - xTaskCreateStatic(cdc_task, "cdc", CDC_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, cdc_stack, &cdc_taskdef); -#else - xTaskCreate(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, NULL); - xTaskCreate(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL); - xTaskCreate(cdc_task, "cdc", CDC_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, NULL); -#endif - -#ifndef ESP_PLATFORM - // only start scheduler for non-espressif mcu - vTaskStartScheduler(); -#endif - - return 0; -} - -#ifdef ESP_PLATFORM -void app_main(void) { - main(); -} -#endif - -// USB Device Driver task -// This top level thread process all usb events and invoke callbacks -static void usb_device_task(void *param) { - (void) param; - - // init device stack on configured roothub port - // This should be called after scheduler/kernel is started. - // Otherwise it could cause kernel issue since USB IRQ handler does use RTOS queue API. - tusb_rhport_init_t dev_init = { - .role = TUSB_ROLE_DEVICE, - .speed = TUSB_SPEED_AUTO - }; - tusb_init(BOARD_TUD_RHPORT, &dev_init); - - board_init_after_tusb(); - - msc_disk_init(); - // RTOS forever loop - while (1) { - // put this thread to waiting state until there is new events - tud_task(); - - // following code only run if tud_task() process at least 1 event - tud_cdc_write_flush(); - } -} - -//--------------------------------------------------------------------+ -// 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; -} - -//--------------------------------------------------------------------+ -// USB CDC -//--------------------------------------------------------------------+ -void cdc_task(void *params) { - (void) params; - - // RTOS forever loop - while (1) { - // connected() check for DTR bit - // Most but not all terminal client set this when making connection - // if ( tud_cdc_connected() ) - { - // There are data available - while (tud_cdc_available()) { - uint8_t buf[64]; - - // read and echo back - uint32_t count = tud_cdc_read(buf, sizeof(buf)); - (void) count; - - // Echo back - // Note: Skip echo by commenting out write() and write_flush() - // for throughput test e.g - // $ dd if=/dev/zero of=/dev/ttyACM0 count=10000 - tud_cdc_write(buf, count); - } - - tud_cdc_write_flush(); - - // Press on-board button to send Uart status notification - static uint32_t btn_prev = 0; - static cdc_notify_uart_state_t uart_state = { .value = 0 }; - const uint32_t btn = board_button_read(); - if (!btn_prev && btn) { - uart_state.dsr ^= 1; - tud_cdc_notify_uart_state(&uart_state); - } - btn_prev = btn; - } - - // For ESP32-Sx this delay is essential to allow idle how to run and reset watchdog - vTaskDelay(1); - } -} - -// Invoked when cdc when line state changed e.g connected/disconnected -void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) { - (void) itf; - (void) rts; - - // TODO set some indicator - if (dtr) { - // Terminal connected - } else { - // Terminal disconnected - } -} - -// Invoked when CDC interface received data from host -void tud_cdc_rx_cb(uint8_t itf) { - (void) itf; -} - -//--------------------------------------------------------------------+ -// BLINKING TASK -//--------------------------------------------------------------------+ -void led_blinking_task(void* param) { - (void) param; - static bool led_state = false; - - while (1) { - // Blink every interval ms - vTaskDelay(blink_interval_ms / portTICK_PERIOD_MS); - - board_led_write(led_state); - led_state = 1 - led_state; // toggle - } -} diff --git a/examples/device/cdc_msc_freertos/src/msc_disk.c b/examples/device/cdc_msc_freertos/src/msc_disk.c deleted file mode 100644 index ab551c288..000000000 --- a/examples/device/cdc_msc_freertos/src/msc_disk.c +++ /dev/null @@ -1,340 +0,0 @@ -/* - * 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. - * - */ - -#include "bsp/board_api.h" -#include "tusb.h" - -#if CFG_TUD_MSC - -// Use async IO in example or not -#define CFG_EXAMPLE_MSC_ASYNC_IO 1 - -// Simulate read/write operation delay -#define CFG_EXAMPLE_MSC_IO_DELAY_MS 0 - -#if CFG_EXAMPLE_MSC_ASYNC_IO -#define IO_STACK_SIZE configMINIMAL_STACK_SIZE - -typedef struct { - uint8_t lun; - bool is_read; - uint32_t lba; - uint32_t offset; - void* buffer; - uint32_t bufsize; -} io_ops_t; - -QueueHandle_t io_queue; -#if configSUPPORT_STATIC_ALLOCATION -uint8_t io_queue_buf[sizeof(io_ops_t)]; -StaticQueue_t io_queue_static; -StackType_t io_stack[IO_STACK_SIZE]; -StaticTask_t io_taskdef; -#endif - -static void io_task(void *params); -#endif - -void msc_disk_init(void); - -// whether host does safe-eject -static bool ejected = false; - -// Some MCU doesn't have enough 8KB SRAM to store the whole disk -// We will use Flash as read-only disk with board that has -// CFG_EXAMPLE_MSC_READONLY defined - -#define README_CONTENTS \ -"This is tinyusb's MassStorage Class demo.\r\n\r\n\ -If you find any bugs or get any questions, feel free to file an\r\n\ -issue at github.com/hathach/tinyusb" - -enum { - DISK_BLOCK_NUM = 16, // 8KB is the smallest size that windows allow to mount - DISK_BLOCK_SIZE = 512 -}; - -static -#ifdef CFG_EXAMPLE_MSC_READONLY -const -#endif -uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = -{ - //------------- Block0: Boot Sector -------------// - // byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM; - // sector_per_cluster = 1; reserved_sectors = 1; - // fat_num = 1; fat12_root_entry_num = 16; - // sector_per_fat = 1; sector_per_track = 1; head_num = 1; hidden_sectors = 0; - // drive_number = 0x80; media_type = 0xf8; extended_boot_signature = 0x29; - // filesystem_type = "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC"; - // FAT magic code at offset 510-511 - { - 0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00, - 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T' , 'i' , 'n' , 'y' , 'U' , - 'S' , 'B' , ' ' , 'M' , 'S' , 'C' , 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00, - - // Zero up to 2 last bytes of FAT magic code - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA - }, - - //------------- Block1: FAT12 Table -------------// - { - 0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third entry is cluster end of readme file - }, - - //------------- Block2: Root Directory -------------// - { - // first entry is volume label - 'T' , 'i' , 'n' , 'y' , 'U' , 'S' , 'B' , ' ' , 'M' , 'S' , 'C' , 0x08, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // second entry is readme file - 'R' , 'E' , 'A' , 'D' , 'M' , 'E' , ' ' , ' ' , 'T' , 'X' , 'T' , 0x20, 0x00, 0xC6, 0x52, 0x6D, - 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00, - sizeof(README_CONTENTS)-1, 0x00, 0x00, 0x00 // readme's files size (4 Bytes) - }, - - //------------- Block3: Readme Content -------------// - README_CONTENTS -}; - -#if CFG_EXAMPLE_MSC_ASYNC_IO -void msc_disk_init(void) { - -#if configSUPPORT_STATIC_ALLOCATION - io_queue = xQueueCreateStatic(1, sizeof(io_ops_t), io_queue_buf, &io_queue_static); - xTaskCreateStatic(io_task, "io", IO_STACK_SIZE, NULL, 2, io_stack, &io_taskdef); -#else - io_queue = xQueueCreate(1, sizeof(io_ops_t)); - xTaskCreate(io_task, "io", IO_STACK_SIZE, NULL, 2, NULL); -#endif -} - -static void io_task(void *params) { - (void) params; - io_ops_t io_ops; - while (1) { - if (xQueueReceive(io_queue, &io_ops, portMAX_DELAY)) { - uint8_t* addr = (uint8_t*) (uintptr_t) (msc_disk[io_ops.lba] + io_ops.offset); - int32_t nbytes = (int32_t) io_ops.bufsize; - if (io_ops.is_read) { - memcpy(io_ops.buffer, addr, io_ops.bufsize); - } else { -#ifndef CFG_EXAMPLE_MSC_READONLY - memcpy((uint8_t*) addr, io_ops.buffer, io_ops.bufsize); -#else - nbytes = -1; // failed to write -#endif - } - - tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS); - tud_msc_async_io_done(nbytes, false); - } - } -} - -#else -void msc_disk_init() {} -#endif - -// Invoked when received SCSI_CMD_INQUIRY, v2 with full inquiry response -// Some inquiry_resp's fields are already filled with default values, application can update them -// Return length of inquiry response, typically sizeof(scsi_inquiry_resp_t) (36 bytes), can be longer if included vendor data. -uint32_t tud_msc_inquiry2_cb(uint8_t lun, scsi_inquiry_resp_t* inquiry_resp, uint32_t bufsize) { - (void) lun; - (void) bufsize; - const char vid[] = "TinyUSB"; - const char pid[] = "Mass Storage"; - const char rev[] = "1.0"; - - strncpy((char*) inquiry_resp->vendor_id, vid, 8); - strncpy((char*) inquiry_resp->product_id, pid, 16); - strncpy((char*) inquiry_resp->product_rev, rev, 4); - - return sizeof(scsi_inquiry_resp_t); // 36 bytes -} - -// Invoked when received Test Unit Ready command. -// return true allowing host to read/write this LUN e.g SD card inserted -bool tud_msc_test_unit_ready_cb(uint8_t lun) { - (void) lun; - - // RAM disk is ready until ejected - if (ejected) { - // Additional Sense 3A-00 is NOT_FOUND - tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00); - return false; - } - - return true; -} - -// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size -// Application update block count and block size -void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) { - (void) lun; - *block_count = DISK_BLOCK_NUM; - *block_size = DISK_BLOCK_SIZE; -} - -// Invoked when received Start Stop Unit command -// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage -// - Start = 1 : active mode, if load_eject = 1 : load disk storage -bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) { - (void) lun; - (void) power_condition; - - if (load_eject) { - if (start) { - // load disk storage - } else { - // unload disk storage - ejected = true; - } - } - - return true; -} - -// Callback invoked when received READ10 command. -// Copy disk's data to buffer (up to bufsize) and return number of copied bytes. -int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) { - (void) lun; - - // out of ramdisk - if (lba >= DISK_BLOCK_NUM) { - return TUD_MSC_RET_ERROR; - } - - // Check for overflow of offset + bufsize - if (lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE) { - return TUD_MSC_RET_ERROR; - } - - #if CFG_EXAMPLE_MSC_ASYNC_IO - io_ops_t io_ops = {.is_read = true, .lun = lun, .lba = lba, .offset = offset, .buffer = buffer, .bufsize = bufsize}; - - // Send IO operation to IO task - TU_ASSERT(xQueueSend(io_queue, &io_ops, 0) == pdPASS); - - return TUD_MSC_RET_ASYNC; - #else - uint8_t const *addr = msc_disk[lba] + offset; - memcpy(buffer, addr, bufsize); - return bufsize; - #endif -} - -bool tud_msc_is_writable_cb (uint8_t lun) { - (void) lun; - - #ifdef CFG_EXAMPLE_MSC_READONLY - return false; - #else - return true; - #endif -} - -// Callback invoked when received WRITE10 command. -// Process data in buffer to disk's storage and return number of written bytes -int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) { - // out of ramdisk - if (lba >= DISK_BLOCK_NUM) { - return TUD_MSC_RET_ERROR; - } - - // Check for overflow of offset + bufsize - if (lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE) { - return TUD_MSC_RET_ERROR; - } - -#ifdef CFG_EXAMPLE_MSC_READONLY - (void) lun; - (void) buffer; - return bufsize; -#elif CFG_EXAMPLE_MSC_ASYNC_IO - io_ops_t io_ops = {.is_read = false, .lun = lun, .lba = lba, .offset = offset, .buffer = buffer, .bufsize = bufsize}; - - // Send IO operation to IO task - TU_ASSERT(xQueueSend(io_queue, &io_ops, 0) == pdPASS); - - return TUD_MSC_RET_ASYNC; - #else - uint8_t *addr = msc_disk[lba] + offset; - memcpy(addr, buffer, bufsize); - tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS); - - return bufsize; -#endif -} - -// Callback invoked when received an SCSI command not in built-in list below -// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE -// - READ10 and WRITE10 has their own callbacks -int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) { - (void) lun; - (void) scsi_cmd; - (void) buffer; - (void) bufsize; - - // currently no other commands are supported - - // Set Sense = Invalid Command Operation - (void) tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); - - return -1; // stall/failed command request; -} - -#endif diff --git a/examples/device/cdc_msc_freertos/src/tusb_config.h b/examples/device/cdc_msc_freertos/src/tusb_config.h deleted file mode 100644 index a78f2ea05..000000000 --- a/examples/device/cdc_msc_freertos/src/tusb_config.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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. - * - */ - -#ifndef TUSB_CONFIG_H_ -#define TUSB_CONFIG_H_ - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Board Specific Configuration -//--------------------------------------------------------------------+ - -// RHPort number used for device can be defined by board.mk, default to port 0 -#ifndef BOARD_TUD_RHPORT -#define BOARD_TUD_RHPORT 0 -#endif - -// RHPort max operational speed can defined by board.mk -#ifndef BOARD_TUD_MAX_SPEED -#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED -#endif - -//-------------------------------------------------------------------- -// COMMON CONFIGURATION -//-------------------------------------------------------------------- - -// defined by board.mk -#ifndef CFG_TUSB_MCU -#error CFG_TUSB_MCU must be defined -#endif - -// This examples use FreeRTOS -#ifndef CFG_TUSB_OS -#define CFG_TUSB_OS OPT_OS_FREERTOS -#endif - -// Espressif IDF requires "freertos/" prefix in include path -#ifdef ESP_PLATFORM -#define CFG_TUSB_OS_INC_PATH freertos/ -#endif - -// can be defined by compiler in DEBUG build -#ifndef CFG_TUSB_DEBUG -#define CFG_TUSB_DEBUG 0 -#endif - -// Enable Device stack -#define CFG_TUD_ENABLED 1 - -// Default is max speed that hardware controller could support with on-chip PHY -#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED - -/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. - * Tinyusb use follows macros to declare transferring memory so that they can be put - * into those specific section. - * e.g - * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) - * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) - */ -#ifndef CFG_TUSB_MEM_SECTION -#define CFG_TUSB_MEM_SECTION -#endif - -#ifndef CFG_TUSB_MEM_ALIGN -#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) -#endif - -//-------------------------------------------------------------------- -// DEVICE CONFIGURATION -//-------------------------------------------------------------------- - -#ifndef CFG_TUD_ENDPOINT0_SIZE -#define CFG_TUD_ENDPOINT0_SIZE 64 -#endif - -//------------- CLASS -------------// -#define CFG_TUD_CDC 1 -#define CFG_TUD_MSC 1 -#define CFG_TUD_HID 0 -#define CFG_TUD_MIDI 0 -#define CFG_TUD_VENDOR 0 - -#define CFG_TUD_CDC_NOTIFY 1 // Enable use of notification endpoint - -// CDC FIFO size of TX and RX -#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) -#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) - -// CDC Endpoint transfer buffer size, default to max bulk packet size (HS 512, FS 64). Larger is faster. -// Larger RX_EPSIZE requires CFG_TUD_CDC_RX_NEED_ZLP = 1 and host ZLP support -#define CFG_TUD_CDC_RX_EPSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) -#define CFG_TUD_CDC_TX_EPSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) - -// MSC Buffer size of Device Mass storage -#define CFG_TUD_MSC_EP_BUFSIZE 512 - -#ifdef __cplusplus - } -#endif - -#endif /* TUSB_CONFIG_H_ */ diff --git a/examples/device/cdc_msc_freertos/src/usb_descriptors.c b/examples/device/cdc_msc_freertos/src/usb_descriptors.c deleted file mode 100644 index 8398f0365..000000000 --- a/examples/device/cdc_msc_freertos/src/usb_descriptors.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - * 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. - * - */ - -#include "bsp/board_api.h" -#include "tusb.h" - -// Unique PID per example: guarantees re-enumeration on re-flash and a fresh host driver match. -#define USB_PID 0x4008 - -#define USB_VID 0xCafe -#define USB_BCD 0x0200 - -//--------------------------------------------------------------------+ -// Device Descriptors -//--------------------------------------------------------------------+ -static tusb_desc_device_t const desc_device = { - .bLength = sizeof(tusb_desc_device_t), - .bDescriptorType = TUSB_DESC_DEVICE, - .bcdUSB = USB_BCD, - - // Use Interface Association Descriptor (IAD) for CDC - // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) - .bDeviceClass = TUSB_CLASS_MISC, - .bDeviceSubClass = MISC_SUBCLASS_COMMON, - .bDeviceProtocol = MISC_PROTOCOL_IAD, - .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, - - .idVendor = USB_VID, - .idProduct = USB_PID, - .bcdDevice = 0x0100, - - .iManufacturer = 0x01, - .iProduct = 0x02, - .iSerialNumber = 0x03, - - .bNumConfigurations = 0x01 -}; - -// Invoked when received GET DEVICE DESCRIPTOR -// Application return pointer to descriptor -uint8_t const *tud_descriptor_device_cb(void) { - return (uint8_t const *) &desc_device; -} - -//--------------------------------------------------------------------+ -// Configuration Descriptor -//--------------------------------------------------------------------+ - -enum { - ITF_NUM_CDC = 0, - ITF_NUM_CDC_DATA, - ITF_NUM_MSC, - ITF_NUM_TOTAL -}; - -#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX - // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number - // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In, 5 Bulk etc ... - #define EPNUM_CDC_NOTIF 0x81 - #define EPNUM_CDC_OUT 0x02 - #define EPNUM_CDC_IN 0x82 - - #define EPNUM_MSC_OUT 0x05 - #define EPNUM_MSC_IN 0x85 - -#elif CFG_TUSB_MCU == OPT_MCU_CXD56 - // CXD56 USB driver has fixed endpoint type (bulk/interrupt/iso) and direction (IN/OUT) by its number - // 0 control (IN/OUT), 1 Bulk (IN), 2 Bulk (OUT), 3 In (IN), 4 Bulk (IN), 5 Bulk (OUT), 6 In (IN) - #define EPNUM_CDC_NOTIF 0x83 - #define EPNUM_CDC_OUT 0x02 - #define EPNUM_CDC_IN 0x81 - - #define EPNUM_MSC_OUT 0x05 - #define EPNUM_MSC_IN 0x84 - -#elif CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY - // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h - // e.g EP1 OUT & EP1 IN cannot exist together - #if TU_CHECK_MCU(OPT_MCU_MAX32650, OPT_MCU_MAX32666, OPT_MCU_MAX32690, OPT_MCU_MAX78002) - // Put bulk on EP>=8 so the 2048/4096-byte FIFOs can back double packet buffering - #define EPNUM_CDC_NOTIF 0x81 - #define EPNUM_CDC_OUT 0x08 - #define EPNUM_CDC_IN 0x89 - - #define EPNUM_MSC_OUT 0x0A - #define EPNUM_MSC_IN 0x8B - #else - #define EPNUM_CDC_NOTIF 0x81 - #define EPNUM_CDC_OUT 0x02 - #define EPNUM_CDC_IN 0x83 - - #define EPNUM_MSC_OUT 0x04 - #define EPNUM_MSC_IN 0x85 - #endif - -#else - #define EPNUM_CDC_NOTIF 0x81 - #define EPNUM_CDC_OUT 0x02 - #define EPNUM_CDC_IN 0x82 - - #define EPNUM_MSC_OUT 0x03 - #define EPNUM_MSC_IN 0x83 - -#endif - -#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_MSC_DESC_LEN) - -static uint8_t const desc_fs_configuration[] = -{ - // Config number, interface count, string index, total length, attribute, power in mA - TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), - - // Interface number, string index, EP notification address and size, EP data address (out, in) and size. - TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 16, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64), - - // Interface number, string index, EP Out & EP In address, EP size - TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 64), -}; - -#if TUD_OPT_HIGH_SPEED -// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration - -// high speed configuration -static uint8_t const desc_hs_configuration[] = -{ - // Config number, interface count, string index, total length, attribute, power in mA - TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), - - // Interface number, string index, EP notification address and size, EP data address (out, in) and size. - TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 16, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512), - - // Interface number, string index, EP Out & EP In address, EP size - TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 512), -}; - -// other speed configuration -static uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN]; - -// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed -static tusb_desc_device_qualifier_t const desc_device_qualifier = -{ - .bLength = sizeof(tusb_desc_device_qualifier_t), - .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER, - .bcdUSB = USB_BCD, - - .bDeviceClass = TUSB_CLASS_MISC, - .bDeviceSubClass = MISC_SUBCLASS_COMMON, - .bDeviceProtocol = MISC_PROTOCOL_IAD, - - .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, - .bNumConfigurations = 0x01, - .bReserved = 0x00 -}; - -// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request -// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. -// device_qualifier descriptor describes information about a high-speed capable device that would -// change if the device were operating at the other speed. If not highspeed capable stall this request. -uint8_t const* tud_descriptor_device_qualifier_cb(void) { - return (uint8_t const*) &desc_device_qualifier; -} - -// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request -// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete -// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa -uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) { - (void) index; // for multiple configurations - - // if link speed is high return fullspeed config, and vice versa - // Note: the descriptor type is OTHER_SPEED_CONFIG instead of CONFIG - memcpy(desc_other_speed_config, - (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration, - CONFIG_TOTAL_LEN); - - desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG; - - return desc_other_speed_config; -} - -#endif // highspeed - -// Invoked when received GET CONFIGURATION DESCRIPTOR -// Application return pointer to descriptor -// Descriptor contents must exist long enough for transfer to complete -uint8_t const * tud_descriptor_configuration_cb(uint8_t index) { - (void) index; // for multiple configurations - -#if TUD_OPT_HIGH_SPEED - // Although we are highspeed, host may be fullspeed. - return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration; -#else - return desc_fs_configuration; -#endif -} - -//--------------------------------------------------------------------+ -// String Descriptors -//--------------------------------------------------------------------+ - -// String Descriptor Index -enum { - STRID_LANGID = 0, - STRID_MANUFACTURER, - STRID_PRODUCT, - STRID_SERIAL, -}; - -// array of pointer to string descriptors -static char const *string_desc_arr[] = { - (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) - "TinyUSB", // 1: Manufacturer - "TinyUSB Device", // 2: Product - NULL, // 3: Serials will use unique ID if possible - "TinyUSB CDC", // 4: CDC Interface - "TinyUSB MSC", // 5: MSC Interface -}; - -static uint16_t _desc_str[32 + 1]; - -// Invoked when received GET STRING DESCRIPTOR request -// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete -uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { - (void) langid; - size_t chr_count; - - switch ( index ) { - case STRID_LANGID: - memcpy(&_desc_str[1], string_desc_arr[0], 2); - chr_count = 1; - break; - - case STRID_SERIAL: - chr_count = board_usb_get_serial(_desc_str + 1, 32); - break; - - default: - // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. - // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors - - if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) { return NULL; } - - const char *str = string_desc_arr[index]; - - // Cap at max char - chr_count = strlen(str); - size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type - if ( chr_count > max_count ) { chr_count = max_count; } - - // Convert ASCII string into UTF-16 - for ( size_t i = 0; i < chr_count; i++ ) { - _desc_str[1 + i] = str[i]; - } - break; - } - - // first byte is length (including header), second byte is string type - _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2)); - return _desc_str; -} diff --git a/examples/device/freertos_noos_merge_todo.md b/examples/device/freertos_noos_merge_todo.md new file mode 100644 index 000000000..cb05c97dc --- /dev/null +++ b/examples/device/freertos_noos_merge_todo.md @@ -0,0 +1,14 @@ +# FreeRTOS/No-OS Example Merge TODO + +Goal: shrink paired no-OS and FreeRTOS examples into one directory where the build selects the RTOS with `RTOS=freertos` / `-DRTOS=freertos`. + +- [x] Add RTOS-aware `skip.txt` entries with `rtos: `. +- [x] Merge `audio_test_freertos` into `audio_test`. +- [x] Merge `audio_4_channel_mic_freertos` into `audio_4_channel_mic`. +- [x] Add FreeRTOS support to `uac2_speaker_fb`. +- [x] Merge `cdc_msc_freertos` into `cdc_msc`. +- [x] Merge `hid_composite_freertos` into `hid_composite`. +- [x] Merge `midi_test_freertos` into `midi_test`. +- [x] Add ESP-IDF component metadata for merged examples that support Espressif. +- [x] Update Espressif build discovery for merged example names. +- [x] Remove merged `_freertos` entries from the device CMake example list. diff --git a/examples/device/hid_composite/CMakeLists.txt b/examples/device/hid_composite/CMakeLists.txt index f1ddbd125..5776ab967 100644 --- a/examples/device/hid_composite/CMakeLists.txt +++ b/examples/device/hid_composite/CMakeLists.txt @@ -2,6 +2,11 @@ cmake_minimum_required(VERSION 3.20) include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake) +# Need to set Espressif defaults before project() is called +if(FAMILY STREQUAL "espressif") + list(APPEND SDKCONFIG_DEFAULTS "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults") +endif() + project(hid_composite C CXX ASM) # Checks this example is valid for the family and initializes the project @@ -24,6 +29,6 @@ target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src ) -# Configure compilation flags and libraries for the example without RTOS. +# Configure compilation flags and libraries for the selected RTOS. # See the corresponding function in hw/bsp/FAMILY/family.cmake for details. -family_configure_device_example(${PROJECT_NAME} noos) +family_configure_device_example(${PROJECT_NAME} ${RTOS}) diff --git a/examples/device/hid_composite_freertos/sdkconfig.defaults b/examples/device/hid_composite/sdkconfig.defaults similarity index 100% rename from examples/device/hid_composite_freertos/sdkconfig.defaults rename to examples/device/hid_composite/sdkconfig.defaults diff --git a/examples/device/hid_composite/skip.txt b/examples/device/hid_composite/skip.txt index 2c6c2a64c..e93f35f24 100644 --- a/examples/device/hid_composite/skip.txt +++ b/examples/device/hid_composite/skip.txt @@ -1 +1,20 @@ -family:espressif +rtos:noos family:espressif + +rtos:freertos mcu:CH32F20X +rtos:freertos mcu:CH32V103 +rtos:freertos mcu:CH32V20X +rtos:freertos mcu:CH32V307 +rtos:freertos mcu:CH583 +rtos:freertos mcu:CXD56 +rtos:freertos mcu:F1C100S +rtos:freertos mcu:GD32VF103 +rtos:freertos mcu:MCXA15 +rtos:freertos mcu:MKL25ZXX +rtos:freertos mcu:MSP430x5xx +rtos:freertos mcu:FT90X +rtos:freertos mcu:SAMD11 +rtos:freertos mcu:VALENTYUSB_EPTRI +rtos:freertos mcu:RAXXX +rtos:freertos family:broadcom_32bit +rtos:freertos family:broadcom_64bit +rtos:freertos family:hpmicro diff --git a/examples/device/hid_composite_freertos/src/CMakeLists.txt b/examples/device/hid_composite/src/CMakeLists.txt similarity index 100% rename from examples/device/hid_composite_freertos/src/CMakeLists.txt rename to examples/device/hid_composite/src/CMakeLists.txt diff --git a/examples/device/hid_composite/src/main.c b/examples/device/hid_composite/src/main.c index 7c9d5af8d..089ff3ff1 100644 --- a/examples/device/hid_composite/src/main.c +++ b/examples/device/hid_composite/src/main.c @@ -49,13 +49,21 @@ enum { static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; -void led_blinking_task(void); -void hid_task(void); +void led_blinking_task(void *param); +void hid_task(void *param); + +#if CFG_TUSB_OS == OPT_OS_FREERTOS +static void usb_device_task(void *param); +static void freertos_init(void); +#endif /*------------- MAIN -------------*/ int main(void) { board_init(); +#if CFG_TUSB_OS == OPT_OS_FREERTOS + freertos_init(); +#else // init device stack on configured roothub port tusb_rhport_init_t dev_init = {.role = TUSB_ROLE_DEVICE, .speed = TUSB_SPEED_AUTO}; tusb_init(BOARD_TUD_RHPORT, &dev_init); @@ -64,9 +72,12 @@ int main(void) { while (1) { tud_task(); // tinyusb device task - led_blinking_task(); - hid_task(); + led_blinking_task(NULL); + hid_task(NULL); } +#endif + + return 0; } //--------------------------------------------------------------------+ @@ -204,26 +215,38 @@ static void send_hid_report(uint8_t report_id, uint32_t btn) { // Every 10ms, we will sent 1 report for each HID profile (keyboard, mouse etc ..) // tud_hid_report_complete_cb() is used to send the next report after previous one is complete -void hid_task(void) { - // Poll every 10ms - const uint32_t interval_ms = 10; - static uint32_t start_ms = 0; +void hid_task(void *param) { + (void) param; - if (tusb_time_millis_api() - start_ms < interval_ms) { - return; // not enough time - } - start_ms += interval_ms; + while (1) { +#if CFG_TUSB_OS == OPT_OS_FREERTOS + vTaskDelay(pdMS_TO_TICKS(10)); +#else + // Poll every 10ms + const uint32_t interval_ms = 10; + static uint32_t start_ms = 0; - uint32_t const btn = board_button_read(); + if (tusb_time_millis_api() - start_ms < interval_ms) { + return; // not enough time + } + start_ms += interval_ms; +#endif - // Remote wakeup - if (tud_suspended() && btn != 0u) { - // Wake up host if we are in suspend mode - // and REMOTE_WAKEUP feature is enabled by host - tud_remote_wakeup(); - } else { - // Send the 1st of report chain, the rest will be sent by tud_hid_report_complete_cb() - send_hid_report(REPORT_ID_KEYBOARD, btn); + uint32_t const btn = board_button_read(); + + // Remote wakeup + if (tud_suspended() && btn != 0u) { + // Wake up host if we are in suspend mode + // and REMOTE_WAKEUP feature is enabled by host + tud_remote_wakeup(); + } else { + // Send the 1st of report chain, the rest will be sent by tud_hid_report_complete_cb() + send_hid_report(REPORT_ID_KEYBOARD, btn); + } + +#if CFG_TUSB_OS != OPT_OS_FREERTOS + break; +#endif } } @@ -288,21 +311,108 @@ void tud_hid_set_report_cb( //--------------------------------------------------------------------+ // BLINKING TASK //--------------------------------------------------------------------+ -void led_blinking_task(void) { - static uint32_t start_ms = 0; +void led_blinking_task(void *param) { + (void) param; static bool led_state = false; +#if CFG_TUSB_OS != OPT_OS_FREERTOS + static uint32_t start_ms = 0; +#endif - // blink is disabled - if (0u == blink_interval_ms) { - return; + while (1) { + // blink is disabled + if (0u == blink_interval_ms) { +#if CFG_TUSB_OS == OPT_OS_FREERTOS + vTaskDelay(1); + continue; +#else + return; +#endif + } + +#if CFG_TUSB_OS == OPT_OS_FREERTOS + vTaskDelay(blink_interval_ms / portTICK_PERIOD_MS); +#else + // Blink every interval ms + if (tusb_time_millis_api() - start_ms < blink_interval_ms) { + return; // not enough time + } + start_ms += blink_interval_ms; +#endif + + board_led_write(led_state); + led_state = 1 - led_state; // toggle + +#if CFG_TUSB_OS != OPT_OS_FREERTOS + break; +#endif } - - // Blink every interval ms - if (tusb_time_millis_api() - start_ms < blink_interval_ms) { - return; // not enough time - } - 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 + +void app_main(void) { + main(); +} +#else + // Increase stack size when debug log is enabled + #define USBD_STACK_SIZE ((3 * configMINIMAL_STACK_SIZE / 2) * (CFG_TUSB_DEBUG ? 2 : 1)) +#endif + +#define HID_STACK_SIZE (configMINIMAL_STACK_SIZE * (CFG_TUSB_DEBUG ? 2 : 1)) +#define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE + +#if configSUPPORT_STATIC_ALLOCATION +StackType_t blinky_stack[BLINKY_STACK_SIZE]; +StaticTask_t blinky_taskdef; + +StackType_t usb_device_stack[USBD_STACK_SIZE]; +StaticTask_t usb_device_taskdef; + +StackType_t hid_stack[HID_STACK_SIZE]; +StaticTask_t hid_taskdef; +#endif + +// USB Device Driver task +// This top level thread processes all USB events and invokes callbacks. +static void usb_device_task(void *param) { + (void) param; + + // init device stack on configured roothub port. + // This should be called after scheduler/kernel is started. + // Otherwise, it could cause kernel issue since USB IRQ handler uses RTOS queue API. + tusb_rhport_init_t dev_init = { + .role = TUSB_ROLE_DEVICE, + .speed = TUSB_SPEED_AUTO + }; + tusb_init(BOARD_TUD_RHPORT, &dev_init); + + board_init_after_tusb(); + + while (1) { + tud_task();// tinyusb device task + } +} + +static void freertos_init(void) { +#if configSUPPORT_STATIC_ALLOCATION + xTaskCreateStatic(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, blinky_stack, &blinky_taskdef); + xTaskCreateStatic(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, usb_device_stack, &usb_device_taskdef); + xTaskCreateStatic(hid_task, "hid", HID_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, hid_stack, &hid_taskdef); +#else + xTaskCreate(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, NULL); + xTaskCreate(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL); + xTaskCreate(hid_task, "hid", HID_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, NULL); +#endif + +#ifndef ESP_PLATFORM + vTaskStartScheduler(); +#endif +} + +#endif diff --git a/examples/device/hid_composite/src/tusb_config.h b/examples/device/hid_composite/src/tusb_config.h index 895745ed2..3e11e846b 100644 --- a/examples/device/hid_composite/src/tusb_config.h +++ b/examples/device/hid_composite/src/tusb_config.h @@ -57,6 +57,11 @@ #define CFG_TUSB_OS OPT_OS_NONE #endif +// Espressif IDF requires "freertos/" prefix in include path +#ifdef ESP_PLATFORM +#define CFG_TUSB_OS_INC_PATH freertos/ +#endif + #ifndef CFG_TUSB_DEBUG #define CFG_TUSB_DEBUG 0 #endif diff --git a/examples/device/hid_composite_freertos/CMakeLists.txt b/examples/device/hid_composite_freertos/CMakeLists.txt deleted file mode 100644 index 2081a7782..000000000 --- a/examples/device/hid_composite_freertos/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -cmake_minimum_required(VERSION 3.20) - -include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake) - -# Need to set Espressif defaults before project() is called -if(FAMILY STREQUAL "espressif") - list(APPEND SDKCONFIG_DEFAULTS "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults") -endif() - -project(hid_composite_freertos C CXX ASM) - -# Checks this example is valid for the family and initializes the project -family_initialize_project(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}) - -# Espressif has its own cmake build system -if(FAMILY STREQUAL "espressif") - return() -endif() - -add_executable(${PROJECT_NAME}) - -# Example source -target_sources(${PROJECT_NAME} PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c - ) - -# Example include -target_include_directories(${PROJECT_NAME} PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/src - ) - -# Configure compilation flags and libraries for the example with FreeRTOS. -# See the corresponding function in hw/bsp/FAMILY/family.cmake for details. -family_configure_device_example(${PROJECT_NAME} freertos) diff --git a/examples/device/hid_composite_freertos/CMakePresets.json b/examples/device/hid_composite_freertos/CMakePresets.json deleted file mode 100644 index 5cd8971e9..000000000 --- a/examples/device/hid_composite_freertos/CMakePresets.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "version": 6, - "include": [ - "../../../hw/bsp/BoardPresets.json" - ] -} diff --git a/examples/device/hid_composite_freertos/Makefile b/examples/device/hid_composite_freertos/Makefile deleted file mode 100644 index 3c421af74..000000000 --- a/examples/device/hid_composite_freertos/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -RTOS = freertos -include ../../../hw/bsp/family_support.mk - -INC += \ - src \ - - -# Example source -EXAMPLE_SOURCE = \ - src/main.c \ - src/usb_descriptors.c - -SRC_C += $(addprefix $(EXAMPLE_PATH)/, $(EXAMPLE_SOURCE)) - -include ../../../hw/bsp/family_rules.mk diff --git a/examples/device/hid_composite_freertos/skip.txt b/examples/device/hid_composite_freertos/skip.txt deleted file mode 100644 index 97d8e168b..000000000 --- a/examples/device/hid_composite_freertos/skip.txt +++ /dev/null @@ -1,18 +0,0 @@ -mcu:CH32F20X -mcu:CH32V103 -mcu:CH32V20X -mcu:CH32V307 -mcu:CH583 -mcu:CXD56 -mcu:F1C100S -mcu:GD32VF103 -mcu:MCXA15 -mcu:MKL25ZXX -mcu:MSP430x5xx -mcu:FT90X -mcu:SAMD11 -mcu:VALENTYUSB_EPTRI -mcu:RAXXX -family:broadcom_32bit -family:broadcom_64bit -family:hpmicro diff --git a/examples/device/hid_composite_freertos/src/main.c b/examples/device/hid_composite_freertos/src/main.c deleted file mode 100644 index 35fdfea9e..000000000 --- a/examples/device/hid_composite_freertos/src/main.c +++ /dev/null @@ -1,387 +0,0 @@ -/* - * 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. - * - */ - -#include -#include -#include - -#include "bsp/board_api.h" -#include "tusb.h" -#include "usb_descriptors.h" - -#ifdef ESP_PLATFORM - // ESP-IDF need "freertos/" prefix in include path. - // CFG_TUSB_OS_INC_PATH should be defined accordingly. - #include "freertos/FreeRTOS.h" - #include "freertos/semphr.h" - #include "freertos/queue.h" - #include "freertos/task.h" - #include "freertos/timers.h" - - #define USBD_STACK_SIZE 4096 - -#else - #include "FreeRTOS.h" - #include "semphr.h" - #include "queue.h" - #include "task.h" - #include "timers.h" - - // Increase stack size when debug log is enabled - #define USBD_STACK_SIZE (3*configMINIMAL_STACK_SIZE/2) * (CFG_TUSB_DEBUG ? 2 : 1) -#endif - -#define HID_STACK_SIZE (configMINIMAL_STACK_SIZE * (CFG_TUSB_DEBUG ? 2 : 1)) - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF PROTYPES -//--------------------------------------------------------------------+ - -/* Blink pattern - * - 250 ms : device not mounted - * - 1000 ms : device mounted - * - 2500 ms : device is suspended - */ -enum { - BLINK_NOT_MOUNTED = 250, - BLINK_MOUNTED = 1000, - BLINK_SUSPENDED = 2500, -}; - -// static timer & task -#if configSUPPORT_STATIC_ALLOCATION -StaticTimer_t blinky_tmdef; - -StackType_t usb_device_stack[USBD_STACK_SIZE]; -StaticTask_t usb_device_taskdef; - -StackType_t hid_stack[HID_STACK_SIZE]; -StaticTask_t hid_taskdef; -#endif - -TimerHandle_t blinky_tm; - -void led_blinky_cb(TimerHandle_t xTimer); -void usb_device_task(void* param); -void hid_task(void* params); - -//--------------------------------------------------------------------+ -// Main -//--------------------------------------------------------------------+ - -int main(void) -{ - board_init(); - -#if configSUPPORT_STATIC_ALLOCATION - // soft timer for blinky - blinky_tm = xTimerCreateStatic(NULL, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), true, NULL, led_blinky_cb, &blinky_tmdef); - - // Create a task for tinyusb device stack - xTaskCreateStatic(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES-1, usb_device_stack, &usb_device_taskdef); - - // Create HID task - xTaskCreateStatic(hid_task, "hid", HID_STACK_SIZE, NULL, configMAX_PRIORITIES-2, hid_stack, &hid_taskdef); -#else - blinky_tm = xTimerCreate(NULL, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), true, NULL, led_blinky_cb); - xTaskCreate(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES-1, NULL); - xTaskCreate(hid_task, "hid", HID_STACK_SIZE, NULL, configMAX_PRIORITIES-2, NULL); -#endif - - xTimerStart(blinky_tm, 0); - - // only start scheduler for non-espressif mcu -#ifndef ESP_PLATFORM - vTaskStartScheduler(); -#endif - - return 0; -} - -#ifdef ESP_PLATFORM -void app_main(void) { - main(); -} -#endif - -// USB Device Driver task -// This top level thread process all usb events and invoke callbacks -void usb_device_task(void* param) -{ - (void) param; - - // init device stack on configured roothub port - // This should be called after scheduler/kernel is started. - // Otherwise it could cause kernel issue since USB IRQ handler does use RTOS queue API. - tusb_rhport_init_t dev_init = { - .role = TUSB_ROLE_DEVICE, - .speed = TUSB_SPEED_AUTO - }; - tusb_init(BOARD_TUD_RHPORT, &dev_init); - - board_init_after_tusb(); - - // RTOS forever loop - while (1) - { - // put this thread to waiting state until there is new events - tud_task(); - - // following code only run if tud_task() process at least 1 event - } -} - -//--------------------------------------------------------------------+ -// Device callbacks -//--------------------------------------------------------------------+ - -// Invoked when device is mounted -void tud_mount_cb(void) -{ - xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_MOUNTED), 0); -} - -// Invoked when device is unmounted -void tud_umount_cb(void) -{ - xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), 0); -} - -// 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; - xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_SUSPENDED), 0); -} - -// Invoked when usb bus is resumed -void tud_resume_cb(void) -{ - if (tud_mounted()) - { - xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_MOUNTED), 0); - } - else - { - xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), 0); - } -} - -//--------------------------------------------------------------------+ -// USB HID -//--------------------------------------------------------------------+ - -static void send_hid_report(uint8_t report_id, uint32_t btn) -{ - // skip if hid is not ready yet - if ( !tud_hid_ready() ) return; - - switch(report_id) - { - case REPORT_ID_KEYBOARD: - { - // use to avoid send multiple consecutive zero report for keyboard - static bool has_keyboard_key = false; - - if ( btn ) - { - uint8_t keycode[6] = { 0 }; - keycode[0] = HID_KEY_A; - - tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, keycode); - has_keyboard_key = true; - }else - { - // send empty key report if previously has key pressed - if (has_keyboard_key) tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, NULL); - has_keyboard_key = false; - } - } - break; - - case REPORT_ID_MOUSE: - { - int8_t const delta = 5; - - // no button, right + down, no scroll, no pan - tud_hid_mouse_report(REPORT_ID_MOUSE, 0x00, delta, delta, 0, 0); - } - break; - - case REPORT_ID_CONSUMER_CONTROL: - { - // use to avoid send multiple consecutive zero report - static bool has_consumer_key = false; - - if ( btn ) - { - // volume down - uint16_t volume_down = HID_USAGE_CONSUMER_VOLUME_DECREMENT; - tud_hid_report(REPORT_ID_CONSUMER_CONTROL, &volume_down, 2); - has_consumer_key = true; - }else - { - // send empty key report (release key) if previously has key pressed - uint16_t empty_key = 0; - if (has_consumer_key) tud_hid_report(REPORT_ID_CONSUMER_CONTROL, &empty_key, 2); - has_consumer_key = false; - } - } - break; - - case REPORT_ID_GAMEPAD: - { - // use to avoid send multiple consecutive zero report for keyboard - static bool has_gamepad_key = false; - - hid_gamepad_report_t report = - { - .x = 0, .y = 0, .z = 0, .rz = 0, .rx = 0, .ry = 0, - .hat = 0, .buttons = 0 - }; - - if ( btn ) - { - report.hat = GAMEPAD_HAT_UP; - report.buttons = GAMEPAD_BUTTON_A; - tud_hid_report(REPORT_ID_GAMEPAD, &report, sizeof(report)); - - has_gamepad_key = true; - }else - { - report.hat = GAMEPAD_HAT_CENTERED; - report.buttons = 0; - if (has_gamepad_key) tud_hid_report(REPORT_ID_GAMEPAD, &report, sizeof(report)); - has_gamepad_key = false; - } - } - break; - - default: break; - } -} - -void hid_task(void* param) -{ - (void) param; - - while(1) - { - // Poll every 10ms - vTaskDelay(pdMS_TO_TICKS(10)); - - uint32_t const btn = board_button_read(); - - // Remote wakeup - if ( tud_suspended() && btn ) - { - // Wake up host if we are in suspend mode - // and REMOTE_WAKEUP feature is enabled by host - tud_remote_wakeup(); - } - else - { - // Send the 1st of report chain, the rest will be sent by tud_hid_report_complete_cb() - send_hid_report(REPORT_ID_KEYBOARD, btn); - } - } -} - -// Invoked when sent REPORT successfully to host -// Application can use this to send the next report -// Note: For composite reports, report[0] is report ID -void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len) -{ - (void) instance; - (void) len; - - uint8_t next_report_id = report[0] + 1; - - if (next_report_id < REPORT_ID_COUNT) - { - send_hid_report(next_report_id, board_button_read()); - } -} - - -// Invoked when received GET_REPORT control request -// Application must fill buffer report's content and return its length. -// Return zero will cause the stack to STALL request -uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) -{ - // TODO not Implemented - (void) instance; - (void) report_id; - (void) report_type; - (void) buffer; - (void) reqlen; - - return 0; -} - -// Invoked when received SET_REPORT control request or -// received data on OUT endpoint ( Report ID = 0, Type = 0 ) -void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) -{ - (void) instance; - - if (report_type == HID_REPORT_TYPE_OUTPUT) - { - // Set keyboard LED e.g Capslock, Numlock etc... - if (report_id == REPORT_ID_KEYBOARD) - { - // bufsize should be (at least) 1 - if ( bufsize < 1 ) return; - - uint8_t const kbd_leds = buffer[0]; - - if (kbd_leds & KEYBOARD_LED_CAPSLOCK) - { - // Capslock On: disable blink, turn led on - xTimerStop(blinky_tm, portMAX_DELAY); - board_led_write(true); - }else - { - // Caplocks Off: back to normal blink - board_led_write(false); - xTimerStart(blinky_tm, portMAX_DELAY); - } - } - } -} - -//--------------------------------------------------------------------+ -// BLINKING TASK -//--------------------------------------------------------------------+ -void led_blinky_cb(TimerHandle_t xTimer) -{ - (void) xTimer; - static bool led_state = false; - - board_led_write(led_state); - led_state = 1 - led_state; // toggle -} diff --git a/examples/device/hid_composite_freertos/src/tusb_config.h b/examples/device/hid_composite_freertos/src/tusb_config.h deleted file mode 100644 index ad067ac82..000000000 --- a/examples/device/hid_composite_freertos/src/tusb_config.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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. - * - */ - -#ifndef TUSB_CONFIG_H_ -#define TUSB_CONFIG_H_ - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Board Specific Configuration -//--------------------------------------------------------------------+ - -// RHPort number used for device can be defined by board.mk, default to port 0 -#ifndef BOARD_TUD_RHPORT -#define BOARD_TUD_RHPORT 0 -#endif - -// RHPort max operational speed can defined by board.mk -#ifndef BOARD_TUD_MAX_SPEED -#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED -#endif - -//-------------------------------------------------------------------- -// COMMON CONFIGURATION -//-------------------------------------------------------------------- - -// defined by board.mk -#ifndef CFG_TUSB_MCU -#error CFG_TUSB_MCU must be defined -#endif - -// This examples use FreeRTOS -#ifndef CFG_TUSB_OS -#define CFG_TUSB_OS OPT_OS_FREERTOS -#endif - -// Espressif IDF requires "freertos/" prefix in include path -#ifdef ESP_PLATFORM -#define CFG_TUSB_OS_INC_PATH freertos/ -#endif - -// can be defined by compiler in DEBUG build -#ifndef CFG_TUSB_DEBUG -#define CFG_TUSB_DEBUG 0 -#endif - -// Enable Device stack -#define CFG_TUD_ENABLED 1 - -// Default is max speed that hardware controller could support with on-chip PHY -#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED - -/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. - * Tinyusb use follows macros to declare transferring memory so that they can be put - * into those specific section. - * e.g - * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) - * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) - */ -#ifndef CFG_TUSB_MEM_SECTION -#define CFG_TUSB_MEM_SECTION -#endif - -#ifndef CFG_TUSB_MEM_ALIGN -#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) -#endif - -//-------------------------------------------------------------------- -// DEVICE CONFIGURATION -//-------------------------------------------------------------------- - -#ifndef CFG_TUD_ENDPOINT0_SIZE -#define CFG_TUD_ENDPOINT0_SIZE 64 -#endif - -//------------- CLASS -------------// -#define CFG_TUD_HID 1 -#define CFG_TUD_CDC 0 -#define CFG_TUD_MSC 0 -#define CFG_TUD_MIDI 0 -#define CFG_TUD_VENDOR 0 - -// HID buffer size Should be sufficient to hold ID (if any) + Data -#define CFG_TUD_HID_EP_BUFSIZE 16 - -#ifdef __cplusplus - } -#endif - -#endif /* TUSB_CONFIG_H_ */ diff --git a/examples/device/hid_composite_freertos/src/usb_descriptors.c b/examples/device/hid_composite_freertos/src/usb_descriptors.c deleted file mode 100644 index a0464afae..000000000 --- a/examples/device/hid_composite_freertos/src/usb_descriptors.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * 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. - * - */ - -#include "bsp/board_api.h" -#include "tusb.h" -#include "usb_descriptors.h" - -// Unique PID per example: guarantees re-enumeration on re-flash and a fresh host driver match. -#define USB_PID 0x4011 - -#define USB_VID 0xCafe -#define USB_BCD 0x0200 - -//--------------------------------------------------------------------+ -// Device Descriptors -//--------------------------------------------------------------------+ -static tusb_desc_device_t const desc_device = -{ - .bLength = sizeof(tusb_desc_device_t), - .bDescriptorType = TUSB_DESC_DEVICE, - .bcdUSB = USB_BCD, - .bDeviceClass = 0x00, - .bDeviceSubClass = 0x00, - .bDeviceProtocol = 0x00, - .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, - - .idVendor = USB_VID, - .idProduct = USB_PID, - .bcdDevice = 0x0100, - - .iManufacturer = 0x01, - .iProduct = 0x02, - .iSerialNumber = 0x03, - - .bNumConfigurations = 0x01 -}; - -// Invoked when received GET DEVICE DESCRIPTOR -// Application return pointer to descriptor -uint8_t const * tud_descriptor_device_cb(void) -{ - return (uint8_t const *) &desc_device; -} - -//--------------------------------------------------------------------+ -// HID Report Descriptor -//--------------------------------------------------------------------+ - -uint8_t const desc_hid_report[] = -{ - TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(REPORT_ID_KEYBOARD )), - TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(REPORT_ID_MOUSE )), - TUD_HID_REPORT_DESC_CONSUMER( HID_REPORT_ID(REPORT_ID_CONSUMER_CONTROL )), - TUD_HID_REPORT_DESC_GAMEPAD ( HID_REPORT_ID(REPORT_ID_GAMEPAD )) -}; - -// Invoked when received GET HID REPORT DESCRIPTOR -// Application return pointer to descriptor -// Descriptor contents must exist long enough for transfer to complete -uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance) -{ - (void) instance; - return desc_hid_report; -} - -//--------------------------------------------------------------------+ -// Configuration Descriptor -//--------------------------------------------------------------------+ - -enum -{ - ITF_NUM_HID, - ITF_NUM_TOTAL -}; - -#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN) - -#define EPNUM_HID 0x81 - -uint8_t const desc_configuration[] = -{ - // Config number, interface count, string index, total length, attribute, power in mA - TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), - - // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval - TUD_HID_DESCRIPTOR(ITF_NUM_HID, 0, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 5) -}; - -#if TUD_OPT_HIGH_SPEED -// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration - -// other speed configuration -static uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN]; - -// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed -static tusb_desc_device_qualifier_t const desc_device_qualifier = -{ - .bLength = sizeof(tusb_desc_device_qualifier_t), - .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER, - .bcdUSB = USB_BCD, - - .bDeviceClass = 0x00, - .bDeviceSubClass = 0x00, - .bDeviceProtocol = 0x00, - - .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, - .bNumConfigurations = 0x01, - .bReserved = 0x00 -}; - -// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request -// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. -// device_qualifier descriptor describes information about a high-speed capable device that would -// change if the device were operating at the other speed. If not highspeed capable stall this request. -uint8_t const* tud_descriptor_device_qualifier_cb(void) -{ - return (uint8_t const*) &desc_device_qualifier; -} - -// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request -// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete -// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa -uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) -{ - (void) index; // for multiple configurations - - // other speed config is basically configuration with type = OTHER_SPEED_CONFIG - memcpy(desc_other_speed_config, desc_configuration, CONFIG_TOTAL_LEN); - desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG; - - // this example use the same configuration for both high and full speed mode - return desc_other_speed_config; -} - -#endif // highspeed - -// Invoked when received GET CONFIGURATION DESCRIPTOR -// Application return pointer to descriptor -// Descriptor contents must exist long enough for transfer to complete -uint8_t const * tud_descriptor_configuration_cb(uint8_t index) -{ - (void) index; // for multiple configurations - return desc_configuration; -} - -//--------------------------------------------------------------------+ -// String Descriptors -//--------------------------------------------------------------------+ - -// String Descriptor Index -enum { - STRID_LANGID = 0, - STRID_MANUFACTURER, - STRID_PRODUCT, - STRID_SERIAL, -}; - -// array of pointer to string descriptors -static char const *string_desc_arr[] = -{ - (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) - "TinyUSB", // 1: Manufacturer - "TinyUSB Device", // 2: Product - NULL, // 3: Serials will use unique ID if possible -}; - -static uint16_t _desc_str[32 + 1]; - -// Invoked when received GET STRING DESCRIPTOR request -// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete -uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { - (void) langid; - size_t chr_count; - - switch ( index ) { - case STRID_LANGID: - memcpy(&_desc_str[1], string_desc_arr[0], 2); - chr_count = 1; - break; - - case STRID_SERIAL: - chr_count = board_usb_get_serial(_desc_str + 1, 32); - break; - - default: - // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. - // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors - - if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL; - - const char *str = string_desc_arr[index]; - - // Cap at max char - chr_count = strlen(str); - size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type - if ( chr_count > max_count ) chr_count = max_count; - - // Convert ASCII string into UTF-16 - for ( size_t i = 0; i < chr_count; i++ ) { - _desc_str[1 + i] = str[i]; - } - break; - } - - // first byte is length (including header), second byte is string type - _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2)); - - return _desc_str; -} diff --git a/examples/device/hid_composite_freertos/src/usb_descriptors.h b/examples/device/hid_composite_freertos/src/usb_descriptors.h deleted file mode 100644 index e733d31dd..000000000 --- a/examples/device/hid_composite_freertos/src/usb_descriptors.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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. - */ - -#ifndef USB_DESCRIPTORS_H_ -#define USB_DESCRIPTORS_H_ - -enum -{ - REPORT_ID_KEYBOARD = 1, - REPORT_ID_MOUSE, - REPORT_ID_CONSUMER_CONTROL, - REPORT_ID_GAMEPAD, - REPORT_ID_COUNT -}; - -#endif /* USB_DESCRIPTORS_H_ */ diff --git a/examples/device/midi_test/CMakeLists.txt b/examples/device/midi_test/CMakeLists.txt index 09fbf20f0..496fc122b 100644 --- a/examples/device/midi_test/CMakeLists.txt +++ b/examples/device/midi_test/CMakeLists.txt @@ -25,6 +25,6 @@ target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src ) -# Configure compilation flags and libraries for the example without RTOS. +# Configure compilation flags and libraries for the selected RTOS. # See the corresponding function in hw/bsp/FAMILY/family.cmake for details. -family_configure_device_example(${PROJECT_NAME} noos) +family_configure_device_example(${PROJECT_NAME} ${RTOS}) diff --git a/examples/device/midi_test/skip.txt b/examples/device/midi_test/skip.txt index 2c6c2a64c..e93f35f24 100644 --- a/examples/device/midi_test/skip.txt +++ b/examples/device/midi_test/skip.txt @@ -1 +1,20 @@ -family:espressif +rtos:noos family:espressif + +rtos:freertos mcu:CH32F20X +rtos:freertos mcu:CH32V103 +rtos:freertos mcu:CH32V20X +rtos:freertos mcu:CH32V307 +rtos:freertos mcu:CH583 +rtos:freertos mcu:CXD56 +rtos:freertos mcu:F1C100S +rtos:freertos mcu:GD32VF103 +rtos:freertos mcu:MCXA15 +rtos:freertos mcu:MKL25ZXX +rtos:freertos mcu:MSP430x5xx +rtos:freertos mcu:FT90X +rtos:freertos mcu:SAMD11 +rtos:freertos mcu:VALENTYUSB_EPTRI +rtos:freertos mcu:RAXXX +rtos:freertos family:broadcom_32bit +rtos:freertos family:broadcom_64bit +rtos:freertos family:hpmicro diff --git a/examples/device/midi_test_freertos/src/CMakeLists.txt b/examples/device/midi_test/src/CMakeLists.txt similarity index 100% rename from examples/device/midi_test_freertos/src/CMakeLists.txt rename to examples/device/midi_test/src/CMakeLists.txt diff --git a/examples/device/midi_test/src/main.c b/examples/device/midi_test/src/main.c index 1154c1d60..3e86d2dd6 100644 --- a/examples/device/midi_test/src/main.c +++ b/examples/device/midi_test/src/main.c @@ -54,13 +54,21 @@ enum { static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; -void led_blinking_task(void); -void midi_task(void); +void led_blinking_task(void *param); +void midi_task(void *param); + +#if CFG_TUSB_OS == OPT_OS_FREERTOS +static void usb_device_task(void *param); +static void freertos_init(void); +#endif /*------------- MAIN -------------*/ int main(void) { board_init(); +#if CFG_TUSB_OS == OPT_OS_FREERTOS + freertos_init(); +#else // init device stack on configured roothub port tusb_rhport_init_t dev_init = { .role = TUSB_ROLE_DEVICE, @@ -72,9 +80,12 @@ int main(void) { while (1) { tud_task(); // tinyusb device task - led_blinking_task(); - midi_task(); + led_blinking_task(NULL); + midi_task(NULL); } +#endif + + return 0; } //--------------------------------------------------------------------+ @@ -118,65 +129,157 @@ const uint8_t note_sequence[] = { 56,61,64,68,74,78,81,86,90,93,98,102 }; -void midi_task(void) -{ - static uint32_t start_ms = 0; - +void midi_task(void *param) { + (void) param; uint8_t const cable_num = 0; // MIDI jack associated with USB endpoint uint8_t const channel = 0; // 0 for channel 1 - // The MIDI interface always creates input and output port/jack descriptors - // regardless of these being used or not. Therefore incoming traffic should be read - // (possibly just discarded) to avoid the sender blocking in IO - while (tud_midi_available()) { - uint8_t packet[4]; - tud_midi_packet_read(packet); - } + while (1) { + // The MIDI interface always creates input and output port/jack descriptors + // regardless of these being used or not. Therefore incoming traffic should be read + // (possibly just discarded) to avoid the sender blocking in IO + while (tud_midi_available()) { + uint8_t packet[4]; + tud_midi_packet_read(packet); + } - // send note periodically - if (tusb_time_millis_api() - start_ms < 286) { - return; // not enough time - } - start_ms += 286; +#if CFG_TUSB_OS == OPT_OS_FREERTOS + vTaskDelay(286 / portTICK_PERIOD_MS); +#else + static uint32_t start_ms = 0; + // send note periodically + if (tusb_time_millis_api() - start_ms < 286) { + return; // not enough time + } + start_ms += 286; +#endif - // Previous positions in the note sequence. - int previous = (int) (note_pos - 1); + // Previous positions in the note sequence. + int previous = (int) (note_pos - 1); - // If we currently are at position 0, set the - // previous position to the last note in the sequence. - if (previous < 0) { - previous = sizeof(note_sequence) - 1; - } + // If we currently are at position 0, set the + // previous position to the last note in the sequence. + if (previous < 0) { + previous = sizeof(note_sequence) - 1; + } - // Send Note On for current position at full velocity (127) on channel 1. - uint8_t note_on[3] = { 0x90 | channel, note_sequence[note_pos], 127 }; - tud_midi_stream_write(cable_num, note_on, 3); + // Send Note On for current position at full velocity (127) on channel 1. + uint8_t note_on[3] = { 0x90 | channel, note_sequence[note_pos], 127 }; + tud_midi_stream_write(cable_num, note_on, 3); - // Send Note Off for previous note. - uint8_t note_off[3] = { 0x80 | channel, note_sequence[previous], 0}; - tud_midi_stream_write(cable_num, note_off, 3); + // Send Note Off for previous note. + uint8_t note_off[3] = { 0x80 | channel, note_sequence[previous], 0}; + tud_midi_stream_write(cable_num, note_off, 3); - // Increment position - note_pos++; + // Increment position + note_pos++; - // If we are at the end of the sequence, start over. - if (note_pos >= sizeof(note_sequence)) { - note_pos = 0; + // If we are at the end of the sequence, start over. + if (note_pos >= sizeof(note_sequence)) { + note_pos = 0; + } + +#if CFG_TUSB_OS != OPT_OS_FREERTOS + break; +#endif } } //--------------------------------------------------------------------+ // BLINKING TASK //--------------------------------------------------------------------+ -void led_blinking_task(void) -{ - static uint32_t start_ms = 0; +void led_blinking_task(void *param) { + (void) param; static bool led_state = false; +#if CFG_TUSB_OS != OPT_OS_FREERTOS + static uint32_t start_ms = 0; +#endif - // 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); +#else + // Blink every interval ms + if (tusb_time_millis_api() - start_ms < blink_interval_ms) { + return; // not enough time + } + start_ms += blink_interval_ms; +#endif - board_led_write(led_state); - led_state = 1 - led_state; // toggle + board_led_write(led_state); + led_state = 1 - led_state; // toggle + +#if CFG_TUSB_OS != OPT_OS_FREERTOS + break; +#endif + } } + +//--------------------------------------------------------------------+ +// FreeRTOS +//--------------------------------------------------------------------+ +#if CFG_TUSB_OS == OPT_OS_FREERTOS + +#ifdef ESP_PLATFORM + #define USBD_STACK_SIZE 4096 + +void app_main(void) { + main(); +} +#else + // Increase stack size when debug log is enabled + #define USBD_STACK_SIZE ((3 * configMINIMAL_STACK_SIZE / 2) * (CFG_TUSB_DEBUG ? 2 : 1)) +#endif + +#define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE +#define MIDI_STACK_SIZE (configMINIMAL_STACK_SIZE * (CFG_TUSB_DEBUG ? 2 : 1)) + +#if configSUPPORT_STATIC_ALLOCATION +StackType_t blinky_stack[BLINKY_STACK_SIZE]; +StaticTask_t blinky_taskdef; + +StackType_t usb_device_stack[USBD_STACK_SIZE]; +StaticTask_t usb_device_taskdef; + +StackType_t midi_stack[MIDI_STACK_SIZE]; +StaticTask_t midi_taskdef; +#endif + +// USB Device Driver task +// This top level thread processes all USB events and invokes callbacks. +static void usb_device_task(void *param) { + (void) param; + + // init device stack on configured roothub port. + // This should be called after scheduler/kernel is started. + // Otherwise, it could cause kernel issue since USB IRQ handler uses RTOS queue API. + tusb_rhport_init_t dev_init = { + .role = TUSB_ROLE_DEVICE, + .speed = TUSB_SPEED_AUTO + }; + tusb_init(BOARD_TUD_RHPORT, &dev_init); + + board_init_after_tusb(); + + while (1) { + tud_task();// tinyusb device task + } +} + +static void freertos_init(void) { +#if configSUPPORT_STATIC_ALLOCATION + xTaskCreateStatic(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, blinky_stack, &blinky_taskdef); + xTaskCreateStatic(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, usb_device_stack, &usb_device_taskdef); + xTaskCreateStatic(midi_task, "midi", MIDI_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, midi_stack, &midi_taskdef); +#else + xTaskCreate(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, NULL); + xTaskCreate(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL); + xTaskCreate(midi_task, "midi", MIDI_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, NULL); +#endif + +#ifndef ESP_PLATFORM + vTaskStartScheduler(); +#endif +} + +#endif diff --git a/examples/device/midi_test/src/tusb_config.h b/examples/device/midi_test/src/tusb_config.h index f4282b2d7..3e47af7bb 100644 --- a/examples/device/midi_test/src/tusb_config.h +++ b/examples/device/midi_test/src/tusb_config.h @@ -57,6 +57,11 @@ #define CFG_TUSB_OS OPT_OS_NONE #endif +// Espressif IDF requires "freertos/" prefix in include path +#ifdef ESP_PLATFORM +#define CFG_TUSB_OS_INC_PATH freertos/ +#endif + #ifndef CFG_TUSB_DEBUG #define CFG_TUSB_DEBUG 0 #endif diff --git a/examples/device/midi_test_freertos/CMakeLists.txt b/examples/device/midi_test_freertos/CMakeLists.txt deleted file mode 100644 index 7e5d3e89e..000000000 --- a/examples/device/midi_test_freertos/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -cmake_minimum_required(VERSION 3.20) - -include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake) - -project(midi_test_freertos C CXX ASM) - -# Checks this example is valid for the family and initializes the project -family_initialize_project(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}) - -# Espressif has its own cmake build system -if(FAMILY STREQUAL "espressif") - return() -endif() - -add_executable(${PROJECT_NAME}) - -# Example source -target_sources(${PROJECT_NAME} PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c - ) - -# Example include -target_include_directories(${PROJECT_NAME} PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/src - ) - -# Configure compilation flags and libraries for the example with FreeRTOS. -# See the corresponding function in hw/bsp/FAMILY/family.cmake for details. -family_configure_device_example(${PROJECT_NAME} freertos) diff --git a/examples/device/midi_test_freertos/CMakePresets.json b/examples/device/midi_test_freertos/CMakePresets.json deleted file mode 100644 index 5cd8971e9..000000000 --- a/examples/device/midi_test_freertos/CMakePresets.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "version": 6, - "include": [ - "../../../hw/bsp/BoardPresets.json" - ] -} diff --git a/examples/device/midi_test_freertos/Makefile b/examples/device/midi_test_freertos/Makefile deleted file mode 100644 index ebacfecdf..000000000 --- a/examples/device/midi_test_freertos/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -RTOS = freertos -include ../../../hw/bsp/family_support.mk - -INC += \ - src \ - - -# Example source -EXAMPLE_SOURCE += \ - src/main.c \ - src/usb_descriptors.c \ - -SRC_C += $(addprefix $(EXAMPLE_PATH)/, $(EXAMPLE_SOURCE)) - -include ../../../hw/bsp/family_rules.mk diff --git a/examples/device/midi_test_freertos/skip.txt b/examples/device/midi_test_freertos/skip.txt deleted file mode 100644 index 97d8e168b..000000000 --- a/examples/device/midi_test_freertos/skip.txt +++ /dev/null @@ -1,18 +0,0 @@ -mcu:CH32F20X -mcu:CH32V103 -mcu:CH32V20X -mcu:CH32V307 -mcu:CH583 -mcu:CXD56 -mcu:F1C100S -mcu:GD32VF103 -mcu:MCXA15 -mcu:MKL25ZXX -mcu:MSP430x5xx -mcu:FT90X -mcu:SAMD11 -mcu:VALENTYUSB_EPTRI -mcu:RAXXX -family:broadcom_32bit -family:broadcom_64bit -family:hpmicro diff --git a/examples/device/midi_test_freertos/src/main.c b/examples/device/midi_test_freertos/src/main.c deleted file mode 100644 index f5267214e..000000000 --- a/examples/device/midi_test_freertos/src/main.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - * 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. - * - */ - -#include -#include -#include - -#include "bsp/board_api.h" -#include "tusb.h" - -/* This MIDI example send sequence of note (on/off) repeatedly. To test on PC, you need to install - * synth software and midi connection management software. On - * - Linux (Ubuntu): install qsynth, qjackctl. Then connect TinyUSB output port to FLUID Synth input port - * - Windows: install MIDI-OX - * - MacOS: SimpleSynth - */ - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF PROTYPES -//--------------------------------------------------------------------+ -#ifdef ESP_PLATFORM - #define USBD_STACK_SIZE 4096 -#else - // Increase stack size when debug log is enabled - #define USBD_STACK_SIZE (3*configMINIMAL_STACK_SIZE/2) * (CFG_TUSB_DEBUG ? 2 : 1) -#endif - -#define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE -#define MIDI_STACK_SIZE (configMINIMAL_STACK_SIZE * (CFG_TUSB_DEBUG ? 2 : 1)) - -// static task -#if configSUPPORT_STATIC_ALLOCATION -StackType_t blinky_stack[BLINKY_STACK_SIZE]; -StaticTask_t blinky_taskdef; - -StackType_t usb_device_stack[USBD_STACK_SIZE]; -StaticTask_t usb_device_taskdef; - -StackType_t midi_stack[MIDI_STACK_SIZE]; -StaticTask_t midi_taskdef; -#endif - -/* Blink pattern - * - 250 ms : device not mounted - * - 1000 ms : device mounted - * - 2500 ms : device is suspended - */ -enum { - BLINK_NOT_MOUNTED = 250, - BLINK_MOUNTED = 1000, - BLINK_SUSPENDED = 2500, -}; - -static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; - -void usb_device_task(void *param); -void led_blinking_task(void* param); -void midi_task(void* param); - -//--------------------------------------------------------------------+ -// Main -//--------------------------------------------------------------------+ -int main(void) { - board_init(); - -#if configSUPPORT_STATIC_ALLOCATION - xTaskCreateStatic(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, blinky_stack, &blinky_taskdef); - xTaskCreateStatic(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES-1, usb_device_stack, &usb_device_taskdef); - xTaskCreateStatic(midi_task, "midi", MIDI_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, midi_stack, &midi_taskdef); -#else - xTaskCreate(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, NULL); - xTaskCreate(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL); - xTaskCreate(midi_task, "midi", MIDI_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, NULL); -#endif - -#ifndef ESP_PLATFORM - // only start scheduler for non-espressif mcu - vTaskStartScheduler(); -#endif - - return 0; -} - -#ifdef ESP_PLATFORM -void app_main(void) { - main(); -} -#endif - -// USB Device Driver task -// This top level thread process all usb events and invoke callbacks -void usb_device_task(void *param) { - (void) param; - - // init device stack on configured roothub port - // This should be called after scheduler/kernel is started. - // Otherwise it could cause kernel issue since USB IRQ handler does use RTOS queue API. - tusb_rhport_init_t dev_init = { - .role = TUSB_ROLE_DEVICE, - .speed = TUSB_SPEED_AUTO - }; - tusb_init(BOARD_TUD_RHPORT, &dev_init); - - board_init_after_tusb(); - - // RTOS forever loop - while (1) { - // put this thread to waiting state until there is new events - tud_task(); - } -} - -//--------------------------------------------------------------------+ -// 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; -} - -//--------------------------------------------------------------------+ -// MIDI Task -//--------------------------------------------------------------------+ - -// Store example melody as an array of note values -const uint8_t note_sequence[] = { - 74,78,81,86,90,93,98,102,57,61,66,69,73,78,81,85,88,92,97,100,97,92,88,85,81,78, - 74,69,66,62,57,62,66,69,74,78,81,86,90,93,97,102,97,93,90,85,81,78,73,68,64,61, - 56,61,64,68,74,78,81,86,90,93,98,102 -}; - -void midi_task(void* param) { - (void) param; - - const uint8_t cable_num = 0; // MIDI jack associated with USB endpoint - const uint8_t channel = 0; // 0 for channel 1 - - // Variable that holds the current position in the sequence. - uint32_t note_pos = 0; - - while (1) { - // send note periodically - vTaskDelay(286 / portTICK_PERIOD_MS); - - // Previous positions in the note sequence. - int previous = (int) (note_pos - 1); - - // If we currently are at position 0, set the - // previous position to the last note in the sequence. - if (previous < 0) { - previous = sizeof(note_sequence) - 1; - } - - // Send Note On for current position at full velocity (127) on channel 1. - uint8_t note_on[3] = { 0x90 | channel, note_sequence[note_pos], 127 }; - tud_midi_stream_write(cable_num, note_on, 3); - - // Send Note Off for previous note. - uint8_t note_off[3] = { 0x80 | channel, note_sequence[previous], 0}; - tud_midi_stream_write(cable_num, note_off, 3); - - // Increment position - note_pos++; - - // If we are at the end of the sequence, start over. - if (note_pos >= sizeof(note_sequence)) { - note_pos = 0; - } - - // The MIDI interface always creates input and output port/jack descriptors - // regardless of these being used or not. Therefore incoming traffic should be read - // (possibly just discarded) to avoid the sender blocking in IO - while (tud_midi_available()) { - uint8_t packet[4]; - tud_midi_packet_read(packet); - } - } -} - -//--------------------------------------------------------------------+ -// BLINKING TASK -//--------------------------------------------------------------------+ -void led_blinking_task(void* param) { - (void) param; - static bool led_state = false; - - while (1) { - // Blink every interval ms - vTaskDelay(blink_interval_ms / portTICK_PERIOD_MS); - - board_led_write(led_state); - led_state = 1 - led_state; // toggle - } -} diff --git a/examples/device/midi_test_freertos/src/tusb_config.h b/examples/device/midi_test_freertos/src/tusb_config.h deleted file mode 100644 index c158f5197..000000000 --- a/examples/device/midi_test_freertos/src/tusb_config.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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. - * - */ - -#ifndef TUSB_CONFIG_H_ -#define TUSB_CONFIG_H_ - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Board Specific Configuration -//--------------------------------------------------------------------+ - -// RHPort number used for device can be defined by board.mk, default to port 0 -#ifndef BOARD_TUD_RHPORT -#define BOARD_TUD_RHPORT 0 -#endif - -// RHPort max operational speed can defined by board.mk -#ifndef BOARD_TUD_MAX_SPEED -#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED -#endif - -//-------------------------------------------------------------------- -// COMMON CONFIGURATION -//-------------------------------------------------------------------- - -// defined by compiler flags for flexibility -#ifndef CFG_TUSB_MCU -#error CFG_TUSB_MCU must be defined -#endif - -#ifndef CFG_TUSB_OS -#define CFG_TUSB_OS OPT_OS_FREERTOS -#endif - -#ifndef CFG_TUSB_DEBUG -#define CFG_TUSB_DEBUG 0 -#endif - -// Enable Device stack -#define CFG_TUD_ENABLED 1 - -// Default is max speed that hardware controller could support with on-chip PHY -#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED - -/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. - * Tinyusb use follows macros to declare transferring memory so that they can be put - * into those specific section. - * e.g - * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) - * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) - */ -#ifndef CFG_TUSB_MEM_SECTION -#define CFG_TUSB_MEM_SECTION -#endif - -#ifndef CFG_TUSB_MEM_ALIGN -#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) -#endif - -//-------------------------------------------------------------------- -// DEVICE CONFIGURATION -//-------------------------------------------------------------------- - -#ifndef CFG_TUD_ENDPOINT0_SIZE -#define CFG_TUD_ENDPOINT0_SIZE 64 -#endif - -//------------- CLASS -------------// -#define CFG_TUD_CDC 0 -#define CFG_TUD_MSC 0 -#define CFG_TUD_HID 0 -#define CFG_TUD_MIDI 1 -#define CFG_TUD_VENDOR 0 - -// MIDI FIFO size of TX and RX -#define CFG_TUD_MIDI_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) -#define CFG_TUD_MIDI_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) - -#ifdef __cplusplus - } -#endif - -#endif /* TUSB_CONFIG_H_ */ diff --git a/examples/device/midi_test_freertos/src/usb_descriptors.c b/examples/device/midi_test_freertos/src/usb_descriptors.c deleted file mode 100644 index bfdbc555e..000000000 --- a/examples/device/midi_test_freertos/src/usb_descriptors.c +++ /dev/null @@ -1,192 +0,0 @@ -/* - * 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. - * - */ - -#include "bsp/board_api.h" -#include "tusb.h" - -// Unique PID per example: guarantees re-enumeration on re-flash and a fresh host driver match. -#define USB_PID 0x4015 - -//--------------------------------------------------------------------+ -// Device Descriptors -//--------------------------------------------------------------------+ -static tusb_desc_device_t const desc_device = { - .bLength = sizeof(tusb_desc_device_t), - .bDescriptorType = TUSB_DESC_DEVICE, - .bcdUSB = 0x0200, - .bDeviceClass = 0x00, - .bDeviceSubClass = 0x00, - .bDeviceProtocol = 0x00, - .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, - - .idVendor = 0xCafe, - .idProduct = USB_PID, - .bcdDevice = 0x0100, - - .iManufacturer = 0x01, - .iProduct = 0x02, - .iSerialNumber = 0x03, - - .bNumConfigurations = 0x01 -}; - -// Invoked when received GET DEVICE DESCRIPTOR -// Application return pointer to descriptor -uint8_t const * tud_descriptor_device_cb(void) { - return (uint8_t const *) &desc_device; -} -//--------------------------------------------------------------------+ -// Configuration Descriptor -//--------------------------------------------------------------------+ -enum { - ITF_NUM_MIDI = 0, - ITF_NUM_MIDI_STREAMING, - ITF_NUM_TOTAL -}; - -#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MIDI_DESC_LEN) - -#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX - // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number - // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ... - #define EPNUM_MIDI_OUT 0x02 - #define EPNUM_MIDI_IN 0x82 - -#elif CFG_TUSB_MCU == OPT_MCU_CXD56 - // CXD56 USB driver has fixed endpoint type (bulk/interrupt/iso) and direction (IN/OUT) by its number - // 0 control (IN/OUT), 1 Bulk (IN), 2 Bulk (OUT), 3 In (IN), 4 Bulk (IN), 5 Bulk (OUT), 6 In (IN) - #define EPNUM_MIDI_OUT 0x02 - #define EPNUM_MIDI_IN 0x81 - -#elif CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY - // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h - // e.g EP1 OUT & EP1 IN cannot exist together - #define EPNUM_MIDI_OUT 0x01 - #define EPNUM_MIDI_IN 0x82 - -#else - #define EPNUM_MIDI_OUT 0x01 - #define EPNUM_MIDI_IN 0x81 -#endif - -static uint8_t const desc_fs_configuration[] = { - // Config number, interface count, string index, total length, attribute, power in mA - TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), - - // Interface number, string index, EP Out & EP In address, EP size - TUD_MIDI_DESCRIPTOR(ITF_NUM_MIDI, 0, EPNUM_MIDI_OUT, (0x80 | EPNUM_MIDI_IN), 64) -}; - -#if TUD_OPT_HIGH_SPEED -static uint8_t const desc_hs_configuration[] = { - // Config number, interface count, string index, total length, attribute, power in mA - TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), - - // Interface number, string index, EP Out & EP In address, EP size - TUD_MIDI_DESCRIPTOR(ITF_NUM_MIDI, 0, EPNUM_MIDI_OUT, (0x80 | EPNUM_MIDI_IN), 512) -}; -#endif - -// Invoked when received GET CONFIGURATION DESCRIPTOR -// Application return pointer to descriptor -// Descriptor contents must exist long enough for transfer to complete -uint8_t const * tud_descriptor_configuration_cb(uint8_t index) { - (void) index; // for multiple configurations - -#if TUD_OPT_HIGH_SPEED - // Although we are highspeed, host may be fullspeed. - return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration; -#else - return desc_fs_configuration; -#endif -} - -//--------------------------------------------------------------------+ -// String Descriptors -//--------------------------------------------------------------------+ - -// String Descriptor Index -enum { - STRID_LANGID = 0, - STRID_MANUFACTURER, - STRID_PRODUCT, - STRID_SERIAL, -}; - -// array of pointer to string descriptors -static char const *string_desc_arr[] = { - (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) - "TinyUSB", // 1: Manufacturer - "TinyUSB Device", // 2: Product - NULL, // 3: Serials will use unique ID if possible -}; - -static uint16_t _desc_str[32 + 1]; - -// Invoked when received GET STRING DESCRIPTOR request -// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete -uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { - (void) langid; - size_t chr_count; - - switch ( index ) { - case STRID_LANGID: - memcpy(&_desc_str[1], string_desc_arr[0], 2); - chr_count = 1; - break; - - case STRID_SERIAL: - chr_count = board_usb_get_serial(_desc_str + 1, 32); - break; - - default: - // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. - // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors - - if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0]))) { - return NULL; - } - - const char *str = string_desc_arr[index]; - - // Cap at max char - chr_count = strlen(str); - const size_t max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type - if ( chr_count > max_count ) { - chr_count = max_count; - } - - // Convert ASCII string into UTF-16 - for ( size_t i = 0; i < chr_count; i++ ) { - _desc_str[1 + i] = str[i]; - } - break; - } - - // first byte is length (including header), second byte is string type - _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2)); - - return _desc_str; -} diff --git a/examples/device/uac2_speaker_fb/CMakeLists.txt b/examples/device/uac2_speaker_fb/CMakeLists.txt index cddbf6a31..1965596e1 100644 --- a/examples/device/uac2_speaker_fb/CMakeLists.txt +++ b/examples/device/uac2_speaker_fb/CMakeLists.txt @@ -2,6 +2,11 @@ cmake_minimum_required(VERSION 3.20) include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake) +# Need to set Espressif defaults before project() is called +if(FAMILY STREQUAL "espressif") + list(APPEND SDKCONFIG_DEFAULTS "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults") +endif() + project(uac2_speaker_fb C CXX ASM) # Checks this example is valid for the family and initializes the project @@ -25,6 +30,6 @@ target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src ) -# Configure compilation flags and libraries for the example without RTOS. +# Configure compilation flags and libraries for the selected RTOS. # See the corresponding function in hw/bsp/FAMILY/family.cmake for details. -family_configure_device_example(${PROJECT_NAME} noos) +family_configure_device_example(${PROJECT_NAME} ${RTOS}) diff --git a/examples/device/uac2_speaker_fb/freertos_merge_todo.md b/examples/device/uac2_speaker_fb/freertos_merge_todo.md new file mode 100644 index 000000000..c1e7450c3 --- /dev/null +++ b/examples/device/uac2_speaker_fb/freertos_merge_todo.md @@ -0,0 +1,11 @@ +# UAC2 Speaker FreeRTOS Merge TODO + +Goal: keep `uac2_speaker_fb` as one example that can build in no-OS mode by default and FreeRTOS mode with the existing `RTOS=freertos` / `-DRTOS=freertos` build switch. + +- [x] Keep the existing no-OS speaker behavior unchanged. +- [x] Fold the FreeRTOS task setup from `uac2_speaker_freertos` into `src/main.c`. +- [x] Add ESP-IDF component metadata and FreeRTOS sdkconfig defaults. +- [x] Let CMake choose the RTOS through `${RTOS}` instead of hardcoding `noos`. +- [x] Keep Make defaulting to no-OS while allowing `RTOS=freertos`. +- [x] Keep Espressif build discovery aware of the merged example. +- [x] Verify at least CMake configure/build targets for no-OS and FreeRTOS. diff --git a/examples/device/uac2_speaker_fb/sdkconfig.defaults b/examples/device/uac2_speaker_fb/sdkconfig.defaults new file mode 100644 index 000000000..eaa9fb902 --- /dev/null +++ b/examples/device/uac2_speaker_fb/sdkconfig.defaults @@ -0,0 +1,4 @@ +CONFIG_IDF_CMAKE=y +CONFIG_FREERTOS_HZ=1000 +CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y +CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y diff --git a/examples/device/uac2_speaker_fb/src/CMakeLists.txt b/examples/device/uac2_speaker_fb/src/CMakeLists.txt new file mode 100644 index 000000000..cef2b46ee --- /dev/null +++ b/examples/device/uac2_speaker_fb/src/CMakeLists.txt @@ -0,0 +1,4 @@ +# This file is for ESP-IDF only +idf_component_register(SRCS "main.c" "usb_descriptors.c" + INCLUDE_DIRS "." + REQUIRES boards tinyusb_src) diff --git a/examples/device/uac2_speaker_fb/src/main.c b/examples/device/uac2_speaker_fb/src/main.c index 7e4d27f1c..e09015382 100644 --- a/examples/device/uac2_speaker_fb/src/main.c +++ b/examples/device/uac2_speaker_fb/src/main.c @@ -74,8 +74,13 @@ uint32_t current_sample_rate = 44100; // Buffer for speaker data uint16_t i2s_dummy_buffer[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ / 2]; -void led_blinking_task(void); -void audio_task(void); +void led_blinking_task(void *param); +void audio_task(void *param); + +#if CFG_TUSB_OS == OPT_OS_FREERTOS +static void usb_device_task(void *param); +static void freertos_init(void); +#endif #if CFG_AUDIO_DEBUG void audio_debug_task(void); @@ -88,6 +93,9 @@ volatile uint32_t fifo_count_avg; int main(void) { board_init(); +#if CFG_TUSB_OS == OPT_OS_FREERTOS + freertos_init(); +#else // init device stack on configured roothub port tusb_rhport_init_t dev_init = { .role = TUSB_ROLE_DEVICE, @@ -100,12 +108,15 @@ int main(void) { while (1) { tud_task();// TinyUSB device task - led_blinking_task(); + led_blinking_task(NULL); #if CFG_AUDIO_DEBUG audio_debug_task(); #endif - audio_task(); + audio_task(NULL); } +#endif + + return 0; } //--------------------------------------------------------------------+ @@ -587,40 +598,58 @@ bool tud_audio_rx_done_isr(uint8_t rhport, uint16_t n_bytes_received, uint8_t fu // This task simulates an audio transmit callback, one frame is sent every 1ms. // In a real application, this would be replaced with actual I2S transmit callback. -void audio_task(void) { +void audio_task(void *param) { + (void) param; static uint32_t start_ms = 0; - uint32_t curr_ms = tusb_time_millis_api(); - if (start_ms == curr_ms) return;// not enough time - start_ms = curr_ms; - uint16_t length = (uint16_t) (current_sample_rate / 1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX); + while (1) { + uint32_t curr_ms = tusb_time_millis_api(); + if (start_ms != curr_ms) { + start_ms = curr_ms; - if (current_sample_rate == 44100 && (curr_ms % 10 == 0)) { - // Take one more sample every 10 cycles, to have a average reading speed of 44.1 - // This correction is not needed in real world cases - length += CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX; - } else if (current_sample_rate == 88200 && (curr_ms % 5 == 0)) { - // Take one more sample every 5 cycles, to have a average reading speed of 88.2 - // This correction is not needed in real world cases - length += CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX; + uint16_t length = (uint16_t) (current_sample_rate / 1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX); + + if (current_sample_rate == 44100 && (curr_ms % 10 == 0)) { + // Take one more sample every 10 cycles, to have a average reading speed of 44.1 + // This correction is not needed in real world cases + length += CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX; + } else if (current_sample_rate == 88200 && (curr_ms % 5 == 0)) { + // Take one more sample every 5 cycles, to have a average reading speed of 88.2 + // This correction is not needed in real world cases + length += CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX; + } + + tud_audio_read(i2s_dummy_buffer, length); + } + +#if CFG_TUSB_OS == OPT_OS_FREERTOS + vTaskDelay(1); +#else + return; +#endif } - - tud_audio_read(i2s_dummy_buffer, length); } //--------------------------------------------------------------------+ // BLINKING TASK //--------------------------------------------------------------------+ -void led_blinking_task(void) { - static uint32_t start_ms = 0; +void led_blinking_task(void *param) { + (void) param; static bool led_state = false; - // Blink every interval ms - if (tusb_time_millis_api() - start_ms < blink_interval_ms) return; - start_ms += blink_interval_ms; + while (1) { +#if CFG_TUSB_OS == OPT_OS_FREERTOS + vTaskDelay(blink_interval_ms / portTICK_PERIOD_MS); +#else + static uint32_t start_ms = 0; + // Blink every interval ms + if (tusb_time_millis_api() - start_ms < blink_interval_ms) return; + start_ms += blink_interval_ms; +#endif - board_led_write(led_state); - led_state = 1 - led_state; + board_led_write(led_state); + led_state = 1 - led_state; + } } #if CFG_AUDIO_DEBUG @@ -674,3 +703,76 @@ void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t rep } #endif + +//--------------------------------------------------------------------+ +// FreeRTOS +//--------------------------------------------------------------------+ +#if CFG_TUSB_OS == OPT_OS_FREERTOS + +#define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE +#define AUDIO_STACK_SIZE (configMINIMAL_STACK_SIZE * (CFG_TUSB_DEBUG ? 3 : 2)) + +#ifdef ESP_PLATFORM + #define USBD_STACK_SIZE 4096 + +void app_main(void) { + main(); +} +#else + #define USBD_STACK_SIZE (configMINIMAL_STACK_SIZE * (CFG_TUSB_DEBUG ? 4 : 2)) +#endif + +#if configSUPPORT_STATIC_ALLOCATION +StackType_t blinky_stack[BLINKY_STACK_SIZE]; +StaticTask_t blinky_taskdef; + +StackType_t usb_device_stack[USBD_STACK_SIZE]; +StaticTask_t usb_device_taskdef; + +StackType_t audio_stack[AUDIO_STACK_SIZE]; +StaticTask_t audio_taskdef; +#endif + +// USB Device Driver task +// This top level thread processes all USB events and invokes callbacks. +static void usb_device_task(void *param) { + (void) param; + + // init device stack on configured roothub port. + // This should be called after scheduler/kernel is started. + // Otherwise, it could cause kernel issue since USB IRQ handler uses RTOS queue API. + tusb_rhport_init_t dev_init = { + .role = TUSB_ROLE_DEVICE, + .speed = TUSB_SPEED_AUTO + }; + tusb_init(BOARD_TUD_RHPORT, &dev_init); + + board_init_after_tusb(); + + TU_LOG1("Speaker running\r\n"); + + while (1) { + tud_task();// TinyUSB device task +#if CFG_AUDIO_DEBUG + audio_debug_task(); +#endif + } +} + +static void freertos_init(void) { +#if configSUPPORT_STATIC_ALLOCATION + xTaskCreateStatic(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, blinky_stack, &blinky_taskdef); + xTaskCreateStatic(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, usb_device_stack, &usb_device_taskdef); + xTaskCreateStatic(audio_task, "audio", AUDIO_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, audio_stack, &audio_taskdef); +#else + xTaskCreate(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, NULL); + xTaskCreate(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL); + xTaskCreate(audio_task, "audio", AUDIO_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, NULL); +#endif + +#ifndef ESP_PLATFORM + vTaskStartScheduler(); +#endif +} + +#endif diff --git a/examples/device/uac2_speaker_fb/src/tusb_config.h b/examples/device/uac2_speaker_fb/src/tusb_config.h index 46f5703c8..0e42bb29c 100644 --- a/examples/device/uac2_speaker_fb/src/tusb_config.h +++ b/examples/device/uac2_speaker_fb/src/tusb_config.h @@ -60,6 +60,11 @@ extern "C" { #define CFG_TUSB_OS OPT_OS_NONE #endif +// Espressif IDF requires "freertos/" prefix in include path +#ifdef ESP_PLATFORM +#define CFG_TUSB_OS_INC_PATH freertos/ +#endif + // It's recommended to disable debug unless for control requests debugging, // as the extra time needed will impact data stream ! #ifndef CFG_TUSB_DEBUG