diff --git a/cpu/esp32/Makefile b/cpu/esp32/Makefile index c0885a57ba3da..1c18ffcba3772 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 600b94af0a1f0..d12cdff2c598a 100644 --- a/cpu/esp32/Makefile.dep +++ b/cpu/esp32/Makefile.dep @@ -166,6 +166,13 @@ ifneq (,$(filter shell,$(USEMODULE))) USEMODULE += ps endif +ifneq (,$(filter stdio_usb_serial_jtag, $(USEMODULE))) + USEMODULE += tsrb +endif +ifneq (,$(filter stdio_usb_serial_jtag_rx, $(USEMODULE))) + USEMODULE += isrpipe +endif + ifneq (,$(filter tinyusb_portable_espressif,$(USEMODULE))) USEMODULE += esp_idf_usb endif diff --git a/cpu/esp32/include/irq_arch.h b/cpu/esp32/include/irq_arch.h index faccdf19160c2..7afbb0d88a37b 100644 --- a/cpu/esp32/include/irq_arch.h +++ b/cpu/esp32/include/irq_arch.h @@ -50,6 +50,7 @@ extern "C" { #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_SERIAL_JTAG 26 /**< Level interrupt with low priority 1 */ /** @} */ /** diff --git a/cpu/esp32/irq_arch.c b/cpu/esp32/irq_arch.c index f43e30482466e..f0084657b3349 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(CPU_INUM_SERIAL_JTAG) + { 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 0000000000000..48422e909a47d --- /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 0000000000000..a15c1cf4d44a8 --- /dev/null +++ b/cpu/esp32/stdio_usb_serial_jtag/usb_serial_jtag.c @@ -0,0 +1,115 @@ +/* + * 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 "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; +} + +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/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 18ae0c5f8c82a..b1bf66132a73f 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -479,6 +479,7 @@ PSEUDOMODULES += stdio_telnet PSEUDOMODULES += stdio_uart_onlcr ## @} PSEUDOMODULES += stdio_uart_rx +PSEUDOMODULES += stdio_usb_serial_jtag_rx PSEUDOMODULES += stm32_eth PSEUDOMODULES += stm32_eth_auto PSEUDOMODULES += stm32_eth_link_up diff --git a/makefiles/stdio.inc.mk b/makefiles/stdio.inc.mk index 5ceb452228bbc..91474c413e713 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 @@ -52,6 +53,9 @@ ifneq (,$(filter stdin,$(USEMODULE))) ifneq (,$(filter stdio_uart,$(USEMODULE))) USEMODULE += stdio_uart_rx endif + ifneq (,$(filter stdio_usb_serial_jtag,$(USEMODULE))) + USEMODULE += stdio_usb_serial_jtag_rx + endif endif ifneq (,$(filter stdio_uart_rx,$(USEMODULE)))