From 55b5c47bc8b7cc07b418835e0ebb692da02bf30c Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Thu, 29 Dec 2022 00:35:41 +0100 Subject: [PATCH] cpu/esp32: add stdio_usb_serial_jtag --- cpu/esp32/Makefile | 4 + cpu/esp32/Makefile.dep | 11 ++ cpu/esp32/Makefile.include | 1 + cpu/esp32/include/irq_arch.h | 29 ++-- cpu/esp32/irq_arch.c | 3 + cpu/esp32/stdio_usb_serial_jtag/Makefile | 1 + .../stdio_usb_serial_jtag/usb_serial_jtag.c | 126 ++++++++++++++++++ makefiles/stdio.inc.mk | 1 + sys/Kconfig.stdio | 15 +++ 9 files changed, 177 insertions(+), 14 deletions(-) create mode 100644 cpu/esp32/stdio_usb_serial_jtag/Makefile create mode 100644 cpu/esp32/stdio_usb_serial_jtag/usb_serial_jtag.c diff --git a/cpu/esp32/Makefile b/cpu/esp32/Makefile index c0885a57ba..1c18ffcba3 100644 --- a/cpu/esp32/Makefile +++ b/cpu/esp32/Makefile @@ -25,6 +25,10 @@ ifneq (, $(filter esp_freertos, $(USEMODULE))) DIRS += freertos endif +ifneq (, $(filter stdio_usb_serial_jtag, $(USEMODULE))) + DIRS += stdio_usb_serial_jtag +endif + ifneq (,$(filter esp_wifi% esp_eth, $(USEMODULE))) SRC += esp_ztimer.c endif diff --git a/cpu/esp32/Makefile.dep b/cpu/esp32/Makefile.dep index 600b94af0a..0f33413057 100644 --- a/cpu/esp32/Makefile.dep +++ b/cpu/esp32/Makefile.dep @@ -166,6 +166,17 @@ ifneq (,$(filter shell,$(USEMODULE))) USEMODULE += ps endif +ifneq (,$(filter stdio_usb_serial_jtag, $(USEMODULE))) + USEMODULE += tsrb + ifneq (,$(filter stdin,$(USEMODULE))) + USEMODULE += stdio_usb_serial_jtag_rx + endif +endif +ifneq (,$(filter stdio_usb_serial_jtag_rx, $(USEMODULE))) + USEMODULE += isrpipe + USEMODULE += stdio_available +endif + ifneq (,$(filter tinyusb_portable_espressif,$(USEMODULE))) USEMODULE += esp_idf_usb endif diff --git a/cpu/esp32/Makefile.include b/cpu/esp32/Makefile.include index baef045969..6964bb09c1 100644 --- a/cpu/esp32/Makefile.include +++ b/cpu/esp32/Makefile.include @@ -50,6 +50,7 @@ PSEUDOMODULES += esp_rtc_timer_32k PSEUDOMODULES += esp_spi_ram PSEUDOMODULES += esp_spi_oct PSEUDOMODULES += esp_wifi_enterprise +PSEUDOMODULES += stdio_usb_serial_jtag_rx INCLUDES += -I$(RIOTCPU)/$(CPU)/esp-idf/include INCLUDES += -I$(RIOTCPU)/$(CPU)/esp-idf/include/log diff --git a/cpu/esp32/include/irq_arch.h b/cpu/esp32/include/irq_arch.h index faccdf1916..a8ca7cf15b 100644 --- a/cpu/esp32/include/irq_arch.h +++ b/cpu/esp32/include/irq_arch.h @@ -36,20 +36,21 @@ extern "C" { * * @{ */ -#define CPU_INUM_GPIO 2 /**< Level interrupt with low priority 1 */ -#define CPU_INUM_CAN 3 /**< Level interrupt with low priority 1 */ -#define CPU_INUM_UART 4 /**< Level interrupt with low priority 1 */ -#define CPU_INUM_USB 8 /**< Level interrupt with low priority 1 */ -#define CPU_INUM_RTT 9 /**< Level interrupt with low priority 1 */ -#define CPU_INUM_I2C 12 /**< Level interrupt with low priority 1 */ -#define CPU_INUM_WDT 13 /**< Level interrupt with low priority 1 */ -#define CPU_INUM_SOFTWARE 17 /**< Level interrupt with low priority 1 */ -#define CPU_INUM_ETH 18 /**< Level interrupt with low priority 1 */ -#define CPU_INUM_TIMER 19 /**< Level interrupt with medium priority 2 */ -#define CPU_INUM_FRC2 20 /**< Level interrupt with medium priority 2 */ -#define CPU_INUM_SYSTIMER 20 /**< Level interrupt with medium priority 2 */ -#define CPU_INUM_BLE 21 /**< Level interrupt with medium priority 2 */ -#define CPU_INUM_CACHEERR 25 /**< Level interrupt with high priority 4 */ +#define CPU_INUM_GPIO 2 /**< Level interrupt with low priority 1 */ +#define CPU_INUM_CAN 3 /**< Level interrupt with low priority 1 */ +#define CPU_INUM_UART 4 /**< Level interrupt with low priority 1 */ +#define CPU_INUM_USB 8 /**< Level interrupt with low priority 1 */ +#define CPU_INUM_RTT 9 /**< Level interrupt with low priority 1 */ +#define CPU_INUM_SERIAL_JTAG 10 /**< Level interrupt with low priority 1 */ +#define CPU_INUM_I2C 12 /**< Level interrupt with low priority 1 */ +#define CPU_INUM_WDT 13 /**< Level interrupt with low priority 1 */ +#define CPU_INUM_SOFTWARE 17 /**< Level interrupt with low priority 1 */ +#define CPU_INUM_ETH 18 /**< Level interrupt with low priority 1 */ +#define CPU_INUM_TIMER 19 /**< Level interrupt with medium priority 2 */ +#define CPU_INUM_FRC2 20 /**< Level interrupt with medium priority 2 */ +#define CPU_INUM_SYSTIMER 20 /**< Level interrupt with medium priority 2 */ +#define CPU_INUM_BLE 21 /**< Level interrupt with medium priority 2 */ +#define CPU_INUM_CACHEERR 25 /**< Level interrupt with high priority 4 */ /** @} */ /** diff --git a/cpu/esp32/irq_arch.c b/cpu/esp32/irq_arch.c index f43e304824..d401383c50 100644 --- a/cpu/esp32/irq_arch.c +++ b/cpu/esp32/irq_arch.c @@ -83,6 +83,9 @@ static const struct intr_handle_data_t _irq_data_table[] = { #if defined(CPU_FAM_ESP32S2) || defined(CPU_FAM_ESP32S3) { ETS_USB_INTR_SOURCE, CPU_INUM_USB, 1 }, #endif +#if defined(ETS_USB_SERIAL_JTAG_INTR_SOURCE) + { ETS_USB_SERIAL_JTAG_INTR_SOURCE, CPU_INUM_SERIAL_JTAG, 1 }, +#endif }; #define IRQ_DATA_TABLE_SIZE ARRAY_SIZE(_irq_data_table) diff --git a/cpu/esp32/stdio_usb_serial_jtag/Makefile b/cpu/esp32/stdio_usb_serial_jtag/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/cpu/esp32/stdio_usb_serial_jtag/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/cpu/esp32/stdio_usb_serial_jtag/usb_serial_jtag.c b/cpu/esp32/stdio_usb_serial_jtag/usb_serial_jtag.c new file mode 100644 index 0000000000..d47597c9bf --- /dev/null +++ b/cpu/esp32/stdio_usb_serial_jtag/usb_serial_jtag.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2023 Benjamin Valentin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup cpu_esp32_usb_serial_jtag ESP32 USB Serial/JTAG interface + * @ingroup cpu_esp32 + * @{ + * + * @file + * @brief stdio via USB Serial JTAG debug interface + * + * @author Benjamin Valentin + */ + +#include +#include +#include +#include + +#include "isrpipe.h" +#include "tsrb.h" + +#include "irq_arch.h" +#include "esp_attr.h" +#include "hal/interrupt_controller_types.h" +#include "hal/interrupt_controller_ll.h" +#include "hal/usb_serial_jtag_ll.h" +#include "soc/periph_defs.h" +#include "rom/ets_sys.h" + +static uint8_t _rx_buf_mem[USB_SERIAL_JTAG_PACKET_SZ_BYTES]; +static isrpipe_t stdio_serial_isrpipe = ISRPIPE_INIT(_rx_buf_mem); + +static tsrb_t serial_tx_rb; +static uint8_t serial_tx_rb_buf[USB_SERIAL_JTAG_PACKET_SZ_BYTES]; + +#define IRQ_MASK (USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY | \ + (IS_USED(MODULE_STDIO_USB_SERIAL_JTAG_RX) * USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT)) + +ssize_t stdio_write(const void *buffer, size_t len) +{ + tsrb_add(&serial_tx_rb, buffer, len); + USB_SERIAL_JTAG.int_ena.val = IRQ_MASK; + + return len; +} + +ssize_t stdio_read(void* buffer, size_t count) +{ + if (IS_USED(MODULE_STDIO_USB_SERIAL_JTAG_RX)) { + return (ssize_t)isrpipe_read(&stdio_serial_isrpipe, buffer, count); + } + + return -ENOTSUP; +} + +int stdio_available(void) +{ + if (IS_USED(MODULE_STDIO_AVAILABLE)) { + return tsrb_avail(&stdio_serial_isrpipe.tsrb); + } + + return -ENOTSUP; +} + +IRAM_ATTR +static void _serial_intr_handler(void *arg) +{ + (void)arg; + + irq_isr_enter(); + + uint32_t mask = usb_serial_jtag_ll_get_intsts_mask(); + + /* read data if available */ + while (IS_USED(MODULE_STDIO_USB_SERIAL_JTAG_RX) && + usb_serial_jtag_ll_rxfifo_data_available()) { + isrpipe_write_one(&stdio_serial_isrpipe, USB_SERIAL_JTAG.ep1.rdwr_byte); + } + + /* write data if there is a free stop */ + if (mask & USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY) { + + while (usb_serial_jtag_ll_txfifo_writable()) { + int c = tsrb_get_one(&serial_tx_rb); + if (c < 0) { + /* no more data to send - disable interrupt */ + USB_SERIAL_JTAG.int_ena.val = IRQ_MASK & ~USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY; + break; + } + USB_SERIAL_JTAG.ep1.rdwr_byte = c; + } + usb_serial_jtag_ll_txfifo_flush(); + } + + /* clear all interrupt flags */ + usb_serial_jtag_ll_clr_intsts_mask(mask); + + irq_isr_exit(); +} + +void stdio_init(void) +{ + tsrb_init(&serial_tx_rb, serial_tx_rb_buf, sizeof(serial_tx_rb_buf)); + + /* enable RX interrupt */ + if (IS_USED(MODULE_STDIO_USB_SERIAL_JTAG_RX)) { + USB_SERIAL_JTAG.int_ena.val = USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT; + } + + /* clear all interrupt flags */ + usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_LL_INTR_MASK); + + /* route all UART interrupt sources to same the CPU interrupt */ + intr_matrix_set(PRO_CPU_NUM, ETS_USB_SERIAL_JTAG_INTR_SOURCE, CPU_INUM_SERIAL_JTAG); + + /* we have to enable therefore the CPU interrupt here */ + intr_cntrl_ll_set_int_handler(CPU_INUM_SERIAL_JTAG, _serial_intr_handler, NULL); + intr_cntrl_ll_enable_interrupts(BIT(CPU_INUM_SERIAL_JTAG)); +} +/**@}*/ diff --git a/makefiles/stdio.inc.mk b/makefiles/stdio.inc.mk index 5ceb452228..2b53f54107 100644 --- a/makefiles/stdio.inc.mk +++ b/makefiles/stdio.inc.mk @@ -10,6 +10,7 @@ STDIO_MODULES = \ stdio_uart \ stdio_telnet \ stdio_tinyusb_cdc_acm \ + stdio_usb_serial_jtag \ # # select stdio_uart if no other stdio module is slected diff --git a/sys/Kconfig.stdio b/sys/Kconfig.stdio index 7506943dda..7ee523cb71 100644 --- a/sys/Kconfig.stdio +++ b/sys/Kconfig.stdio @@ -49,6 +49,12 @@ config MODULE_STDIO_ETHOS select MODULE_ETHOS_STDIO select USE_STDOUT_BUFFERED +config MODULE_STDIO_USB_SERIAL_JTAG + bool "STDIO via ESP32 Debug USB Serial/JTAG interface" + depends on TEST_KCONFIG + depends on CPU_FAM_ESP32C3 || CPU_FAM_ESP32S3 + select MODULE_TSRB + endchoice config MODULE_STDIN @@ -63,6 +69,15 @@ config MODULE_STDIO_UART_RX help Reception when using UART-based STDIO needs to be enabled. +config MODULE_STDIO_USB_SERIAL_JTAG_RX + bool + depends on MODULE_STDIO_USB_SERIAL_JTAG + select MODULE_ISRPIPE + select MODULE_STDIO_AVAILABLE + default y if MODULE_STDIN + help + Reception when using ESP32 USB Serial/JTAG STDIO needs to be enabled. + config MODULE_STDIO_AVAILABLE bool help