Skip to content

Commit

Permalink
ports/esp32: Use shared/tinyusb integration.
Browse files Browse the repository at this point in the history
Uses newer libusb synopsys/dwc2 driver rather than
the IDF tinyusb component.

Signed-off-by: Andrew Leech <andrew@alelec.net>
  • Loading branch information
pi-anl committed Aug 23, 2024
1 parent 6c3dc0c commit 25d4a27
Show file tree
Hide file tree
Showing 11 changed files with 187 additions and 73 deletions.
2 changes: 1 addition & 1 deletion lib/tinyusb
Submodule tinyusb updated 59 files
+7 −1 .github/actions/setup_toolchain/download/action.yml
+7 −3 .github/workflows/build.yml
+0 −66 .github/workflows/build_renesas.yml
+4 −2 .github/workflows/ci_set_matrix.py
+1 −1 .idea/cmake.xml
+1 −0 examples/device/audio_4_channel_mic_freertos/skip.txt
+1 −0 examples/device/audio_test_freertos/skip.txt
+1 −0 examples/device/cdc_msc_freertos/skip.txt
+1 −0 examples/device/hid_composite_freertos/skip.txt
+1 −0 examples/device/net_lwip_webserver/skip.txt
+1 −0 examples/device/video_capture/skip.txt
+1 −0 examples/device/video_capture_2ch/skip.txt
+8 −0 hw/bsp/ch32v10x/boards/ch32v103r_r1_1v0/board.cmake
+20 −0 hw/bsp/ch32v10x/boards/ch32v103r_r1_1v0/board.h
+5 −0 hw/bsp/ch32v10x/boards/ch32v103r_r1_1v0/board.mk
+37 −0 hw/bsp/ch32v10x/ch32v10x_conf.h
+15 −0 hw/bsp/ch32v10x/ch32v10x_it.h
+148 −0 hw/bsp/ch32v10x/family.c
+117 −0 hw/bsp/ch32v10x/family.cmake
+53 −0 hw/bsp/ch32v10x/family.mk
+165 −0 hw/bsp/ch32v10x/linker/ch32v10x.ld
+600 −0 hw/bsp/ch32v10x/system_ch32v10x.c
+29 −0 hw/bsp/ch32v10x/system_ch32v10x.h
+17 −0 hw/bsp/ch32v10x/wch-riscv.cfg
+2 −0 hw/bsp/ch32v20x/boards/ch32v203_r0_1v0/board.cmake
+0 −572 hw/bsp/ch32v20x/core_riscv.h
+13 −1 hw/bsp/ch32v20x/family.c
+5 −0 hw/bsp/ch32v20x/family.cmake
+9 −5 hw/bsp/ch32v20x/family.mk
+0 −379 hw/bsp/ch32v307/core_riscv.h
+9 −0 hw/bsp/ch32v307/debug_uart.c
+13 −0 hw/bsp/ch32v307/family.c
+1 −0 hw/bsp/ch32v307/family.cmake
+4 −0 hw/bsp/ch32v307/family.mk
+2 −0 hw/bsp/espressif/boards/espressif_c6_devkitc/board.cmake
+51 −0 hw/bsp/espressif/boards/espressif_c6_devkitc/board.h
+17 −1 hw/bsp/family_support.cmake
+8 −0 hw/bsp/stm32u5/boards/stm32u545nucleo/board.cmake
+112 −0 hw/bsp/stm32u5/boards/stm32u545nucleo/board.h
+11 −0 hw/bsp/stm32u5/boards/stm32u545nucleo/board.mk
+1 −0 hw/bsp/stm32u5/boards/stm32u575eval/board.mk
+1 −0 hw/bsp/stm32u5/boards/stm32u575nucleo/board.mk
+1 −0 hw/bsp/stm32u5/boards/stm32u5a5nucleo/board.mk
+16 −1 hw/bsp/stm32u5/family.c
+10 −4 hw/bsp/stm32u5/family.cmake
+12 −2 hw/bsp/stm32u5/family.mk
+2 −2 src/class/hid/hid.h
+2 −0 src/class/net/ncm_device.c
+25 −9 src/common/tusb_mcu.h
+1 −1 src/host/usbh.c
+4 −4 src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+13 −3 src/portable/st/stm32_fsdev/fsdev_ch32.h
+2 −22 src/portable/st/stm32_fsdev/fsdev_common.h
+31 −0 src/portable/st/stm32_fsdev/fsdev_stm32.h
+1 −0 src/portable/synopsys/dwc2/dwc2_esp32.h
+69 −5 src/portable/wch/ch32_usbfs_reg.h
+12 −0 src/portable/wch/ch32_usbhs_reg.h
+1 −1 src/tusb_option.h
+4 −1 tools/get_deps.py
48 changes: 48 additions & 0 deletions ports/esp32/esp32_common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,45 @@ list(APPEND MICROPY_SOURCE_DRIVERS
${MICROPY_DIR}/drivers/dht/dht.c
)

if(MICROPY_PY_TINYUSB)
string(CONCAT GIT_SUBMODULES "${GIT_SUBMODULES} " lib/tinyusb)

if(ECHO_SUBMODULES)
# No-op, we're just doing submodule/variant discovery.
# Cannot run the add_library/target_include_directories rules (even though
# the build won't run) because IDF will attempt verify the files exist.
else()

set(TINYUSB_SRC "${MICROPY_DIR}/lib/tinyusb/src")
string(TOUPPER OPT_MCU_${IDF_TARGET} tusb_mcu)

list(APPEND MICROPY_DEF_TINYUSB
CFG_TUSB_MCU=${tusb_mcu}
)

list(APPEND MICROPY_SOURCE_TINYUSB
${TINYUSB_SRC}/tusb.c
${TINYUSB_SRC}/common/tusb_fifo.c
${TINYUSB_SRC}/device/usbd.c
${TINYUSB_SRC}/device/usbd_control.c
${TINYUSB_SRC}/class/cdc/cdc_device.c
${TINYUSB_SRC}/portable/synopsys/dwc2/dcd_dwc2.c
${MICROPY_DIR}/shared/tinyusb/mp_usbd.c
${MICROPY_DIR}/shared/tinyusb/mp_usbd_cdc.c
${MICROPY_DIR}/shared/tinyusb/mp_usbd_descriptor.c
)

list(APPEND MICROPY_INC_TINYUSB
${TINYUSB_SRC}
${MICROPY_DIR}/shared/tinyusb/
)

list(APPEND MICROPY_LINK_TINYUSB
-Wl,--wrap=dcd_event_handler
)
endif()
endif()

list(APPEND MICROPY_SOURCE_PORT
panichandler.c
adc.c
Expand Down Expand Up @@ -99,6 +138,7 @@ list(APPEND MICROPY_SOURCE_QSTR
${MICROPY_SOURCE_LIB}
${MICROPY_SOURCE_PORT}
${MICROPY_SOURCE_BOARD}
${MICROPY_SOURCE_TINYUSB}
)

list(APPEND IDF_COMPONENTS
Expand Down Expand Up @@ -133,6 +173,7 @@ list(APPEND IDF_COMPONENTS
soc
spi_flash
ulp
usb
vfs
)

Expand All @@ -146,9 +187,11 @@ idf_component_register(
${MICROPY_SOURCE_DRIVERS}
${MICROPY_SOURCE_PORT}
${MICROPY_SOURCE_BOARD}
${MICROPY_SOURCE_TINYUSB}
INCLUDE_DIRS
${MICROPY_INC_CORE}
${MICROPY_INC_USERMOD}
${MICROPY_INC_TINYUSB}
${MICROPY_PORT_DIR}
${MICROPY_BOARD_DIR}
${CMAKE_BINARY_DIR}
Expand All @@ -170,6 +213,7 @@ endif()
target_compile_definitions(${MICROPY_TARGET} PUBLIC
${MICROPY_DEF_CORE}
${MICROPY_DEF_BOARD}
${MICROPY_DEF_TINYUSB}
MICROPY_ESP_IDF_4=1
MICROPY_VFS_FAT=1
MICROPY_VFS_LFS2=1
Expand All @@ -185,6 +229,10 @@ target_compile_options(${MICROPY_TARGET} PUBLIC
-Wno-missing-field-initializers
)

target_link_options(${MICROPY_TARGET} PUBLIC
${MICROPY_LINK_TINYUSB}
)

# Additional include directories needed for private NimBLE headers.
target_include_directories(${MICROPY_TARGET} PUBLIC
${IDF_PATH}/components/bt/host/nimble/nimble
Expand Down
3 changes: 2 additions & 1 deletion ports/esp32/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
#include "shared/readline/readline.h"
#include "shared/runtime/pyexec.h"
#include "shared/timeutils/timeutils.h"
#include "shared/tinyusb/mp_usbd.h"
#include "mbedtls/platform_time.h"

#include "uart.h"
Expand Down Expand Up @@ -101,7 +102,7 @@ void mp_task(void *pvParameter) {
#endif
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED
usb_serial_jtag_init();
#elif CONFIG_USB_OTG_SUPPORTED
#elif MICROPY_HW_ENABLE_USBDEV
usb_init();
#endif
#if MICROPY_HW_ENABLE_UART_REPL
Expand Down
2 changes: 2 additions & 0 deletions ports/esp32/main_esp32s2/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ if(NOT MICROPY_PORT_DIR)
get_filename_component(MICROPY_PORT_DIR ${MICROPY_DIR}/ports/esp32 ABSOLUTE)
endif()

set(MICROPY_PY_TINYUSB ON)

include(${MICROPY_PORT_DIR}/esp32_common.cmake)
2 changes: 2 additions & 0 deletions ports/esp32/main_esp32s3/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ if(NOT MICROPY_PORT_DIR)
get_filename_component(MICROPY_PORT_DIR ${MICROPY_DIR}/ports/esp32 ABSOLUTE)
endif()

set(MICROPY_PY_TINYUSB ON)

include(${MICROPY_PORT_DIR}/esp32_common.cmake)
56 changes: 56 additions & 0 deletions ports/esp32/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,62 @@

#define MP_STATE_PORT MP_STATE_VM

#if CONFIG_USB_OTG_SUPPORTED
#ifndef MICROPY_HW_ENABLE_USBDEV
#define MICROPY_HW_ENABLE_USBDEV (1)
#endif
#endif

#if MICROPY_HW_ENABLE_USBDEV
#define MICROPY_SCHEDULER_STATIC_NODES (1)

// Enable USB-CDC serial port
#ifndef MICROPY_HW_USB_CDC
#define MICROPY_HW_USB_CDC (1)
#endif

#ifndef MICROPY_HW_USB_VID
#define USB_ESPRESSIF_VID 0x303A
#if CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID
#define MICROPY_HW_USB_VID (USB_ESPRESSIF_VID)
#else
#define MICROPY_HW_USB_VID (CONFIG_TINYUSB_DESC_CUSTOM_VID)
#endif
#endif

#ifndef MICROPY_HW_USB_PID
#if CONFIG_TINYUSB_DESC_USE_DEFAULT_PID
#define _PID_MAP(itf, n) ((CFG_TUD_##itf) << (n))
// A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
// Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
// Auto ProductID layout's Bitmap:
// [MSB] HID | MSC | CDC [LSB]
#define USB_TUSB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3)) // | _PID_MAP(AUDIO, 4) | _PID_MAP(VENDOR, 5) )
#define MICROPY_HW_USB_PID (USB_TUSB_PID)
#else
#define MICROPY_HW_USB_PID (CONFIG_TINYUSB_DESC_CUSTOM_PID)
#endif
#endif

#ifndef MICROPY_HW_USB_MANUFACTURER_STRING
#ifdef CONFIG_TINYUSB_DESC_MANUFACTURER_STRING
#define MICROPY_HW_USB_MANUFACTURER_STRING CONFIG_TINYUSB_DESC_MANUFACTURER_STRING
#else
#define MICROPY_HW_USB_MANUFACTURER_STRING "MicroPython"
#endif
#endif

#ifndef MICROPY_HW_USB_PRODUCT_FS_STRING
#ifdef CONFIG_TINYUSB_DESC_PRODUCT_STRING
#define MICROPY_HW_USB_PRODUCT_FS_STRING CONFIG_TINYUSB_DESC_PRODUCT_STRING
#else
#define MICROPY_HW_USB_PRODUCT_FS_STRING "Board in FS mode"
#endif
#endif
#endif


// type definitions for the specific machine

#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p)))
Expand Down
35 changes: 26 additions & 9 deletions ports/esp32/mphalport.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
#include "extmod/misc.h"
#include "shared/timeutils/timeutils.h"
#include "shared/runtime/pyexec.h"
#include "shared/tinyusb/mp_usbd.h"
#include "shared/tinyusb/mp_usbd_cdc.h"
#include "mphalport.h"
#include "usb.h"
#include "usb_serial_jtag.h"
Expand Down Expand Up @@ -106,13 +108,19 @@ uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
uintptr_t ret = 0;
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED
usb_serial_jtag_poll_rx();
#endif
if ((poll_flags & MP_STREAM_POLL_RD) && stdin_ringbuf.iget != stdin_ringbuf.iput) {
if ((poll_flags & MP_STREAM_POLL_RD) && ringbuf_peek(&stdin_ringbuf) != -1) {
ret |= MP_STREAM_POLL_RD;
}
if (poll_flags & MP_STREAM_POLL_WR) {
ret |= MP_STREAM_POLL_WR;
}
#endif
#if MICROPY_HW_USB_CDC
ret |= mp_usbd_cdc_poll_interfaces(poll_flags);
#endif
#if MICROPY_PY_OS_DUPTERM
ret |= mp_os_dupterm_poll(poll_flags);
#endif
return ret;
}

Expand All @@ -121,6 +129,9 @@ int mp_hal_stdin_rx_chr(void) {
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED
usb_serial_jtag_poll_rx();
#endif
#if MICROPY_HW_USB_CDC
mp_usbd_cdc_poll_interfaces(0);
#endif
int c = ringbuf_get(&stdin_ringbuf);
if (c != -1) {
return c;
Expand All @@ -133,6 +144,7 @@ mp_uint_t mp_hal_stdout_tx_strn(const char *str, size_t len) {
// Only release the GIL if many characters are being sent
mp_uint_t ret = len;
bool did_write = false;
#if MICROPY_HW_ENABLE_UART_REPL || CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED
bool release_gil = len > MICROPY_PY_STRING_TX_GIL_THRESHOLD;
#if MICROPY_DEBUG_PRINTERS && MICROPY_DEBUG_VERBOSE && MICROPY_PY_THREAD_GIL
// If verbose debug output is enabled some strings are printed before the
Expand All @@ -143,20 +155,25 @@ mp_uint_t mp_hal_stdout_tx_strn(const char *str, size_t len) {
if (release_gil) {
MP_THREAD_GIL_EXIT();
}
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED
usb_serial_jtag_tx_strn(str, len);
did_write = true;
#elif CONFIG_USB_OTG_SUPPORTED
usb_tx_strn(str, len);
did_write = true;
#endif
#if MICROPY_HW_ENABLE_UART_REPL
uart_stdout_tx_strn(str, len);
did_write = true;
#endif
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED
usb_serial_jtag_tx_strn(str, len);
did_write = true;
#endif
if (release_gil) {
MP_THREAD_GIL_ENTER();
}
#endif
#if MICROPY_HW_USB_CDC
mp_uint_t cdc_res = mp_usbd_cdc_tx_strn(str, len);
if (cdc_res > 0) {
did_write = true;
ret = MIN(cdc_res, ret);
}
#endif
int dupterm_res = mp_os_dupterm_tx_strn(str, len);
if (dupterm_res >= 0) {
did_write = true;
Expand Down
107 changes: 48 additions & 59 deletions ports/esp32/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,76 +28,65 @@
#include "py/mphal.h"
#include "usb.h"

#if CONFIG_USB_OTG_SUPPORTED && !CONFIG_ESP_CONSOLE_USB_CDC && !CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED
#if CONFIG_USB_OTG_SUPPORTED && !CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED
#include "esp_rom_gpio.h"
#include "esp_mac.h"
#include "esp_private/usb_phy.h"

#include "esp_timer.h"
#ifndef NO_QSTR
#include "tinyusb.h"
#include "tusb_cdc_acm.h"
#endif
#include "shared/tinyusb/mp_usbd.h"

#define CDC_ITF TINYUSB_CDC_ACM_0
#define EXTERNAL_PHY 0
#define SELF_POWERED 0

static uint8_t usb_rx_buf[CONFIG_TINYUSB_CDC_RX_BUFSIZE];
static usb_phy_handle_t phy_hdl;

// This is called from FreeRTOS task "tusb_tsk" in espressif__esp_tinyusb (not an ISR).
static void usb_callback_rx(int itf, cdcacm_event_t *event) {
// espressif__esp_tinyusb places tinyusb rx data onto freertos ringbuffer which
// this function forwards onto our stdin_ringbuf.
for (;;) {
size_t len = 0;
esp_err_t ret = tinyusb_cdcacm_read(itf, usb_rx_buf, sizeof(usb_rx_buf), &len);
if (ret != ESP_OK) {
break;
}
if (len == 0) {
break;
}
for (size_t i = 0; i < len; ++i) {
if (usb_rx_buf[i] == mp_interrupt_char) {
mp_sched_keyboard_interrupt();
} else {
ringbuf_put(&stdin_ringbuf, usb_rx_buf[i]);
}
}
mp_hal_wake_main_task();
}
}

void usb_init(void) {
// Initialise the USB with defaults.
tinyusb_config_t tusb_cfg = {0};
ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg));
// ref: https://github.com/espressif/esp-usb/blob/4b6a798d0bed444fff48147c8dcdbbd038e92892/device/esp_tinyusb/tinyusb.c

// Initialise the USB serial interface.
tinyusb_config_cdcacm_t acm_cfg = {
.usb_dev = TINYUSB_USBDEV_0,
.cdc_port = CDC_ITF,
.rx_unread_buf_sz = 256,
.callback_rx = &usb_callback_rx,
#ifdef MICROPY_HW_USB_CUSTOM_RX_WANTED_CHAR_CB
.callback_rx_wanted_char = &MICROPY_HW_USB_CUSTOM_RX_WANTED_CHAR_CB,
#endif
#ifdef MICROPY_HW_USB_CUSTOM_LINE_STATE_CB
.callback_line_state_changed = (tusb_cdcacm_callback_t)&MICROPY_HW_USB_CUSTOM_LINE_STATE_CB,
#endif
#ifdef MICROPY_HW_USB_CUSTOM_LINE_CODING_CB
.callback_line_coding_changed = &MICROPY_HW_USB_CUSTOM_LINE_CODING_CB,
#endif
// Configure USB PHY
usb_phy_config_t phy_conf = {
.controller = USB_PHY_CTRL_OTG,
.otg_mode = USB_OTG_MODE_DEVICE,
};
ESP_ERROR_CHECK(tusb_cdc_acm_init(&acm_cfg));

}
#if EXTERNAL_PHY
// External PHY IOs config
usb_phy_ext_io_conf_t ext_io_conf = {
.vp_io_num = USBPHY_VP_NUM,
.vm_io_num = USBPHY_VM_NUM,
.rcv_io_num = USBPHY_RCV_NUM,
.oen_io_num = USBPHY_OEN_NUM,
.vpo_io_num = USBPHY_VPO_NUM,
.vmo_io_num = USBPHY_VMO_NUM,
};
phy_conf.target = USB_PHY_TARGET_EXT;
phy_conf.ext_io_conf = &ext_io_conf;
#else
phy_conf.target = USB_PHY_TARGET_INT;
#endif

void usb_tx_strn(const char *str, size_t len) {
// Write out the data to the CDC interface, but only while the USB host is connected.
uint64_t timeout = esp_timer_get_time() + (uint64_t)(MICROPY_HW_USB_CDC_TX_TIMEOUT_MS * 1000);
while (tud_cdc_n_connected(CDC_ITF) && len && esp_timer_get_time() < timeout) {
size_t l = tinyusb_cdcacm_write_queue(CDC_ITF, (uint8_t *)str, len);
str += l;
len -= l;
tud_cdc_n_write_flush(CDC_ITF);
#if SELF_POWERED
// OTG IOs config
const usb_phy_otg_io_conf_t otg_io_conf = USB_PHY_SELF_POWERED_DEVICE(config->vbus_monitor_io);
if (config->self_powered) {
phy_conf.otg_io_conf = &otg_io_conf;
}
#endif
// Init ESP USB Phy
usb_new_phy(&phy_conf, &phy_hdl);

// Init MicroPython / TinyUSB
mp_usbd_init();

}

void mp_usbd_port_get_serial_number(char *serial_buf) {
// use factory default MAC as serial ID
uint8_t mac[8];
esp_efuse_mac_get_default(mac);
MP_STATIC_ASSERT(sizeof(mac) * 2 <= MICROPY_HW_USB_DESC_STR_MAX);
mp_usbd_hex_str(serial_buf, mac, sizeof(mac));
}

#endif // CONFIG_USB_OTG_SUPPORTED && !CONFIG_ESP_CONSOLE_USB_CDC && !CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED
Loading

0 comments on commit 25d4a27

Please sign in to comment.