Skip to content

Commit f566b50

Browse files
committed
feat(uhci): Add uhci (uart-dma) support on esp32c5, esp32h2
1 parent f66a750 commit f566b50

File tree

14 files changed

+298
-16
lines changed

14 files changed

+298
-16
lines changed
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-P4 | ESP32-S3 |
2-
| ----------------- | -------- | -------- | -------- | -------- |
1+
| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S3 |
2+
| ----------------- | -------- | -------- | -------- | -------- | -------- | -------- |

components/esp_driver_uart/test_apps/uhci/main/test_uhci.c

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ static void uhci_receive_test(void *arg)
143143
if (xQueueReceive(ctx->uhci_queue, &evt, portMAX_DELAY) == pdTRUE) {
144144
if (evt == UHCI_EVT_EOF) {
145145
disp_buf(receive_data, ctx->receive_size);
146-
for (int i = 0; i < DATA_LENGTH; i++) {
146+
for (int i = 0; i < ctx->receive_size; i++) {
147147
TEST_ASSERT(receive_data[i] == (uint8_t)i);
148148
}
149149
printf("Received size: %d\n", ctx->receive_size);
@@ -160,7 +160,7 @@ static void uhci_receive_test(void *arg)
160160
vTaskDelete(NULL);
161161
}
162162

163-
TEST_CASE("UHCI write and receive", "[uhci]")
163+
TEST_CASE("UHCI write and receive with idle eof", "[uhci]")
164164
{
165165
uart_config_t uart_config = {
166166
.baud_rate = 5 * 1000 * 1000,
@@ -202,6 +202,49 @@ TEST_CASE("UHCI write and receive", "[uhci]")
202202
vSemaphoreDelete(exit_sema);
203203
}
204204

205+
TEST_CASE("UHCI write and receive with length eof", "[uhci]")
206+
{
207+
uart_config_t uart_config = {
208+
.baud_rate = 5 * 1000 * 1000,
209+
.data_bits = UART_DATA_8_BITS,
210+
.parity = UART_PARITY_DISABLE,
211+
.stop_bits = UART_STOP_BITS_1,
212+
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
213+
.source_clk = UART_SCLK_XTAL,
214+
};
215+
TEST_ESP_OK(uart_param_config(EX_UART_NUM, &uart_config));
216+
// Connect TX and RX together for testing self send-receive
217+
TEST_ESP_OK(uart_set_pin(EX_UART_NUM, UART_TX_IO, UART_TX_IO, -1, -1));
218+
219+
uhci_controller_config_t uhci_cfg = {
220+
.uart_port = EX_UART_NUM,
221+
.tx_trans_queue_depth = 30,
222+
.max_receive_internal_mem = 10 * 1024,
223+
.max_transmit_size = 10 * 1024,
224+
.dma_burst_size = 32,
225+
.max_packet_receive = 100,
226+
.rx_eof_flags.length_eof = 1,
227+
};
228+
229+
uhci_controller_handle_t uhci_ctrl;
230+
SemaphoreHandle_t exit_sema = xSemaphoreCreateBinary();
231+
TEST_ESP_OK(uhci_new_controller(&uhci_cfg, &uhci_ctrl));
232+
233+
void *args[] = { uhci_ctrl, exit_sema };
234+
xTaskCreate(uhci_receive_test, "uhci_receive_test", 4096 * 2, args, 5, NULL);
235+
236+
uint8_t data_wr[DATA_LENGTH];
237+
for (int i = 0; i < DATA_LENGTH; i++) {
238+
data_wr[i] = i;
239+
}
240+
TEST_ESP_OK(uhci_transmit(uhci_ctrl, data_wr, DATA_LENGTH));
241+
uhci_wait_all_tx_transaction_done(uhci_ctrl, portMAX_DELAY);
242+
xSemaphoreTake(exit_sema, portMAX_DELAY);
243+
vTaskDelay(2);
244+
TEST_ESP_OK(uhci_del_controller(uhci_ctrl));
245+
vSemaphoreDelete(exit_sema);
246+
}
247+
205248
#if CONFIG_SPIRAM
206249
#if CONFIG_IDF_TARGET_ESP32S3
207250
static void uhci_receive_test_in_psram(void *arg)

components/hal/esp32c3/include/hal/uhci_ll.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ extern "C" {
1919
#endif
2020

2121
#define UHCI_LL_GET_HW(num) (((num) == 0) ? (&UHCI0) : (NULL))
22+
#define UHCI_LL_MAX_RECEIVE_PACKET_THRESHOLD (8192)
2223

2324
typedef enum {
2425
UHCI_RX_BREAK_CHR_EOF = 0x1,
@@ -159,6 +160,11 @@ static inline void uhci_ll_rx_set_eof_mode(uhci_dev_t *hw, uint32_t eof_mode)
159160
}
160161
}
161162

163+
static inline void uhci_ll_rx_set_packet_threshold(uhci_dev_t *hw, uint16_t length)
164+
{
165+
hw->pkt_thres.thrs = length;
166+
}
167+
162168
#ifdef __cplusplus
163169
}
164170
#endif
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+
// The LL layer for UHCI register operations.
8+
// Note that most of the register operations in this layer are non-atomic operations.
9+
10+
#pragma once
11+
#include <stdio.h>
12+
#include "hal/uhci_types.h"
13+
#include "soc/uhci_struct.h"
14+
#include "soc/pcr_struct.h"
15+
#include "hal/misc.h"
16+
17+
#ifdef __cplusplus
18+
extern "C" {
19+
#endif
20+
21+
#define UHCI_LL_GET_HW(num) (((num) == 0) ? (&UHCI) : (NULL))
22+
#define UHCI_LL_MAX_RECEIVE_PACKET_THRESHOLD (8192)
23+
24+
typedef enum {
25+
UHCI_RX_BREAK_CHR_EOF = 0x1,
26+
UHCI_RX_IDLE_EOF = 0x2,
27+
UHCI_RX_LEN_EOF = 0x4,
28+
UHCI_RX_EOF_MAX = 0x7,
29+
} uhci_rxeof_cfg_t;
30+
31+
/**
32+
* @brief Enable the bus clock for UHCI module
33+
*
34+
* @param group_id Group ID
35+
* @param enable true to enable, false to disable
36+
*/
37+
static inline void uhci_ll_enable_bus_clock(int group_id, bool enable)
38+
{
39+
(void)group_id;
40+
PCR.uhci_conf.uhci_clk_en = enable;
41+
}
42+
43+
/**
44+
* @brief Reset the UHCI module
45+
*
46+
* @param group_id Group ID
47+
*/
48+
static inline void uhci_ll_reset_register(int group_id)
49+
{
50+
(void)group_id;
51+
PCR.uhci_conf.uhci_rst_en = 1;
52+
PCR.uhci_conf.uhci_rst_en = 0;
53+
}
54+
55+
static inline void uhci_ll_init(uhci_dev_t *hw)
56+
{
57+
typeof(hw->conf0) conf0_reg;
58+
hw->conf0.clk_en = 1;
59+
conf0_reg.val = 0;
60+
conf0_reg.clk_en = 1;
61+
hw->conf0.val = conf0_reg.val;
62+
hw->conf1.val = 0;
63+
}
64+
65+
static inline void uhci_ll_attach_uart_port(uhci_dev_t *hw, int uart_num)
66+
{
67+
hw->conf0.uart_sel = uart_num;
68+
}
69+
70+
static inline void uhci_ll_set_seper_chr(uhci_dev_t *hw, uhci_seper_chr_t *seper_char)
71+
{
72+
if (seper_char->sub_chr_en) {
73+
hw->conf0.seper_en = 1;
74+
typeof(hw->esc_conf0) esc_conf0_reg;
75+
esc_conf0_reg.val = hw->esc_conf0.val;
76+
77+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf0_reg, seper_char, seper_char->seper_chr);
78+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf0_reg, seper_esc_char0, seper_char->sub_chr1);
79+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf0_reg, seper_esc_char1, seper_char->sub_chr2);
80+
hw->esc_conf0.val = esc_conf0_reg.val;
81+
hw->escape_conf.tx_c0_esc_en = 1;
82+
hw->escape_conf.rx_c0_esc_en = 1;
83+
} else {
84+
hw->conf0.seper_en = 0;
85+
hw->escape_conf.val = 0;
86+
}
87+
}
88+
89+
static inline void uhci_ll_set_swflow_ctrl_sub_chr(uhci_dev_t *hw, uhci_swflow_ctrl_sub_chr_t *sub_ctr)
90+
{
91+
typeof(hw->escape_conf) escape_conf_reg;
92+
escape_conf_reg.val = hw->escape_conf.val;
93+
94+
if (sub_ctr->flow_en == 1) {
95+
typeof(hw->esc_conf2) esc_conf2_reg;
96+
esc_conf2_reg.val = hw->esc_conf2.val;
97+
typeof(hw->esc_conf3) esc_conf3_reg;
98+
esc_conf3_reg.val = hw->esc_conf3.val;
99+
100+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf2_reg, esc_seq1, sub_ctr->xon_chr);
101+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf2_reg, esc_seq1_char0, sub_ctr->xon_sub1);
102+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf2_reg, esc_seq1_char1, sub_ctr->xon_sub2);
103+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf3_reg, esc_seq2, sub_ctr->xoff_chr);
104+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf3_reg, esc_seq2_char0, sub_ctr->xoff_sub1);
105+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf3_reg, esc_seq2_char1, sub_ctr->xoff_sub2);
106+
escape_conf_reg.tx_11_esc_en = 1;
107+
escape_conf_reg.tx_13_esc_en = 1;
108+
escape_conf_reg.rx_11_esc_en = 1;
109+
escape_conf_reg.rx_13_esc_en = 1;
110+
hw->esc_conf2.val = esc_conf2_reg.val;
111+
hw->esc_conf3.val = esc_conf3_reg.val;
112+
} else {
113+
escape_conf_reg.tx_11_esc_en = 0;
114+
escape_conf_reg.tx_13_esc_en = 0;
115+
escape_conf_reg.rx_11_esc_en = 0;
116+
escape_conf_reg.rx_13_esc_en = 0;
117+
}
118+
hw->escape_conf.val = escape_conf_reg.val;
119+
}
120+
121+
static inline void uhci_ll_enable_intr(uhci_dev_t *hw, uint32_t intr_mask)
122+
{
123+
hw->int_ena.val |= intr_mask;
124+
}
125+
126+
static inline void uhci_ll_disable_intr(uhci_dev_t *hw, uint32_t intr_mask)
127+
{
128+
hw->int_ena.val &= (~intr_mask);
129+
}
130+
131+
static inline void uhci_ll_clear_intr(uhci_dev_t *hw, uint32_t intr_mask)
132+
{
133+
hw->int_clr.val = intr_mask;
134+
}
135+
136+
static inline uint32_t uhci_ll_get_intr(uhci_dev_t *hw)
137+
{
138+
return hw->int_st.val;
139+
}
140+
141+
static inline void uhci_ll_rx_set_eof_mode(uhci_dev_t *hw, uint32_t eof_mode)
142+
{
143+
if (eof_mode & UHCI_RX_BREAK_CHR_EOF) {
144+
hw->conf0.uart_rx_brk_eof_en = 1;
145+
}
146+
if (eof_mode & UHCI_RX_IDLE_EOF) {
147+
hw->conf0.uart_idle_eof_en = 1;
148+
}
149+
if (eof_mode & UHCI_RX_LEN_EOF) {
150+
hw->conf0.len_eof_en = 1;
151+
}
152+
}
153+
154+
static inline void uhci_ll_rx_set_packet_threshold(uhci_dev_t *hw, uint16_t length)
155+
{
156+
hw->pkt_thres.pkt_thrs = length;
157+
}
158+
159+
#ifdef __cplusplus
160+
}
161+
#endif

components/hal/esp32c6/include/hal/uhci_ll.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ extern "C" {
1919
#endif
2020

2121
#define UHCI_LL_GET_HW(num) (((num) == 0) ? (&UHCI0) : (NULL))
22+
#define UHCI_LL_MAX_RECEIVE_PACKET_THRESHOLD (8192)
2223

2324
typedef enum {
2425
UHCI_RX_BREAK_CHR_EOF = 0x1,
@@ -151,6 +152,11 @@ static inline void uhci_ll_rx_set_eof_mode(uhci_dev_t *hw, uint32_t eof_mode)
151152
}
152153
}
153154

155+
static inline void uhci_ll_rx_set_packet_threshold(uhci_dev_t *hw, uint16_t length)
156+
{
157+
hw->pkt_thres.pkt_thrs = length;
158+
}
159+
154160
#ifdef __cplusplus
155161
}
156162
#endif

components/hal/esp32h2/include/hal/uhci_ll.h

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
#include <stdio.h>
99
#include "hal/uhci_types.h"
1010
#include "soc/uhci_struct.h"
11+
#include "soc/pcr_struct.h"
1112
#include "hal/misc.h"
1213

1314
#ifdef __cplusplus
1415
extern "C" {
1516
#endif
1617

1718
#define UHCI_LL_GET_HW(num) (((num) == 0) ? (&UHCI0) : (NULL))
19+
#define UHCI_LL_MAX_RECEIVE_PACKET_THRESHOLD (8192)
1820

1921
typedef enum {
2022
UHCI_RX_BREAK_CHR_EOF = 0x1,
@@ -23,6 +25,30 @@ typedef enum {
2325
UHCI_RX_EOF_MAX = 0x7,
2426
} uhci_rxeof_cfg_t;
2527

28+
/**
29+
* @brief Enable the bus clock for UHCI module
30+
*
31+
* @param group_id Group ID
32+
* @param enable true to enable, false to disable
33+
*/
34+
static inline void uhci_ll_enable_bus_clock(int group_id, bool enable)
35+
{
36+
(void)group_id;
37+
PCR.uhci_conf.uhci_clk_en = enable;
38+
}
39+
40+
/**
41+
* @brief Reset the UHCI module
42+
*
43+
* @param group_id Group ID
44+
*/
45+
static inline void uhci_ll_reset_register(int group_id)
46+
{
47+
(void)group_id;
48+
PCR.uhci_conf.uhci_rst_en = 1;
49+
PCR.uhci_conf.uhci_rst_en = 0;
50+
}
51+
2652
static inline void uhci_ll_init(uhci_dev_t *hw)
2753
{
2854
typeof(hw->conf0) conf0_reg;
@@ -35,8 +61,8 @@ static inline void uhci_ll_init(uhci_dev_t *hw)
3561

3662
static inline void uhci_ll_attach_uart_port(uhci_dev_t *hw, int uart_num)
3763
{
38-
hw->conf0.uart0_ce = (uart_num == 0)? 1: 0;
39-
hw->conf0.uart1_ce = (uart_num == 1)? 1: 0;
64+
hw->conf0.uart0_ce = (uart_num == 0) ? 1 : 0;
65+
hw->conf0.uart1_ce = (uart_num == 1) ? 1 : 0;
4066
}
4167

4268
static inline void uhci_ll_set_seper_chr(uhci_dev_t *hw, uhci_seper_chr_t *seper_char)
@@ -69,12 +95,12 @@ static inline void uhci_ll_set_swflow_ctrl_sub_chr(uhci_dev_t *hw, uhci_swflow_c
6995
typeof(hw->esc_conf3) esc_conf3_reg;
7096
esc_conf3_reg.val = hw->esc_conf3.val;
7197

72-
esc_conf2_reg.esc_seq1 = sub_ctr->xon_chr;
73-
esc_conf2_reg.esc_seq1_char0 = sub_ctr->xon_sub1;
74-
esc_conf2_reg.esc_seq1_char1 = sub_ctr->xon_sub2;
75-
esc_conf3_reg.esc_seq2 = sub_ctr->xoff_chr;
76-
esc_conf3_reg.esc_seq2_char0 = sub_ctr->xoff_sub1;
77-
esc_conf3_reg.esc_seq2_char1 = sub_ctr->xoff_sub2;
98+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf2_reg, esc_seq1, sub_ctr->xon_chr);
99+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf2_reg, esc_seq1_char0, sub_ctr->xon_sub1);
100+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf2_reg, esc_seq1_char1, sub_ctr->xon_sub2);
101+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf3_reg, esc_seq2, sub_ctr->xoff_chr);
102+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf3_reg, esc_seq2_char0, sub_ctr->xoff_sub1);
103+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf3_reg, esc_seq2_char1, sub_ctr->xoff_sub2);
78104
escape_conf_reg.tx_11_esc_en = 1;
79105
escape_conf_reg.tx_13_esc_en = 1;
80106
escape_conf_reg.rx_11_esc_en = 1;
@@ -110,7 +136,6 @@ static inline uint32_t uhci_ll_get_intr(uhci_dev_t *hw)
110136
return hw->int_st.val;
111137
}
112138

113-
114139
static inline void uhci_ll_rx_set_eof_mode(uhci_dev_t *hw, uint32_t eof_mode)
115140
{
116141
if (eof_mode & UHCI_RX_BREAK_CHR_EOF) {
@@ -124,6 +149,11 @@ static inline void uhci_ll_rx_set_eof_mode(uhci_dev_t *hw, uint32_t eof_mode)
124149
}
125150
}
126151

152+
static inline void uhci_ll_rx_set_packet_threshold(uhci_dev_t *hw, uint16_t length)
153+
{
154+
hw->pkt_thres.pkt_thrs = length;
155+
}
156+
127157
#ifdef __cplusplus
128158
}
129159
#endif

components/hal/esp32p4/include/hal/uhci_ll.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ extern "C" {
1919
#endif
2020

2121
#define UHCI_LL_GET_HW(num) (((num) == 0) ? (&UHCI0) : (NULL))
22+
#define UHCI_LL_MAX_RECEIVE_PACKET_THRESHOLD (8192)
2223

2324
typedef enum {
2425
UHCI_RX_BREAK_CHR_EOF = 0x1,
@@ -107,6 +108,11 @@ static inline void uhci_ll_rx_set_eof_mode(uhci_dev_t *hw, uint32_t eof_mode)
107108
}
108109
}
109110

111+
static inline void uhci_ll_rx_set_packet_threshold(uhci_dev_t *hw, uint16_t length)
112+
{
113+
hw->pkt_thres.pkt_thrs = length;
114+
}
115+
110116
#ifdef __cplusplus
111117
}
112118
#endif

0 commit comments

Comments
 (0)