Skip to content

Commit 616a2a6

Browse files
committed
feat: Add UART support
This commit adds support for UART with interrupt possibility and helper functions especially for RX path
1 parent c75846d commit 616a2a6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+18772
-207
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ set(srcs
2121
src/mem_utils.c
2222
src/rom_wrappers.c
2323
src/security.c
24+
src/uart.c
2425
)
2526

2627
if(STUB_LOG_ENABLED IN_LIST STUB_COMPILE_DEFS)

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ A complete example project is provided in the [example](example/) directory. It
3131

3232
See the [example README](example/README.md) for build instructions.
3333

34+
## Function Naming Conventions
35+
36+
Functions that contain `rominit` (e.g., `stub_target_uart_rominit_intr_attach`) require ROM preinitialization by entering download mode to work correctly. These functions are simplified compared to full implementation and expect some initialization done by ROM. They should only be called in contexts where the ROM download mode has been entered.
37+
3438
## Project Structure
3539

3640
The library uses a three-layer architecture to eliminate circular dependencies and maximize code reuse:

example/stub_main.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <esp-stub-lib/err.h>
1515
#include <esp-stub-lib/mem_utils.h>
1616
#include <esp-stub-lib/security.h>
17+
#include <esp-stub-lib/uart.h>
1718

1819
#include "stub_main.h"
1920

@@ -62,6 +63,24 @@ static void example_security(void)
6263
}
6364
}
6465

66+
static int __attribute__((unused)) handle_test_uart(void)
67+
{
68+
void *uart_rx_interrupt_handler = NULL;
69+
stub_lib_uart_wait_idle(UART_NUM_0);
70+
71+
stub_lib_uart_init(UART_NUM_0);
72+
stub_lib_uart_set_rx_timeout(UART_NUM_0, 10);
73+
(void)stub_lib_uart_get_rxfifo_count(UART_NUM_0);
74+
(void)stub_lib_uart_get_intr_flags(UART_NUM_0);
75+
(void)stub_lib_uart_read_rxfifo_byte(UART_NUM_0);
76+
(void)stub_lib_uart_rx_one_char();
77+
stub_lib_uart_rominit_intr_attach(UART_NUM_0, 5, uart_rx_interrupt_handler, UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT);
78+
stub_lib_uart_tx_one_char('A');
79+
stub_lib_uart_tx_flush();
80+
81+
return 0;
82+
}
83+
6584
static __attribute__((unused)) int handle_test1(va_list ap)
6685
{
6786
(void)ap;

include/esp-stub-lib/rom_wrappers.h

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,26 +29,6 @@ void stub_lib_delay_us(uint32_t us);
2929
*/
3030
uint16_t stub_lib_crc16_le(uint16_t crc, const uint8_t *buf, uint32_t len);
3131

32-
/**
33-
* @brief Transmit a single byte over UART.
34-
*
35-
* @param c Byte to transmit.
36-
* @return 0 if successful, non-zero if error occurred.
37-
*/
38-
uint8_t stub_lib_uart_tx_one_char(uint8_t c);
39-
40-
/**
41-
* @brief Receive a single byte (blocking) from UART.
42-
*
43-
* @return Received byte.
44-
*/
45-
uint8_t stub_lib_uart_rx_one_char(void);
46-
47-
/**
48-
* @brief Flush any buffered transmit data.
49-
*/
50-
void stub_lib_uart_tx_flush(void);
51-
5232
#ifdef __cplusplus
5333
}
5434
#endif // __cplusplus

include/esp-stub-lib/uart.h

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0 OR MIT
5+
*/
6+
7+
#pragma once
8+
9+
#include <stdint.h>
10+
#include <stdbool.h>
11+
#include <soc/soc_caps.h>
12+
13+
#ifdef __cplusplus
14+
extern "C" {
15+
#endif // __cplusplus
16+
17+
/**
18+
* @brief UART port number type
19+
*
20+
* Available UART ports depend on the chip's SOC_UART_HP_NUM capability.
21+
* Use the UART_NUM_* enum values (e.g., UART_NUM_0, UART_NUM_1, etc.)
22+
*/
23+
24+
typedef enum {
25+
UART_NUM_0, /*!< UART port 0 */
26+
UART_NUM_1, /*!< UART port 1 */
27+
#if SOC_UART_HP_NUM > 2
28+
UART_NUM_2, /*!< UART port 2 */
29+
#endif
30+
#if SOC_UART_HP_NUM > 3
31+
UART_NUM_3, /*!< UART port 3 */
32+
#endif
33+
#if SOC_UART_HP_NUM > 4
34+
UART_NUM_4, /*!< UART port 4 */
35+
#endif
36+
UART_NUM_MAX, /*!< UART port max */
37+
} uart_port_t;
38+
39+
#define UART_INTR_RXFIFO_FULL (0x1 << 0)
40+
#define UART_INTR_RXFIFO_TOUT (0x1 << 8)
41+
42+
/**
43+
* @brief Wait until UART is idle
44+
*
45+
* @param uart_num UART port number
46+
*/
47+
void stub_lib_uart_wait_idle(uart_port_t uart_num);
48+
49+
/**
50+
* @brief Initialize UART
51+
*
52+
* @param uart_num UART port number
53+
*/
54+
void stub_lib_uart_init(uart_port_t uart_num);
55+
56+
/**
57+
* @brief Set UART baud rate
58+
*
59+
* @param uart_num UART port number
60+
* @param baudrate Baud rate
61+
*/
62+
void stub_lib_uart_rominit_set_baudrate(uart_port_t uart_num, uint32_t baudrate);
63+
64+
/**
65+
* @brief Attach interrupt handler to UART and configure interrupts
66+
*
67+
* @note This function requires ROM preinit (download mode initialization) to work correctly.
68+
* It uses ROM functions (ets_isr_attach, ets_isr_unmask) that are only available
69+
* after the ROM has entered download mode and completed its initialization.
70+
* Functions that contain "rominit" have this requirement.
71+
*
72+
* @param uart_num UART port number
73+
* @param intr_num CPU interrupt source
74+
* @param handler Interrupt handler function pointer
75+
* @param flags Interrupt enable flags (bitwise OR of UART_INTR_* values)
76+
*/
77+
void stub_lib_uart_rominit_intr_attach(uart_port_t uart_num, int intr_num, void *handler, uint32_t flags);
78+
79+
/**
80+
* @brief Get and clear UART interrupt status
81+
*
82+
* This function returns the interrupt status and automatically clears it.
83+
* Call this at the beginning of your interrupt handler.
84+
*
85+
* @param uart_num UART port number
86+
* @return Bitmask of active interrupts that were cleared
87+
*/
88+
uint32_t stub_lib_uart_get_intr_flags(uart_port_t uart_num);
89+
90+
/**
91+
* @brief Get number of bytes available in RX FIFO
92+
*
93+
* @param uart_num UART port number
94+
* @return Number of bytes currently in the RX FIFO
95+
*/
96+
uint32_t stub_lib_uart_get_rxfifo_count(uart_port_t uart_num);
97+
98+
/**
99+
* @brief Read a single byte from UART RX FIFO
100+
*
101+
* This function reads one byte from the RX FIFO without checking
102+
* if data is available. Call stub_lib_uart_get_rxfifo_count()
103+
* first to ensure data is available.
104+
*
105+
* @param uart_num UART port number
106+
* @return The byte read from the FIFO
107+
*/
108+
uint8_t stub_lib_uart_read_rxfifo_byte(uart_port_t uart_num);
109+
110+
/**
111+
* @brief Configure RX timeout threshold
112+
*
113+
* @param uart_num UART port number
114+
* @param timeout Timeout value in bit times (1-126, 0 to disable)
115+
* timeout mean the multiple of UART packets (~11 bytes) that can be received before timeout
116+
*/
117+
void stub_lib_uart_set_rx_timeout(uart_port_t uart_num, uint8_t timeout);
118+
119+
/**
120+
* @brief Transmit a single byte over UART.
121+
*
122+
* @note This function operates on the console UART (set via stub_lib_uart_set_as_console).
123+
* It does not take a uart_num parameter.
124+
*
125+
* @param c Byte to transmit.
126+
* @return 0 if successful, non-zero if error occurred.
127+
*/
128+
uint8_t stub_lib_uart_tx_one_char(uint8_t c);
129+
130+
/**
131+
* @brief Receive a single byte (blocking) from UART.
132+
*
133+
* @note This function operates on the console UART (set via stub_lib_uart_set_as_console).
134+
* It does not take a uart_num parameter.
135+
*
136+
* @return Received byte.
137+
*/
138+
uint8_t stub_lib_uart_rx_one_char(void);
139+
140+
/**
141+
* @brief Flush any buffered transmit data.
142+
*/
143+
void stub_lib_uart_tx_flush(void);
144+
145+
#ifdef __cplusplus
146+
}
147+
#endif // __cplusplus

src/log_uart.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ extern void ets_install_uart_printf(void);
1414

1515
void stub_lib_log_init()
1616
{
17-
stub_target_uart_init(0, 115200);
17+
stub_target_uart_init(0);
1818
ets_install_putc1(NULL);
1919
ets_install_putc2(NULL);
2020
ets_install_uart_printf();

src/rom_wrappers.c

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77

88
extern void ets_delay_us(uint32_t us);
99
extern uint16_t crc16_le(uint16_t crc, const uint8_t *buf, uint32_t len);
10-
extern uint8_t uart_tx_one_char(uint8_t ch);
11-
extern uint8_t uart_rx_one_char(void);
12-
extern void uart_tx_flush(void);
1310

1411
void stub_lib_delay_us(uint32_t us)
1512
{
@@ -20,18 +17,3 @@ uint16_t stub_lib_crc16_le(uint16_t crc, const uint8_t *buf, uint32_t len)
2017
{
2118
return crc16_le(crc, buf, len);
2219
}
23-
24-
uint8_t stub_lib_uart_tx_one_char(uint8_t c)
25-
{
26-
return uart_tx_one_char(c);
27-
}
28-
29-
uint8_t stub_lib_uart_rx_one_char(void)
30-
{
31-
return uart_rx_one_char();
32-
}
33-
34-
void stub_lib_uart_tx_flush(void)
35-
{
36-
uart_tx_flush();
37-
}

src/target/CMakeLists.txt

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,31 @@ add_subdirectory(${ESP_TARGET} ${ESP_TARGET_LIB})
1010
# Build common library
1111
add_subdirectory(common ${ESP_COMMON_LIB})
1212

13+
# Get target type to handle both STATIC and INTERFACE libraries
14+
get_target_property(target_type ${ESP_TARGET_LIB} TYPE)
15+
1316
# Apply common configurations to target library
1417
# This ensures strong symbols override weak ones
15-
target_link_options(${ESP_TARGET_LIB}
16-
PUBLIC -Wl,--whole-archive
17-
)
18+
if(target_type STREQUAL "INTERFACE_LIBRARY")
19+
target_link_options(${ESP_TARGET_LIB}
20+
INTERFACE -Wl,--whole-archive
21+
)
22+
23+
target_include_directories(${ESP_TARGET_LIB}
24+
INTERFACE ${CMAKE_CURRENT_LIST_DIR}/${ESP_TARGET}/include
25+
)
26+
27+
target_link_libraries(${ESP_TARGET_LIB} INTERFACE ${ESP_BASE_LIB})
28+
else()
29+
target_link_options(${ESP_TARGET_LIB}
30+
PUBLIC -Wl,--whole-archive
31+
)
32+
33+
target_include_directories(${ESP_TARGET_LIB}
34+
PUBLIC ${CMAKE_CURRENT_LIST_DIR}/${ESP_TARGET}/include
35+
)
1836

19-
# Set common include directories for target library
20-
target_include_directories(${ESP_TARGET_LIB}
21-
PUBLIC ${CMAKE_CURRENT_LIST_DIR}/${ESP_TARGET}/include
22-
)
37+
target_link_libraries(${ESP_TARGET_LIB} PUBLIC ${ESP_BASE_LIB})
38+
endif()
2339

24-
# Setup dependency chain: target → base, common → base + target
25-
target_link_libraries(${ESP_TARGET_LIB} PUBLIC ${ESP_BASE_LIB})
2640
target_link_libraries(${ESP_COMMON_LIB} PUBLIC ${ESP_BASE_LIB} ${ESP_TARGET_LIB})

src/target/base/include/target/uart.h

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,48 @@
77
#pragma once
88

99
#include <stdint.h>
10+
#include <stdbool.h>
1011

11-
void stub_target_uart_init(uint8_t uart_num, uint32_t baudrate);
12+
/**
13+
* @brief Wait until UART is idle
14+
*
15+
* @param uart_num UART port number
16+
*/
17+
void stub_target_uart_wait_idle(uint8_t uart_num);
18+
19+
/**
20+
* @brief Initialize UART
21+
*
22+
* @param uart_num UART port number
23+
*/
24+
void stub_target_uart_init(uint8_t uart_num);
25+
26+
/**
27+
* @brief Set UART baud rate
28+
*
29+
* @param uart_num UART port number
30+
* @param baudrate Baud rate
31+
*/
32+
void stub_target_uart_rominit_set_baudrate(uint8_t uart_num, uint32_t baudrate);
33+
34+
/**
35+
* @brief Flush any buffered transmit data.
36+
*/
37+
void stub_target_uart_tx_flush(void);
38+
39+
/**
40+
* @brief Wrapper for esp_rom_uart_attach
41+
*
42+
* Each target must implement this to adapt to its ROM function signature.
43+
* @param rxBuffer RX buffer pointer (may be ignored by some targets)
44+
*/
45+
void stub_target_rom_uart_attach(void *rxBuffer);
46+
47+
/**
48+
* @brief Wrapper for esp_rom_uart_init
49+
*
50+
* Each target must implement this to adapt to its ROM function signature.
51+
* @param uart_no UART number
52+
* @param clock Clock frequency (may be calculated internally by some targets)
53+
*/
54+
void stub_target_rom_uart_init(uint8_t uart_no, uint32_t clock);

0 commit comments

Comments
 (0)