diff options
| -rw-r--r-- | ports/renesas-ra/Makefile | 29 | ||||
| -rw-r--r-- | ports/renesas-ra/main.c | 5 | ||||
| -rw-r--r-- | ports/renesas-ra/mpconfigport.h | 52 | ||||
| -rw-r--r-- | ports/renesas-ra/mphalport.c | 231 | ||||
| -rw-r--r-- | ports/renesas-ra/mphalport.h | 4 | ||||
| -rw-r--r-- | ports/renesas-ra/uart.c | 6 | ||||
| -rw-r--r-- | ports/renesas-ra/usbd.c | 48 |
7 files changed, 357 insertions, 18 deletions
diff --git a/ports/renesas-ra/Makefile b/ports/renesas-ra/Makefile index 77077d6cc..a8cc6d191 100644 --- a/ports/renesas-ra/Makefile +++ b/ports/renesas-ra/Makefile @@ -44,7 +44,7 @@ FROZEN_MANIFEST ?= boards/manifest.py include $(TOP)/py/py.mk include $(TOP)/extmod/extmod.mk -GIT_SUBMODULES += lib/fsp +GIT_SUBMODULES += lib/fsp lib/tinyusb MCU_SERIES_UPPER = $(shell echo $(MCU_SERIES) | tr '[:lower:]' '[:upper:]') CMSIS_MCU_LOWER = $(shell echo $(CMSIS_MCU) | tr '[:upper:]' '[:lower:]') @@ -69,6 +69,9 @@ INC += -I$(TOP)/$(HAL_DIR)/ra/fsp/inc INC += -I$(TOP)/$(HAL_DIR)/ra/fsp/inc/api INC += -I$(TOP)/$(HAL_DIR)/ra/fsp/inc/instances INC += -I$(TOP)/$(HAL_DIR)/ra/fsp/src/bsp/cmsis/Device/RENESAS/Include +INC += -I$(TOP)/lib/tinyusb/hw +INC += -I$(TOP)/lib/tinyusb/src +INC += -I$(TOP)/shared/tinyusb #INC += -Ilwip_inc ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),RA4M1 RA4W1 RA6M1 RA6M2 RA6M5)) INC += -Ira @@ -82,6 +85,7 @@ INC += -Idebug CFLAGS += -D$(CMSIS_MCU) CFLAGS += -DRA_HAL_H='<$(CMSIS_MCU)_hal.h>' CFLAGS += -DRA_CFG_H='<$(FSP_BOARD_NAME)_conf.h>' +CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_RAXXX # Basic Cortex-M flags CFLAGS_CORTEX_M = -mthumb @@ -171,6 +175,27 @@ SHARED_SRC_C += $(addprefix shared/,\ runtime/stdout_helpers.c \ runtime/sys_stdio_mphal.c \ timeutils/timeutils.c \ + tinyusb/mp_cdc_common.c \ + tinyusb/mp_usbd.c \ + tinyusb/mp_usbd_descriptor.c \ + ) + +# TinyUSB Stack source +TINYUSB_SRC_C += $(addprefix lib/tinyusb/,\ + src/class/cdc/cdc_device.c \ + src/class/dfu/dfu_rt_device.c \ + src/class/hid/hid_device.c \ + src/class/midi/midi_device.c \ + src/class/msc/msc_device.c \ + src/class/usbtmc/usbtmc_device.c \ + src/class/vendor/vendor_device.c \ + src/common/tusb_fifo.c \ + src/device/usbd.c \ + src/device/usbd_control.c \ + src/portable/renesas/rusb2/dcd_rusb2.c \ + src/portable/renesas/rusb2/hcd_rusb2.c \ + src/portable/renesas/rusb2/rusb2_common.c \ + src/tusb.c \ ) ifeq ($(MICROPY_FLOAT_IMPL),double) @@ -307,6 +332,7 @@ SRC_C += \ flashbdev.c \ storage.c \ fatfs_port.c \ + usbd.c \ $(wildcard $(BOARD_DIR)/*.c) SRC_C += $(addprefix $(BOARD_DIR)/ra_gen/,\ @@ -401,6 +427,7 @@ OBJ += $(LIBM_O) OBJ += $(addprefix $(BUILD)/, $(SHARED_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(HAL_SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(TINYUSB_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_CXX:.cpp=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_O)) diff --git a/ports/renesas-ra/main.c b/ports/renesas-ra/main.c index 8f4baa8e2..f23539625 100644 --- a/ports/renesas-ra/main.c +++ b/ports/renesas-ra/main.c @@ -62,6 +62,7 @@ #include "usrsw.h" #include "rtc.h" #include "storage.h" +#include "tusb.h" #define RA_EARLY_PRINT 1 /* for enabling mp_print in boardctrl. */ @@ -259,6 +260,10 @@ int main(void) { state.reset_mode = 1; state.log_soft_reset = false; + #if MICROPY_HW_ENABLE_USBDEV + tusb_init(); + #endif + MICROPY_BOARD_BEFORE_SOFT_RESET_LOOP(&state); soft_reset: diff --git a/ports/renesas-ra/mpconfigport.h b/ports/renesas-ra/mpconfigport.h index 34b299bd1..eb21db843 100644 --- a/ports/renesas-ra/mpconfigport.h +++ b/ports/renesas-ra/mpconfigport.h @@ -37,6 +37,28 @@ #define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES) #endif +#ifndef MICROPY_HW_ENABLE_USBDEV +#define MICROPY_HW_ENABLE_USBDEV (0) +#endif +#ifndef MICROPY_HW_ENABLE_UART_REPL +#define MICROPY_HW_ENABLE_UART_REPL (1) // useful if there is no USB +#endif + +#if MICROPY_HW_ENABLE_USBDEV +// Enable USB-CDC serial port +#ifndef MICROPY_HW_USB_CDC +#define MICROPY_HW_USB_CDC (1) +#endif +// Enable USB Mass Storage with FatFS filesystem. +#ifndef MICROPY_HW_USB_MSC +#define MICROPY_HW_USB_MSC (0) +#endif +// RA unique ID is 16 bytes (hex string == 32) +#ifndef MICROPY_HW_USB_DESC_STR_MAX +#define MICROPY_HW_USB_DESC_STR_MAX (32) +#endif +#endif + // memory allocation policies #ifndef MICROPY_GC_STACK_ENTRY_TYPE #if MICROPY_HW_SDRAM_SIZE @@ -139,6 +161,11 @@ #define MICROPY_FATFS_USE_LABEL (1) #define MICROPY_FATFS_RPATH (2) #define MICROPY_FATFS_MULTI_PARTITION (1) +#if MICROPY_HW_USB_MSC +// Set FatFS block size to flash sector size to avoid caching +// the flash sector in memory to support smaller block sizes. +#define MICROPY_FATFS_MAX_SS (FLASH_SECTOR_SIZE) +#endif #if MICROPY_PY_MACHINE #define MACHINE_BUILTIN_MODULE_CONSTANTS \ @@ -153,6 +180,15 @@ #define MP_STATE_PORT MP_STATE_VM +// Miscellaneous settings + +#ifndef MICROPY_HW_USB_VID +#define MICROPY_HW_USB_VID (0xf055) +#endif +#ifndef MICROPY_HW_USB_PID +#define MICROPY_HW_USB_PID (0x9800) +#endif + // type definitions for the specific machine #define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((uint32_t)(p) | 1)) @@ -190,10 +226,25 @@ static inline mp_uint_t disable_irq(void) { #define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq() #define MICROPY_END_ATOMIC_SECTION(state) enable_irq(state) +#if MICROPY_HW_ENABLE_USBDEV +#define MICROPY_HW_USBDEV_TASK_HOOK extern void usbd_task(void); usbd_task(); +#define MICROPY_VM_HOOK_COUNT (10) +#define MICROPY_VM_HOOK_INIT static uint vm_hook_divisor = MICROPY_VM_HOOK_COUNT; +#define MICROPY_VM_HOOK_POLL if (--vm_hook_divisor == 0) { \ + vm_hook_divisor = MICROPY_VM_HOOK_COUNT; \ + MICROPY_HW_USBDEV_TASK_HOOK \ +} +#define MICROPY_VM_HOOK_LOOP MICROPY_VM_HOOK_POLL +#define MICROPY_VM_HOOK_RETURN MICROPY_VM_HOOK_POLL +#else +#define MICROPY_HW_USBDEV_TASK_HOOK +#endif + #if MICROPY_PY_THREAD #define MICROPY_EVENT_POLL_HOOK \ do { \ extern void mp_handle_pending(bool); \ + MICROPY_HW_USBDEV_TASK_HOOK \ mp_handle_pending(true); \ if (pyb_thread_enabled) { \ MP_THREAD_GIL_EXIT(); \ @@ -209,6 +260,7 @@ static inline mp_uint_t disable_irq(void) { #define MICROPY_EVENT_POLL_HOOK \ do { \ extern void mp_handle_pending(bool); \ + MICROPY_HW_USBDEV_TASK_HOOK \ mp_handle_pending(true); \ __WFI(); \ } while (0); diff --git a/ports/renesas-ra/mphalport.c b/ports/renesas-ra/mphalport.c index b35ab7571..91705129c 100644 --- a/ports/renesas-ra/mphalport.c +++ b/ports/renesas-ra/mphalport.c @@ -3,8 +3,9 @@ * * The MIT License (MIT) * - * Copyright (c) 2018 Damien P. George + * Copyright (c) 2018,2021 Damien P. George * Copyright (c) 2021,2022 Renesas Electronics Corporation + * Copyright (c) 2023 Arduino SA * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,15 +26,32 @@ * THE SOFTWARE. */ -#include <string.h> - #include "py/runtime.h" #include "py/stream.h" +#include "py/mphal.h" #include "py/mperrno.h" #include "py/mphal.h" +#include "py/ringbuf.h" #include "extmod/misc.h" +#include "shared/runtime/interrupt_char.h" +#include "tusb.h" #include "uart.h" +#if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE +void flash_cache_commit(void); +#endif + +#if MICROPY_HW_ENABLE_UART_REPL || MICROPY_HW_USB_CDC + +#ifndef MICROPY_HW_STDIN_BUFFER_LEN +#define MICROPY_HW_STDIN_BUFFER_LEN 512 +#endif + +STATIC uint8_t stdin_ringbuf_array[MICROPY_HW_STDIN_BUFFER_LEN]; +ringbuf_t stdin_ringbuf = { stdin_ringbuf_array, sizeof(stdin_ringbuf_array) }; + +#endif + // this table converts from HAL_StatusTypeDef to POSIX errno const byte mp_hal_status_to_errno_table[4] = { [HAL_OK] = 0, @@ -46,42 +64,128 @@ NORETURN void mp_hal_raise(HAL_StatusTypeDef status) { mp_raise_OSError(mp_hal_status_to_errno_table[status]); } -MP_WEAK uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) { - uintptr_t ret = 0; - if (MP_STATE_PORT(pyb_stdio_uart) != NULL) { - mp_obj_t pyb_stdio_uart = MP_OBJ_FROM_PTR(MP_STATE_PORT(pyb_stdio_uart)); - int errcode; - const mp_stream_p_t *stream_p = mp_get_stream(pyb_stdio_uart); - ret = stream_p->ioctl(pyb_stdio_uart, MP_STREAM_POLL, poll_flags, &errcode); +#if MICROPY_HW_USB_CDC + +uint8_t cdc_itf_pending; // keep track of cdc interfaces which need attention to poll + +void poll_cdc_interfaces(void) { + // any CDC interfaces left to poll? + if (cdc_itf_pending && ringbuf_free(&stdin_ringbuf)) { + for (uint8_t itf = 0; itf < 8; ++itf) { + if (cdc_itf_pending & (1 << itf)) { + tud_cdc_rx_cb(itf); + if (!cdc_itf_pending) { + break; + } + } + } + } +} + +void tud_cdc_rx_cb(uint8_t itf) { + // consume pending USB data immediately to free usb buffer and keep the endpoint from stalling. + // in case the ringbuffer is full, mark the CDC interface that need attention later on for polling + cdc_itf_pending &= ~(1 << itf); + for (uint32_t bytes_avail = tud_cdc_n_available(itf); bytes_avail > 0; --bytes_avail) { + if (ringbuf_free(&stdin_ringbuf)) { + int data_char = tud_cdc_read_char(); + if (data_char == mp_interrupt_char) { + mp_sched_keyboard_interrupt(); + } else { + ringbuf_put(&stdin_ringbuf, data_char); + } + } else { + cdc_itf_pending |= (1 << itf); + return; + } } - return ret | mp_os_dupterm_poll(poll_flags); } -#if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE -void flash_cache_commit(void); #endif -MP_WEAK int mp_hal_stdin_rx_chr(void) { +uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) { + uintptr_t ret = 0; + #if MICROPY_HW_USB_CDC + poll_cdc_interfaces(); + #endif + #if MICROPY_HW_ENABLE_UART_REPL || MICROPY_HW_USB_CDC + if ((poll_flags & MP_STREAM_POLL_RD) && ringbuf_peek(&stdin_ringbuf) != -1) { + ret |= MP_STREAM_POLL_RD; + } + if (poll_flags & MP_STREAM_POLL_WR) { + #if MICROPY_HW_ENABLE_UART_REPL + ret |= MP_STREAM_POLL_WR; + #else + if (tud_cdc_connected() && tud_cdc_write_available() > 0) { + ret |= MP_STREAM_POLL_WR; + } + #endif + } + #endif + #if MICROPY_PY_OS_DUPTERM + ret |= mp_os_dupterm_poll(poll_flags); + #endif + return ret; +} + +// Receive single character +int mp_hal_stdin_rx_chr(void) { for (;;) { + #if MICROPY_HW_USB_CDC + poll_cdc_interfaces(); + #endif + #if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE flash_cache_commit(); #endif - if (MP_STATE_PORT(pyb_stdio_uart) != NULL && uart_rx_any(MP_STATE_PORT(pyb_stdio_uart))) { - return uart_rx_char(MP_STATE_PORT(pyb_stdio_uart)); + + int c = ringbuf_get(&stdin_ringbuf); + if (c != -1) { + return c; } + #if MICROPY_PY_OS_DUPTERM int dupterm_c = mp_os_dupterm_rx_chr(); if (dupterm_c >= 0) { return dupterm_c; } + #endif MICROPY_EVENT_POLL_HOOK } } -MP_WEAK void mp_hal_stdout_tx_strn(const char *str, size_t len) { +// Send string of given length +void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { + #if MICROPY_HW_ENABLE_UART_REPL if (MP_STATE_PORT(pyb_stdio_uart) != NULL) { uart_tx_strn(MP_STATE_PORT(pyb_stdio_uart), str, len); } + #endif + + #if MICROPY_HW_USB_CDC + if (tud_cdc_connected()) { + for (size_t i = 0; i < len;) { + uint32_t n = len - i; + if (n > CFG_TUD_CDC_EP_BUFSIZE) { + n = CFG_TUD_CDC_EP_BUFSIZE; + } + int timeout = 0; + // Wait with a max of USC_CDC_TIMEOUT ms + while (n > tud_cdc_write_available() && timeout++ < MICROPY_HW_USB_CDC_TX_TIMEOUT) { + MICROPY_EVENT_POLL_HOOK + } + if (timeout >= MICROPY_HW_USB_CDC_TX_TIMEOUT) { + break; + } + uint32_t n2 = tud_cdc_write(str + i, n); + tud_cdc_write_flush(); + i += n2; + } + } + #endif + + #if MICROPY_PY_OS_DUPTERM mp_os_dupterm_tx_strn(str, len); + #endif } void mp_hal_ticks_cpu_enable(void) { @@ -119,4 +223,97 @@ void mp_hal_get_mac_ascii(int idx, size_t chr_off, size_t chr_len, char *dest) { } } +#if MICROPY_HW_ENABLE_USBDEV +void usbfs_interrupt_handler(void) { + IRQn_Type irq = R_FSP_CurrentIrqGet(); + R_BSP_IrqStatusClear(irq); + + #if CFG_TUSB_RHPORT0_MODE & OPT_MODE_HOST + tuh_int_handler(0); + #endif + + #if CFG_TUSB_RHPORT0_MODE & OPT_MODE_DEVICE + tud_int_handler(0); + #endif +} + +void usbfs_resume_handler(void) { + IRQn_Type irq = R_FSP_CurrentIrqGet(); + R_BSP_IrqStatusClear(irq); + + #if CFG_TUSB_RHPORT0_MODE & OPT_MODE_HOST + tuh_int_handler(0); + #endif + + #if CFG_TUSB_RHPORT0_MODE & OPT_MODE_DEVICE + tud_int_handler(0); + #endif +} + +void usbfs_d0fifo_handler(void) { + IRQn_Type irq = R_FSP_CurrentIrqGet(); + R_BSP_IrqStatusClear(irq); + + #if CFG_TUSB_RHPORT0_MODE & OPT_MODE_HOST + tuh_int_handler(0); + #endif + + #if CFG_TUSB_RHPORT0_MODE & OPT_MODE_DEVICE + tud_int_handler(0); + #endif +} + +void usbfs_d1fifo_handler(void) { + IRQn_Type irq = R_FSP_CurrentIrqGet(); + R_BSP_IrqStatusClear(irq); + + #if CFG_TUSB_RHPORT0_MODE & OPT_MODE_HOST + tuh_int_handler(0); + #endif + + #if CFG_TUSB_RHPORT0_MODE & OPT_MODE_DEVICE + tud_int_handler(0); + #endif +} + +void usbhs_interrupt_handler(void) { + IRQn_Type irq = R_FSP_CurrentIrqGet(); + R_BSP_IrqStatusClear(irq); + + #if CFG_TUSB_RHPORT1_MODE & OPT_MODE_HOST + tuh_int_handler(1); + #endif + + #if CFG_TUSB_RHPORT1_MODE & OPT_MODE_DEVICE + tud_int_handler(1); + #endif +} + +void usbhs_d0fifo_handler(void) { + IRQn_Type irq = R_FSP_CurrentIrqGet(); + R_BSP_IrqStatusClear(irq); + + #if CFG_TUSB_RHPORT1_MODE & OPT_MODE_HOST + tuh_int_handler(1); + #endif + + #if CFG_TUSB_RHPORT1_MODE & OPT_MODE_DEVICE + tud_int_handler(1); + #endif +} + +void usbhs_d1fifo_handler(void) { + IRQn_Type irq = R_FSP_CurrentIrqGet(); + R_BSP_IrqStatusClear(irq); + + #if CFG_TUSB_RHPORT1_MODE & OPT_MODE_HOST + tuh_int_handler(1); + #endif + + #if CFG_TUSB_RHPORT1_MODE & OPT_MODE_DEVICE + tud_int_handler(1); + #endif +} +#endif + MP_REGISTER_ROOT_POINTER(struct _machine_uart_obj_t *pyb_stdio_uart); diff --git a/ports/renesas-ra/mphalport.h b/ports/renesas-ra/mphalport.h index 2648e22f9..2b25a36fb 100644 --- a/ports/renesas-ra/mphalport.h +++ b/ports/renesas-ra/mphalport.h @@ -27,8 +27,12 @@ #include RA_HAL_H #include "pin.h" +#include "py/ringbuf.h" + +#define MICROPY_HW_USB_CDC_TX_TIMEOUT (500) extern const unsigned char mp_hal_status_to_errno_table[4]; +extern ringbuf_t stdin_ringbuf; static inline int mp_hal_status_to_neg_errno(HAL_StatusTypeDef status) { return -mp_hal_status_to_errno_table[status]; diff --git a/ports/renesas-ra/uart.c b/ports/renesas-ra/uart.c index e41c68f0c..47c793e7d 100644 --- a/ports/renesas-ra/uart.c +++ b/ports/renesas-ra/uart.c @@ -33,6 +33,7 @@ #include "py/stream.h" #include "py/mperrno.h" #include "py/mphal.h" +#include "py/ringbuf.h" #include "shared/runtime/interrupt_char.h" #include "shared/runtime/mpirq.h" #include "uart.h" @@ -75,6 +76,11 @@ static void uart_rx_cb(uint32_t ch, int d) { (*keyex_cb[ch])(d); } #endif + + #if MICROPY_HW_ENABLE_UART_REPL + ringbuf_put(&stdin_ringbuf, d); + #endif + // Check the flags to see if the user handler should be called if (self->mp_irq_trigger) { mp_irq_handler(self->mp_irq_obj); diff --git a/ports/renesas-ra/usbd.c b/ports/renesas-ra/usbd.c new file mode 100644 index 000000000..704750386 --- /dev/null +++ b/ports/renesas-ra/usbd.c @@ -0,0 +1,48 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 Arduino SA + * + * 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 "py/mpconfig.h" + +#if MICROPY_HW_ENABLE_USBDEV + +#include "mp_usbd.h" +#include "string.h" +#include "tusb.h" + +void mp_usbd_port_get_serial_number(char *serial_buf) { + const bsp_unique_id_t *id = R_BSP_UniqueIdGet(); + // convert to hex + int hexlen = sizeof(id->unique_id_bytes) * 2; + MP_STATIC_ASSERT(hexlen <= MICROPY_HW_USB_DESC_STR_MAX); + for (int i = 0; i < hexlen; i += 2) { + static const char *hexdig = "0123456789abcdef"; + serial_buf[i] = hexdig[id->unique_id_bytes[i / 2] >> 4]; + serial_buf[i + 1] = hexdig[id->unique_id_bytes[i / 2] & 0x0f]; + } + serial_buf[hexlen] = 0; +} + +#endif |
