mirror of
https://github.com/hathach/tinyusb.git
synced 2025-04-23 17:42:22 +00:00
Merge pull request #2270 from hathach/add-max3421-esp32
Add max3421 support for esp32
This commit is contained in:
commit
b394ae1786
21
.github/workflows/build_esp.yml
vendored
21
.github/workflows/build_esp.yml
vendored
@ -29,12 +29,10 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
board:
|
board:
|
||||||
# Alphabetical order
|
|
||||||
# ESP32-S2
|
# ESP32-S2
|
||||||
- 'espressif_saola_1'
|
- 'espressif_kaluga_1'
|
||||||
# ESP32-S3
|
# ESP32-S3
|
||||||
#- 'espressif_s3_devkitm'
|
- 'espressif_s3_devkitm'
|
||||||
# S3 compile error with "dangerous relocation: call8: call target out of range: memcpy"
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
@ -48,20 +46,5 @@ jobs:
|
|||||||
- name: Checkout TinyUSB
|
- name: Checkout TinyUSB
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Checkout hathach/linkermap
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
repository: hathach/linkermap
|
|
||||||
path: linkermap
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: docker run --rm -v $PWD:/project -w /project espressif/idf:latest python3 tools/build_esp32.py ${{ matrix.board }}
|
run: docker run --rm -v $PWD:/project -w /project espressif/idf:latest python3 tools/build_esp32.py ${{ matrix.board }}
|
||||||
|
|
||||||
- name: Linker Map
|
|
||||||
run: |
|
|
||||||
pip install linkermap/
|
|
||||||
# find -quit to only print linkermap of 1 board per example
|
|
||||||
for ex in `ls -d examples/device/*/`
|
|
||||||
do
|
|
||||||
find ${ex} -maxdepth 3 -name *.map -print -quit | xargs -I % sh -c 'echo "::group::%"; linkermap -v %; echo "::endgroup::"'
|
|
||||||
done
|
|
||||||
|
26
.idea/cmake.xml
generated
26
.idea/cmake.xml
generated
@ -2,23 +2,24 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="CMakeSharedSettings">
|
<component name="CMakeSharedSettings">
|
||||||
<configurations>
|
<configurations>
|
||||||
<configuration PROFILE_NAME="esp32s2" ENABLED="false" GENERATION_OPTIONS="-DBOARD=espressif_saola_1 -DIDF_TARGET=esp32s2">
|
<configuration PROFILE_NAME="esp32s2" ENABLED="false" TOOLCHAIN_NAME="ESP-IDF" GENERATION_OPTIONS="-DBOARD=espressif_saola_1">
|
||||||
<ADDITIONAL_GENERATION_ENVIRONMENT>
|
<ADDITIONAL_GENERATION_ENVIRONMENT>
|
||||||
<envs>
|
<envs>
|
||||||
<env name="ESPBAUD" value="1500000" />
|
<env name="ESPBAUD" value="1500000" />
|
||||||
<env name="ESPPORT" value="/dev/ttyUSB0" />
|
|
||||||
<env name="IDF_PATH" value="$PROJECT_DIR$/../esp-idf" />
|
|
||||||
<env name="PATH" value="$PROJECT_DIR$/../esp-idf/components/esptool_py/esptool:/home/hathach/code/esp-idf/components/espcoredump:/home/hathach/code/esp-idf/components/partition_table:/home/hathach/code/esp-idf/components/app_update:/home/hathach/.espressif/tools/xtensa-esp-elf-gdb/11.2_20220823/xtensa-esp-elf-gdb/bin:/home/hathach/.espressif/tools/riscv32-esp-elf-gdb/11.2_20220823/riscv32-esp-elf-gdb/bin:/home/hathach/.espressif/tools/xtensa-esp32-elf/esp-2021r2-patch5-8.4.0/xtensa-esp32-elf/bin:/home/hathach/.espressif/tools/xtensa-esp32s2-elf/esp-2021r2-patch5-8.4.0/xtensa-esp32s2-elf/bin:/home/hathach/.espressif/tools/xtensa-esp32s3-elf/esp-2021r2-patch5-8.4.0/xtensa-esp32s3-elf/bin:/home/hathach/.espressif/tools/riscv32-esp-elf/esp-2021r2-patch5-8.4.0/riscv32-esp-elf/bin:/home/hathach/.espressif/tools/esp32ulp-elf/2.35_20220830/esp32ulp-elf/bin:/home/hathach/.espressif/tools/openocd-esp32/v0.11.0-esp32-20221026/openocd-esp32/bin:/home/hathach/.espressif/python_env/idf4.4_py3.10_env/bin:/home/hathach/code/esp-idf/tools:/home/hathach/app/riscv-openocd-wch/src:/home/hathach/app/arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-eabi/bin:/home/hathach/.local/bin:/home/hathach/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin:/opt/SEGGER/JLink:/home/hathach/app/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf/bin:/home/hathach/.local/xPacks/@xpack-dev-tools/riscv-none-embed-gcc/10.2.0-1.2.1/.content/bin:/home/hathach/.local/xPacks/@xpack-dev-tools/openocd/*/.content/bin:/home/hathach/ti/msp430-gcc/bin:/home/hathach/ti/MSPFlasher_1.3.20:/home/hathach/ti/uniflash_7.0.0:/home/hathach/app/gcc_8.3.0.202102_gnurx-elf/bin:/home/hathach/app/RFP_CLI_Linux_V31101_x64/linux-x64:/home/hathach/app/fomu-toolchain-linux_x86_64-v1.5.5/bin:/home/hathach/app/nuclei_riscv_newlibc_prebuilt_linux64_2020.08/gcc/bin:/home/hathach/app/riscv32-embecosm-ubuntu2004-gcc11.1.0/bin:/home/hathach/app/cov-analysis-linux64-2019.03/bin:/opt/iarsystems/bxarm/arm/bin:/home/hathach/.local/bin" />
|
|
||||||
</envs>
|
</envs>
|
||||||
</ADDITIONAL_GENERATION_ENVIRONMENT>
|
</ADDITIONAL_GENERATION_ENVIRONMENT>
|
||||||
</configuration>
|
</configuration>
|
||||||
<configuration PROFILE_NAME="esp32s3" ENABLED="false" GENERATION_OPTIONS="-DBOARD=espressif_s3_devkitm -DIDF_TARGET=esp32s3">
|
<configuration PROFILE_NAME="kaluga" ENABLED="true" TOOLCHAIN_NAME="ESP-IDF" GENERATION_OPTIONS="-DBOARD=espressif_kaluga_1 -DMAX3421_HOST=1 -DLOG=2">
|
||||||
|
<ADDITIONAL_GENERATION_ENVIRONMENT>
|
||||||
|
<envs>
|
||||||
|
<env name="ESPBAUD" value="1500000" />
|
||||||
|
</envs>
|
||||||
|
</ADDITIONAL_GENERATION_ENVIRONMENT>
|
||||||
|
</configuration>
|
||||||
|
<configuration PROFILE_NAME="esp32s3" ENABLED="false" TOOLCHAIN_NAME="ESP-IDF" GENERATION_OPTIONS="-DBOARD=espressif_s3_devkitm">
|
||||||
<ADDITIONAL_GENERATION_ENVIRONMENT>
|
<ADDITIONAL_GENERATION_ENVIRONMENT>
|
||||||
<envs>
|
<envs>
|
||||||
<env name="ESPBAUD" value="1500000" />
|
<env name="ESPBAUD" value="1500000" />
|
||||||
<env name="ESPPORT" value="/dev/ttyUSB0" />
|
|
||||||
<env name="IDF_PATH" value="$PROJECT_DIR$/../esp-idf" />
|
|
||||||
<env name="PATH" value="$PROJECT_DIR$/../esp-idf/components/esptool_py/esptool:/home/hathach/code/esp-idf/components/espcoredump:/home/hathach/code/esp-idf/components/partition_table:/home/hathach/code/esp-idf/components/app_update:/home/hathach/.espressif/tools/xtensa-esp-elf-gdb/11.2_20220823/xtensa-esp-elf-gdb/bin:/home/hathach/.espressif/tools/riscv32-esp-elf-gdb/11.2_20220823/riscv32-esp-elf-gdb/bin:/home/hathach/.espressif/tools/xtensa-esp32-elf/esp-2021r2-patch5-8.4.0/xtensa-esp32-elf/bin:/home/hathach/.espressif/tools/xtensa-esp32s2-elf/esp-2021r2-patch5-8.4.0/xtensa-esp32s2-elf/bin:/home/hathach/.espressif/tools/xtensa-esp32s3-elf/esp-2021r2-patch5-8.4.0/xtensa-esp32s3-elf/bin:/home/hathach/.espressif/tools/riscv32-esp-elf/esp-2021r2-patch5-8.4.0/riscv32-esp-elf/bin:/home/hathach/.espressif/tools/esp32ulp-elf/2.35_20220830/esp32ulp-elf/bin:/home/hathach/.espressif/tools/openocd-esp32/v0.11.0-esp32-20221026/openocd-esp32/bin:/home/hathach/.espressif/python_env/idf4.4_py3.10_env/bin:/home/hathach/code/esp-idf/tools:/home/hathach/app/riscv-openocd-wch/src:/home/hathach/app/arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-eabi/bin:/home/hathach/.local/bin:/home/hathach/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin:/opt/SEGGER/JLink:/home/hathach/app/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf/bin:/home/hathach/.local/xPacks/@xpack-dev-tools/riscv-none-embed-gcc/10.2.0-1.2.1/.content/bin:/home/hathach/.local/xPacks/@xpack-dev-tools/openocd/*/.content/bin:/home/hathach/ti/msp430-gcc/bin:/home/hathach/ti/MSPFlasher_1.3.20:/home/hathach/ti/uniflash_7.0.0:/home/hathach/app/gcc_8.3.0.202102_gnurx-elf/bin:/home/hathach/app/RFP_CLI_Linux_V31101_x64/linux-x64:/home/hathach/app/fomu-toolchain-linux_x86_64-v1.5.5/bin:/home/hathach/app/nuclei_riscv_newlibc_prebuilt_linux64_2020.08/gcc/bin:/home/hathach/app/riscv32-embecosm-ubuntu2004-gcc11.1.0/bin:/home/hathach/app/cov-analysis-linux64-2019.03/bin:/opt/iarsystems/bxarm/arm/bin:/home/hathach/.local/bin" />
|
|
||||||
</envs>
|
</envs>
|
||||||
</ADDITIONAL_GENERATION_ENVIRONMENT>
|
</ADDITIONAL_GENERATION_ENVIRONMENT>
|
||||||
</configuration>
|
</configuration>
|
||||||
@ -53,9 +54,16 @@
|
|||||||
<configuration PROFILE_NAME="ra6m5 PORT0" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=ra6m5_ek -DLOG=3 -DLOGGER=RTT -DTRACE_ETM=1 -DPORT=0" />
|
<configuration PROFILE_NAME="ra6m5 PORT0" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=ra6m5_ek -DLOG=3 -DLOGGER=RTT -DTRACE_ETM=1 -DPORT=0" />
|
||||||
<configuration PROFILE_NAME="uno_r4" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=uno_r4 -DLOG=4 -DLOGGER=RTT" />
|
<configuration PROFILE_NAME="uno_r4" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=uno_r4 -DLOG=4 -DLOGGER=RTT" />
|
||||||
<configuration PROFILE_NAME="portenta_c33" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=portenta_c33 -DLOG=3" />
|
<configuration PROFILE_NAME="portenta_c33" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=portenta_c33 -DLOG=3" />
|
||||||
<configuration PROFILE_NAME="metro_m4_express" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=metro_m4_express -DLOG=3 -DLOGGER=RTT -DMAX3421_HOST=1" />
|
<configuration PROFILE_NAME="metro_m4_express" ENABLED="true" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=metro_m4_express -DLOG=3 -DLOGGER=RTT -DMAX3421_HOST=1" />
|
||||||
<configuration PROFILE_NAME="metro_m0_express" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=metro_m0_express -DLOG=3 -DLOGGER=RTT -DMAX3421_HOST=1" />
|
<configuration PROFILE_NAME="metro_m0_express" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=metro_m0_express -DLOG=3 -DLOGGER=RTT -DMAX3421_HOST=1" />
|
||||||
<configuration PROFILE_NAME="stm32u5" ENABLED="true" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32u575eval" />
|
<configuration PROFILE_NAME="stm32u5" ENABLED="true" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32u575eval" />
|
||||||
|
<configuration PROFILE_NAME="metro esp32s2" ENABLED="false" TOOLCHAIN_NAME="ESP-IDF" GENERATION_OPTIONS="-DBOARD=adafruit_metro_esp32s2 -DMAX3421_HOST=1 -DLOG=2">
|
||||||
|
<ADDITIONAL_GENERATION_ENVIRONMENT>
|
||||||
|
<envs>
|
||||||
|
<env name="ESPBAUD" value="1500000" />
|
||||||
|
</envs>
|
||||||
|
</ADDITIONAL_GENERATION_ENVIRONMENT>
|
||||||
|
</configuration>
|
||||||
</configurations>
|
</configurations>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
@ -1,5 +1,3 @@
|
|||||||
DEPS_SUBMODULES += lib/FreeRTOS-Kernel
|
|
||||||
|
|
||||||
include ../../make.mk
|
include ../../make.mk
|
||||||
|
|
||||||
FREERTOS_SRC = lib/FreeRTOS-Kernel
|
FREERTOS_SRC = lib/FreeRTOS-Kernel
|
||||||
@ -10,7 +8,7 @@ INC += \
|
|||||||
src/FreeRTOSConfig \
|
src/FreeRTOSConfig \
|
||||||
$(TOP)/hw \
|
$(TOP)/hw \
|
||||||
$(TOP)/$(FREERTOS_SRC)/include \
|
$(TOP)/$(FREERTOS_SRC)/include \
|
||||||
$(TOP)/$(FREERTOS_PORTABLE_SRC)
|
$(TOP)/$(FREERTOS_PORTABLE_SRC) \
|
||||||
|
|
||||||
# Example source
|
# Example source
|
||||||
EXAMPLE_SOURCE = \
|
EXAMPLE_SOURCE = \
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
|
|
||||||
#define USBD_STACK_SIZE 4096
|
#define USBD_STACK_SIZE 4096
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
#include "semphr.h"
|
#include "semphr.h"
|
||||||
#include "queue.h"
|
#include "queue.h"
|
||||||
@ -54,7 +55,7 @@
|
|||||||
#define CDC_STACK_SZIE configMINIMAL_STACK_SIZE
|
#define CDC_STACK_SZIE configMINIMAL_STACK_SIZE
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// MACRO CONSTANT TYPEDEF PROTYPES
|
// MACRO CONSTANT TYPEDEF PROTOTYPES
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
/* Blink pattern
|
/* Blink pattern
|
||||||
@ -81,16 +82,15 @@ StaticTask_t cdc_taskdef;
|
|||||||
|
|
||||||
TimerHandle_t blinky_tm;
|
TimerHandle_t blinky_tm;
|
||||||
|
|
||||||
void led_blinky_cb(TimerHandle_t xTimer);
|
static void led_blinky_cb(TimerHandle_t xTimer);
|
||||||
void usb_device_task(void* param);
|
static void usb_device_task(void *param);
|
||||||
void cdc_task(void *params);
|
void cdc_task(void *params);
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// Main
|
// Main
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
int main(void)
|
int main(void) {
|
||||||
{
|
|
||||||
board_init();
|
board_init();
|
||||||
|
|
||||||
#if configSUPPORT_STATIC_ALLOCATION
|
#if configSUPPORT_STATIC_ALLOCATION
|
||||||
@ -119,16 +119,14 @@ int main(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
|
#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
|
||||||
void app_main(void)
|
void app_main(void) {
|
||||||
{
|
|
||||||
main();
|
main();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// USB Device Driver task
|
// USB Device Driver task
|
||||||
// This top level thread process all usb events and invoke callbacks
|
// This top level thread process all usb events and invoke callbacks
|
||||||
void usb_device_task(void* param)
|
static void usb_device_task(void *param) {
|
||||||
{
|
|
||||||
(void) param;
|
(void) param;
|
||||||
|
|
||||||
// init device stack on configured roothub port
|
// init device stack on configured roothub port
|
||||||
@ -141,8 +139,7 @@ void usb_device_task(void* param)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RTOS forever loop
|
// RTOS forever loop
|
||||||
while (1)
|
while (1) {
|
||||||
{
|
|
||||||
// put this thread to waiting state until there is new events
|
// put this thread to waiting state until there is new events
|
||||||
tud_task();
|
tud_task();
|
||||||
|
|
||||||
@ -156,35 +153,28 @@ void usb_device_task(void* param)
|
|||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
// Invoked when device is mounted
|
// Invoked when device is mounted
|
||||||
void tud_mount_cb(void)
|
void tud_mount_cb(void) {
|
||||||
{
|
|
||||||
xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_MOUNTED), 0);
|
xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_MOUNTED), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoked when device is unmounted
|
// Invoked when device is unmounted
|
||||||
void tud_umount_cb(void)
|
void tud_umount_cb(void) {
|
||||||
{
|
|
||||||
xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), 0);
|
xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoked when usb bus is suspended
|
// Invoked when usb bus is suspended
|
||||||
// remote_wakeup_en : if host allow us to perform remote wakeup
|
// 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
|
// 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 tud_suspend_cb(bool remote_wakeup_en) {
|
||||||
{
|
|
||||||
(void) remote_wakeup_en;
|
(void) remote_wakeup_en;
|
||||||
xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_SUSPENDED), 0);
|
xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_SUSPENDED), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoked when usb bus is resumed
|
// Invoked when usb bus is resumed
|
||||||
void tud_resume_cb(void)
|
void tud_resume_cb(void) {
|
||||||
{
|
if (tud_mounted()) {
|
||||||
if (tud_mounted())
|
|
||||||
{
|
|
||||||
xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_MOUNTED), 0);
|
xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_MOUNTED), 0);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), 0);
|
xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,20 +182,17 @@ void tud_resume_cb(void)
|
|||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// USB CDC
|
// USB CDC
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
void cdc_task(void* params)
|
void cdc_task(void *params) {
|
||||||
{
|
|
||||||
(void) params;
|
(void) params;
|
||||||
|
|
||||||
// RTOS forever loop
|
// RTOS forever loop
|
||||||
while ( 1 )
|
while (1) {
|
||||||
{
|
|
||||||
// connected() check for DTR bit
|
// connected() check for DTR bit
|
||||||
// Most but not all terminal client set this when making connection
|
// Most but not all terminal client set this when making connection
|
||||||
// if ( tud_cdc_connected() )
|
// if ( tud_cdc_connected() )
|
||||||
{
|
{
|
||||||
// There are data available
|
// There are data available
|
||||||
while ( tud_cdc_available() )
|
while (tud_cdc_available()) {
|
||||||
{
|
|
||||||
uint8_t buf[64];
|
uint8_t buf[64];
|
||||||
|
|
||||||
// read and echo back
|
// read and echo back
|
||||||
@ -228,32 +215,27 @@ void cdc_task(void* params)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoked when cdc when line state changed e.g connected/disconnected
|
// 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 tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) {
|
||||||
{
|
|
||||||
(void) itf;
|
(void) itf;
|
||||||
(void) rts;
|
(void) rts;
|
||||||
|
|
||||||
// TODO set some indicator
|
// TODO set some indicator
|
||||||
if ( dtr )
|
if (dtr) {
|
||||||
{
|
|
||||||
// Terminal connected
|
// Terminal connected
|
||||||
}else
|
} else {
|
||||||
{
|
|
||||||
// Terminal disconnected
|
// Terminal disconnected
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoked when CDC interface received data from host
|
// Invoked when CDC interface received data from host
|
||||||
void tud_cdc_rx_cb(uint8_t itf)
|
void tud_cdc_rx_cb(uint8_t itf) {
|
||||||
{
|
|
||||||
(void) itf;
|
(void) itf;
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// BLINKING TASK
|
// BLINKING TASK
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
void led_blinky_cb(TimerHandle_t xTimer)
|
static void led_blinky_cb(TimerHandle_t xTimer) {
|
||||||
{
|
|
||||||
(void) xTimer;
|
(void) xTimer;
|
||||||
static bool led_state = false;
|
static bool led_state = false;
|
||||||
|
|
||||||
|
@ -10,6 +10,11 @@ project(${PROJECT} C CXX ASM)
|
|||||||
# Checks this example is valid for the family and initializes the project
|
# Checks this example is valid for the family and initializes the project
|
||||||
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
|
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
|
||||||
|
# Espressif has its own cmake build system
|
||||||
|
if(FAMILY STREQUAL "espressif")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
add_executable(${PROJECT})
|
add_executable(${PROJECT})
|
||||||
|
|
||||||
# Example source
|
# Example source
|
||||||
|
@ -10,14 +10,4 @@ EXAMPLE_SOURCE += \
|
|||||||
|
|
||||||
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
|
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
|
||||||
|
|
||||||
# TinyUSB Host Stack source
|
|
||||||
SRC_C += \
|
|
||||||
src/class/cdc/cdc_host.c \
|
|
||||||
src/class/hid/hid_host.c \
|
|
||||||
src/class/msc/msc_host.c \
|
|
||||||
src/host/hub.c \
|
|
||||||
src/host/usbh.c \
|
|
||||||
src/portable/ohci/ohci.c \
|
|
||||||
src/portable/nxp/lpc17_40/hcd_lpc17_40.c
|
|
||||||
|
|
||||||
include ../../rules.mk
|
include ../../rules.mk
|
||||||
|
@ -10,6 +10,11 @@ project(${PROJECT} C CXX ASM)
|
|||||||
# Checks this example is valid for the family and initializes the project
|
# Checks this example is valid for the family and initializes the project
|
||||||
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
|
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
|
||||||
|
# Espressif has its own cmake build system
|
||||||
|
if(FAMILY STREQUAL "espressif")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
add_executable(${PROJECT})
|
add_executable(${PROJECT})
|
||||||
|
|
||||||
# Example source
|
# Example source
|
||||||
|
@ -13,14 +13,4 @@ EXAMPLE_SOURCE = \
|
|||||||
|
|
||||||
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
|
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
|
||||||
|
|
||||||
# TinyUSB Host Stack source
|
|
||||||
SRC_C += \
|
|
||||||
src/class/cdc/cdc_host.c \
|
|
||||||
src/class/hid/hid_host.c \
|
|
||||||
src/class/msc/msc_host.c \
|
|
||||||
src/host/hub.c \
|
|
||||||
src/host/usbh.c \
|
|
||||||
src/portable/ohci/ohci.c \
|
|
||||||
src/portable/nxp/lpc17_40/hcd_lpc17_40.c
|
|
||||||
|
|
||||||
include ../../rules.mk
|
include ../../rules.mk
|
||||||
|
36
examples/host/cdc_msc_hid_freertos/CMakeLists.txt
Normal file
36
examples/host/cdc_msc_hid_freertos/CMakeLists.txt
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.17)
|
||||||
|
|
||||||
|
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
|
||||||
|
|
||||||
|
# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
|
||||||
|
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
|
||||||
|
project(${PROJECT} C CXX ASM)
|
||||||
|
|
||||||
|
# Checks this example is valid for the family and initializes the project
|
||||||
|
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
|
||||||
|
# Espressif has its own cmake build system
|
||||||
|
if(FAMILY STREQUAL "espressif")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_executable(${PROJECT})
|
||||||
|
|
||||||
|
# Example source
|
||||||
|
target_sources(${PROJECT} PUBLIC
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/cdc_app.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/freertos_hook.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/hid_app.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/msc_app.c
|
||||||
|
)
|
||||||
|
|
||||||
|
# Example include
|
||||||
|
target_include_directories(${PROJECT} PUBLIC
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||||
|
)
|
||||||
|
|
||||||
|
# Configure compilation flags and libraries for the example without RTOS.
|
||||||
|
# See the corresponding function in hw/bsp/FAMILY/family.cmake for details.
|
||||||
|
family_configure_host_example(${PROJECT} freertos)
|
34
examples/host/cdc_msc_hid_freertos/Makefile
Normal file
34
examples/host/cdc_msc_hid_freertos/Makefile
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
include ../../make.mk
|
||||||
|
|
||||||
|
FREERTOS_SRC = lib/FreeRTOS-Kernel
|
||||||
|
FREERTOS_PORTABLE_PATH= $(FREERTOS_SRC)/portable/$(if $(USE_IAR),IAR,GCC)
|
||||||
|
|
||||||
|
INC += \
|
||||||
|
src \
|
||||||
|
src/FreeRTOSConfig \
|
||||||
|
$(TOP)/hw \
|
||||||
|
$(TOP)/$(FREERTOS_SRC)/include \
|
||||||
|
$(TOP)/$(FREERTOS_PORTABLE_SRC) \
|
||||||
|
|
||||||
|
# Example source
|
||||||
|
EXAMPLE_SOURCE = \
|
||||||
|
src/cdc_app.c \
|
||||||
|
src/freertos_hook.c \
|
||||||
|
src/hid_app.c \
|
||||||
|
src/main.c \
|
||||||
|
src/msc_app.c \
|
||||||
|
|
||||||
|
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
|
||||||
|
|
||||||
|
# FreeRTOS source, all files in port folder
|
||||||
|
SRC_C += \
|
||||||
|
$(FREERTOS_SRC)/list.c \
|
||||||
|
$(FREERTOS_SRC)/queue.c \
|
||||||
|
$(FREERTOS_SRC)/tasks.c \
|
||||||
|
$(FREERTOS_SRC)/timers.c \
|
||||||
|
$(subst $(TOP)/,,$(wildcard $(TOP)/$(FREERTOS_PORTABLE_SRC)/*.c))
|
||||||
|
|
||||||
|
SRC_S += \
|
||||||
|
$(subst $(TOP)/,,$(wildcard $(TOP)/$(FREERTOS_PORTABLE_SRC)/*.s))
|
||||||
|
|
||||||
|
include ../../rules.mk
|
13
examples/host/cdc_msc_hid_freertos/only.txt
Normal file
13
examples/host/cdc_msc_hid_freertos/only.txt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
mcu:LPC175X_6X
|
||||||
|
mcu:LPC177X_8X
|
||||||
|
mcu:LPC18XX
|
||||||
|
mcu:LPC40XX
|
||||||
|
mcu:LPC43XX
|
||||||
|
mcu:MIMXRT1XXX
|
||||||
|
mcu:MIMXRT10XX
|
||||||
|
mcu:MIMXRT11XX
|
||||||
|
mcu:RP2040
|
||||||
|
mcu:MSP432E4
|
||||||
|
mcu:RX65X
|
||||||
|
mcu:RAXXX
|
||||||
|
mcu:MAX3421
|
6
examples/host/cdc_msc_hid_freertos/src/CMakeLists.txt
Normal file
6
examples/host/cdc_msc_hid_freertos/src/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# This file is for ESP-IDF only
|
||||||
|
idf_component_register(SRCS "cdc_app.c" "hid_app.c" "main.c" "msc_app.c"
|
||||||
|
INCLUDE_DIRS "."
|
||||||
|
REQUIRES boards tinyusb_src)
|
||||||
|
|
||||||
|
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-error=format)
|
@ -0,0 +1,215 @@
|
|||||||
|
/*
|
||||||
|
* FreeRTOS Kernel V10.0.0
|
||||||
|
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* 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. If you wish to use our Amazon
|
||||||
|
* FreeRTOS name, please do so in a fair use way that does not cause confusion.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org
|
||||||
|
* http://aws.amazon.com/freertos
|
||||||
|
*
|
||||||
|
* 1 tab == 4 spaces!
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FREERTOS_CONFIG_H
|
||||||
|
#define FREERTOS_CONFIG_H
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------
|
||||||
|
* Application specific definitions.
|
||||||
|
*
|
||||||
|
* These definitions should be adjusted for your particular hardware and
|
||||||
|
* application requirements.
|
||||||
|
*
|
||||||
|
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
|
||||||
|
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
|
||||||
|
*
|
||||||
|
* See http://www.freertos.org/a00110.html.
|
||||||
|
*----------------------------------------------------------*/
|
||||||
|
|
||||||
|
// skip if included from IAR assembler
|
||||||
|
#ifndef __IASMARM__
|
||||||
|
|
||||||
|
// Include MCU header
|
||||||
|
#include "bsp/board_mcu.h"
|
||||||
|
|
||||||
|
#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3
|
||||||
|
#error "ESP32-Sx should use IDF's FreeRTOSConfig.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wredundant-decls"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// TODO fix later
|
||||||
|
// FIXME cause redundant-decls warnings
|
||||||
|
#if CFG_TUSB_MCU == OPT_MCU_MM32F327X
|
||||||
|
extern u32 SystemCoreClock;
|
||||||
|
#else
|
||||||
|
extern uint32_t SystemCoreClock;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Cortex M23/M33 port configuration. */
|
||||||
|
#define configENABLE_MPU 0
|
||||||
|
#define configENABLE_FPU 1
|
||||||
|
#define configENABLE_TRUSTZONE 0
|
||||||
|
#define configMINIMAL_SECURE_STACK_SIZE ( 1024 )
|
||||||
|
|
||||||
|
#define configUSE_PREEMPTION 1
|
||||||
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
#define configCPU_CLOCK_HZ SystemCoreClock
|
||||||
|
#define configTICK_RATE_HZ ( 1000 )
|
||||||
|
#define configMAX_PRIORITIES ( 5 )
|
||||||
|
#define configMINIMAL_STACK_SIZE ( 128 )
|
||||||
|
#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 )
|
||||||
|
#define configMAX_TASK_NAME_LEN 16
|
||||||
|
#define configUSE_16_BIT_TICKS 0
|
||||||
|
#define configIDLE_SHOULD_YIELD 1
|
||||||
|
#define configUSE_MUTEXES 1
|
||||||
|
#define configUSE_RECURSIVE_MUTEXES 1
|
||||||
|
#define configUSE_COUNTING_SEMAPHORES 1
|
||||||
|
#define configQUEUE_REGISTRY_SIZE 4
|
||||||
|
#define configUSE_QUEUE_SETS 0
|
||||||
|
#define configUSE_TIME_SLICING 0
|
||||||
|
#define configUSE_NEWLIB_REENTRANT 0
|
||||||
|
#define configENABLE_BACKWARD_COMPATIBILITY 1
|
||||||
|
#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0
|
||||||
|
|
||||||
|
#define configSUPPORT_STATIC_ALLOCATION 1
|
||||||
|
#define configSUPPORT_DYNAMIC_ALLOCATION 0
|
||||||
|
|
||||||
|
/* Hook function related definitions. */
|
||||||
|
#define configUSE_IDLE_HOOK 0
|
||||||
|
#define configUSE_TICK_HOOK 0
|
||||||
|
#define configUSE_MALLOC_FAILED_HOOK 0 // cause nested extern warning
|
||||||
|
#define configCHECK_FOR_STACK_OVERFLOW 2
|
||||||
|
|
||||||
|
/* Run time and task stats gathering related definitions. */
|
||||||
|
#define configGENERATE_RUN_TIME_STATS 0
|
||||||
|
#define configUSE_TRACE_FACILITY 1 // legacy trace
|
||||||
|
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
|
||||||
|
|
||||||
|
/* Co-routine definitions. */
|
||||||
|
#define configUSE_CO_ROUTINES 0
|
||||||
|
#define configMAX_CO_ROUTINE_PRIORITIES 2
|
||||||
|
|
||||||
|
/* Software timer related definitions. */
|
||||||
|
#define configUSE_TIMERS 1
|
||||||
|
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-2)
|
||||||
|
#define configTIMER_QUEUE_LENGTH 32
|
||||||
|
#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
|
||||||
|
|
||||||
|
/* Optional functions - most linkers will remove unused functions anyway. */
|
||||||
|
#define INCLUDE_vTaskPrioritySet 0
|
||||||
|
#define INCLUDE_uxTaskPriorityGet 0
|
||||||
|
#define INCLUDE_vTaskDelete 0
|
||||||
|
#define INCLUDE_vTaskSuspend 1 // required for queue, semaphore, mutex to be blocked indefinitely with portMAX_DELAY
|
||||||
|
#define INCLUDE_xResumeFromISR 0
|
||||||
|
#define INCLUDE_vTaskDelayUntil 1
|
||||||
|
#define INCLUDE_vTaskDelay 1
|
||||||
|
#define INCLUDE_xTaskGetSchedulerState 0
|
||||||
|
#define INCLUDE_xTaskGetCurrentTaskHandle 0
|
||||||
|
#define INCLUDE_uxTaskGetStackHighWaterMark 0
|
||||||
|
#define INCLUDE_xTaskGetIdleTaskHandle 0
|
||||||
|
#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0
|
||||||
|
#define INCLUDE_pcTaskGetTaskName 0
|
||||||
|
#define INCLUDE_eTaskGetState 0
|
||||||
|
#define INCLUDE_xEventGroupSetBitFromISR 0
|
||||||
|
#define INCLUDE_xTimerPendFunctionCall 0
|
||||||
|
|
||||||
|
/* Define to trap errors during development. */
|
||||||
|
// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7
|
||||||
|
#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__)
|
||||||
|
#define configASSERT(_exp) \
|
||||||
|
do {\
|
||||||
|
if ( !(_exp) ) { \
|
||||||
|
volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \
|
||||||
|
if ( (*ARM_CM_DHCSR) & 1UL ) { /* Only halt mcu if debugger is attached */ \
|
||||||
|
taskDISABLE_INTERRUPTS(); \
|
||||||
|
__asm("BKPT #0\n"); \
|
||||||
|
}\
|
||||||
|
}\
|
||||||
|
} while(0)
|
||||||
|
#else
|
||||||
|
#define configASSERT( x )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __RX__
|
||||||
|
/* Renesas RX series */
|
||||||
|
#define vSoftwareInterruptISR INT_Excep_ICU_SWINT
|
||||||
|
#define vTickISR INT_Excep_CMT0_CMI0
|
||||||
|
#define configPERIPHERAL_CLOCK_HZ (configCPU_CLOCK_HZ/2)
|
||||||
|
#define configKERNEL_INTERRUPT_PRIORITY 1
|
||||||
|
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 4
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* FreeRTOS hooks to NVIC vectors */
|
||||||
|
#define xPortPendSVHandler PendSV_Handler
|
||||||
|
#define xPortSysTickHandler SysTick_Handler
|
||||||
|
#define vPortSVCHandler SVC_Handler
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Interrupt nesting behavior configuration.
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
#if defined(__NVIC_PRIO_BITS)
|
||||||
|
// For Cortex-M specific: __NVIC_PRIO_BITS is defined in core_cmx.h
|
||||||
|
#define configPRIO_BITS __NVIC_PRIO_BITS
|
||||||
|
|
||||||
|
#elif defined(__ECLIC_INTCTLBITS)
|
||||||
|
// RISC-V Bumblebee core from nuclei
|
||||||
|
#define configPRIO_BITS __ECLIC_INTCTLBITS
|
||||||
|
|
||||||
|
#elif defined(__IASMARM__)
|
||||||
|
// FIXME: IAR Assembler cannot include mcu header directly to get __NVIC_PRIO_BITS.
|
||||||
|
// Therefore we will hard coded it to minimum value of 2 to get pass ci build.
|
||||||
|
// IAR user must update this to correct value of the target MCU
|
||||||
|
#message "configPRIO_BITS is hard coded to 2 to pass IAR build only. User should update it per MCU"
|
||||||
|
#define configPRIO_BITS 2
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "FreeRTOS configPRIO_BITS to be defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The lowest interrupt priority that can be used in a call to a "set priority" function. */
|
||||||
|
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1<<configPRIO_BITS) - 1)
|
||||||
|
|
||||||
|
/* The highest interrupt priority that can be used by any interrupt service
|
||||||
|
routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
|
||||||
|
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
|
||||||
|
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
|
||||||
|
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 2
|
||||||
|
|
||||||
|
/* Interrupt priorities used by the kernel port layer itself. These are generic
|
||||||
|
to all Cortex-M ports, and do not rely on any particular library functions. */
|
||||||
|
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
|
||||||
|
|
||||||
|
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
|
||||||
|
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
|
||||||
|
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __FREERTOS_CONFIG__H */
|
145
examples/host/cdc_msc_hid_freertos/src/cdc_app.c
Normal file
145
examples/host/cdc_msc_hid_freertos/src/cdc_app.c
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022, Ha Thach (tinyusb.org)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* This file is part of the TinyUSB stack.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tusb.h"
|
||||||
|
#include "bsp/board_api.h"
|
||||||
|
|
||||||
|
#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
|
||||||
|
// 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 CDC_STACK_SZIE 2048
|
||||||
|
#else
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "semphr.h"
|
||||||
|
#include "queue.h"
|
||||||
|
#include "task.h"
|
||||||
|
#include "timers.h"
|
||||||
|
|
||||||
|
#define CDC_STACK_SZIE (3*configMINIMAL_STACK_SIZE/2)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
#if configSUPPORT_STATIC_ALLOCATION
|
||||||
|
StackType_t cdc_stack[CDC_STACK_SZIE];
|
||||||
|
StaticTask_t cdc_taskdef;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void cdc_app_task(void* param);
|
||||||
|
|
||||||
|
void cdc_app_init(void) {
|
||||||
|
#if configSUPPORT_STATIC_ALLOCATION
|
||||||
|
xTaskCreateStatic(cdc_app_task, "cdc", CDC_STACK_SZIE, NULL, configMAX_PRIORITIES-2, cdc_stack, &cdc_taskdef);
|
||||||
|
#else
|
||||||
|
xTaskCreate(cdc_app_task, "cdc", CDC_STACK_SZIE, NULL, configMAX_PRIORITIES-2, NULL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper
|
||||||
|
size_t get_console_inputs(uint8_t *buf, size_t bufsize) {
|
||||||
|
size_t count = 0;
|
||||||
|
while (count < bufsize) {
|
||||||
|
int ch = board_getchar();
|
||||||
|
if (ch <= 0) break;
|
||||||
|
|
||||||
|
buf[count] = (uint8_t) ch;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cdc_app_task(void* param) {
|
||||||
|
(void) param;
|
||||||
|
|
||||||
|
uint8_t buf[64 + 1]; // +1 for extra null character
|
||||||
|
uint32_t const bufsize = sizeof(buf) - 1;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
uint32_t count = get_console_inputs(buf, bufsize);
|
||||||
|
buf[count] = 0;
|
||||||
|
|
||||||
|
if (count) {
|
||||||
|
// loop over all mounted interfaces
|
||||||
|
for (uint8_t idx = 0; idx < CFG_TUH_CDC; idx++) {
|
||||||
|
if (tuh_cdc_mounted(idx)) {
|
||||||
|
// console --> cdc interfaces
|
||||||
|
tuh_cdc_write(idx, buf, count);
|
||||||
|
tuh_cdc_write_flush(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskDelay(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// TinyUSB Callbacks
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// Invoked when received new data
|
||||||
|
void tuh_cdc_rx_cb(uint8_t idx) {
|
||||||
|
uint8_t buf[64 + 1]; // +1 for extra null character
|
||||||
|
uint32_t const bufsize = sizeof(buf) - 1;
|
||||||
|
|
||||||
|
// forward cdc interfaces -> console
|
||||||
|
uint32_t count = tuh_cdc_read(idx, buf, bufsize);
|
||||||
|
buf[count] = 0;
|
||||||
|
|
||||||
|
printf((char *) buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tuh_cdc_mount_cb(uint8_t idx) {
|
||||||
|
tuh_itf_info_t itf_info = { 0 };
|
||||||
|
tuh_cdc_itf_get_info(idx, &itf_info);
|
||||||
|
|
||||||
|
printf("CDC Interface is mounted: address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.desc.bInterfaceNumber);
|
||||||
|
|
||||||
|
#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
|
||||||
|
// CFG_TUH_CDC_LINE_CODING_ON_ENUM must be defined for line coding is set by tinyusb in enumeration
|
||||||
|
// otherwise you need to call tuh_cdc_set_line_coding() first
|
||||||
|
cdc_line_coding_t line_coding = { 0 };
|
||||||
|
if (tuh_cdc_get_local_line_coding(idx, &line_coding)) {
|
||||||
|
printf(" Baudrate: %lu, Stop Bits : %u\r\n", line_coding.bit_rate, line_coding.stop_bits);
|
||||||
|
printf(" Parity : %u, Data Width: %u\r\n", line_coding.parity, line_coding.data_bits);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void tuh_cdc_umount_cb(uint8_t idx) {
|
||||||
|
tuh_itf_info_t itf_info = { 0 };
|
||||||
|
tuh_cdc_itf_get_info(idx, &itf_info);
|
||||||
|
|
||||||
|
printf("CDC Interface is unmounted: address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.desc.bInterfaceNumber);
|
||||||
|
}
|
111
examples/host/cdc_msc_hid_freertos/src/freertos_hook.c
Normal file
111
examples/host/cdc_msc_hid_freertos/src/freertos_hook.c
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* 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 "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
#include "common/tusb_common.h"
|
||||||
|
|
||||||
|
void vApplicationMallocFailedHook(void) {
|
||||||
|
taskDISABLE_INTERRUPTS();
|
||||||
|
TU_ASSERT(false,);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vApplicationStackOverflowHook(xTaskHandle pxTask, char *pcTaskName) {
|
||||||
|
(void) pxTask;
|
||||||
|
(void) pcTaskName;
|
||||||
|
|
||||||
|
taskDISABLE_INTERRUPTS();
|
||||||
|
TU_ASSERT(false,);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* configSUPPORT_STATIC_ALLOCATION is set to 1, so the application must provide an
|
||||||
|
* implementation of vApplicationGetIdleTaskMemory() to provide the memory that is
|
||||||
|
* used by the Idle task. */
|
||||||
|
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer,
|
||||||
|
uint32_t *pulIdleTaskStackSize) {
|
||||||
|
/* If the buffers to be provided to the Idle task are declared inside this
|
||||||
|
* function then they must be declared static - otherwise they will be allocated on
|
||||||
|
* the stack and so not exists after this function exits. */
|
||||||
|
static StaticTask_t xIdleTaskTCB;
|
||||||
|
static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE];
|
||||||
|
|
||||||
|
/* Pass out a pointer to the StaticTask_t structure in which the Idle task's
|
||||||
|
state will be stored. */
|
||||||
|
*ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
|
||||||
|
|
||||||
|
/* Pass out the array that will be used as the Idle task's stack. */
|
||||||
|
*ppxIdleTaskStackBuffer = uxIdleTaskStack;
|
||||||
|
|
||||||
|
/* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer.
|
||||||
|
Note that, as the array is necessarily of type StackType_t,
|
||||||
|
configMINIMAL_STACK_SIZE is specified in words, not bytes. */
|
||||||
|
*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* configSUPPORT_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the
|
||||||
|
* application must provide an implementation of vApplicationGetTimerTaskMemory()
|
||||||
|
* to provide the memory that is used by the Timer service task. */
|
||||||
|
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer,
|
||||||
|
uint32_t *pulTimerTaskStackSize) {
|
||||||
|
/* If the buffers to be provided to the Timer task are declared inside this
|
||||||
|
* function then they must be declared static - otherwise they will be allocated on
|
||||||
|
* the stack and so not exists after this function exits. */
|
||||||
|
static StaticTask_t xTimerTaskTCB;
|
||||||
|
static StackType_t uxTimerTaskStack[configTIMER_TASK_STACK_DEPTH];
|
||||||
|
|
||||||
|
/* Pass out a pointer to the StaticTask_t structure in which the Timer
|
||||||
|
task's state will be stored. */
|
||||||
|
*ppxTimerTaskTCBBuffer = &xTimerTaskTCB;
|
||||||
|
|
||||||
|
/* Pass out the array that will be used as the Timer task's stack. */
|
||||||
|
*ppxTimerTaskStackBuffer = uxTimerTaskStack;
|
||||||
|
|
||||||
|
/* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer.
|
||||||
|
Note that, as the array is necessarily of type StackType_t,
|
||||||
|
configTIMER_TASK_STACK_DEPTH is specified in words, not bytes. */
|
||||||
|
*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CFG_TUSB_MCU == OPT_MCU_RX63X | CFG_TUSB_MCU == OPT_MCU_RX65X
|
||||||
|
#include "iodefine.h"
|
||||||
|
void vApplicationSetupTimerInterrupt(void)
|
||||||
|
{
|
||||||
|
/* Enable CMT0 */
|
||||||
|
SYSTEM.PRCR.WORD = (0xA5u<<8) | TU_BIT(1);
|
||||||
|
MSTP(CMT0) = 0;
|
||||||
|
SYSTEM.PRCR.WORD = (0xA5u<<8);
|
||||||
|
|
||||||
|
CMT0.CMCNT = 0;
|
||||||
|
CMT0.CMCOR = (unsigned short)(((configPERIPHERAL_CLOCK_HZ/configTICK_RATE_HZ)-1)/128);
|
||||||
|
CMT0.CMCR.WORD = TU_BIT(6) | 2;
|
||||||
|
IR(CMT0, CMI0) = 0;
|
||||||
|
IPR(CMT0, CMI0) = configKERNEL_INTERRUPT_PRIORITY;
|
||||||
|
IEN(CMT0, CMI0) = 1;
|
||||||
|
CMT.CMSTR0.BIT.STR0 = 1;
|
||||||
|
}
|
||||||
|
#endif
|
267
examples/host/cdc_msc_hid_freertos/src/hid_app.c
Normal file
267
examples/host/cdc_msc_hid_freertos/src/hid_app.c
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
/*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021, 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"
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// If your host terminal support ansi escape code such as TeraTerm
|
||||||
|
// it can be use to simulate mouse cursor movement within terminal
|
||||||
|
#define USE_ANSI_ESCAPE 0
|
||||||
|
|
||||||
|
#define MAX_REPORT 4
|
||||||
|
|
||||||
|
static uint8_t const keycode2ascii[128][2] = { HID_KEYCODE_TO_ASCII };
|
||||||
|
|
||||||
|
// Each HID instance can has multiple reports
|
||||||
|
static struct {
|
||||||
|
uint8_t report_count;
|
||||||
|
tuh_hid_report_info_t report_info[MAX_REPORT];
|
||||||
|
} hid_info[CFG_TUH_HID];
|
||||||
|
|
||||||
|
static void process_kbd_report(hid_keyboard_report_t const *report);
|
||||||
|
static void process_mouse_report(hid_mouse_report_t const *report);
|
||||||
|
static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len);
|
||||||
|
|
||||||
|
void hid_app_init(void) {
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// TinyUSB Callbacks
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// Invoked when device with hid interface is mounted
|
||||||
|
// Report descriptor is also available for use. tuh_hid_parse_report_descriptor()
|
||||||
|
// can be used to parse common/simple enough descriptor.
|
||||||
|
// Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped
|
||||||
|
// therefore report_desc = NULL, desc_len = 0
|
||||||
|
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
|
||||||
|
printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
|
||||||
|
|
||||||
|
// Interface protocol (hid_interface_protocol_enum_t)
|
||||||
|
const char *protocol_str[] = { "None", "Keyboard", "Mouse" };
|
||||||
|
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
|
||||||
|
|
||||||
|
printf("HID Interface Protocol = %s\r\n", protocol_str[itf_protocol]);
|
||||||
|
|
||||||
|
// By default host stack will use activate boot protocol on supported interface.
|
||||||
|
// Therefore for this simple example, we only need to parse generic report descriptor (with built-in parser)
|
||||||
|
if (itf_protocol == HID_ITF_PROTOCOL_NONE) {
|
||||||
|
hid_info[instance].report_count = tuh_hid_parse_report_descriptor(hid_info[instance].report_info, MAX_REPORT,
|
||||||
|
desc_report, desc_len);
|
||||||
|
printf("HID has %u reports \r\n", hid_info[instance].report_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// request to receive report
|
||||||
|
// tuh_hid_report_received_cb() will be invoked when report is available
|
||||||
|
if (!tuh_hid_receive_report(dev_addr, instance)) {
|
||||||
|
printf("Error: cannot request to receive report\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoked when device with hid interface is un-mounted
|
||||||
|
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
|
||||||
|
printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoked when received report from device via interrupt endpoint
|
||||||
|
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) {
|
||||||
|
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
|
||||||
|
|
||||||
|
switch (itf_protocol) {
|
||||||
|
case HID_ITF_PROTOCOL_KEYBOARD:
|
||||||
|
TU_LOG2("HID receive boot keyboard report\r\n");
|
||||||
|
process_kbd_report((hid_keyboard_report_t const *) report);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HID_ITF_PROTOCOL_MOUSE:
|
||||||
|
TU_LOG2("HID receive boot mouse report\r\n");
|
||||||
|
process_mouse_report((hid_mouse_report_t const *) report);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Generic report requires matching ReportID and contents with previous parsed report info
|
||||||
|
process_generic_report(dev_addr, instance, report, len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// continue to request to receive report
|
||||||
|
if (!tuh_hid_receive_report(dev_addr, instance)) {
|
||||||
|
printf("Error: cannot request to receive report\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Keyboard
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// look up new key in previous keys
|
||||||
|
static inline bool find_key_in_report(hid_keyboard_report_t const *report, uint8_t keycode) {
|
||||||
|
for (uint8_t i = 0; i < 6; i++) {
|
||||||
|
if (report->keycode[i] == keycode) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void process_kbd_report(hid_keyboard_report_t const *report) {
|
||||||
|
static hid_keyboard_report_t prev_report = { 0, 0, { 0 } }; // previous report to check key released
|
||||||
|
|
||||||
|
//------------- example code ignore control (non-printable) key affects -------------//
|
||||||
|
for (uint8_t i = 0; i < 6; i++) {
|
||||||
|
if (report->keycode[i]) {
|
||||||
|
if (find_key_in_report(&prev_report, report->keycode[i])) {
|
||||||
|
// exist in previous report means the current key is holding
|
||||||
|
} else {
|
||||||
|
// not existed in previous report means the current key is pressed
|
||||||
|
bool const is_shift = report->modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT);
|
||||||
|
uint8_t ch = keycode2ascii[report->keycode[i]][is_shift ? 1 : 0];
|
||||||
|
putchar(ch);
|
||||||
|
if (ch == '\r') putchar('\n'); // added new line for enter key
|
||||||
|
|
||||||
|
#ifndef __ICCARM__ // TODO IAR doesn't support stream control ?
|
||||||
|
fflush(stdout); // flush right away, else nanolib will wait for newline
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO example skips key released
|
||||||
|
}
|
||||||
|
|
||||||
|
prev_report = *report;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Mouse
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
void cursor_movement(int8_t x, int8_t y, int8_t wheel) {
|
||||||
|
#if USE_ANSI_ESCAPE
|
||||||
|
// Move X using ansi escape
|
||||||
|
if ( x < 0) {
|
||||||
|
printf(ANSI_CURSOR_BACKWARD(%d), (-x)); // move left
|
||||||
|
}else if ( x > 0) {
|
||||||
|
printf(ANSI_CURSOR_FORWARD(%d), x); // move right
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move Y using ansi escape
|
||||||
|
if ( y < 0) {
|
||||||
|
printf(ANSI_CURSOR_UP(%d), (-y)); // move up
|
||||||
|
}else if ( y > 0) {
|
||||||
|
printf(ANSI_CURSOR_DOWN(%d), y); // move down
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scroll using ansi escape
|
||||||
|
if (wheel < 0) {
|
||||||
|
printf(ANSI_SCROLL_UP(%d), (-wheel)); // scroll up
|
||||||
|
}else if (wheel > 0) {
|
||||||
|
printf(ANSI_SCROLL_DOWN(%d), wheel); // scroll down
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\r\n");
|
||||||
|
#else
|
||||||
|
printf("(%d %d %d)\r\n", x, y, wheel);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void process_mouse_report(hid_mouse_report_t const *report) {
|
||||||
|
static hid_mouse_report_t prev_report = { 0 };
|
||||||
|
|
||||||
|
//------------- button state -------------//
|
||||||
|
uint8_t button_changed_mask = report->buttons ^ prev_report.buttons;
|
||||||
|
if (button_changed_mask & report->buttons) {
|
||||||
|
printf(" %c%c%c ",
|
||||||
|
report->buttons & MOUSE_BUTTON_LEFT ? 'L' : '-',
|
||||||
|
report->buttons & MOUSE_BUTTON_MIDDLE ? 'M' : '-',
|
||||||
|
report->buttons & MOUSE_BUTTON_RIGHT ? 'R' : '-');
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------- cursor movement -------------//
|
||||||
|
cursor_movement(report->x, report->y, report->wheel);
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Generic Report
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) {
|
||||||
|
(void) dev_addr;
|
||||||
|
|
||||||
|
uint8_t const rpt_count = hid_info[instance].report_count;
|
||||||
|
tuh_hid_report_info_t *rpt_info_arr = hid_info[instance].report_info;
|
||||||
|
tuh_hid_report_info_t *rpt_info = NULL;
|
||||||
|
|
||||||
|
if (rpt_count == 1 && rpt_info_arr[0].report_id == 0) {
|
||||||
|
// Simple report without report ID as 1st byte
|
||||||
|
rpt_info = &rpt_info_arr[0];
|
||||||
|
} else {
|
||||||
|
// Composite report, 1st byte is report ID, data starts from 2nd byte
|
||||||
|
uint8_t const rpt_id = report[0];
|
||||||
|
|
||||||
|
// Find report id in the array
|
||||||
|
for (uint8_t i = 0; i < rpt_count; i++) {
|
||||||
|
if (rpt_id == rpt_info_arr[i].report_id) {
|
||||||
|
rpt_info = &rpt_info_arr[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
report++;
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rpt_info) {
|
||||||
|
printf("Couldn't find report info !\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For complete list of Usage Page & Usage checkout src/class/hid/hid.h. For examples:
|
||||||
|
// - Keyboard : Desktop, Keyboard
|
||||||
|
// - Mouse : Desktop, Mouse
|
||||||
|
// - Gamepad : Desktop, Gamepad
|
||||||
|
// - Consumer Control (Media Key) : Consumer, Consumer Control
|
||||||
|
// - System Control (Power key) : Desktop, System Control
|
||||||
|
// - Generic (vendor) : 0xFFxx, xx
|
||||||
|
if (rpt_info->usage_page == HID_USAGE_PAGE_DESKTOP) {
|
||||||
|
switch (rpt_info->usage) {
|
||||||
|
case HID_USAGE_DESKTOP_KEYBOARD:
|
||||||
|
TU_LOG1("HID receive keyboard report\r\n");
|
||||||
|
// Assume keyboard follow boot report layout
|
||||||
|
process_kbd_report((hid_keyboard_report_t const *) report);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HID_USAGE_DESKTOP_MOUSE:
|
||||||
|
TU_LOG1("HID receive mouse report\r\n");
|
||||||
|
// Assume mouse follow boot report layout
|
||||||
|
process_mouse_report((hid_mouse_report_t const *) report);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
165
examples/host/cdc_msc_hid_freertos/src/main.c
Normal file
165
examples/host/cdc_msc_hid_freertos/src/main.c
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
/*
|
||||||
|
* 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 <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "bsp/board_api.h"
|
||||||
|
#include "tusb.h"
|
||||||
|
|
||||||
|
#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
|
||||||
|
// 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 USBH_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 USBH_STACK_SIZE (3*configMINIMAL_STACK_SIZE/2) * (CFG_TUSB_DEBUG ? 2 : 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// 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 timer & task
|
||||||
|
#if configSUPPORT_STATIC_ALLOCATION
|
||||||
|
StaticTimer_t blinky_tmdef;
|
||||||
|
|
||||||
|
StackType_t usb_host_stack[USBH_STACK_SIZE];
|
||||||
|
StaticTask_t usb_host_taskdef;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TimerHandle_t blinky_tm;
|
||||||
|
|
||||||
|
static void led_blinky_cb(TimerHandle_t xTimer);
|
||||||
|
static void usb_host_task(void* param);
|
||||||
|
|
||||||
|
extern void cdc_app_init(void);
|
||||||
|
extern void hid_app_init(void);
|
||||||
|
extern void msc_app_init(void);
|
||||||
|
|
||||||
|
/*------------- MAIN -------------*/
|
||||||
|
int main(void) {
|
||||||
|
board_init();
|
||||||
|
|
||||||
|
printf("TinyUSB Host CDC MSC HID with FreeRTOS Example\r\n");
|
||||||
|
|
||||||
|
// Create soft timer for blinky, task for tinyusb stack
|
||||||
|
#if configSUPPORT_STATIC_ALLOCATION
|
||||||
|
blinky_tm = xTimerCreateStatic(NULL, pdMS_TO_TICKS(BLINK_MOUNTED), true, NULL, led_blinky_cb, &blinky_tmdef);
|
||||||
|
xTaskCreateStatic(usb_host_task, "usbh", USBH_STACK_SIZE, NULL, configMAX_PRIORITIES-1, usb_host_stack, &usb_host_taskdef);
|
||||||
|
#else
|
||||||
|
blinky_tm = xTimerCreate(NULL, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), true, NULL, led_blinky_cb);
|
||||||
|
xTaskCreate(usb_host_task, "usbd", USBH_STACK_SIZE, NULL, configMAX_PRIORITIES-1, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
xTimerStart(blinky_tm, 0);
|
||||||
|
|
||||||
|
// skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
|
||||||
|
#if !TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
|
||||||
|
vTaskStartScheduler();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
|
||||||
|
void app_main(void) {
|
||||||
|
main();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// USB Host task
|
||||||
|
// This top level thread process all usb events and invoke callbacks
|
||||||
|
static void usb_host_task(void *param) {
|
||||||
|
(void) param;
|
||||||
|
|
||||||
|
// init host stack on configured roothub port
|
||||||
|
tuh_init(BOARD_TUH_RHPORT);
|
||||||
|
|
||||||
|
if (board_init_after_tusb) {
|
||||||
|
board_init_after_tusb();
|
||||||
|
}
|
||||||
|
|
||||||
|
cdc_app_init();
|
||||||
|
hid_app_init();
|
||||||
|
msc_app_init();
|
||||||
|
|
||||||
|
// RTOS forever loop
|
||||||
|
while (1) {
|
||||||
|
// put this thread to waiting state until there is new events
|
||||||
|
tuh_task();
|
||||||
|
|
||||||
|
// following code only run if tuh_task() process at least 1 event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// TinyUSB Callbacks
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
void tuh_mount_cb(uint8_t dev_addr) {
|
||||||
|
// application set-up
|
||||||
|
printf("A device with address %d is mounted\r\n", dev_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tuh_umount_cb(uint8_t dev_addr) {
|
||||||
|
// application tear-down
|
||||||
|
printf("A device with address %d is unmounted \r\n", dev_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// BLINKING TASK
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
static 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
|
||||||
|
}
|
67
examples/host/cdc_msc_hid_freertos/src/msc_app.c
Normal file
67
examples/host/cdc_msc_hid_freertos/src/msc_app.c
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* 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 "tusb.h"
|
||||||
|
|
||||||
|
static scsi_inquiry_resp_t inquiry_resp;
|
||||||
|
|
||||||
|
void msc_app_init(void) {
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const *cb_data) {
|
||||||
|
msc_cbw_t const *cbw = cb_data->cbw;
|
||||||
|
msc_csw_t const *csw = cb_data->csw;
|
||||||
|
|
||||||
|
if (csw->status != 0) {
|
||||||
|
printf("Inquiry failed\r\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print out Vendor ID, Product ID and Rev
|
||||||
|
printf("%.8s %.16s rev %.4s\r\n", inquiry_resp.vendor_id, inquiry_resp.product_id, inquiry_resp.product_rev);
|
||||||
|
|
||||||
|
// Get capacity of device
|
||||||
|
uint32_t const block_count = tuh_msc_get_block_count(dev_addr, cbw->lun);
|
||||||
|
uint32_t const block_size = tuh_msc_get_block_size(dev_addr, cbw->lun);
|
||||||
|
|
||||||
|
printf("Disk Size: %lu MB\r\n", block_count / ((1024 * 1024) / block_size));
|
||||||
|
printf("Block Count = %lu, Block Size: %lu\r\n", block_count, block_size);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------- IMPLEMENTATION -------------//
|
||||||
|
void tuh_msc_mount_cb(uint8_t dev_addr) {
|
||||||
|
printf("A MassStorage device is mounted\r\n");
|
||||||
|
|
||||||
|
uint8_t const lun = 0;
|
||||||
|
tuh_msc_inquiry(dev_addr, lun, &inquiry_resp, inquiry_complete_cb, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tuh_msc_umount_cb(uint8_t dev_addr) {
|
||||||
|
(void) dev_addr;
|
||||||
|
printf("A MassStorage device is unmounted\r\n");
|
||||||
|
}
|
133
examples/host/cdc_msc_hid_freertos/src/tusb_config.h
Normal file
133
examples/host/cdc_msc_hid_freertos/src/tusb_config.h
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
#if CFG_TUSB_MCU == OPT_MCU_RP2040
|
||||||
|
// change to 1 if using pico-pio-usb as host controller for raspberry rp2040
|
||||||
|
#define CFG_TUH_RPI_PIO_USB 0
|
||||||
|
#define BOARD_TUH_RHPORT CFG_TUH_RPI_PIO_USB
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// RHPort number used for host can be defined by board.mk, default to port 0
|
||||||
|
#ifndef BOARD_TUH_RHPORT
|
||||||
|
#define BOARD_TUH_RHPORT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// RHPort max operational speed can defined by board.mk
|
||||||
|
#ifndef BOARD_TUH_MAX_SPEED
|
||||||
|
#define BOARD_TUH_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
|
||||||
|
|
||||||
|
// Espressif IDF requires "freertos/" prefix in include path
|
||||||
|
#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
|
||||||
|
#define CFG_TUSB_OS_INC_PATH freertos/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CFG_TUSB_DEBUG
|
||||||
|
#define CFG_TUSB_DEBUG 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Enable Host stack
|
||||||
|
#define CFG_TUH_ENABLED 1
|
||||||
|
|
||||||
|
// Default is max speed that hardware controller could support with on-chip PHY
|
||||||
|
#define CFG_TUH_MAX_SPEED BOARD_TUH_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_TUH_MEM_SECTION
|
||||||
|
#define CFG_TUH_MEM_SECTION
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CFG_TUH_MEM_ALIGN
|
||||||
|
#define CFG_TUH_MEM_ALIGN __attribute__ ((aligned(4)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
// CONFIGURATION
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Size of buffer to hold descriptors and other data used for enumeration
|
||||||
|
#define CFG_TUH_ENUMERATION_BUFSIZE 256
|
||||||
|
|
||||||
|
#define CFG_TUH_HUB 1 // number of supported hubs
|
||||||
|
#define CFG_TUH_CDC 1 // CDC ACM
|
||||||
|
#define CFG_TUH_CDC_FTDI 1 // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API
|
||||||
|
#define CFG_TUH_CDC_CP210X 1 // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API
|
||||||
|
#define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces
|
||||||
|
#define CFG_TUH_MSC 1
|
||||||
|
#define CFG_TUH_VENDOR 0
|
||||||
|
|
||||||
|
// max device support (excluding hub device): 1 hub typically has 4 ports
|
||||||
|
#define CFG_TUH_DEVICE_MAX (3*CFG_TUH_HUB + 1)
|
||||||
|
|
||||||
|
//------------- HID -------------//
|
||||||
|
#define CFG_TUH_HID_EPIN_BUFSIZE 64
|
||||||
|
#define CFG_TUH_HID_EPOUT_BUFSIZE 64
|
||||||
|
|
||||||
|
//------------- CDC -------------//
|
||||||
|
|
||||||
|
// Set Line Control state on enumeration/mounted:
|
||||||
|
// DTR ( bit 0), RTS (bit 1)
|
||||||
|
#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03
|
||||||
|
|
||||||
|
// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t
|
||||||
|
// bit rate = 115200, 1 stop bit, no parity, 8 bit data width
|
||||||
|
#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _TUSB_CONFIG_H_ */
|
@ -10,6 +10,11 @@ project(${PROJECT} C CXX ASM)
|
|||||||
# Checks this example is valid for the family and initializes the project
|
# Checks this example is valid for the family and initializes the project
|
||||||
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
|
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
|
||||||
|
# Espressif has its own cmake build system
|
||||||
|
if(FAMILY STREQUAL "espressif")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
add_executable(${PROJECT})
|
add_executable(${PROJECT})
|
||||||
|
|
||||||
# Example source
|
# Example source
|
||||||
|
@ -11,14 +11,4 @@ EXAMPLE_SOURCE += \
|
|||||||
|
|
||||||
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
|
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
|
||||||
|
|
||||||
# TinyUSB Host Stack source
|
|
||||||
SRC_C += \
|
|
||||||
src/class/cdc/cdc_host.c \
|
|
||||||
src/class/hid/hid_host.c \
|
|
||||||
src/class/msc/msc_host.c \
|
|
||||||
src/host/hub.c \
|
|
||||||
src/host/usbh.c \
|
|
||||||
src/portable/ohci/ohci.c \
|
|
||||||
src/portable/nxp/lpc17_40/hcd_lpc17_40.c
|
|
||||||
|
|
||||||
include ../../rules.mk
|
include ../../rules.mk
|
||||||
|
@ -10,6 +10,11 @@ project(${PROJECT} C CXX ASM)
|
|||||||
# Checks this example is valid for the family and initializes the project
|
# Checks this example is valid for the family and initializes the project
|
||||||
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
|
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
|
||||||
|
# Espressif has its own cmake build system
|
||||||
|
if(FAMILY STREQUAL "espressif")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
add_executable(${PROJECT})
|
add_executable(${PROJECT})
|
||||||
|
|
||||||
# Example source
|
# Example source
|
||||||
|
@ -24,14 +24,4 @@ SRC_C += \
|
|||||||
# suppress warning caused by fatfs
|
# suppress warning caused by fatfs
|
||||||
CFLAGS += -Wno-error=cast-qual
|
CFLAGS += -Wno-error=cast-qual
|
||||||
|
|
||||||
# TinyUSB Host Stack source
|
|
||||||
SRC_C += \
|
|
||||||
src/class/cdc/cdc_host.c \
|
|
||||||
src/class/hid/hid_host.c \
|
|
||||||
src/class/msc/msc_host.c \
|
|
||||||
src/host/hub.c \
|
|
||||||
src/host/usbh.c \
|
|
||||||
src/portable/ohci/ohci.c \
|
|
||||||
src/portable/nxp/lpc17_40/hcd_lpc17_40.c
|
|
||||||
|
|
||||||
include ../../rules.mk
|
include ../../rules.mk
|
||||||
|
@ -26,9 +26,6 @@ ifeq '$(findstring ;,$(PATH))' ';'
|
|||||||
CMDEXE := 1
|
CMDEXE := 1
|
||||||
|
|
||||||
# makefile shell commands should use syntax for DOS CMD, not unix sh
|
# makefile shell commands should use syntax for DOS CMD, not unix sh
|
||||||
# Unfortunately, SHELL may point to sh or bash, which can't accept DOS syntax.
|
|
||||||
# We can't just use sh, because while sh and/or bash shell may be available,
|
|
||||||
# many Windows environments won't have utilities like realpath used below, so...
|
|
||||||
# Force DOS command shell on Windows.
|
# Force DOS command shell on Windows.
|
||||||
SHELL := cmd.exe
|
SHELL := cmd.exe
|
||||||
endif
|
endif
|
||||||
|
@ -4,3 +4,5 @@ idf_component_register(SRCS family.c
|
|||||||
INCLUDE_DIRS "." ${BOARD} ${hw_dir}
|
INCLUDE_DIRS "." ${BOARD} ${hw_dir}
|
||||||
PRIV_REQUIRES "driver"
|
PRIV_REQUIRES "driver"
|
||||||
REQUIRES led_strip src tinyusb_src)
|
REQUIRES led_strip src tinyusb_src)
|
||||||
|
|
||||||
|
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-error=format)
|
||||||
|
@ -36,6 +36,14 @@
|
|||||||
#define BUTTON_PIN 0
|
#define BUTTON_PIN 0
|
||||||
#define BUTTON_STATE_ACTIVE 0
|
#define BUTTON_STATE_ACTIVE 0
|
||||||
|
|
||||||
|
// SPI for USB host shield
|
||||||
|
#define MAX3421_SPI_HOST SPI2_HOST
|
||||||
|
#define MAX3421_SCK_PIN 36
|
||||||
|
#define MAX3421_MOSI_PIN 35
|
||||||
|
#define MAX3421_MISO_PIN 37
|
||||||
|
#define MAX3421_CS_PIN 15
|
||||||
|
#define MAX3421_INTR_PIN 14
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -37,6 +37,14 @@
|
|||||||
#define BUTTON_PIN 0
|
#define BUTTON_PIN 0
|
||||||
#define BUTTON_STATE_ACTIVE 0
|
#define BUTTON_STATE_ACTIVE 0
|
||||||
|
|
||||||
|
// SPI for USB host shield
|
||||||
|
#define MAX3421_SPI_HOST SPI2_HOST
|
||||||
|
#define MAX3421_SCK_PIN 36
|
||||||
|
#define MAX3421_MOSI_PIN 35
|
||||||
|
#define MAX3421_MISO_PIN 37
|
||||||
|
#define MAX3421_CS_PIN 15
|
||||||
|
#define MAX3421_INTR_PIN 14
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
2
hw/bsp/espressif/boards/espressif_s2_devkitc/board.cmake
Normal file
2
hw/bsp/espressif/boards/espressif_s2_devkitc/board.cmake
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Apply board specific content here
|
||||||
|
set(IDF_TARGET "esp32s2")
|
45
hw/bsp/espressif/boards/espressif_s2_devkitc/board.h
Normal file
45
hw/bsp/espressif/boards/espressif_s2_devkitc/board.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020, Ha Thach (tinyusb.org)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* This file is part of the TinyUSB stack.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOARD_H_
|
||||||
|
#define BOARD_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Note: On the production version (v1.2) WS2812 is connected to GPIO 18,
|
||||||
|
// however earlier revision v1.1 WS2812 is connected to GPIO 17
|
||||||
|
#define NEOPIXEL_PIN 18
|
||||||
|
|
||||||
|
#define BUTTON_PIN 0
|
||||||
|
#define BUTTON_STATE_ACTIVE 0
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* BOARD_H_ */
|
@ -36,6 +36,14 @@
|
|||||||
#define BUTTON_PIN 0
|
#define BUTTON_PIN 0
|
||||||
#define BUTTON_STATE_ACTIVE 0
|
#define BUTTON_STATE_ACTIVE 0
|
||||||
|
|
||||||
|
// SPI for USB host shield
|
||||||
|
#define MAX3421_SPI_HOST SPI2_HOST
|
||||||
|
#define MAX3421_SCK_PIN 36
|
||||||
|
#define MAX3421_MOSI_PIN 35
|
||||||
|
#define MAX3421_MISO_PIN 37
|
||||||
|
#define MAX3421_CS_PIN 15
|
||||||
|
#define MAX3421_INTR_PIN 14
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "soc/usb_periph.h"
|
#include "soc/usb_periph.h"
|
||||||
|
|
||||||
#include "driver/rmt.h"
|
#include "driver/rmt.h"
|
||||||
|
#include "driver/uart.h"
|
||||||
|
|
||||||
#if ESP_IDF_VERSION_MAJOR > 4
|
#if ESP_IDF_VERSION_MAJOR > 4
|
||||||
#include "esp_private/periph_ctrl.h"
|
#include "esp_private/periph_ctrl.h"
|
||||||
@ -40,20 +41,36 @@
|
|||||||
#include "driver/periph_ctrl.h"
|
#include "driver/periph_ctrl.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define UART_ID UART_NUM_0
|
||||||
|
|
||||||
#ifdef NEOPIXEL_PIN
|
#ifdef NEOPIXEL_PIN
|
||||||
#include "led_strip.h"
|
#include "led_strip.h"
|
||||||
static led_strip_t *strip;
|
static led_strip_t *strip;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
#if CFG_TUH_ENABLED && CFG_TUH_MAX3421
|
||||||
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
|
#include "driver/spi_master.h"
|
||||||
//--------------------------------------------------------------------+
|
static void max3421_init(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
static void configure_pins(usb_hal_context_t *usb);
|
static void configure_pins(usb_hal_context_t *usb);
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Implementation
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
// Initialize on-board peripherals : led, button, uart and USB
|
// Initialize on-board peripherals : led, button, uart and USB
|
||||||
void board_init(void)
|
void board_init(void) {
|
||||||
{
|
// uart init
|
||||||
|
uart_config_t uart_config = {
|
||||||
|
.baud_rate = 115200,
|
||||||
|
.data_bits = UART_DATA_8_BITS,
|
||||||
|
.parity = UART_PARITY_DISABLE,
|
||||||
|
.stop_bits = UART_STOP_BITS_1,
|
||||||
|
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE
|
||||||
|
};
|
||||||
|
uart_driver_install(UART_ID, 1024, 0, 0, NULL, 0);
|
||||||
|
uart_param_config(UART_ID, &uart_config);
|
||||||
|
|
||||||
#ifdef NEOPIXEL_PIN
|
#ifdef NEOPIXEL_PIN
|
||||||
#ifdef NEOPIXEL_POWER_PIN
|
#ifdef NEOPIXEL_POWER_PIN
|
||||||
@ -88,14 +105,16 @@ void board_init(void)
|
|||||||
};
|
};
|
||||||
usb_hal_init(&hal);
|
usb_hal_init(&hal);
|
||||||
configure_pins(&hal);
|
configure_pins(&hal);
|
||||||
|
|
||||||
|
#if CFG_TUH_ENABLED && CFG_TUH_MAX3421
|
||||||
|
max3421_init();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void configure_pins(usb_hal_context_t *usb)
|
static void configure_pins(usb_hal_context_t *usb) {
|
||||||
{
|
|
||||||
/* usb_periph_iopins currently configures USB_OTG as USB Device.
|
/* usb_periph_iopins currently configures USB_OTG as USB Device.
|
||||||
* Introduce additional parameters in usb_hal_context_t when adding support
|
* Introduce additional parameters in usb_hal_context_t when adding support
|
||||||
* for USB Host.
|
* for USB Host. */
|
||||||
*/
|
|
||||||
for (const usb_iopin_dsc_t *iopin = usb_periph_iopins; iopin->pin != -1; ++iopin) {
|
for (const usb_iopin_dsc_t *iopin = usb_periph_iopins; iopin->pin != -1; ++iopin) {
|
||||||
if ((usb->use_external_phy) || (iopin->ext_phy_only == 0)) {
|
if ((usb->use_external_phy) || (iopin->ext_phy_only == 0)) {
|
||||||
esp_rom_gpio_pad_select_gpio(iopin->pin);
|
esp_rom_gpio_pad_select_gpio(iopin->pin);
|
||||||
@ -115,6 +134,7 @@ static void configure_pins(usb_hal_context_t *usb)
|
|||||||
esp_rom_gpio_pad_unhold(iopin->pin);
|
esp_rom_gpio_pad_unhold(iopin->pin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!usb->use_external_phy) {
|
if (!usb->use_external_phy) {
|
||||||
gpio_set_drive_capability(USBPHY_DM_NUM, GPIO_DRIVE_CAP_3);
|
gpio_set_drive_capability(USBPHY_DM_NUM, GPIO_DRIVE_CAP_3);
|
||||||
gpio_set_drive_capability(USBPHY_DP_NUM, GPIO_DRIVE_CAP_3);
|
gpio_set_drive_capability(USBPHY_DP_NUM, GPIO_DRIVE_CAP_3);
|
||||||
@ -122,8 +142,7 @@ static void configure_pins(usb_hal_context_t *usb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Turn LED on or off
|
// Turn LED on or off
|
||||||
void board_led_write(bool state)
|
void board_led_write(bool state) {
|
||||||
{
|
|
||||||
#ifdef NEOPIXEL_PIN
|
#ifdef NEOPIXEL_PIN
|
||||||
strip->set_pixel(strip, 0, (state ? 0x88 : 0x00), 0x00, 0x00);
|
strip->set_pixel(strip, 0, (state ? 0x88 : 0x00), 0x00, 0x00);
|
||||||
strip->refresh(strip, 100);
|
strip->refresh(strip, 100);
|
||||||
@ -132,21 +151,132 @@ void board_led_write(bool state)
|
|||||||
|
|
||||||
// Get the current state of button
|
// Get the current state of button
|
||||||
// a '1' means active (pressed), a '0' means inactive.
|
// a '1' means active (pressed), a '0' means inactive.
|
||||||
uint32_t board_button_read(void)
|
uint32_t board_button_read(void) {
|
||||||
{
|
|
||||||
return gpio_get_level(BUTTON_PIN) == BUTTON_STATE_ACTIVE;
|
return gpio_get_level(BUTTON_PIN) == BUTTON_STATE_ACTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get characters from UART
|
// Get characters from UART
|
||||||
int board_uart_read(uint8_t* buf, int len)
|
int board_uart_read(uint8_t *buf, int len) {
|
||||||
{
|
return uart_read_bytes(UART_ID, buf, len, 0);
|
||||||
(void) buf; (void) len;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send characters to UART
|
// Send characters to UART
|
||||||
int board_uart_write(void const * buf, int len)
|
int board_uart_write(void const *buf, int len) {
|
||||||
{
|
(void) buf;
|
||||||
(void) buf; (void) len;
|
(void) len;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int board_getchar(void) {
|
||||||
|
char c;
|
||||||
|
return (uart_read_bytes(UART_ID, &c, 1, 0) > 0) ? (int) c : (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// API: SPI transfer with MAX3421E, must be implemented by application
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
|
||||||
|
static spi_device_handle_t max3421_spi;
|
||||||
|
SemaphoreHandle_t max3421_intr_sem;
|
||||||
|
|
||||||
|
static void IRAM_ATTR max3421_isr_handler(void* arg) {
|
||||||
|
(void) arg; // arg is gpio num
|
||||||
|
gpio_set_level(13, 1);
|
||||||
|
|
||||||
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
|
xSemaphoreGiveFromISR(max3421_intr_sem, &xHigherPriorityTaskWoken);
|
||||||
|
if (xHigherPriorityTaskWoken) {
|
||||||
|
portYIELD_FROM_ISR();
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_set_level(13, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void max3421_intr_task(void* param) {
|
||||||
|
(void) param;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
xSemaphoreTake(max3421_intr_sem, portMAX_DELAY);
|
||||||
|
tuh_int_handler(BOARD_TUH_RHPORT, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void max3421_init(void) {
|
||||||
|
// CS pin
|
||||||
|
gpio_set_direction(MAX3421_CS_PIN, GPIO_MODE_OUTPUT);
|
||||||
|
gpio_set_level(MAX3421_CS_PIN, 1);
|
||||||
|
|
||||||
|
// SPI
|
||||||
|
spi_bus_config_t buscfg={
|
||||||
|
.miso_io_num = MAX3421_MISO_PIN,
|
||||||
|
.mosi_io_num = MAX3421_MOSI_PIN,
|
||||||
|
.sclk_io_num = MAX3421_SCK_PIN,
|
||||||
|
.quadwp_io_num = -1,
|
||||||
|
.quadhd_io_num = -1,
|
||||||
|
.data4_io_num = -1,
|
||||||
|
.data5_io_num = -1,
|
||||||
|
.data6_io_num = -1,
|
||||||
|
.data7_io_num = -1,
|
||||||
|
.max_transfer_sz = 1024
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK( spi_bus_initialize(MAX3421_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO) );
|
||||||
|
|
||||||
|
spi_device_interface_config_t max3421_cfg = {
|
||||||
|
.mode = 0,
|
||||||
|
.clock_speed_hz = 4000000, // 26000000
|
||||||
|
.spics_io_num = -1, // manual control CS
|
||||||
|
.queue_size = 1
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK( spi_bus_add_device(MAX3421_SPI_HOST, &max3421_cfg, &max3421_spi) );
|
||||||
|
|
||||||
|
// debug
|
||||||
|
gpio_set_direction(13, GPIO_MODE_OUTPUT);
|
||||||
|
gpio_set_level(13, 0);
|
||||||
|
|
||||||
|
// Interrupt pin
|
||||||
|
max3421_intr_sem = xSemaphoreCreateBinary();
|
||||||
|
xTaskCreate(max3421_intr_task, "max3421 intr", 2048, NULL, configMAX_PRIORITIES-2, NULL);
|
||||||
|
|
||||||
|
gpio_set_direction(MAX3421_INTR_PIN, GPIO_MODE_INPUT);
|
||||||
|
gpio_set_intr_type(MAX3421_INTR_PIN, GPIO_INTR_NEGEDGE);
|
||||||
|
|
||||||
|
gpio_install_isr_service(0);
|
||||||
|
gpio_isr_handler_add(MAX3421_INTR_PIN, max3421_isr_handler, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tuh_max3421_int_api(uint8_t rhport, bool enabled) {
|
||||||
|
(void) rhport;
|
||||||
|
if (enabled) {
|
||||||
|
gpio_intr_enable(MAX3421_INTR_PIN);
|
||||||
|
} else {
|
||||||
|
gpio_intr_disable(MAX3421_INTR_PIN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tuh_max3421_spi_cs_api(uint8_t rhport, bool active) {
|
||||||
|
(void) rhport;
|
||||||
|
gpio_set_level(MAX3421_CS_PIN, active ? 0 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const *tx_buf, size_t tx_len, uint8_t *rx_buf, size_t rx_len) {
|
||||||
|
(void) rhport;
|
||||||
|
|
||||||
|
if (tx_len == 0) {
|
||||||
|
// fifo read, transmit rx_buf as dummy
|
||||||
|
tx_buf = rx_buf;
|
||||||
|
tx_len = rx_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
spi_transaction_t xact = {
|
||||||
|
.length = tx_len << 3, // length in bits
|
||||||
|
.rxlength = rx_len << 3, // length in bits
|
||||||
|
.tx_buffer = tx_buf,
|
||||||
|
.rx_buffer = rx_buf
|
||||||
|
};
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(spi_device_transmit(max3421_spi, &xact));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -16,40 +16,58 @@ else()
|
|||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
list(APPEND compile_options
|
list(APPEND compile_definitions
|
||||||
"-DCFG_TUSB_MCU=${tusb_mcu}"
|
CFG_TUSB_MCU=${tusb_mcu}
|
||||||
"-DCFG_TUSB_OS=OPT_OS_FREERTOS"
|
CFG_TUSB_OS=OPT_OS_FREERTOS
|
||||||
#"-DCFG_TUSB_DEBUG=1"
|
|
||||||
)
|
|
||||||
|
|
||||||
idf_component_get_property(freertos_component_dir freertos COMPONENT_DIR)
|
|
||||||
|
|
||||||
list(APPEND includes_public
|
|
||||||
"${tusb_src}"
|
|
||||||
# The FreeRTOS API include convention in tinyusb is different from esp-idf
|
|
||||||
#"${freertos_component_dir}/include/freertos"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND srcs
|
list(APPEND srcs
|
||||||
"${tusb_src}/tusb.c"
|
# common
|
||||||
"${tusb_src}/common/tusb_fifo.c"
|
${tusb_src}/tusb.c
|
||||||
"${tusb_src}/device/usbd.c"
|
${tusb_src}/common/tusb_fifo.c
|
||||||
"${tusb_src}/device/usbd_control.c"
|
# device
|
||||||
"${tusb_src}/class/cdc/cdc_device.c"
|
${tusb_src}/device/usbd.c
|
||||||
"${tusb_src}/class/dfu/dfu_rt_device.c"
|
${tusb_src}/device/usbd_control.c
|
||||||
"${tusb_src}/class/hid/hid_device.c"
|
${tusb_src}/class/audio/audio_device.c
|
||||||
"${tusb_src}/class/midi/midi_device.c"
|
${tusb_src}/class/cdc/cdc_device.c
|
||||||
"${tusb_src}/class/msc/msc_device.c"
|
${tusb_src}/class/dfu/dfu_device.c
|
||||||
"${tusb_src}/class/net/ecm_rndis_device.c"
|
${tusb_src}/class/dfu/dfu_rt_device.c
|
||||||
"${tusb_src}/class/net/ncm_device.c"
|
${tusb_src}/class/hid/hid_device.c
|
||||||
"${tusb_src}/class/usbtmc/usbtmc_device.c"
|
${tusb_src}/class/midi/midi_device.c
|
||||||
"${tusb_src}/class/vendor/vendor_device.c"
|
${tusb_src}/class/msc/msc_device.c
|
||||||
"${tusb_src}/portable/synopsys/dwc2/dcd_dwc2.c"
|
${tusb_src}/class/net/ecm_rndis_device.c
|
||||||
|
${tusb_src}/class/net/ncm_device.c
|
||||||
|
${tusb_src}/class/usbtmc/usbtmc_device.c
|
||||||
|
${tusb_src}/class/vendor/vendor_device.c
|
||||||
|
${tusb_src}/class/video/video_device.c
|
||||||
|
${tusb_src}/portable/synopsys/dwc2/dcd_dwc2.c
|
||||||
|
# host
|
||||||
|
${tusb_src}/host/usbh.c
|
||||||
|
${tusb_src}/host/hub.c
|
||||||
|
${tusb_src}/class/cdc/cdc_host.c
|
||||||
|
${tusb_src}/class/hid/hid_host.c
|
||||||
|
${tusb_src}/class/msc/msc_host.c
|
||||||
|
${tusb_src}/class/vendor/vendor_host.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# use max3421 as host controller
|
||||||
|
if (MAX3421_HOST STREQUAL "1")
|
||||||
|
list(APPEND srcs ${tusb_src}/portable/analog/max3421/hcd_max3421.c)
|
||||||
|
list(APPEND compile_definitions CFG_TUH_MAX3421=1)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if (DEFINED LOG)
|
||||||
|
list(APPEND compile_definitions CFG_TUSB_DEBUG=${LOG})
|
||||||
|
if (LOG STREQUAL "4")
|
||||||
|
# no inline for debug level 4
|
||||||
|
list(APPEND compile_definitions TU_ATTR_ALWAYS_INLINE=)
|
||||||
|
endif ()
|
||||||
|
endif()
|
||||||
|
|
||||||
idf_component_register(SRCS ${srcs}
|
idf_component_register(SRCS ${srcs}
|
||||||
INCLUDE_DIRS ${includes_public}
|
INCLUDE_DIRS ${tusb_src}
|
||||||
REQUIRES src
|
REQUIRES src
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_options(${COMPONENT_LIB} PUBLIC ${compile_options})
|
target_compile_definitions(${COMPONENT_LIB} PUBLIC ${compile_definitions})
|
||||||
|
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-error=format)
|
||||||
|
@ -22,6 +22,8 @@ MCU_DIR = hw/mcu/nxp/lpcopen/lpc175x_6x/lpc_chip_175x_6x
|
|||||||
|
|
||||||
SRC_C += \
|
SRC_C += \
|
||||||
src/portable/nxp/lpc17_40/dcd_lpc17_40.c \
|
src/portable/nxp/lpc17_40/dcd_lpc17_40.c \
|
||||||
|
src/portable/ohci/ohci.c \
|
||||||
|
src/portable/nxp/lpc17_40/hcd_lpc17_40.c \
|
||||||
$(MCU_DIR)/../gcc/cr_startup_lpc175x_6x.c \
|
$(MCU_DIR)/../gcc/cr_startup_lpc175x_6x.c \
|
||||||
$(MCU_DIR)/src/chip_17xx_40xx.c \
|
$(MCU_DIR)/src/chip_17xx_40xx.c \
|
||||||
$(MCU_DIR)/src/clock_17xx_40xx.c \
|
$(MCU_DIR)/src/clock_17xx_40xx.c \
|
||||||
@ -29,7 +31,7 @@ SRC_C += \
|
|||||||
$(MCU_DIR)/src/iocon_17xx_40xx.c \
|
$(MCU_DIR)/src/iocon_17xx_40xx.c \
|
||||||
$(MCU_DIR)/src/sysctl_17xx_40xx.c \
|
$(MCU_DIR)/src/sysctl_17xx_40xx.c \
|
||||||
$(MCU_DIR)/src/sysinit_17xx_40xx.c \
|
$(MCU_DIR)/src/sysinit_17xx_40xx.c \
|
||||||
$(MCU_DIR)/src/uart_17xx_40xx.c
|
$(MCU_DIR)/src/uart_17xx_40xx.c \
|
||||||
|
|
||||||
INC += \
|
INC += \
|
||||||
$(TOP)/$(MCU_DIR)/inc
|
$(TOP)/$(MCU_DIR)/inc
|
||||||
|
@ -95,13 +95,8 @@ TU_ATTR_UNUSED static void power_event_handler(nrfx_power_usb_evt_t event) {
|
|||||||
|
|
||||||
//------------- Host using MAX2341E -------------//
|
//------------- Host using MAX2341E -------------//
|
||||||
#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
static void max3421_init(void);
|
||||||
static nrfx_spim_t _spi = NRFX_SPIM_INSTANCE(1);
|
static nrfx_spim_t _spi = NRFX_SPIM_INSTANCE(1);
|
||||||
|
|
||||||
void max3421_int_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {
|
|
||||||
if (!(pin == MAX3421_INTR_PIN && action == NRF_GPIOTE_POLARITY_HITOLO)) return;
|
|
||||||
|
|
||||||
tuh_int_handler(1, true);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -191,50 +186,7 @@ void board_init(void) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
// MAX3421 need 3.3v signal (may not be needed)
|
max3421_init();
|
||||||
#if defined(UICR_REGOUT0_VOUT_Msk) && 0
|
|
||||||
if ((NRF_UICR->REGOUT0 & UICR_REGOUT0_VOUT_Msk) != UICR_REGOUT0_VOUT_3V3) {
|
|
||||||
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
|
|
||||||
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
|
|
||||||
|
|
||||||
NRF_UICR->REGOUT0 = (NRF_UICR->REGOUT0 & ~UICR_REGOUT0_VOUT_Msk) | UICR_REGOUT0_VOUT_3V3;
|
|
||||||
|
|
||||||
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
|
|
||||||
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
|
|
||||||
|
|
||||||
NVIC_SystemReset();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// manually manage CS
|
|
||||||
nrf_gpio_cfg_output(MAX3421_CS_PIN);
|
|
||||||
nrf_gpio_pin_write(MAX3421_CS_PIN, 1);
|
|
||||||
|
|
||||||
// USB host using max3421e usb controller via SPI
|
|
||||||
nrfx_spim_config_t cfg = {
|
|
||||||
.sck_pin = MAX3421_SCK_PIN,
|
|
||||||
.mosi_pin = MAX3421_MOSI_PIN,
|
|
||||||
.miso_pin = MAX3421_MISO_PIN,
|
|
||||||
.ss_pin = NRFX_SPIM_PIN_NOT_USED,
|
|
||||||
.ss_active_high = false,
|
|
||||||
.irq_priority = 3,
|
|
||||||
.orc = 0xFF,
|
|
||||||
// default setting 4 Mhz, Mode 0, MSB first
|
|
||||||
.frequency = NRF_SPIM_FREQ_4M,
|
|
||||||
.mode = NRF_SPIM_MODE_0,
|
|
||||||
.bit_order = NRF_SPIM_BIT_ORDER_MSB_FIRST,
|
|
||||||
};
|
|
||||||
|
|
||||||
// no handler --> blocking
|
|
||||||
nrfx_spim_init(&_spi, &cfg, NULL, NULL);
|
|
||||||
|
|
||||||
// max3421e interrupt pin
|
|
||||||
nrfx_gpiote_init(1);
|
|
||||||
nrfx_gpiote_in_config_t in_config = NRFX_GPIOTE_CONFIG_IN_SENSE_HITOLO(true);
|
|
||||||
in_config.pull = NRF_GPIO_PIN_PULLUP;
|
|
||||||
|
|
||||||
nrfx_gpiote_in_init(MAX3421_INTR_PIN, &in_config, max3421_int_handler);
|
|
||||||
nrfx_gpiote_trigger_enable(MAX3421_INTR_PIN, true);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -317,6 +269,60 @@ void nrf_error_cb(uint32_t id, uint32_t pc, uint32_t info) {
|
|||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
|
||||||
|
void max3421_int_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {
|
||||||
|
if (!(pin == MAX3421_INTR_PIN && action == NRF_GPIOTE_POLARITY_HITOLO)) return;
|
||||||
|
tuh_int_handler(1, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void max3421_init(void) {
|
||||||
|
// MAX3421 need 3.3v signal (may not be needed)
|
||||||
|
// #if defined(UICR_REGOUT0_VOUT_Msk)
|
||||||
|
// if ((NRF_UICR->REGOUT0 & UICR_REGOUT0_VOUT_Msk) != UICR_REGOUT0_VOUT_3V3) {
|
||||||
|
// NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
|
||||||
|
// while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
|
||||||
|
//
|
||||||
|
// NRF_UICR->REGOUT0 = (NRF_UICR->REGOUT0 & ~UICR_REGOUT0_VOUT_Msk) | UICR_REGOUT0_VOUT_3V3;
|
||||||
|
//
|
||||||
|
// NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
|
||||||
|
// while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
|
||||||
|
//
|
||||||
|
// NVIC_SystemReset();
|
||||||
|
// }
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// manually manage CS
|
||||||
|
nrf_gpio_cfg_output(MAX3421_CS_PIN);
|
||||||
|
nrf_gpio_pin_write(MAX3421_CS_PIN, 1);
|
||||||
|
|
||||||
|
// USB host using max3421e usb controller via SPI
|
||||||
|
nrfx_spim_config_t cfg = {
|
||||||
|
.sck_pin = MAX3421_SCK_PIN,
|
||||||
|
.mosi_pin = MAX3421_MOSI_PIN,
|
||||||
|
.miso_pin = MAX3421_MISO_PIN,
|
||||||
|
.ss_pin = NRFX_SPIM_PIN_NOT_USED,
|
||||||
|
.ss_active_high = false,
|
||||||
|
.irq_priority = 3,
|
||||||
|
.orc = 0xFF,
|
||||||
|
// default setting 4 Mhz, Mode 0, MSB first
|
||||||
|
.frequency = NRF_SPIM_FREQ_4M,
|
||||||
|
.mode = NRF_SPIM_MODE_0,
|
||||||
|
.bit_order = NRF_SPIM_BIT_ORDER_MSB_FIRST,
|
||||||
|
};
|
||||||
|
|
||||||
|
// no handler --> blocking
|
||||||
|
nrfx_spim_init(&_spi, &cfg, NULL, NULL);
|
||||||
|
|
||||||
|
// max3421e interrupt pin
|
||||||
|
nrfx_gpiote_init(1);
|
||||||
|
nrfx_gpiote_in_config_t in_config = NRFX_GPIOTE_CONFIG_IN_SENSE_HITOLO(true);
|
||||||
|
in_config.pull = NRF_GPIO_PIN_PULLUP;
|
||||||
|
|
||||||
|
NVIC_SetPriority(GPIOTE_IRQn, 2);
|
||||||
|
|
||||||
|
nrfx_gpiote_in_init(MAX3421_INTR_PIN, &in_config, max3421_int_handler);
|
||||||
|
nrfx_gpiote_trigger_enable(MAX3421_INTR_PIN, true);
|
||||||
|
}
|
||||||
|
|
||||||
void tuh_max3421_int_api(uint8_t rhport, bool enabled) {
|
void tuh_max3421_int_api(uint8_t rhport, bool enabled) {
|
||||||
(void) rhport;
|
(void) rhport;
|
||||||
|
|
||||||
|
@ -261,6 +261,7 @@ void SysTick_Handler(void) {
|
|||||||
uint32_t board_millis(void) {
|
uint32_t board_millis(void) {
|
||||||
return system_ticks;
|
return system_ticks;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
//
|
//
|
||||||
@ -269,7 +270,8 @@ uint32_t board_millis(void) {
|
|||||||
|
|
||||||
static void max3421_init(void) {
|
static void max3421_init(void) {
|
||||||
//------------- SPI Init -------------//
|
//------------- SPI Init -------------//
|
||||||
uint32_t const baudrate = 4000000u;
|
// MAX3421E max SPI clock is 26MHz however SAMD can only work reliably at 12 Mhz
|
||||||
|
uint32_t const baudrate = 12000000u;
|
||||||
|
|
||||||
// Enable the APB clock for SERCOM
|
// Enable the APB clock for SERCOM
|
||||||
PM->APBCMASK.reg |= 1u << (PM_APBCMASK_SERCOM0_Pos + MAX3421_SERCOM_ID);
|
PM->APBCMASK.reg |= 1u << (PM_APBCMASK_SERCOM0_Pos + MAX3421_SERCOM_ID);
|
||||||
@ -343,6 +345,11 @@ static void max3421_init(void) {
|
|||||||
EIC->CONFIG[0].reg &= ~(7 << sense_shift);
|
EIC->CONFIG[0].reg &= ~(7 << sense_shift);
|
||||||
EIC->CONFIG[0].reg |= 2 << sense_shift;
|
EIC->CONFIG[0].reg |= 2 << sense_shift;
|
||||||
|
|
||||||
|
#if CFG_TUSB_OS == OPT_OS_FREERTOS
|
||||||
|
// If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher )
|
||||||
|
NVIC_SetPriority(EIC_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Enable External Interrupt
|
// Enable External Interrupt
|
||||||
EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << MAX3421_INTR_EIC_ID);
|
EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << MAX3421_INTR_EIC_ID);
|
||||||
|
|
||||||
@ -412,6 +419,3 @@ bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const *tx_buf, size_t tx_l
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
@ -59,7 +59,7 @@
|
|||||||
#define configTICK_RATE_HZ ( 1000 )
|
#define configTICK_RATE_HZ ( 1000 )
|
||||||
#define configMAX_PRIORITIES ( 5 )
|
#define configMAX_PRIORITIES ( 5 )
|
||||||
#define configMINIMAL_STACK_SIZE ( 128 )
|
#define configMINIMAL_STACK_SIZE ( 128 )
|
||||||
#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 )
|
#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*6*1024 )
|
||||||
#define configMAX_TASK_NAME_LEN 16
|
#define configMAX_TASK_NAME_LEN 16
|
||||||
#define configUSE_16_BIT_TICKS 0
|
#define configUSE_16_BIT_TICKS 0
|
||||||
#define configIDLE_SHOULD_YIELD 1
|
#define configIDLE_SHOULD_YIELD 1
|
||||||
|
@ -175,6 +175,7 @@ void SysTick_Handler(void) {
|
|||||||
uint32_t board_millis(void) {
|
uint32_t board_millis(void) {
|
||||||
return system_ticks;
|
return system_ticks;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// API: SPI transfer with MAX3421E, must be implemented by application
|
// API: SPI transfer with MAX3421E, must be implemented by application
|
||||||
@ -183,7 +184,9 @@ uint32_t board_millis(void) {
|
|||||||
|
|
||||||
static void max3421_init(void) {
|
static void max3421_init(void) {
|
||||||
//------------- SPI Init -------------//
|
//------------- SPI Init -------------//
|
||||||
uint32_t const baudrate = 4000000u;
|
|
||||||
|
// MAX3421E max SPI clock is 26MHz however SAMD can only work reliably at 12 Mhz
|
||||||
|
uint32_t const baudrate = 12000000u;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
volatile uint32_t *mck_apb;
|
volatile uint32_t *mck_apb;
|
||||||
@ -229,7 +232,12 @@ static void max3421_init(void) {
|
|||||||
while (sercom->SPI.SYNCBUSY.bit.CTRLB == 1);
|
while (sercom->SPI.SYNCBUSY.bit.CTRLB == 1);
|
||||||
|
|
||||||
// Set the baud rate
|
// Set the baud rate
|
||||||
sercom->SPI.BAUD.reg = (uint8_t) (SystemCoreClock / (2 * baudrate) - 1);
|
uint8_t baud_reg = (uint8_t) (SystemCoreClock / (2 * baudrate));
|
||||||
|
if (baud_reg) {
|
||||||
|
baud_reg--;
|
||||||
|
}
|
||||||
|
|
||||||
|
sercom->SPI.BAUD.reg = baud_reg;
|
||||||
|
|
||||||
// Configure PA12 as MOSI (PAD0), PA13 as SCK (PAD1), PA14 as MISO (PAD2), function C (sercom)
|
// Configure PA12 as MOSI (PAD0), PA13 as SCK (PAD1), PA14 as MISO (PAD2), function C (sercom)
|
||||||
gpio_set_pin_direction(MAX3421_SCK_PIN, GPIO_DIRECTION_OUT);
|
gpio_set_pin_direction(MAX3421_SCK_PIN, GPIO_DIRECTION_OUT);
|
||||||
@ -283,6 +291,11 @@ static void max3421_init(void) {
|
|||||||
*eic_config &= ~(7 << sense_shift);
|
*eic_config &= ~(7 << sense_shift);
|
||||||
*eic_config |= 2 << sense_shift;
|
*eic_config |= 2 << sense_shift;
|
||||||
|
|
||||||
|
#if CFG_TUSB_OS == OPT_OS_FREERTOS
|
||||||
|
// If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher )
|
||||||
|
NVIC_SetPriority(EIC_0_IRQn + MAX3421_INTR_EIC_ID, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Enable External Interrupt
|
// Enable External Interrupt
|
||||||
EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << MAX3421_INTR_EIC_ID);
|
EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << MAX3421_INTR_EIC_ID);
|
||||||
|
|
||||||
@ -353,5 +366,3 @@ bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const *tx_buf, size_t tx_l
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
|
||||||
|
@ -43,16 +43,14 @@
|
|||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// MACRO CONSTANT TYPEDEF
|
// MACRO CONSTANT TYPEDEF
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
enum
|
enum {
|
||||||
{
|
|
||||||
MSC_STAGE_IDLE = 0,
|
MSC_STAGE_IDLE = 0,
|
||||||
MSC_STAGE_CMD,
|
MSC_STAGE_CMD,
|
||||||
MSC_STAGE_DATA,
|
MSC_STAGE_DATA,
|
||||||
MSC_STAGE_STATUS,
|
MSC_STAGE_STATUS,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
|
||||||
uint8_t itf_num;
|
uint8_t itf_num;
|
||||||
uint8_t ep_in;
|
uint8_t ep_in;
|
||||||
uint8_t ep_out;
|
uint8_t ep_out;
|
||||||
@ -86,40 +84,34 @@ static uint8_t _msch_buffer[sizeof(scsi_inquiry_resp_t)];
|
|||||||
|
|
||||||
// FIXME potential nul reference
|
// FIXME potential nul reference
|
||||||
TU_ATTR_ALWAYS_INLINE
|
TU_ATTR_ALWAYS_INLINE
|
||||||
static inline msch_interface_t* get_itf(uint8_t dev_addr)
|
static inline msch_interface_t* get_itf(uint8_t dev_addr) {
|
||||||
{
|
|
||||||
return &_msch_itf[dev_addr - 1];
|
return &_msch_itf[dev_addr - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// PUBLIC API
|
// PUBLIC API
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
uint8_t tuh_msc_get_maxlun(uint8_t dev_addr)
|
uint8_t tuh_msc_get_maxlun(uint8_t dev_addr) {
|
||||||
{
|
|
||||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||||
return p_msc->max_lun;
|
return p_msc->max_lun;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t tuh_msc_get_block_count(uint8_t dev_addr, uint8_t lun)
|
uint32_t tuh_msc_get_block_count(uint8_t dev_addr, uint8_t lun) {
|
||||||
{
|
|
||||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||||
return p_msc->capacity[lun].block_count;
|
return p_msc->capacity[lun].block_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun)
|
uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun) {
|
||||||
{
|
|
||||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||||
return p_msc->capacity[lun].block_size;
|
return p_msc->capacity[lun].block_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tuh_msc_mounted(uint8_t dev_addr)
|
bool tuh_msc_mounted(uint8_t dev_addr) {
|
||||||
{
|
|
||||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||||
return p_msc->mounted;
|
return p_msc->mounted;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tuh_msc_ready(uint8_t dev_addr)
|
bool tuh_msc_ready(uint8_t dev_addr) {
|
||||||
{
|
|
||||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||||
return p_msc->mounted && !usbh_edpt_busy(dev_addr, p_msc->ep_in) && !usbh_edpt_busy(dev_addr, p_msc->ep_out);
|
return p_msc->mounted && !usbh_edpt_busy(dev_addr, p_msc->ep_in) && !usbh_edpt_busy(dev_addr, p_msc->ep_out);
|
||||||
}
|
}
|
||||||
@ -127,20 +119,20 @@ bool tuh_msc_ready(uint8_t dev_addr)
|
|||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// PUBLIC API: SCSI COMMAND
|
// PUBLIC API: SCSI COMMAND
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
static inline void cbw_init(msc_cbw_t *cbw, uint8_t lun)
|
static inline void cbw_init(msc_cbw_t* cbw, uint8_t lun) {
|
||||||
{
|
|
||||||
tu_memclr(cbw, sizeof(msc_cbw_t));
|
tu_memclr(cbw, sizeof(msc_cbw_t));
|
||||||
cbw->signature = MSC_CBW_SIGNATURE;
|
cbw->signature = MSC_CBW_SIGNATURE;
|
||||||
cbw->tag = 0x54555342; // TUSB
|
cbw->tag = 0x54555342; // TUSB
|
||||||
cbw->lun = lun;
|
cbw->lun = lun;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
|
bool tuh_msc_scsi_command(uint8_t daddr, msc_cbw_t const* cbw, void* data,
|
||||||
{
|
tuh_msc_complete_cb_t complete_cb, uintptr_t arg) {
|
||||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
msch_interface_t* p_msc = get_itf(daddr);
|
||||||
TU_VERIFY(p_msc->configured);
|
TU_VERIFY(p_msc->configured);
|
||||||
|
|
||||||
// TODO claim endpoint
|
// claim endpoint
|
||||||
|
TU_VERIFY(usbh_edpt_claim(daddr, p_msc->ep_out));
|
||||||
|
|
||||||
p_msc->cbw = *cbw;
|
p_msc->cbw = *cbw;
|
||||||
p_msc->stage = MSC_STAGE_CMD;
|
p_msc->stage = MSC_STAGE_CMD;
|
||||||
@ -148,13 +140,16 @@ bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tu
|
|||||||
p_msc->complete_cb = complete_cb;
|
p_msc->complete_cb = complete_cb;
|
||||||
p_msc->complete_arg = arg;
|
p_msc->complete_arg = arg;
|
||||||
|
|
||||||
TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t)));
|
if (!usbh_edpt_xfer(daddr, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t))) {
|
||||||
|
usbh_edpt_release(daddr, p_msc->ep_out);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
|
bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response,
|
||||||
{
|
tuh_msc_complete_cb_t complete_cb, uintptr_t arg) {
|
||||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||||
TU_VERIFY(p_msc->configured);
|
TU_VERIFY(p_msc->configured);
|
||||||
|
|
||||||
@ -169,8 +164,8 @@ bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_r
|
|||||||
return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg);
|
return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
|
bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response,
|
||||||
{
|
tuh_msc_complete_cb_t complete_cb, uintptr_t arg) {
|
||||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||||
TU_VERIFY(p_msc->mounted);
|
TU_VERIFY(p_msc->mounted);
|
||||||
|
|
||||||
@ -181,8 +176,7 @@ bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* respons
|
|||||||
cbw.dir = TUSB_DIR_IN_MASK;
|
cbw.dir = TUSB_DIR_IN_MASK;
|
||||||
cbw.cmd_len = sizeof(scsi_inquiry_t);
|
cbw.cmd_len = sizeof(scsi_inquiry_t);
|
||||||
|
|
||||||
scsi_inquiry_t const cmd_inquiry =
|
scsi_inquiry_t const cmd_inquiry = {
|
||||||
{
|
|
||||||
.cmd_code = SCSI_CMD_INQUIRY,
|
.cmd_code = SCSI_CMD_INQUIRY,
|
||||||
.alloc_length = sizeof(scsi_inquiry_resp_t)
|
.alloc_length = sizeof(scsi_inquiry_resp_t)
|
||||||
};
|
};
|
||||||
@ -191,8 +185,7 @@ bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* respons
|
|||||||
return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg);
|
return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
|
bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) {
|
||||||
{
|
|
||||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||||
TU_VERIFY(p_msc->configured);
|
TU_VERIFY(p_msc->configured);
|
||||||
|
|
||||||
@ -208,8 +201,8 @@ bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_
|
|||||||
return tuh_msc_scsi_command(dev_addr, &cbw, NULL, complete_cb, arg);
|
return tuh_msc_scsi_command(dev_addr, &cbw, NULL, complete_cb, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
|
bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void* response,
|
||||||
{
|
tuh_msc_complete_cb_t complete_cb, uintptr_t arg) {
|
||||||
msc_cbw_t cbw;
|
msc_cbw_t cbw;
|
||||||
cbw_init(&cbw, lun);
|
cbw_init(&cbw, lun);
|
||||||
|
|
||||||
@ -217,19 +210,17 @@ bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *response, tuh_ms
|
|||||||
cbw.dir = TUSB_DIR_IN_MASK;
|
cbw.dir = TUSB_DIR_IN_MASK;
|
||||||
cbw.cmd_len = sizeof(scsi_request_sense_t);
|
cbw.cmd_len = sizeof(scsi_request_sense_t);
|
||||||
|
|
||||||
scsi_request_sense_t const cmd_request_sense =
|
scsi_request_sense_t const cmd_request_sense = {
|
||||||
{
|
|
||||||
.cmd_code = SCSI_CMD_REQUEST_SENSE,
|
.cmd_code = SCSI_CMD_REQUEST_SENSE,
|
||||||
.alloc_length = 18
|
.alloc_length = 18
|
||||||
};
|
};
|
||||||
|
|
||||||
memcpy(cbw.command, &cmd_request_sense, cbw.cmd_len);
|
memcpy(cbw.command, &cmd_request_sense, cbw.cmd_len);
|
||||||
|
|
||||||
return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg);
|
return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
|
bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void* buffer, uint32_t lba, uint16_t block_count,
|
||||||
{
|
tuh_msc_complete_cb_t complete_cb, uintptr_t arg) {
|
||||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||||
TU_VERIFY(p_msc->mounted);
|
TU_VERIFY(p_msc->mounted);
|
||||||
|
|
||||||
@ -240,20 +231,18 @@ bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba,
|
|||||||
cbw.dir = TUSB_DIR_IN_MASK;
|
cbw.dir = TUSB_DIR_IN_MASK;
|
||||||
cbw.cmd_len = sizeof(scsi_read10_t);
|
cbw.cmd_len = sizeof(scsi_read10_t);
|
||||||
|
|
||||||
scsi_read10_t const cmd_read10 =
|
scsi_read10_t const cmd_read10 = {
|
||||||
{
|
|
||||||
.cmd_code = SCSI_CMD_READ_10,
|
.cmd_code = SCSI_CMD_READ_10,
|
||||||
.lba = tu_htonl(lba),
|
.lba = tu_htonl(lba),
|
||||||
.block_count = tu_htons(block_count)
|
.block_count = tu_htons(block_count)
|
||||||
};
|
};
|
||||||
|
|
||||||
memcpy(cbw.command, &cmd_read10, cbw.cmd_len);
|
memcpy(cbw.command, &cmd_read10, cbw.cmd_len);
|
||||||
|
|
||||||
return tuh_msc_scsi_command(dev_addr, &cbw, buffer, complete_cb, arg);
|
return tuh_msc_scsi_command(dev_addr, &cbw, buffer, complete_cb, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
|
bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const* buffer, uint32_t lba, uint16_t block_count,
|
||||||
{
|
tuh_msc_complete_cb_t complete_cb, uintptr_t arg) {
|
||||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||||
TU_VERIFY(p_msc->mounted);
|
TU_VERIFY(p_msc->mounted);
|
||||||
|
|
||||||
@ -264,13 +253,11 @@ bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_
|
|||||||
cbw.dir = TUSB_DIR_OUT;
|
cbw.dir = TUSB_DIR_OUT;
|
||||||
cbw.cmd_len = sizeof(scsi_write10_t);
|
cbw.cmd_len = sizeof(scsi_write10_t);
|
||||||
|
|
||||||
scsi_write10_t const cmd_write10 =
|
scsi_write10_t const cmd_write10 = {
|
||||||
{
|
|
||||||
.cmd_code = SCSI_CMD_WRITE_10,
|
.cmd_code = SCSI_CMD_WRITE_10,
|
||||||
.lba = tu_htonl(lba),
|
.lba = tu_htonl(lba),
|
||||||
.block_count = tu_htons(block_count)
|
.block_count = tu_htons(block_count)
|
||||||
};
|
};
|
||||||
|
|
||||||
memcpy(cbw.command, &cmd_write10, cbw.cmd_len);
|
memcpy(cbw.command, &cmd_write10, cbw.cmd_len);
|
||||||
|
|
||||||
return tuh_msc_scsi_command(dev_addr, &cbw, (void*) (uintptr_t) buffer, complete_cb, arg);
|
return tuh_msc_scsi_command(dev_addr, &cbw, (void*) (uintptr_t) buffer, complete_cb, arg);
|
||||||
@ -278,12 +265,9 @@ bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_
|
|||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// MSC interface Reset (not used now)
|
// MSC interface Reset (not used now)
|
||||||
bool tuh_msc_reset(uint8_t dev_addr)
|
bool tuh_msc_reset(uint8_t dev_addr) {
|
||||||
{
|
tusb_control_request_t const new_request = {
|
||||||
tusb_control_request_t const new_request =
|
.bmRequestType_bit = {
|
||||||
{
|
|
||||||
.bmRequestType_bit =
|
|
||||||
{
|
|
||||||
.recipient = TUSB_REQ_RCPT_INTERFACE,
|
.recipient = TUSB_REQ_RCPT_INTERFACE,
|
||||||
.type = TUSB_REQ_TYPE_CLASS,
|
.type = TUSB_REQ_TYPE_CLASS,
|
||||||
.direction = TUSB_DIR_OUT
|
.direction = TUSB_DIR_OUT
|
||||||
@ -300,13 +284,11 @@ bool tuh_msc_reset(uint8_t dev_addr)
|
|||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// CLASS-USBH API
|
// CLASS-USBH API
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
void msch_init(void)
|
void msch_init(void) {
|
||||||
{
|
|
||||||
tu_memclr(_msch_itf, sizeof(_msch_itf));
|
tu_memclr(_msch_itf, sizeof(_msch_itf));
|
||||||
}
|
}
|
||||||
|
|
||||||
void msch_close(uint8_t dev_addr)
|
void msch_close(uint8_t dev_addr) {
|
||||||
{
|
|
||||||
TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX,);
|
TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX,);
|
||||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||||
TU_VERIFY(p_msc->configured,);
|
TU_VERIFY(p_msc->configured,);
|
||||||
@ -321,27 +303,22 @@ void msch_close(uint8_t dev_addr)
|
|||||||
tu_memclr(p_msc, sizeof(msch_interface_t));
|
tu_memclr(p_msc, sizeof(msch_interface_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
|
bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) {
|
||||||
{
|
|
||||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||||
msc_cbw_t const * cbw = &p_msc->cbw;
|
msc_cbw_t const * cbw = &p_msc->cbw;
|
||||||
msc_csw_t * csw = &p_msc->csw;
|
msc_csw_t * csw = &p_msc->csw;
|
||||||
|
|
||||||
switch (p_msc->stage)
|
switch (p_msc->stage) {
|
||||||
{
|
|
||||||
case MSC_STAGE_CMD:
|
case MSC_STAGE_CMD:
|
||||||
// Must be Command Block
|
// Must be Command Block
|
||||||
TU_ASSERT(ep_addr == p_msc->ep_out && event == XFER_RESULT_SUCCESS && xferred_bytes == sizeof(msc_cbw_t));
|
TU_ASSERT(ep_addr == p_msc->ep_out && event == XFER_RESULT_SUCCESS && xferred_bytes == sizeof(msc_cbw_t));
|
||||||
|
|
||||||
if ( cbw->total_bytes && p_msc->buffer )
|
if (cbw->total_bytes && p_msc->buffer) {
|
||||||
{
|
|
||||||
// Data stage if any
|
// Data stage if any
|
||||||
p_msc->stage = MSC_STAGE_DATA;
|
p_msc->stage = MSC_STAGE_DATA;
|
||||||
|
|
||||||
uint8_t const ep_data = (cbw->dir & TUSB_DIR_IN_MASK) ? p_msc->ep_in : p_msc->ep_out;
|
uint8_t const ep_data = (cbw->dir & TUSB_DIR_IN_MASK) ? p_msc->ep_in : p_msc->ep_out;
|
||||||
TU_ASSERT(usbh_edpt_xfer(dev_addr, ep_data, p_msc->buffer, (uint16_t) cbw->total_bytes));
|
TU_ASSERT(usbh_edpt_xfer(dev_addr, ep_data, p_msc->buffer, (uint16_t) cbw->total_bytes));
|
||||||
}else
|
} else {
|
||||||
{
|
|
||||||
// Status stage
|
// Status stage
|
||||||
p_msc->stage = MSC_STAGE_STATUS;
|
p_msc->stage = MSC_STAGE_STATUS;
|
||||||
TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, (uint16_t) sizeof(msc_csw_t)));
|
TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, (uint16_t) sizeof(msc_csw_t)));
|
||||||
@ -358,10 +335,8 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32
|
|||||||
// SCSI op is complete
|
// SCSI op is complete
|
||||||
p_msc->stage = MSC_STAGE_IDLE;
|
p_msc->stage = MSC_STAGE_IDLE;
|
||||||
|
|
||||||
if (p_msc->complete_cb)
|
if (p_msc->complete_cb) {
|
||||||
{
|
tuh_msc_complete_data_t const cb_data = {
|
||||||
tuh_msc_complete_data_t const cb_data =
|
|
||||||
{
|
|
||||||
.cbw = cbw,
|
.cbw = cbw,
|
||||||
.csw = csw,
|
.csw = csw,
|
||||||
.scsi_data = p_msc->buffer,
|
.scsi_data = p_msc->buffer,
|
||||||
@ -372,7 +347,8 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
// unknown state
|
// unknown state
|
||||||
default: break;
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -381,35 +357,31 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32
|
|||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// MSC Enumeration
|
// MSC Enumeration
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
static void config_get_maxlun_complete(tuh_xfer_t* xfer);
|
static void config_get_maxlun_complete(tuh_xfer_t* xfer);
|
||||||
static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data);
|
static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data);
|
||||||
static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data);
|
static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data);
|
||||||
static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data);
|
static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data);
|
||||||
|
|
||||||
bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
|
bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const* desc_itf, uint16_t max_len) {
|
||||||
{
|
|
||||||
(void) rhport;
|
(void) rhport;
|
||||||
TU_VERIFY (MSC_SUBCLASS_SCSI == desc_itf->bInterfaceSubClass &&
|
TU_VERIFY (MSC_SUBCLASS_SCSI == desc_itf->bInterfaceSubClass &&
|
||||||
MSC_PROTOCOL_BOT == desc_itf->bInterfaceProtocol);
|
MSC_PROTOCOL_BOT == desc_itf->bInterfaceProtocol);
|
||||||
|
|
||||||
// msc driver length is fixed
|
// msc driver length is fixed
|
||||||
uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
|
uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) +
|
||||||
|
desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
|
||||||
TU_ASSERT(drv_len <= max_len);
|
TU_ASSERT(drv_len <= max_len);
|
||||||
|
|
||||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||||
tusb_desc_endpoint_t const* ep_desc = (tusb_desc_endpoint_t const*) tu_desc_next(desc_itf);
|
tusb_desc_endpoint_t const* ep_desc = (tusb_desc_endpoint_t const*) tu_desc_next(desc_itf);
|
||||||
|
|
||||||
for(uint32_t i=0; i<2; i++)
|
for (uint32_t i = 0; i < 2; i++) {
|
||||||
{
|
|
||||||
TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType && TUSB_XFER_BULK == ep_desc->bmAttributes.xfer);
|
TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType && TUSB_XFER_BULK == ep_desc->bmAttributes.xfer);
|
||||||
TU_ASSERT(tuh_edpt_open(dev_addr, ep_desc));
|
TU_ASSERT(tuh_edpt_open(dev_addr, ep_desc));
|
||||||
|
|
||||||
if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN )
|
if (TUSB_DIR_IN == tu_edpt_dir(ep_desc->bEndpointAddress)) {
|
||||||
{
|
|
||||||
p_msc->ep_in = ep_desc->bEndpointAddress;
|
p_msc->ep_in = ep_desc->bEndpointAddress;
|
||||||
}else
|
} else {
|
||||||
{
|
|
||||||
p_msc->ep_out = ep_desc->bEndpointAddress;
|
p_msc->ep_out = ep_desc->bEndpointAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -454,8 +426,7 @@ bool msch_set_config(uint8_t dev_addr, uint8_t itf_num) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void config_get_maxlun_complete (tuh_xfer_t* xfer)
|
static void config_get_maxlun_complete(tuh_xfer_t* xfer) {
|
||||||
{
|
|
||||||
uint8_t const daddr = xfer->daddr;
|
uint8_t const daddr = xfer->daddr;
|
||||||
msch_interface_t* p_msc = get_itf(daddr);
|
msch_interface_t* p_msc = get_itf(daddr);
|
||||||
|
|
||||||
@ -471,18 +442,16 @@ static void config_get_maxlun_complete (tuh_xfer_t* xfer)
|
|||||||
tuh_msc_test_unit_ready(daddr, lun, config_test_unit_ready_complete, 0);
|
tuh_msc_test_unit_ready(daddr, lun, config_test_unit_ready_complete, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data)
|
static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data) {
|
||||||
{
|
|
||||||
msc_cbw_t const* cbw = cb_data->cbw;
|
msc_cbw_t const* cbw = cb_data->cbw;
|
||||||
msc_csw_t const* csw = cb_data->csw;
|
msc_csw_t const* csw = cb_data->csw;
|
||||||
|
|
||||||
if (csw->status == 0)
|
if (csw->status == 0) {
|
||||||
{
|
|
||||||
// Unit is ready, read its capacity
|
// Unit is ready, read its capacity
|
||||||
TU_LOG_DRV("SCSI Read Capacity\r\n");
|
TU_LOG_DRV("SCSI Read Capacity\r\n");
|
||||||
tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer), config_read_capacity_complete, 0);
|
tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer),
|
||||||
}else
|
config_read_capacity_complete, 0);
|
||||||
{
|
} else {
|
||||||
// Note: During enumeration, some device fails Test Unit Ready and require a few retries
|
// Note: During enumeration, some device fails Test Unit Ready and require a few retries
|
||||||
// with Request Sense to start working !!
|
// with Request Sense to start working !!
|
||||||
// TODO limit number of retries
|
// TODO limit number of retries
|
||||||
@ -493,8 +462,7 @@ static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_d
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data)
|
static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data) {
|
||||||
{
|
|
||||||
msc_cbw_t const* cbw = cb_data->cbw;
|
msc_cbw_t const* cbw = cb_data->cbw;
|
||||||
msc_csw_t const* csw = cb_data->csw;
|
msc_csw_t const* csw = cb_data->csw;
|
||||||
|
|
||||||
@ -503,8 +471,7 @@ static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_dat
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data)
|
static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data) {
|
||||||
{
|
|
||||||
msc_cbw_t const* cbw = cb_data->cbw;
|
msc_cbw_t const* cbw = cb_data->cbw;
|
||||||
msc_csw_t const* csw = cb_data->csw;
|
msc_csw_t const* csw = cb_data->csw;
|
||||||
|
|
||||||
|
@ -24,8 +24,8 @@
|
|||||||
* This file is part of the TinyUSB stack.
|
* This file is part of the TinyUSB stack.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _TUSB_MSC_HOST_H_
|
#ifndef TUSB_MSC_HOST_H_
|
||||||
#define _TUSB_MSC_HOST_H_
|
#define TUSB_MSC_HOST_H_
|
||||||
|
|
||||||
#include "msc.h"
|
#include "msc.h"
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun);
|
|||||||
// Perform a full SCSI command (cbw, data, csw) in non-blocking manner.
|
// Perform a full SCSI command (cbw, data, csw) in non-blocking manner.
|
||||||
// Complete callback is invoked when SCSI op is complete.
|
// Complete callback is invoked when SCSI op is complete.
|
||||||
// return true if success, false if there is already pending operation.
|
// return true if success, false if there is already pending operation.
|
||||||
bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg);
|
bool tuh_msc_scsi_command(uint8_t daddr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg);
|
||||||
|
|
||||||
// Perform SCSI Inquiry command
|
// Perform SCSI Inquiry command
|
||||||
// Complete callback is invoked when SCSI op is complete.
|
// Complete callback is invoked when SCSI op is complete.
|
||||||
@ -123,4 +123,4 @@ bool msch_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, ui
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _TUSB_MSC_HOST_H_ */
|
#endif
|
||||||
|
@ -817,6 +817,7 @@ bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Submit an transfer
|
// Submit an transfer
|
||||||
|
// TODO call usbh_edpt_release if failed
|
||||||
bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes,
|
bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes,
|
||||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data)
|
tuh_xfer_cb_t complete_cb, uintptr_t user_data)
|
||||||
{
|
{
|
||||||
@ -1713,19 +1714,16 @@ static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configur
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
|
void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) {
|
||||||
{
|
|
||||||
usbh_device_t* dev = get_device(dev_addr);
|
usbh_device_t* dev = get_device(dev_addr);
|
||||||
|
|
||||||
for(itf_num++; itf_num < CFG_TUH_INTERFACE_MAX; itf_num++)
|
for(itf_num++; itf_num < CFG_TUH_INTERFACE_MAX; itf_num++) {
|
||||||
{
|
|
||||||
// continue with next valid interface
|
// continue with next valid interface
|
||||||
// IAD binding interface such as CDCs should return itf_num + 1 when complete
|
// IAD binding interface such as CDCs should return itf_num + 1 when complete
|
||||||
// with usbh_driver_set_config_complete()
|
// with usbh_driver_set_config_complete()
|
||||||
uint8_t const drv_id = dev->itf2drv[itf_num];
|
uint8_t const drv_id = dev->itf2drv[itf_num];
|
||||||
usbh_class_driver_t const * driver = get_driver(drv_id);
|
usbh_class_driver_t const * driver = get_driver(drv_id);
|
||||||
if (driver)
|
if (driver) {
|
||||||
{
|
|
||||||
TU_LOG_USBH("%s set config: itf = %u\r\n", driver->name, itf_num);
|
TU_LOG_USBH("%s set config: itf = %u\r\n", driver->name, itf_num);
|
||||||
driver->set_config(dev_addr, itf_num);
|
driver->set_config(dev_addr, itf_num);
|
||||||
break;
|
break;
|
||||||
@ -1733,23 +1731,19 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// all interface are configured
|
// all interface are configured
|
||||||
if (itf_num == CFG_TUH_INTERFACE_MAX)
|
if (itf_num == CFG_TUH_INTERFACE_MAX) {
|
||||||
{
|
|
||||||
enum_full_complete();
|
enum_full_complete();
|
||||||
|
|
||||||
if (is_hub_addr(dev_addr))
|
if (is_hub_addr(dev_addr)) {
|
||||||
{
|
|
||||||
TU_LOG(CFG_TUH_LOG_LEVEL, "HUB address = %u is mounted\r\n", dev_addr);
|
TU_LOG(CFG_TUH_LOG_LEVEL, "HUB address = %u is mounted\r\n", dev_addr);
|
||||||
}else
|
}else {
|
||||||
{
|
|
||||||
// Invoke callback if available
|
// Invoke callback if available
|
||||||
if (tuh_mount_cb) tuh_mount_cb(dev_addr);
|
if (tuh_mount_cb) tuh_mount_cb(dev_addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void enum_full_complete(void)
|
static void enum_full_complete(void) {
|
||||||
{
|
|
||||||
// mark enumeration as complete
|
// mark enumeration as complete
|
||||||
_dev0.enumerating = 0;
|
_dev0.enumerating = 0;
|
||||||
|
|
||||||
|
@ -263,7 +263,7 @@ static void fifo_read(uint8_t rhport, uint8_t * buffer, uint16_t len, bool in_is
|
|||||||
|
|
||||||
max3421_spi_lock(rhport, in_isr);
|
max3421_spi_lock(rhport, in_isr);
|
||||||
|
|
||||||
tuh_max3421_spi_xfer_api(rhport, ®, 1, &hirq, 0);
|
tuh_max3421_spi_xfer_api(rhport, ®, 1, &hirq, 1);
|
||||||
_hcd_data.hirq = hirq;
|
_hcd_data.hirq = hirq;
|
||||||
tuh_max3421_spi_xfer_api(rhport, NULL, 0, buffer, len);
|
tuh_max3421_spi_xfer_api(rhport, NULL, 0, buffer, len);
|
||||||
|
|
||||||
@ -693,9 +693,7 @@ static void handle_connect_irq(uint8_t rhport, bool in_isr) {
|
|||||||
|
|
||||||
// port reset anyway, this will help to stable bus signal for next connection
|
// port reset anyway, this will help to stable bus signal for next connection
|
||||||
reg_write(rhport, HCTL_ADDR, HCTL_BUSRST, in_isr);
|
reg_write(rhport, HCTL_ADDR, HCTL_BUSRST, in_isr);
|
||||||
|
|
||||||
hcd_event_device_remove(rhport, in_isr);
|
hcd_event_device_remove(rhport, in_isr);
|
||||||
|
|
||||||
reg_write(rhport, HCTL_ADDR, 0, in_isr);
|
reg_write(rhport, HCTL_ADDR, 0, in_isr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -721,13 +719,12 @@ static void handle_connect_irq(uint8_t rhport, bool in_isr) {
|
|||||||
free_ep(daddr);
|
free_ep(daddr);
|
||||||
|
|
||||||
hcd_event_device_attach(rhport, in_isr);
|
hcd_event_device_attach(rhport, in_isr);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t result, uint8_t hrsl) {
|
static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t result, uint8_t hrsl, bool in_isr) {
|
||||||
uint8_t const ep_addr = tu_edpt_addr(ep->ep_num, ep->ep_dir);
|
uint8_t const ep_addr = tu_edpt_addr(ep->ep_num, ep->ep_dir);
|
||||||
|
|
||||||
// save data toggle
|
// save data toggle
|
||||||
@ -738,20 +735,20 @@ static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t re
|
|||||||
}
|
}
|
||||||
|
|
||||||
ep->xfer_pending = 0;
|
ep->xfer_pending = 0;
|
||||||
hcd_event_xfer_complete(ep->daddr, ep_addr, ep->xferred_len, result, true);
|
hcd_event_xfer_complete(ep->daddr, ep_addr, ep->xferred_len, result, in_isr);
|
||||||
|
|
||||||
// Find next pending endpoint
|
// Find next pending endpoint
|
||||||
max3421_ep_t *next_ep = find_next_pending_ep(ep);
|
max3421_ep_t *next_ep = find_next_pending_ep(ep);
|
||||||
if (next_ep) {
|
if (next_ep) {
|
||||||
xact_inout(rhport, next_ep, true, true);
|
xact_inout(rhport, next_ep, true, in_isr);
|
||||||
}else {
|
}else {
|
||||||
// no more pending
|
// no more pending
|
||||||
atomic_flag_clear(&_hcd_data.busy);
|
atomic_flag_clear(&_hcd_data.busy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_xfer_done(uint8_t rhport) {
|
static void handle_xfer_done(uint8_t rhport, bool in_isr) {
|
||||||
uint8_t const hrsl = reg_read(rhport, HRSL_ADDR, true);
|
uint8_t const hrsl = reg_read(rhport, HRSL_ADDR, in_isr);
|
||||||
uint8_t const hresult = hrsl & HRSL_RESULT_MASK;
|
uint8_t const hresult = hrsl & HRSL_RESULT_MASK;
|
||||||
|
|
||||||
uint8_t const ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK;
|
uint8_t const ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK;
|
||||||
@ -774,17 +771,17 @@ static void handle_xfer_done(uint8_t rhport) {
|
|||||||
case HRSL_NAK:
|
case HRSL_NAK:
|
||||||
if (ep_num == 0) {
|
if (ep_num == 0) {
|
||||||
// NAK on control, retry immediately
|
// NAK on control, retry immediately
|
||||||
hxfr_write(rhport, _hcd_data.hxfr, true);
|
hxfr_write(rhport, _hcd_data.hxfr, in_isr);
|
||||||
}else {
|
}else {
|
||||||
// NAK on non-control, find next pending to switch
|
// NAK on non-control, find next pending to switch
|
||||||
max3421_ep_t *next_ep = find_next_pending_ep(ep);
|
max3421_ep_t *next_ep = find_next_pending_ep(ep);
|
||||||
|
|
||||||
if (ep == next_ep) {
|
if (ep == next_ep) {
|
||||||
// this endpoint is only one pending, retry immediately
|
// this endpoint is only one pending, retry immediately
|
||||||
hxfr_write(rhport, _hcd_data.hxfr, true);
|
hxfr_write(rhport, _hcd_data.hxfr, in_isr);
|
||||||
}else if (next_ep) {
|
}else if (next_ep) {
|
||||||
// switch to next pending TODO could have issue with double buffered if not clear previously out data
|
// switch to next pending TODO could have issue with double buffered if not clear previously out data
|
||||||
xact_inout(rhport, next_ep, true, true);
|
xact_inout(rhport, next_ep, true, in_isr);
|
||||||
}else {
|
}else {
|
||||||
TU_ASSERT(false,);
|
TU_ASSERT(false,);
|
||||||
}
|
}
|
||||||
@ -802,7 +799,7 @@ static void handle_xfer_done(uint8_t rhport) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (xfer_result != XFER_RESULT_SUCCESS) {
|
if (xfer_result != XFER_RESULT_SUCCESS) {
|
||||||
xfer_complete_isr(rhport, ep, xfer_result, hrsl);
|
xfer_complete_isr(rhport, ep, xfer_result, hrsl, in_isr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -814,10 +811,10 @@ static void handle_xfer_done(uint8_t rhport) {
|
|||||||
|
|
||||||
// short packet or all bytes transferred
|
// short packet or all bytes transferred
|
||||||
if ( ep->xfer_complete ) {
|
if ( ep->xfer_complete ) {
|
||||||
xfer_complete_isr(rhport, ep, xfer_result, hrsl);
|
xfer_complete_isr(rhport, ep, xfer_result, hrsl, in_isr);
|
||||||
}else {
|
}else {
|
||||||
// more to transfer
|
// more to transfer
|
||||||
hxfr_write(rhport, _hcd_data.hxfr, true);
|
hxfr_write(rhport, _hcd_data.hxfr, in_isr);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// SETUP or OUT transfer
|
// SETUP or OUT transfer
|
||||||
@ -835,10 +832,10 @@ static void handle_xfer_done(uint8_t rhport) {
|
|||||||
ep->buf += xact_len;
|
ep->buf += xact_len;
|
||||||
|
|
||||||
if (xact_len < ep->packet_size || ep->xferred_len >= ep->total_len) {
|
if (xact_len < ep->packet_size || ep->xferred_len >= ep->total_len) {
|
||||||
xfer_complete_isr(rhport, ep, xfer_result, hrsl);
|
xfer_complete_isr(rhport, ep, xfer_result, hrsl, in_isr);
|
||||||
} else {
|
} else {
|
||||||
// more to transfer
|
// more to transfer
|
||||||
xact_out(rhport, ep, false, true);
|
xact_out(rhport, ep, false, in_isr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -862,10 +859,9 @@ void print_hirq(uint8_t hirq) {
|
|||||||
#define print_hirq(hirq)
|
#define print_hirq(hirq)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Interrupt Handler
|
// Interrupt handler
|
||||||
void hcd_int_handler(uint8_t rhport, bool in_isr) {
|
void hcd_int_handler(uint8_t rhport, bool in_isr) {
|
||||||
(void) in_isr;
|
uint8_t hirq = reg_read(rhport, HIRQ_ADDR, in_isr) & _hcd_data.hien;
|
||||||
uint8_t hirq = reg_read(rhport, HIRQ_ADDR, true) & _hcd_data.hien;
|
|
||||||
if (!hirq) return;
|
if (!hirq) return;
|
||||||
// print_hirq(hirq);
|
// print_hirq(hirq);
|
||||||
|
|
||||||
@ -874,7 +870,7 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (hirq & HIRQ_CONDET_IRQ) {
|
if (hirq & HIRQ_CONDET_IRQ) {
|
||||||
handle_connect_irq(rhport, true);
|
handle_connect_irq(rhport, in_isr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// queue more transfer in handle_xfer_done() can cause hirq to be set again while external IRQ may not catch and/or
|
// queue more transfer in handle_xfer_done() can cause hirq to be set again while external IRQ may not catch and/or
|
||||||
@ -883,21 +879,21 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
|
|||||||
if ( hirq & HIRQ_RCVDAV_IRQ ) {
|
if ( hirq & HIRQ_RCVDAV_IRQ ) {
|
||||||
uint8_t const ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK;
|
uint8_t const ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK;
|
||||||
max3421_ep_t *ep = find_opened_ep(_hcd_data.peraddr, ep_num, 1);
|
max3421_ep_t *ep = find_opened_ep(_hcd_data.peraddr, ep_num, 1);
|
||||||
uint8_t xact_len;
|
uint8_t xact_len = 0;
|
||||||
|
|
||||||
// RCVDAV_IRQ can trigger 2 times (dual buffered)
|
// RCVDAV_IRQ can trigger 2 times (dual buffered)
|
||||||
while ( hirq & HIRQ_RCVDAV_IRQ ) {
|
while ( hirq & HIRQ_RCVDAV_IRQ ) {
|
||||||
uint8_t rcvbc = reg_read(rhport, RCVBC_ADDR, true);
|
uint8_t rcvbc = reg_read(rhport, RCVBC_ADDR, in_isr);
|
||||||
xact_len = (uint8_t) tu_min16(rcvbc, ep->total_len - ep->xferred_len);
|
xact_len = (uint8_t) tu_min16(rcvbc, ep->total_len - ep->xferred_len);
|
||||||
if ( xact_len ) {
|
if ( xact_len ) {
|
||||||
fifo_read(rhport, ep->buf, xact_len, true);
|
fifo_read(rhport, ep->buf, xact_len, in_isr);
|
||||||
ep->buf += xact_len;
|
ep->buf += xact_len;
|
||||||
ep->xferred_len += xact_len;
|
ep->xferred_len += xact_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ack RCVDVAV IRQ
|
// ack RCVDVAV IRQ
|
||||||
hirq_write(rhport, HIRQ_RCVDAV_IRQ, true);
|
hirq_write(rhport, HIRQ_RCVDAV_IRQ, in_isr);
|
||||||
hirq = reg_read(rhport, HIRQ_ADDR, true);
|
hirq = reg_read(rhport, HIRQ_ADDR, in_isr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( xact_len < ep->packet_size || ep->xferred_len >= ep->total_len ) {
|
if ( xact_len < ep->packet_size || ep->xferred_len >= ep->total_len ) {
|
||||||
@ -906,17 +902,17 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( hirq & HIRQ_HXFRDN_IRQ ) {
|
if ( hirq & HIRQ_HXFRDN_IRQ ) {
|
||||||
hirq_write(rhport, HIRQ_HXFRDN_IRQ, true);
|
hirq_write(rhport, HIRQ_HXFRDN_IRQ, in_isr);
|
||||||
handle_xfer_done(rhport);
|
handle_xfer_done(rhport, in_isr);
|
||||||
}
|
}
|
||||||
|
|
||||||
hirq = reg_read(rhport, HIRQ_ADDR, true);
|
hirq = reg_read(rhport, HIRQ_ADDR, in_isr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear all interrupt except SNDBAV_IRQ (never clear by us). Note RCVDAV_IRQ, HXFRDN_IRQ already clear while processing
|
// clear all interrupt except SNDBAV_IRQ (never clear by us). Note RCVDAV_IRQ, HXFRDN_IRQ already clear while processing
|
||||||
hirq &= ~HIRQ_SNDBAV_IRQ;
|
hirq &= ~HIRQ_SNDBAV_IRQ;
|
||||||
if ( hirq ) {
|
if ( hirq ) {
|
||||||
hirq_write(rhport, hirq, true);
|
hirq_write(rhport, hirq, in_isr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,3 +17,10 @@ TINYUSB_SRC_C += \
|
|||||||
src/class/usbtmc/usbtmc_device.c \
|
src/class/usbtmc/usbtmc_device.c \
|
||||||
src/class/video/video_device.c \
|
src/class/video/video_device.c \
|
||||||
src/class/vendor/vendor_device.c \
|
src/class/vendor/vendor_device.c \
|
||||||
|
src/host/usbh.c \
|
||||||
|
src/host/hub.c \
|
||||||
|
src/class/cdc/cdc_host.c \
|
||||||
|
src/class/hid/hid_host.c \
|
||||||
|
src/class/msc/msc_host.c \
|
||||||
|
src/class/vendor/vendor_host.c \
|
||||||
|
src/typec/usbc.c \
|
||||||
|
@ -470,6 +470,10 @@
|
|||||||
#define CFG_TUD_RPI_PIO_USB 0
|
#define CFG_TUD_RPI_PIO_USB 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// MAX3421 Host controller option
|
||||||
|
#ifndef CFG_TUH_MAX3421
|
||||||
|
#define CFG_TUH_MAX3421 0
|
||||||
|
#endif
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// TypeC Options (Default)
|
// TypeC Options (Default)
|
||||||
|
@ -17,8 +17,8 @@ exit_status = 0
|
|||||||
|
|
||||||
total_time = time.monotonic()
|
total_time = time.monotonic()
|
||||||
|
|
||||||
build_format = '| {:23} | {:30} | {:18} | {:7} | {:6} | {:6} |'
|
build_format = '| {:30} | {:30} | {:18} | {:7} | {:6} | {:6} |'
|
||||||
build_separator = '-' * 100
|
build_separator = '-' * 107
|
||||||
|
|
||||||
def filter_with_input(mylist):
|
def filter_with_input(mylist):
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
@ -26,12 +26,9 @@ def filter_with_input(mylist):
|
|||||||
if len(input_args) > 0:
|
if len(input_args) > 0:
|
||||||
mylist[:] = input_args
|
mylist[:] = input_args
|
||||||
|
|
||||||
|
|
||||||
# Build all examples if not specified
|
# Build all examples if not specified
|
||||||
all_examples = []
|
all_examples = [entry.replace('examples/', '') for entry in glob.glob("examples/*/*_freertos")]
|
||||||
for entry in os.scandir("examples/device"):
|
|
||||||
# Only includes example with CMakeLists.txt for esp32s, and skip board_test to speed up ci
|
|
||||||
if entry.is_dir() and os.path.exists(entry.path + "/sdkconfig.defaults") and entry.name != 'board_test':
|
|
||||||
all_examples.append(entry.name)
|
|
||||||
filter_with_input(all_examples)
|
filter_with_input(all_examples)
|
||||||
all_examples.sort()
|
all_examples.sort()
|
||||||
|
|
||||||
@ -46,32 +43,41 @@ all_boards.sort()
|
|||||||
def build_board(example, board):
|
def build_board(example, board):
|
||||||
global success_count, fail_count, skip_count, exit_status
|
global success_count, fail_count, skip_count, exit_status
|
||||||
start_time = time.monotonic()
|
start_time = time.monotonic()
|
||||||
|
|
||||||
|
# Check if board is skipped
|
||||||
|
build_dir = f"cmake-build/cmake-build-{board}/{example}"
|
||||||
|
|
||||||
|
# Generate and build
|
||||||
|
r = subprocess.run(f"cmake examples/{example} -B {build_dir} -G \"Ninja\" -DBOARD={board} -DMAX3421_HOST=1",
|
||||||
|
shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||||
|
if r.returncode == 0:
|
||||||
|
r = subprocess.run(f"cmake --build {build_dir}", shell=True, stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.STDOUT)
|
||||||
|
build_duration = time.monotonic() - start_time
|
||||||
flash_size = "-"
|
flash_size = "-"
|
||||||
sram_size = "-"
|
sram_size = "-"
|
||||||
|
|
||||||
# Check if board is skipped
|
if r.returncode == 0:
|
||||||
if build_utils.skip_example(example, board):
|
|
||||||
success = SKIPPED
|
|
||||||
skip_count += 1
|
|
||||||
print(build_format.format(example, board, success, '-', flash_size, sram_size))
|
|
||||||
else:
|
|
||||||
subprocess.run("make -C examples/device/{} BOARD={} clean".format(example, board), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
||||||
build_result = subprocess.run("make -j -C examples/device/{} BOARD={} all".format(example, board), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
||||||
|
|
||||||
if build_result.returncode == 0:
|
|
||||||
success = SUCCEEDED
|
success = SUCCEEDED
|
||||||
success_count += 1
|
success_count += 1
|
||||||
(flash_size, sram_size) = build_size(example, board)
|
#(flash_size, sram_size) = build_size(example, board)
|
||||||
else:
|
else:
|
||||||
exit_status = build_result.returncode
|
exit_status = r.returncode
|
||||||
success = FAILED
|
success = FAILED
|
||||||
fail_count += 1
|
fail_count += 1
|
||||||
|
|
||||||
build_duration = time.monotonic() - start_time
|
title = build_format.format(example, board, success, "{:.2f}s".format(build_duration), flash_size, sram_size)
|
||||||
print(build_format.format(example, board, success, "{:.2f}s".format(build_duration), flash_size, sram_size))
|
if os.getenv('CI'):
|
||||||
|
# always print build output if in CI
|
||||||
|
print(f"::group::{title}")
|
||||||
|
print(r.stdout.decode("utf-8"))
|
||||||
|
print(f"::endgroup::")
|
||||||
|
else:
|
||||||
|
# print build output if failed
|
||||||
|
print(title)
|
||||||
|
if r.returncode != 0:
|
||||||
|
print(r.stdout.decode("utf-8"))
|
||||||
|
|
||||||
if build_result.returncode != 0:
|
|
||||||
print(build_result.stdout.decode("utf-8"))
|
|
||||||
|
|
||||||
def build_size(example, board):
|
def build_size(example, board):
|
||||||
#elf_file = 'examples/device/{}/_build/{}/{}-firmware.elf'.format(example, board, board)
|
#elf_file = 'examples/device/{}/_build/{}/{}-firmware.elf'.format(example, board, board)
|
||||||
@ -82,6 +88,7 @@ def build_size(example, board):
|
|||||||
sram_size = int(size_list[1]) + int(size_list[2])
|
sram_size = int(size_list[1]) + int(size_list[2])
|
||||||
return (flash_size, sram_size)
|
return (flash_size, sram_size)
|
||||||
|
|
||||||
|
|
||||||
print(build_separator)
|
print(build_separator)
|
||||||
print(build_format.format('Example', 'Board', '\033[39mResult\033[0m', 'Time', 'Flash', 'SRAM'))
|
print(build_format.format('Example', 'Board', '\033[39mResult\033[0m', 'Time', 'Flash', 'SRAM'))
|
||||||
print(build_separator)
|
print(build_separator)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user