Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion esp-stub-lib
Submodule esp-stub-lib updated 76 files
+2 −2 .astyle-rules.yml
+1 −0 CMakeLists.txt
+1 −0 example/cmake/build-flags.cmake
+4 −3 example/stub_main.c
+4 −2 include/esp-stub-lib/uart.h
+74 −0 include/esp-stub-lib/usb_serial_jtag.h
+5 −3 src/flash.c
+10 −10 src/target/base/include/private/rom_flash_config.h
+2 −1 src/target/base/include/target/flash.h
+1 −1 src/target/base/include/target/uart.h
+26 −0 src/target/base/include/target/usb_serial_jtag.h
+1 −0 src/target/common/CMakeLists.txt
+6 −4 src/target/common/src/flash.c
+1 −1 src/target/common/src/security.c
+3 −3 src/target/common/src/uart.c
+21 −0 src/target/common/src/usb_serial_jtag.c
+1 −0 src/target/esp32/ld/esp32.rom.api.ld
+1 −0 src/target/esp32c2/ld/esp32c2.rom.api.ld
+1 −0 src/target/esp32c3/CMakeLists.txt
+845 −0 src/target/esp32c3/include/soc/interrupt_core0_reg.h
+989 −0 src/target/esp32c3/include/soc/usb_serial_jtag_reg.h
+1 −0 src/target/esp32c3/ld/esp32c3.rom.api.ld
+2 −2 src/target/esp32c3/src/security.c
+41 −0 src/target/esp32c3/src/usb_serial_jtag.c
+1 −0 src/target/esp32c5/CMakeLists.txt
+173 −0 src/target/esp32c5/include/soc/clic_reg.h
+1,752 −0 src/target/esp32c5/include/soc/interrupt_matrix_reg.h
+1,238 −0 src/target/esp32c5/include/soc/usb_serial_jtag_reg.h
+2 −1 src/target/esp32c5/ld/esp32c5.rom.api.ld
+42 −0 src/target/esp32c5/src/usb_serial_jtag.c
+1 −0 src/target/esp32c6/CMakeLists.txt
+1,002 −0 src/target/esp32c6/include/soc/interrupt_matrix_reg.h
+1,190 −0 src/target/esp32c6/include/soc/usb_serial_jtag_reg.h
+2 −1 src/target/esp32c6/ld/esp32c6.rom.api.ld
+41 −0 src/target/esp32c6/src/usb_serial_jtag.c
+1 −0 src/target/esp32c61/CMakeLists.txt
+3 −2 src/target/esp32c61/include/esp_rom_caps.h
+173 −0 src/target/esp32c61/include/soc/clic_reg.h
+1,410 −0 src/target/esp32c61/include/soc/interrupt_core0_reg.h
+1,231 −0 src/target/esp32c61/include/soc/usb_serial_jtag_reg.h
+2 −1 src/target/esp32c61/ld/esp32c61.rom.api.ld
+42 −0 src/target/esp32c61/src/usb_serial_jtag.c
+1 −0 src/target/esp32h2/CMakeLists.txt
+858 −0 src/target/esp32h2/include/soc/interrupt_matrix_reg.h
+1,190 −0 src/target/esp32h2/include/soc/usb_serial_jtag_reg.h
+2 −1 src/target/esp32h2/ld/esp32h2.rom.api.ld
+41 −0 src/target/esp32h2/src/usb_serial_jtag.c
+1 −0 src/target/esp32h21/CMakeLists.txt
+858 −0 src/target/esp32h21/include/soc/interrupt_matrix_reg.h
+1,231 −0 src/target/esp32h21/include/soc/usb_serial_jtag_reg.h
+2 −1 src/target/esp32h21/ld/esp32h21.rom.api.ld
+41 −0 src/target/esp32h21/src/usb_serial_jtag.c
+1 −0 src/target/esp32h4/CMakeLists.txt
+116 −0 src/target/esp32h4/include/soc/clic_reg.h
+1,868 −0 src/target/esp32h4/include/soc/interrupt_matrix_reg.h
+1,231 −0 src/target/esp32h4/include/soc/usb_serial_jtag_reg.h
+2 −1 src/target/esp32h4/ld/esp32h4.rom.api.ld
+42 −0 src/target/esp32h4/src/usb_serial_jtag.c
+1 −0 src/target/esp32p4/CMakeLists.txt
+167 −0 src/target/esp32p4/include/soc/clic_reg.h
+1,626 −0 src/target/esp32p4/include/soc/interrupt_core0_reg.h
+1,284 −0 src/target/esp32p4/include/soc/usb_serial_jtag_reg.h
+2 −1 src/target/esp32p4/ld/esp32p4.rom.api.ld
+42 −0 src/target/esp32p4/src/usb_serial_jtag.c
+1 −0 src/target/esp32s2/ld/esp32s2.rom.api.ld
+1 −0 src/target/esp32s3/CMakeLists.txt
+860 −0 src/target/esp32s3/include/soc/interrupt_core0_reg.h
+733 −0 src/target/esp32s3/include/soc/usb_serial_jtag_reg.h
+1 −0 src/target/esp32s3/ld/esp32s3.rom.api.ld
+1 −1 src/target/esp32s3/src/flash.c
+39 −0 src/target/esp32s3/src/usb_serial_jtag.c
+1 −0 src/target/esp8266/include/esp_rom_caps.h
+1 −0 src/target/esp8266/ld/esp8266.rom.api.ld
+2 −1 src/target/esp8266/src/uart.c
+3 −3 src/uart.c
+92 −0 src/usb_serial_jtag.c
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ add_executable(${TARGET_NAME}
"main.c"
"slip.c"
"command_handler.c"
"transport.c"
)

target_compile_options(${TARGET_NAME} PRIVATE
Expand Down
2 changes: 1 addition & 1 deletion src/command_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ static void s_mem_end(const uint8_t* buffer, uint16_t size)

if (flag == 1) {
// TODO: consider delay - was in previous code
stub_lib_uart_tx_flush();
stub_lib_uart_tx_flush(UART_NUM_0);

// ROM loader firstly exits the loader routine and then executes the entrypoint,
// but for our purposes, keeping a bit of extra stuff on the stack doesn't really matter.
Expand Down
27 changes: 3 additions & 24 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
#include <stdbool.h>
#include <stdint.h>
#include <esp-stub-lib/flash.h>
#include <esp-stub-lib/uart.h>
#include "slip.h"
#include "command_handler.h"
#include "slip.h"
#include "transport.h"

#ifdef ESP8266
__asm__(
Expand All @@ -22,26 +22,6 @@ __asm__(
"j esp_main;");
#endif //ESP8266

static void uart_rx_interrupt_handler()
{
// This also resets the interrupt flags
uint32_t intr_flags = stub_lib_uart_get_intr_flags(UART_NUM_0);

if ((intr_flags & UART_INTR_RXFIFO_FULL) || (intr_flags & UART_INTR_RXFIFO_TOUT)) {
uint32_t count = stub_lib_uart_get_rxfifo_count(UART_NUM_0);

for (uint32_t i = 0; i < count; ++i) {
uint8_t byte = stub_lib_uart_read_rxfifo_byte(UART_NUM_0);
slip_recv_byte(byte);

// Cannot process more bytes until frame is processed
if (slip_is_frame_complete() || slip_is_frame_error()) {
break;
}
}
}
}

void esp_main(void)
{
extern uint32_t _bss_start;
Expand All @@ -56,8 +36,7 @@ void esp_main(void)
stub_lib_flash_init(&flash_state);
stub_lib_flash_attach(0, false);

stub_lib_uart_wait_idle(UART_NUM_0); // Wait until ROM sends response to last command
stub_lib_uart_rominit_intr_attach(UART_NUM_0, 5, uart_rx_interrupt_handler, UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT);
stub_transport_init();

// Send OHAI greeting to signal stub is active
const uint8_t greeting[4] = {'O', 'H', 'A', 'I'};
Expand Down
29 changes: 17 additions & 12 deletions src/slip.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,10 @@

#include <stdint.h>
#include <esp-stub-lib/uart.h>
#include <esp-stub-lib/usb_serial_jtag.h>
#include "command_handler.h"
#include "slip.h"

/* SLIP Protocol Constants */
#define SLIP_END 0xC0 /* Frame delimiter */
#define SLIP_ESC 0xDB /* Escape character */
#define SLIP_ESC_END 0xDC /* Escaped frame delimiter */
#define SLIP_ESC_ESC 0xDD /* Escaped escape character */

/* SLIP State Machine */
typedef enum {
STATE_NO_FRAME, /* Not in a frame */
Expand Down Expand Up @@ -43,24 +38,34 @@ static slip_recv_ctx_t s_recv_ctx = {

static slip_state_t s_state = STATE_NO_FRAME;

/* TX function pointer set by transport init (defaults to UART) */
static uint8_t (*s_tx_one_char)(uint8_t) = stub_lib_uart_tx_one_char;

void slip_set_tx_fn(uint8_t (*tx_fn)(uint8_t))
{
if (tx_fn) {
s_tx_one_char = tx_fn;
}
}

void slip_send_frame_delimiter(void)
{
stub_lib_uart_tx_one_char(SLIP_END);
s_tx_one_char(SLIP_END);
}

void slip_send_frame_data(uint8_t byte)
{
switch (byte) {
case SLIP_END:
stub_lib_uart_tx_one_char(SLIP_ESC);
stub_lib_uart_tx_one_char(SLIP_ESC_END);
s_tx_one_char(SLIP_ESC);
s_tx_one_char(SLIP_ESC_END);
break;
case SLIP_ESC:
stub_lib_uart_tx_one_char(SLIP_ESC);
stub_lib_uart_tx_one_char(SLIP_ESC_ESC);
s_tx_one_char(SLIP_ESC);
s_tx_one_char(SLIP_ESC_ESC);
break;
default:
stub_lib_uart_tx_one_char(byte);
s_tx_one_char(byte);
break;
}
}
Expand Down
15 changes: 15 additions & 0 deletions src/slip.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,21 @@
extern "C" {
#endif

/* SLIP Protocol Constants */
#define SLIP_END 0xC0 /* Frame delimiter */
#define SLIP_ESC 0xDB /* Escape character */
#define SLIP_ESC_END 0xDC /* Escaped frame delimiter */
#define SLIP_ESC_ESC 0xDD /* Escaped escape character */

/**
* @brief Register TX function used by SLIP to send bytes
*
* The function must transmit a single byte and return 0 on success.
*
* @param tx_fn Function pointer with signature: uint8_t (*)(uint8_t)
*/
void slip_set_tx_fn(uint8_t (*tx_fn)(uint8_t));

/**
* @brief Send SLIP frame delimiter
*/
Expand Down
67 changes: 67 additions & 0 deletions src/transport.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/

#include <stdint.h>
#include <esp-stub-lib/uart.h>
#include <esp-stub-lib/usb_serial_jtag.h>
#include "transport.h"
#include "slip.h"

void uart_rx_interrupt_handler()
{
// This also resets the interrupt flags
uint32_t intr_flags = stub_lib_uart_clear_intr_flags(UART_NUM_0);

if ((intr_flags & UART_INTR_RXFIFO_FULL) || (intr_flags & UART_INTR_RXFIFO_TOUT)) {
uint32_t count = stub_lib_uart_get_rxfifo_count(UART_NUM_0);

for (uint32_t i = 0; i < count; ++i) {
uint8_t byte = stub_lib_uart_read_rxfifo_byte(UART_NUM_0);
slip_recv_byte(byte);

// Cannot process more bytes until frame is processed
if (slip_is_frame_complete() || slip_is_frame_error()) {
break;
}
}
}
}

void usb_jtag_serial_interrupt_handler()
{
stub_lib_usb_serial_jtag_clear_intr_flags();

while (stub_lib_usb_serial_jtag_is_data_available()) {
slip_recv_byte(stub_lib_usb_serial_jtag_read_rxfifo_byte());
}
}

uint8_t usb_serial_jtag_tx_one_char(uint8_t c)
{
// Flush every 63 bytes (some Windows drivers have issues with >= 64 bytes)
// or when a frame delimiter is sent
// TODO: Proper fix with zero-length packets
static unsigned short transferred_without_flush = 0;
stub_lib_usb_serial_jtag_tx_one_char(c);
++transferred_without_flush;
if (c == SLIP_END || transferred_without_flush >= 63) {
stub_lib_usb_serial_jtag_tx_flush();
transferred_without_flush = 0;
}
return 0;
}

void stub_transport_init(void)
{
if (stub_lib_usb_serial_jtag_is_active()) {
stub_lib_usb_serial_jtag_rominit_intr_attach(17, usb_jtag_serial_interrupt_handler, USB_SERIAL_JTAG_OUT_RECV_PKT_INT_ENA);
slip_set_tx_fn(usb_serial_jtag_tx_one_char);
} else {
stub_lib_uart_wait_idle(UART_NUM_0); // Wait until ROM sends response to last command
stub_lib_uart_rominit_intr_attach(UART_NUM_0, 5, uart_rx_interrupt_handler, UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT);
slip_set_tx_fn(stub_lib_uart_tx_one_char);
}
}
39 changes: 39 additions & 0 deletions src/transport.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/

#pragma once

#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Initialize the transport layer
*/
void stub_transport_init(void);

/**
* @brief UART interrupt handler
*/
void uart_rx_interrupt_handler();

/**
* @brief USB-Serial/JTAG interrupt handler
*/
void usb_jtag_serial_interrupt_handler();

/**
* @brief USB-Serial/JTAG transmit one character
*/
uint8_t usb_serial_jtag_tx_one_char(uint8_t c);

#ifdef __cplusplus
}
#endif
6 changes: 3 additions & 3 deletions unittests/target/TestTargetExample.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,15 +168,15 @@ void esp_main(void)
int result = UNITY_END();

// Send test completion marker for load-test.py
stub_lib_uart_tx_flush();
stub_lib_uart_tx_flush(UART_NUM_0);
printf("\n--- UNITY TEST RUN COMPLETE ---\n");
printf("Test Results: %s\n", (result == 0) ? "ALL TESTS PASSED" : "SOME TESTS FAILED");
printf("--- END OF TESTS ---\n");
stub_lib_uart_tx_flush();
stub_lib_uart_tx_flush(UART_NUM_0);

// Exit gracefully (could loop forever or halt depending on system requirements)
while (1) {
stub_lib_uart_tx_flush();
stub_lib_uart_tx_flush(UART_NUM_0);
stub_lib_delay_us(1000000); // 1 second delay
}
}
2 changes: 1 addition & 1 deletion unittests/target/minimal_system.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ void __system_init(void)
stub_lib_uart_tx_one_char('\n');

// Flush UART to ensure data is sent immediately
stub_lib_uart_tx_flush();
stub_lib_uart_tx_flush(UART_NUM_0);
}

// Simple sbrk implementation for heap management
Expand Down