renesas-ra: Add TinyUSB support.

Signed-off-by: iabdalkader <i.abdalkader@gmail.com>
This commit is contained in:
iabdalkader 2023-04-17 17:46:13 +02:00 committed by Damien George
parent 816b88ad07
commit d89a0606e0
7 changed files with 357 additions and 18 deletions

View File

@ -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))

View File

@ -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:

View File

@ -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);

View File

@ -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);

View File

@ -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];

View File

@ -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);

48
ports/renesas-ra/usbd.c Normal file
View File

@ -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