Skip to content

Commit cd5b387

Browse files
peter-marcisovskyespressif-bot
authored andcommitted
feat(usb_host): Move DMA capable memory to external ram on P4
- DWC-OTG internal DMA can access psram on esp32p4 - Move DMA memory buffs to psram, to save internal ram - HCD tests and MSC example runs in CI with psram enabled
1 parent 38e84d5 commit cd5b387

File tree

13 files changed

+97
-21
lines changed

13 files changed

+97
-21
lines changed

components/usb/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ set(priv_includes)
1212
# Thus, always add the (private) requirements, regardless of Kconfig
1313
set(priv_requires esp_driver_gpio esp_mm) # usb_phy driver relies on gpio driver API
1414

15+
# Explicitly add psram component for esp32p4, as the USB-DWC internal DMA can access PSRAM on esp32p4
16+
if(${target} STREQUAL "esp32p4")
17+
list(APPEND priv_requires esp_psram)
18+
endif()
19+
1520
if(CONFIG_SOC_USB_OTG_SUPPORTED)
1621
list(APPEND srcs "hcd_dwc.c"
1722
"enum.c"

components/usb/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,16 @@ menu "USB-OTG"
175175
If enabled, the enumeration filter callback can be set via 'usb_host_config_t' when calling
176176
'usb_host_install()'.
177177

178+
config USB_HOST_DWC_DMA_CAP_MEMORY_IN_PSRAM
179+
depends on IDF_TARGET_ESP32P4 && SPIRAM
180+
bool "Allocate USB_DWC DMA capable memory in PSRAM"
181+
default n
182+
help
183+
In the ESP32P4, the USB-DWC internal DMA can access external RAM. Enabling this configuration can save
184+
internal RAM by allocating the memory buffers used by the USB-DWC peripheral's DMA to external RAM.
185+
However, it introduces minor performance degradation due to the overhead of accessing external RAM.
186+
# Todo: IDF-11368 (aligned memory alloc size)
187+
178188
# Hidden or compatibility options
179189
config USB_OTG_SUPPORTED
180190
# Invisible config kept for compatibility

components/usb/hcd_dwc.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <stdint.h>
88
#include <string.h>
99
#include <sys/queue.h>
10+
#include "sdkconfig.h"
1011
#include "freertos/FreeRTOS.h"
1112
#include "freertos/task.h"
1213
#include "freertos/semphr.h"
@@ -32,8 +33,6 @@
3233

3334
// --------------------- Constants -------------------------
3435

35-
#define XFER_DESC_LIST_CAPS (MALLOC_CAP_DMA | MALLOC_CAP_CACHE_ALIGNED | MALLOC_CAP_INTERNAL)
36-
3736
#define INIT_DELAY_MS 30 // A delay of at least 25ms to enter Host mode. Make it 30ms to be safe
3837
#define DEBOUNCE_DELAY_MS CONFIG_USB_HOST_DEBOUNCE_DELAY_MS
3938
#define RESET_HOLD_MS CONFIG_USB_HOST_RESET_HOLD_MS
@@ -48,6 +47,12 @@
4847

4948
// ----------------------- Configs -------------------------
5049

50+
#ifdef CONFIG_USB_HOST_DWC_DMA_CAP_MEMORY_IN_PSRAM // In esp32p4, the USB-DWC internal DMA can access external RAM
51+
#define XFER_DESC_LIST_CAPS (MALLOC_CAP_DMA | MALLOC_CAP_CACHE_ALIGNED | MALLOC_CAP_SPIRAM)
52+
#else
53+
#define XFER_DESC_LIST_CAPS (MALLOC_CAP_DMA | MALLOC_CAP_CACHE_ALIGNED | MALLOC_CAP_INTERNAL)
54+
#endif
55+
5156
#define FRAME_LIST_LEN USB_HAL_FRAME_LIST_LEN_32
5257
#define NUM_BUFFERS 2
5358

@@ -1514,15 +1519,16 @@ static dma_buffer_block_t *buffer_block_alloc(usb_transfer_type_t type)
15141519
break;
15151520
}
15161521

1517-
// DMA buffer lock: Software structure for managing the transfer buffer
1522+
// DMA buffer block: Software structure for managing the transfer buffer
15181523
dma_buffer_block_t *buffer = calloc(1, sizeof(dma_buffer_block_t));
15191524
if (buffer == NULL) {
15201525
return NULL;
15211526
}
15221527

15231528
// Transfer descriptor list: Must be 512 aligned and DMA capable (USB-DWC requirement) and its size must be cache aligned
15241529
void *xfer_desc_list = heap_caps_aligned_calloc(USB_DWC_QTD_LIST_MEM_ALIGN, desc_list_len * sizeof(usb_dwc_ll_dma_qtd_t), 1, XFER_DESC_LIST_CAPS);
1525-
if (xfer_desc_list == NULL) {
1530+
1531+
if ((xfer_desc_list == NULL) || ((uintptr_t)xfer_desc_list & (USB_DWC_QTD_LIST_MEM_ALIGN - 1))) {
15261532
free(buffer);
15271533
heap_caps_free(xfer_desc_list);
15281534
return NULL;

components/usb/test_apps/common/hcd_common.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
#include "unity.h"
2424
#include "sdkconfig.h"
2525

26+
// ----------------------------------------------------- Macros --------------------------------------------------------
27+
28+
// --------------------- Constants -------------------------
29+
2630
#define PORT_NUM 1
2731
#define EVENT_QUEUE_LEN 5
2832
#define ENUM_ADDR 1 // Device address to use for tests that enumerate the device
@@ -261,9 +265,15 @@ void test_hcd_pipe_free(hcd_pipe_handle_t pipe_hdl)
261265
}
262266

263267
#include "esp_private/esp_cache_private.h"
264-
#define DATA_BUFFER_CAPS (MALLOC_CAP_DMA | MALLOC_CAP_CACHE_ALIGNED)
268+
265269
#define ALIGN_UP(num, align) ((align) == 0 ? (num) : (((num) + ((align) - 1)) & ~((align) - 1)))
266270

271+
#ifdef CONFIG_USB_HOST_DWC_DMA_CAP_MEMORY_IN_PSRAM // In esp32p4, the USB-DWC internal DMA can access external RAM
272+
#define DATA_BUFFER_CAPS (MALLOC_CAP_DMA | MALLOC_CAP_CACHE_ALIGNED | MALLOC_CAP_SPIRAM)
273+
#else
274+
#define DATA_BUFFER_CAPS (MALLOC_CAP_DMA | MALLOC_CAP_CACHE_ALIGNED | MALLOC_CAP_INTERNAL)
275+
#endif
276+
267277
urb_t *test_hcd_alloc_urb(int num_isoc_packets, size_t data_buffer_size)
268278
{
269279
// Allocate a URB and data buffer

components/usb/test_apps/hcd/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33

44
# USB: Host test application
55

6-
There are two sets of tests in this application:
6+
There are three sets of tests in this application:
77
1. Low-speed: Expects low-speed USB mouse with interrupt endpoint to be connected
88
2. Full-speed: Expects full-speed USB flash disk with 2 bulk endpoints to be connected
9+
3. High-speed: Expects high-speed USB flash disk with 2 bulk endpoints to be connected
910

10-
For running these tests locally, you will have to update device definitions (VID, PID, ...) in [test_usb_mock_classes.h](../common/test_usb_mock_classes.h).
11+
For running these tests locally, you will have to update device definitions (VID, PID, ...) in [dev_msc.c](../common/dev_msc.c), [dev_hid.c](../common/dev_hid.c) and [dev_isoc.c](../common/dev_isoc.c).

components/usb/test_apps/hcd/pytest_usb_hcd.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@
77

88
@pytest.mark.temp_skip_ci(targets=['esp32s2'], reason='lack of runners with usb_host_flash_disk tag')
99
@pytest.mark.usb_host_flash_disk
10-
@idf_parametrize('target', ['esp32s2', 'esp32s3', 'esp32p4'], indirect=['target'])
10+
@idf_parametrize(
11+
'config,target',
12+
[('default', 'esp32s2'), ('default', 'esp32s3'), ('default', 'esp32p4'), ('esp32p4_psram', 'esp32p4')],
13+
indirect=['config', 'target'],
14+
)
1115
def test_usb_hcd(dut: Dut) -> None:
12-
if dut.target == 'esp32s3':
13-
dut.run_all_single_board_cases(group='full_speed', reset=True)
14-
else:
16+
if dut.target == 'esp32p4':
1517
dut.run_all_single_board_cases(group='high_speed', reset=True)
18+
else:
19+
dut.run_all_single_board_cases(group='full_speed', reset=True)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CONFIG_IDF_TARGET="esp32p4"
2+
3+
# Enable experimental features, to set PSRAM frequency to 200 MHz
4+
CONFIG_IDF_EXPERIMENTAL_FEATURES=y
5+
6+
# Enable PSRAM and set PSRAM frequency
7+
CONFIG_SPIRAM=y
8+
CONFIG_SPIRAM_SPEED_200M=y
9+
# CONFIG_SPIRAM_MEMTEST is not set
10+
11+
# Allocate USB_DWC DMA capable memory in PSRAM
12+
CONFIG_USB_HOST_DWC_DMA_CAP_MEMORY_IN_PSRAM=y

components/usb/test_apps/usb_host/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33

44
# USB: Host test application
55

6-
There are two sets of tests in this application:
6+
There are three sets of tests in this application:
77
1. Low-speed: Expects low-speed USB mouse with interrupt endpoint to be connected
88
2. Full-speed: Expects full-speed USB flash disk with 2 bulk endpoints to be connected
9+
3. High-speed: Expects high-speed USB flash disk with 2 bulk endpoints to be connected
910

10-
For running these tests locally, you will have to update device definitions (VID, PID, ...) in [mock_msc.h](../common/mock_msc.h) and [mock_hid.h](../common/mock_hid.h).
11+
For running these tests locally, you will have to update device definitions (VID, PID, ...) in [dev_msc.c](../common/dev_msc.c) and [dev_hid.c](../common/dev_hid.c).
1112

components/usb/test_apps/usb_host/pytest_usb_host.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
@pytest.mark.usb_host_flash_disk
1010
@idf_parametrize('target', ['esp32s2', 'esp32s3', 'esp32p4'], indirect=['target'])
1111
def test_usb_host(dut: Dut) -> None:
12-
if dut.target == 'esp32s3':
13-
dut.run_all_single_board_cases(group='full_speed', reset=True)
14-
else:
12+
if dut.target == 'esp32p4':
1513
dut.run_all_single_board_cases(group='high_speed', reset=True)
14+
else:
15+
dut.run_all_single_board_cases(group='full_speed', reset=True)

components/usb/usb_private.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,20 @@
99
#include "usb_private.h"
1010
#include "usb/usb_types_ch9.h"
1111

12+
// ----------------------------------------------------- Macros --------------------------------------------------------
13+
1214
#if !CONFIG_IDF_TARGET_LINUX
1315
#include "esp_private/esp_cache_private.h"
1416
#define ALIGN_UP(num, align) ((align) == 0 ? (num) : (((num) + ((align) - 1)) & ~((align) - 1)))
1517
#endif
16-
#define DATA_BUFFER_CAPS (MALLOC_CAP_DMA | MALLOC_CAP_CACHE_ALIGNED)
18+
19+
// ----------------------- Configs -------------------------
20+
21+
#ifdef CONFIG_USB_HOST_DWC_DMA_CAP_MEMORY_IN_PSRAM // In esp32p4, the USB-DWC internal DMA can access external RAM
22+
#define DATA_BUFFER_CAPS (MALLOC_CAP_DMA | MALLOC_CAP_CACHE_ALIGNED | MALLOC_CAP_SPIRAM)
23+
#else
24+
#define DATA_BUFFER_CAPS (MALLOC_CAP_DMA | MALLOC_CAP_CACHE_ALIGNED | MALLOC_CAP_INTERNAL)
25+
#endif
1726

1827
urb_t *urb_alloc(size_t data_buffer_size, int num_isoc_packets)
1928
{

0 commit comments

Comments
 (0)