Skip to content

Commit 1a3db8e

Browse files
committed
feat(uhci): Add uhci (uart-dma) support on esp32c3, esp32c6, esp32s3, esp32p4
1 parent 182b33e commit 1a3db8e

File tree

30 files changed

+1353
-126
lines changed

30 files changed

+1353
-126
lines changed

components/esp_driver_uart/CMakeLists.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@ set(srcs)
44
set(public_include "include")
55
if(CONFIG_SOC_UART_SUPPORTED)
66
list(APPEND srcs "src/uart.c" "src/uart_wakeup.c")
7+
if(CONFIG_SOC_UHCI_SUPPORTED)
8+
list(APPEND srcs "src/uhci.c")
9+
endif()
710
endif()
811

12+
913
if(${target} STREQUAL "linux")
1014
set(priv_requires esp_ringbuf)
1115
else()
12-
set(priv_requires esp_pm esp_driver_gpio esp_ringbuf)
16+
set(priv_requires esp_pm esp_driver_gpio esp_ringbuf esp_mm)
1317
endif()
1418

1519
idf_component_register(

components/esp_driver_uart/Kconfig

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,31 @@ menu "ESP-Driver:UART Configurations"
1010
may cause data lost when doing spi flash operation.
1111

1212
endmenu
13+
14+
menu "ESP-Driver:UHCI Configurations"
15+
16+
config UHCI_ISR_HANDLER_IN_IRAM
17+
bool "Place UHCI ISR function into IRAM"
18+
default n
19+
help
20+
If this option is not selected, UHCI interrupt will be disabled for a long time and
21+
may cause data lost when doing spi flash operation.
22+
23+
config UHCI_ISR_CACHE_SAFE
24+
bool "Allow UHCI ISR to execute when cache is disabled" if !SPI_FLASH_AUTO_SUSPEND
25+
select UHCI_ISR_HANDLER_IN_IRAM
26+
select GDMA_ISR_HANDLER_IN_IRAM if SOC_GDMA_SUPPORTED
27+
default n
28+
help
29+
Enable this option to allow the ISR for UHCI to execute even when the cache is disabled.
30+
This can be useful in scenarios where the cache might be turned off, but the UHCI
31+
functionality is still required to operate correctly.
32+
33+
config UHCI_ENABLE_DEBUG_LOG
34+
bool "Enable debug log"
35+
default n
36+
help
37+
whether to enable the debug log message for UHCI driver.
38+
Note that, this option only controls the UHCI driver log, won't affect other drivers.
39+
40+
endmenu
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#pragma once
8+
9+
#include "esp_err.h"
10+
#include "freertos/FreeRTOS.h"
11+
#include "freertos/queue.h"
12+
#include "driver/uhci_types.h"
13+
14+
#ifdef __cplusplus
15+
extern "C" {
16+
#endif
17+
18+
/**
19+
* @brief UHCI controller specific configurations
20+
*/
21+
typedef struct {
22+
uart_port_t uart_port; /*!< UART port that connect to UHCI controller */
23+
size_t tx_trans_queue_depth; /*!< Depth of internal transfer queue, increase this value can support more transfers pending in the background */
24+
size_t max_transmit_size; /*!< Maximum transfer size in one transaction, in bytes. This decides the number of DMA nodes will be used for each transaction */
25+
size_t max_receive_internal_mem; /*!< Maximum transfer size in one transaction, in bytes. Each DMA node can point to a maximum of 4096 bytes. This value determines the number of DMA nodes used for each transaction. When your transfer size is large enough, it is recommended to set this value greater than 4096 to facilitate efficient ping-pong operations, such as 10 * 1024. */
26+
size_t dma_burst_size; /*!< DMA burst size, in bytes */
27+
28+
struct {
29+
uint16_t rx_brk_eof: 1; /*!< UHCI will end payload receive process when NULL frame is received by UART. */
30+
uint16_t idle_eof: 1; /*!< UHCI will end payload receive process when UART has been in idle state. */
31+
uint16_t length_eof: 1; /*!< UHCI will end payload receive process when the receiving byte count has reached the specific value. */
32+
} rx_eof_flags; /*!< UHCI eof flags */
33+
} uhci_controller_config_t;
34+
35+
/**
36+
* @brief Structure for defining callback functions for UHCI events.
37+
*/
38+
typedef struct {
39+
uhci_rx_event_callback_t on_rx_trans_event; /*!< Callback function for handling the completion of a reception. */
40+
uhci_tx_done_callback_t on_tx_trans_done; /*!< Callback function for handling the completion of a transmission. */
41+
} uhci_event_callbacks_t;
42+
43+
/**
44+
* @brief Create and initialize a new UHCI controller.
45+
*
46+
* This function initializes a new UHCI controller instance based on the provided configuration.
47+
* It allocates and configures resources required for the UHCI controller, such as DMA and
48+
* communication settings. The created controller handle is returned through the output parameter.
49+
*
50+
* @param[in] config Pointer to a `uhci_controller_config_t` structure containing the
51+
* configuration parameters for the UHCI controller.
52+
* @param[out] ret_uhci_ctrl Pointer to a variable where the handle to the newly created UHCI controller
53+
* will be stored. This handle is used in subsequent operations involving the
54+
* controller.
55+
*
56+
* @return
57+
* - `ESP_OK`: Controller successfully created and initialized.
58+
* - `ESP_ERR_INVALID_ARG`: One or more arguments are invalid (e.g., null pointers or invalid config).
59+
* - `ESP_ERR_NO_MEM`: Memory allocation for the controller failed.
60+
* - Other error codes: Indicate failure in the underlying hardware or driver initialization.
61+
*/
62+
esp_err_t uhci_new_controller(const uhci_controller_config_t *config, uhci_controller_handle_t *ret_uhci_ctrl);
63+
64+
/**
65+
* @brief Receive data from the UHCI controller.
66+
*
67+
* This function retrieves data from the UHCI controller into the provided buffer. It is typically
68+
* used for receiving data that was transmitted via UART and processed by the UHCI DMA controller.
69+
*
70+
* @param[in] uhci_ctrl Handle to the UHCI controller, which was previously created using
71+
* `uhci_new_controller()`.
72+
* @param[out] read_buffer Pointer to the buffer where the received data will be stored.
73+
* The buffer must be pre-allocated by the caller.
74+
* @param[in] buffer_size The size of read buffer.
75+
*
76+
* @note @note The function is non-blocking, it just mounts the user buffer to the DMA.
77+
* The return from the function doesn't mean a finished receive. You need to register corresponding
78+
* callback function to get notification.
79+
*
80+
* @return
81+
* - `ESP_OK`: Data successfully received and written to the buffer.
82+
* - `ESP_ERR_INVALID_ARG`: Invalid arguments (e.g., null buffer or invalid controller handle).
83+
*/
84+
esp_err_t uhci_receive(uhci_controller_handle_t uhci_ctrl, uint8_t *read_buffer, size_t buffer_size);
85+
86+
/**
87+
* @brief Transmit data using the UHCI controller.
88+
*
89+
* This function sends data from the provided buffer through the UHCI controller. It uses the DMA
90+
* capabilities of UHCI to efficiently handle data transmission via UART.
91+
*
92+
* @param[in] uhci_ctrl Handle to the UHCI controller, which was previously created using
93+
* `uhci_new_controller()`.
94+
* @param[in] write_buffer Pointer to the buffer containing the data to be transmitted.
95+
* The buffer must remain valid until the transmission is complete.
96+
* @param[in] write_size The number of bytes to transmit from the buffer.
97+
*
98+
* @note The function is an non-blocking api, which means this function will return immediately. You can
99+
* get corresponding event from callbacks.
100+
*
101+
* @return
102+
* - `ESP_OK`: Data successfully queued for transmission.
103+
* - `ESP_ERR_INVALID_ARG`: Invalid arguments (e.g., null buffer, invalid handle, or zero `write_size`).
104+
*/
105+
esp_err_t uhci_transmit(uhci_controller_handle_t uhci_ctrl, uint8_t *write_buffer, size_t write_size);
106+
107+
/**
108+
* @brief Uninstall the UHCI (UART Host Controller Interface) driver and release resources.
109+
*
110+
* This function deinitializes the UHCI controller and frees any resources allocated during its
111+
* initialization. It ensures proper cleanup and prevents resource leaks when the UHCI controller
112+
* is no longer needed.
113+
*
114+
* @param[in] uhci_ctrl Handle to the UHCI controller, which was previously created using
115+
* `uhci_new_controller()`. Passing an invalid or uninitialized handle
116+
* may result in undefined behavior.
117+
*
118+
* @return
119+
* - `ESP_OK`: The UHCI driver was successfully uninstalled, and resources were released.
120+
* - `ESP_ERR_INVALID_ARG`: The provided `uhci_ctrl` handle is invalid or null.
121+
*/
122+
esp_err_t uhci_del_controller(uhci_controller_handle_t uhci_ctrl);
123+
124+
/**
125+
* @brief Register event callback functions for a UHCI controller.
126+
*
127+
* This function allows the user to register callback functions to handle specific UHCI events, such as
128+
* transmission or reception completion. The callbacks provide a mechanism to handle asynchronous events
129+
* generated by the UHCI controller.
130+
*
131+
* @param[in] uhci_ctrl Handle to the UHCI controller, which was previously created using
132+
* `uhci_new_controller()`.
133+
* @param[in] cbs Pointer to a `uhci_event_callbacks_t` structure that defines the callback
134+
* functions to be registered. This structure includes pointers to the callback
135+
* functions for handling UHCI events.
136+
* @param[in] user_data Pointer to user-defined data that will be passed to the callback functions
137+
* when they are invoked. This can be used to provide context or state information
138+
* specific to the application.
139+
*
140+
* @return
141+
* - `ESP_OK`: Event callbacks were successfully registered.
142+
* - `ESP_ERR_INVALID_ARG`: Invalid arguments (e.g., null `uhci_ctrl` handle or `cbs` pointer).
143+
*/
144+
esp_err_t uhci_register_event_callbacks(uhci_controller_handle_t uhci_ctrl, const uhci_event_callbacks_t *cbs, void *user_data);
145+
146+
/**
147+
* @brief Wait for all pending TX transactions done
148+
*
149+
* @param[in] uhci_ctrl UHCI controller that created by `uhci_new_controller`
150+
* @param[in] timeout_ms Timeout in milliseconds, `-1` means to wait forever
151+
* @return
152+
* - ESP_OK: All pending TX transactions is finished and recycled
153+
* - ESP_ERR_INVALID_ARG: Wait for all pending TX transactions done failed because of invalid argument
154+
* - ESP_ERR_TIMEOUT: Wait for all pending TX transactions done timeout
155+
* - ESP_FAIL: Wait for all pending TX transactions done failed because of other error
156+
*/
157+
esp_err_t uhci_wait_all_tx_transaction_done(uhci_controller_handle_t uhci_ctrl, int timeout_ms);
158+
159+
#ifdef __cplusplus
160+
}
161+
#endif
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#pragma once
8+
9+
#include <stdint.h>
10+
#include <stdbool.h>
11+
#include <stdlib.h>
12+
#include <stddef.h>
13+
#include "hal/uart_types.h"
14+
#include "hal/uhci_types.h"
15+
#include "soc/soc_caps.h"
16+
17+
#ifdef __cplusplus
18+
extern "C" {
19+
#endif
20+
21+
/**
22+
* @brief UHCI Controller Handle Type
23+
*/
24+
typedef struct uhci_controller_t *uhci_controller_handle_t;
25+
26+
/**
27+
* @brief UHCI TX Done Event Data
28+
*/
29+
typedef struct {
30+
uint8_t *buffer; /**< Pointer to the which data buffer has been finished the transaction */
31+
size_t sent_size; /**< Size has been sent out */
32+
} uhci_tx_done_event_data_t;
33+
34+
/**
35+
* @brief UHCI TX Done Callback Function Type
36+
* @param uhci_ctrl Handle to the UHCI controller that initiated the transmission.
37+
* @param edata Pointer to a structure containing event data related to the completed transmission.
38+
* This structure provides details such as the number of bytes transmitted and any
39+
* status information relevant to the operation.
40+
* @param user_ctx User-defined context passed during the callback registration.
41+
* It can be used to maintain application-specific state or data.
42+
*
43+
* @return Whether a high priority task has been waken up by this callback function
44+
*/
45+
typedef bool (*uhci_tx_done_callback_t)(uhci_controller_handle_t uhci_ctrl, const uhci_tx_done_event_data_t *edata, void *user_ctx);
46+
47+
/**
48+
* @brief UHCI RX Done Event Data Structure
49+
*/
50+
typedef struct {
51+
uint8_t *data; /*!< Pointer to the received data buffer */
52+
size_t recv_size; /*!< Number of bytes received */
53+
struct {
54+
uint32_t totally_received: 1; /*!< When callback is invoked, while this bit is not set, means the current event gives partial of whole data, the transaction has not been finished. If set, means the current event gives whole data, the transaction finished. */
55+
} flags; /*!< I2C master config flags */
56+
} uhci_rx_event_data_t;
57+
58+
/**
59+
* @brief UHCI RX Done Callback Function Type
60+
* @param uhci_ctrl Handle to the UHCI controller that initiated the transmission.
61+
* @param edata Pointer to a structure containing event data related to receive event.
62+
* This structure provides details such as the number of bytes received and any
63+
* status information relevant to the operation.
64+
* @param user_ctx User-defined context passed during the callback registration.
65+
* It can be used to maintain application-specific state or data.
66+
*
67+
* @return Whether a high priority task has been waken up by this callback function
68+
*/
69+
typedef bool (*uhci_rx_event_callback_t)(uhci_controller_handle_t uhci_ctrl, const uhci_rx_event_data_t *edata, void *user_ctx);
70+
71+
#ifdef __cplusplus
72+
}
73+
#endif

components/esp_driver_uart/linker.lf

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,20 @@ archive: libhal.a
99
entries:
1010
if UART_ISR_IN_IRAM = y:
1111
uart_hal_iram (noflash)
12+
13+
[mapping:uhci]
14+
archive: libesp_driver_uart.a
15+
entries:
16+
if UHCI_ISR_HANDLER_IN_IRAM = y:
17+
uhci: uhci_gdma_rx_callback_done (noflash)
18+
uhci: uhci_gdma_tx_callback_eof (noflash)
19+
uhci: uhci_do_transmit (noflash)
20+
21+
[mapping:uhci_driver_gdma]
22+
archive: libesp_hw_support.a
23+
entries:
24+
if UHCI_ISR_HANDLER_IN_IRAM = y:
25+
gdma_link: gdma_link_count_buffer_size_till_eof (noflash)
26+
gdma_link: gdma_link_mount_buffers (noflash)
27+
gdma_link: gdma_link_get_head_addr (noflash)
28+
gdma: gdma_start (noflash)

0 commit comments

Comments
 (0)