Skip to content

Commit 8344af1

Browse files
committed
Merge branch 'feat/support_length_eof' into 'master'
feat(uhci): Add UHCI support on esp32c5, esp32h2. See merge request espressif/esp-idf!38794
2 parents 06520a3 + bb03892 commit 8344af1

File tree

21 files changed

+315
-21
lines changed

21 files changed

+315
-21
lines changed

components/esp_driver_uart/include/driver/uhci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ typedef struct {
2424
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 */
2525
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. */
2626
size_t dma_burst_size; /*!< DMA burst size, in bytes */
27+
size_t max_packet_receive; /*!< Max receive size, auto stop receiving after reach this value, only valid when `length_eof` set true */
2728

2829
struct {
2930
uint16_t rx_brk_eof: 1; /*!< UHCI will end payload receive process when NULL frame is received by UART. */

components/esp_driver_uart/linker.lf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,5 @@ entries:
2626
gdma_link: gdma_link_mount_buffers (noflash)
2727
gdma_link: gdma_link_get_head_addr (noflash)
2828
gdma: gdma_start (noflash)
29+
gdma: gdma_stop (noflash)
30+
gdma: gdma_reset (noflash)

components/esp_driver_uart/src/uhci.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,10 @@ static bool uhci_gdma_rx_callback_done(gdma_channel_handle_t dma_chan, gdma_even
149149
need_yield |= uhci_ctrl->rx_dir.on_rx_trans_event(uhci_ctrl, &evt_data, uhci_ctrl->user_data);
150150
}
151151

152+
// Stop the transaction when EOF is detected. In case for length EOF, there is no further more callback to be invoked.
153+
gdma_stop(uhci_ctrl->rx_dir.dma_chan);
154+
gdma_reset(uhci_ctrl->rx_dir.dma_chan);
155+
152156
uhci_ctrl->rx_dir.rx_fsm = UHCI_RX_FSM_ENABLE;
153157
}
154158

@@ -330,6 +334,7 @@ esp_err_t uhci_receive(uhci_controller_handle_t uhci_ctrl, uint8_t *read_buffer,
330334
}
331335
};
332336
ESP_LOGD(TAG, "The DMA node %d has %d byte", i, uhci_ctrl->rx_dir.buffer_size_per_desc_node[i]);
337+
ESP_RETURN_ON_FALSE(uhci_ctrl->rx_dir.buffer_size_per_desc_node[i] != 0, ESP_ERR_INVALID_STATE, TAG, "Allocate dma node length is 0, please reconfigure the buffer_size");
333338
read_buffer += uhci_ctrl->rx_dir.buffer_size_per_desc_node[i];
334339
}
335340

@@ -451,6 +456,9 @@ esp_err_t uhci_new_controller(const uhci_controller_config_t *config, uhci_contr
451456

452457
uhci_controller_handle_t uhci_ctrl = (uhci_controller_handle_t)heap_caps_calloc(1, sizeof(uhci_controller_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
453458
ESP_RETURN_ON_FALSE(uhci_ctrl, ESP_ERR_NO_MEM, TAG, "no mem for uhci controller handle");
459+
if (config->rx_eof_flags.length_eof) {
460+
ESP_RETURN_ON_FALSE(config->max_packet_receive < UHCI_LL_MAX_RECEIVE_PACKET_THRESHOLD, ESP_ERR_INVALID_ARG, TAG, "max receive packet is over threshold");
461+
}
454462

455463
atomic_init(&uhci_ctrl->tx_dir.tx_fsm, UHCI_TX_FSM_ENABLE);
456464
atomic_init(&uhci_ctrl->rx_dir.rx_fsm, UHCI_TX_FSM_ENABLE);
@@ -509,6 +517,7 @@ esp_err_t uhci_new_controller(const uhci_controller_config_t *config, uhci_contr
509517
}
510518
if (config->rx_eof_flags.length_eof) {
511519
uhci_ll_rx_set_eof_mode(uhci_ctrl->hal.dev, UHCI_RX_LEN_EOF);
520+
uhci_ll_rx_set_packet_threshold(uhci_ctrl->hal.dev, config->max_packet_receive);
512521
}
513522
if (config->rx_eof_flags.rx_brk_eof) {
514523
uhci_ll_rx_set_eof_mode(uhci_ctrl->hal.dev, UHCI_RX_BREAK_CHR_EOF);

components/esp_driver_uart/test_apps/.build-test-rules.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,6 @@ components/esp_driver_uart/test_apps/uart_vfs:
3232
components/esp_driver_uart/test_apps/uhci:
3333
disable:
3434
- if: SOC_UHCI_SUPPORTED != 1
35-
- if: CONFIG_NAME == "psram" and SOC_SPIRAM_SUPPORTED != 1
35+
- if: CONFIG_NAME == "psram" and SOC_AHB_GDMA_SUPPORT_PSRAM != 1
3636
depends_components:
3737
- esp_driver_uart
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: 46 additions & 3 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,8 +202,51 @@ 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
206-
#if CONFIG_IDF_TARGET_ESP32S3
249+
#if SOC_AHB_GDMA_SUPPORT_PSRAM
207250
static void uhci_receive_test_in_psram(void *arg)
208251
{
209252
uhci_controller_handle_t uhci_ctrl = ((uhci_controller_handle_t *)arg)[0];

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: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
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+
conf0_reg.val = 0;
59+
conf0_reg.clk_en = 1;
60+
hw->conf0.val = conf0_reg.val;
61+
hw->conf1.val = 0;
62+
}
63+
64+
static inline void uhci_ll_attach_uart_port(uhci_dev_t *hw, int uart_num)
65+
{
66+
hw->conf0.uart_sel = uart_num;
67+
}
68+
69+
static inline void uhci_ll_set_seper_chr(uhci_dev_t *hw, uhci_seper_chr_t *seper_char)
70+
{
71+
if (seper_char->sub_chr_en) {
72+
hw->conf0.seper_en = 1;
73+
typeof(hw->esc_conf0) esc_conf0_reg;
74+
esc_conf0_reg.val = hw->esc_conf0.val;
75+
76+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf0_reg, seper_char, seper_char->seper_chr);
77+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf0_reg, seper_esc_char0, seper_char->sub_chr1);
78+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf0_reg, seper_esc_char1, seper_char->sub_chr2);
79+
hw->esc_conf0.val = esc_conf0_reg.val;
80+
hw->escape_conf.tx_c0_esc_en = 1;
81+
hw->escape_conf.rx_c0_esc_en = 1;
82+
} else {
83+
hw->conf0.seper_en = 0;
84+
hw->escape_conf.val = 0;
85+
}
86+
}
87+
88+
static inline void uhci_ll_set_swflow_ctrl_sub_chr(uhci_dev_t *hw, uhci_swflow_ctrl_sub_chr_t *sub_ctr)
89+
{
90+
typeof(hw->escape_conf) escape_conf_reg;
91+
escape_conf_reg.val = hw->escape_conf.val;
92+
93+
if (sub_ctr->flow_en == 1) {
94+
typeof(hw->esc_conf2) esc_conf2_reg;
95+
esc_conf2_reg.val = hw->esc_conf2.val;
96+
typeof(hw->esc_conf3) esc_conf3_reg;
97+
esc_conf3_reg.val = hw->esc_conf3.val;
98+
99+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf2_reg, esc_seq1, sub_ctr->xon_chr);
100+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf2_reg, esc_seq1_char0, sub_ctr->xon_sub1);
101+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf2_reg, esc_seq1_char1, sub_ctr->xon_sub2);
102+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf3_reg, esc_seq2, sub_ctr->xoff_chr);
103+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf3_reg, esc_seq2_char0, sub_ctr->xoff_sub1);
104+
HAL_FORCE_MODIFY_U32_REG_FIELD(esc_conf3_reg, esc_seq2_char1, sub_ctr->xoff_sub2);
105+
escape_conf_reg.tx_11_esc_en = 1;
106+
escape_conf_reg.tx_13_esc_en = 1;
107+
escape_conf_reg.rx_11_esc_en = 1;
108+
escape_conf_reg.rx_13_esc_en = 1;
109+
hw->esc_conf2.val = esc_conf2_reg.val;
110+
hw->esc_conf3.val = esc_conf3_reg.val;
111+
} else {
112+
escape_conf_reg.tx_11_esc_en = 0;
113+
escape_conf_reg.tx_13_esc_en = 0;
114+
escape_conf_reg.rx_11_esc_en = 0;
115+
escape_conf_reg.rx_13_esc_en = 0;
116+
}
117+
hw->escape_conf.val = escape_conf_reg.val;
118+
}
119+
120+
static inline void uhci_ll_enable_intr(uhci_dev_t *hw, uint32_t intr_mask)
121+
{
122+
hw->int_ena.val |= intr_mask;
123+
}
124+
125+
static inline void uhci_ll_disable_intr(uhci_dev_t *hw, uint32_t intr_mask)
126+
{
127+
hw->int_ena.val &= (~intr_mask);
128+
}
129+
130+
static inline void uhci_ll_clear_intr(uhci_dev_t *hw, uint32_t intr_mask)
131+
{
132+
hw->int_clr.val = intr_mask;
133+
}
134+
135+
static inline uint32_t uhci_ll_get_intr(uhci_dev_t *hw)
136+
{
137+
return hw->int_st.val;
138+
}
139+
140+
static inline void uhci_ll_rx_set_eof_mode(uhci_dev_t *hw, uint32_t eof_mode)
141+
{
142+
if (eof_mode & UHCI_RX_BREAK_CHR_EOF) {
143+
hw->conf0.uart_rx_brk_eof_en = 1;
144+
}
145+
if (eof_mode & UHCI_RX_IDLE_EOF) {
146+
hw->conf0.uart_idle_eof_en = 1;
147+
}
148+
if (eof_mode & UHCI_RX_LEN_EOF) {
149+
hw->conf0.len_eof_en = 1;
150+
}
151+
}
152+
153+
static inline void uhci_ll_rx_set_packet_threshold(uhci_dev_t *hw, uint16_t length)
154+
{
155+
hw->pkt_thres.pkt_thrs = length;
156+
}
157+
158+
#ifdef __cplusplus
159+
}
160+
#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

0 commit comments

Comments
 (0)