1. Transfer data from ESP32 (master) to ESP32-S3 (slave) over SPI using IRAM buffers
2. Transfer data from ESP32-S3 (slave) IRAM to PSRAM using DMA
Step 1 works fine. But step 2 doesn't - keeps rebooting because it says that memory isn't DMA aligned.
Here's my code and log. Appreciate if you could point out any issues you might notice:
Code:
Code: Select all
static IRAM_ATTR bool dmacpy_cb(async_memcpy_handle_t hdl, async_memcpy_event_t *event, void *args) {
SemaphoreHandle_t sem = (SemaphoreHandle_t)args;
BaseType_t task_wakeup = pdFALSE;
xSemaphoreGiveFromISR(sem, &task_wakeup);
return (task_wakeup==pdTRUE);
}
void spi_receive_start(void)
{
int n=0;
esp_err_t ret;
//Configuration for the SPI bus
spi_bus_config_t buscfg={
.mosi_io_num=GPIO_MOSI,
.miso_io_num=GPIO_MISO,
.sclk_io_num=GPIO_SCLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
};
//Configuration for the SPI slave interface
spi_slave_interface_config_t slvcfg={
.mode=0,
.spics_io_num=GPIO_CS,
.queue_size=3,
.flags=0,
.post_setup_cb=my_post_setup_cb,
.post_trans_cb=my_post_trans_cb
};
//Configuration for the handshake line
gpio_config_t io_conf={
//.intr_type=GPIO_INTR_DISABLE,
.intr_type=GPIO_INTR_POSEDGE,
.mode=GPIO_MODE_OUTPUT,
.pin_bit_mask=(1<<GPIO_HANDSHAKE)
};
//Configure handshake line as output
gpio_config(&io_conf);
//Enable pull-ups on SPI lines so we don't detect rogue pulses when no master is connected.
gpio_set_pull_mode(GPIO_MOSI, GPIO_PULLUP_ONLY);
gpio_set_pull_mode(GPIO_SCLK, GPIO_PULLUP_ONLY);
gpio_set_pull_mode(GPIO_CS, GPIO_PULLUP_ONLY);
//Initialize SPI slave interface
ret=spi_slave_initialize(RCV_HOST, &buscfg, &slvcfg, SPI_DMA_CH_AUTO);
assert(ret==ESP_OK);
WORD_ALIGNED_ATTR char sendbuf[128]={0}; //IRAM buffer for spi transaction tx_buffer
WORD_ALIGNED_ATTR char recvbuf[128]={0}; //IRAM buffer for spi transaction rx_buffer
//Define external memory to store data received by spi_slave_transaction_t.rx_buffer
WORD_ALIGNED_ATTR static uint32_t *psram_mem;
const uint32_t PSRAM_ALIGN = cache_hal_get_cache_line_size(CACHE_TYPE_DATA); //why this vs hard coding to 16, 32 or 64
const uint32_t INTRAM_ALIGN = PSRAM_ALIGN;
const uint32t length = 2048000;
psram_mem = heap_caps_aligned_alloc(PSRAM_ALIGN, length, MALLOC_CAP_SPIRAM);
assert(psram_mem != NULL);
//Define async_memcpy_config
const async_memcpy_config_t cfg = {
.backlog = (length+4091)/4092, //don't understand the rationale behind this formula
.sram_trans_align = INTRAM_ALIGN,
.psram_trans_align = PSRAM_ALIGN,
.flags = 0
};
//Install GDMA controller
async_memcpy_handle_t async_memcpy_handle = NULL;
ESP_ERROR_CHECK(esp_async_memcpy_install_gdma_ahb(&cfg, &async_memcpy_handle));
//Prepare for SPI transfer between master and slave
spi_slave_transaction_t t;
t.length=128*8;
memset(&t, 0, sizeof(t));
SemaphoreHandle_t semphr = xSemaphoreCreateBinary();
while(n<=10) {
memset(recvbuf, 0, sizeof(recvbuf));
sprintf(sendbuf, "Transaction %04d received", n);
t.tx_buffer=sendbuf;
t.rx_buffer=recvbuf;
ret=spi_slave_transmit(RCV_HOST, &t, portMAX_DELAY);
//Save content received by t.rx_buffer into psram_mem
ESP_LOGI(TAG, "Starting DMA copy.");
ESP_ERROR_CHECK(esp_async_memcpy(async_memcpy_handle, psram_mem, t.rx_buffer, sizeof(t.rx_buffer), &dmacpy_cb, semphr));
xSemaphoreTake(semphr, portMAX_DELAY);
n++;
}
esp_async_memcpy_uninstall(async_memcpy_handle);
}
Code: Select all
# ESP PSRAM
#
CONFIG_SPIRAM=y
#
# SPI RAM config
#
# CONFIG_SPIRAM_MODE_QUAD is not set
CONFIG_SPIRAM_MODE_OCT=y
CONFIG_SPIRAM_TYPE_AUTO=y
# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set
CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y
CONFIG_SPIRAM_CLK_IO=30
CONFIG_SPIRAM_CS_IO=26
CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y
CONFIG_SPIRAM_RODATA=y
CONFIG_SPIRAM_SPEED_80M=y
# CONFIG_SPIRAM_SPEED_40M is not set
CONFIG_SPIRAM_SPEED=80
# CONFIG_SPIRAM_ECC_ENABLE is not set
CONFIG_SPIRAM_BOOT_INIT=y
# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set
# CONFIG_SPIRAM_USE_MEMMAP is not set
CONFIG_SPIRAM_USE_CAPS_ALLOC=y
# CONFIG_SPIRAM_USE_MALLOC is not set
CONFIG_SPIRAM_MEMTEST=y
# CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP is not set
# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set
# end of SPI RAM config
# end of ESP PSRAM
Code: Select all
Leaving...
Hard resetting via RTS pin...
Executing action: monitor
Running idf_monitor in directory 'C:\Users\Alpha\ESP-IDF Peripherals - SPI slave example\receiver'
Executing "c:\Users\Alpha\ESP\.espressif\python_env\idf5.2_py3.11_env\Scripts\python.exe C:\Users\Alpha\esp\esp-idf\tools/idf_monitor.py -p COM6 -b 115200 --toolchain-prefix xtensa-esp32s3-elf- --target esp32s3 --revision 0 'C:\Users\Alpha\ESP-IDF Peripherals - SPI slave example\receiver\build\spi_slave_receiver.elf' --force-color -m 'c:\Users\Alpha\ESP\.espressif\python_env\idf5.2_py3.11_env\Scripts\python.exe' 'C:\Users\Alpha\esp\esp-idf\tools\idf.py'"...
--- WARNING: GDB cannot open serial ports accessed as COMx
--- Using \\.\COM6 instead...
--- esp-idf-monitor 1.2.1 on \\.\COM6 115200 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
I (100) boot: 2 factory factory app 00 00 ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x15 (USB_UART_CHIP_RESET),boot:0xa (SPI_FAST_FLASH_BOOT)
Saved PC:0x42007c3c
0x42007c3c: s_test_psram at C:/Users/Alpha/ESP/esp-idf/components/esp_psram/esp_psram.c:418
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3810,len:0x171c
load:0x403c9700,len:0x4
load:0x403c9704,len:0xc20
load:0x403cc700,len:0x2f94
SHA-256 comparison failed:
Calculated: 69b7a3013875b94363c030717518c738ac90a249877a1ef67f5047554d9c611a
Expected: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
Attempting to boot anyway...
entry 0x403c9910
I (45) boot: ESP-IDF v5.2-dev-2756-g2bc1f2f574-dirty 2nd stage bootloader
I (45) boot: compile time Nov 8 2024 14:43:18
I (46) boot: Multicore bootloader
I (50) boot: chip revision: v0.2
I (54) boot.esp32s3: Boot SPI Speed : 80MHz
I (59) boot.esp32s3: SPI Mode : DIO
I (64) boot.esp32s3: SPI Flash Size : 16MB
I (69) boot: Enabling RNG early entropy source...
I (74) boot: Partition Table:
I (78) boot: ## Label Usage Type ST Offset Length
I (85) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (92) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (100) boot: 2 factory factory app 00 00 00010000 00300000
I (107) boot: End of partition table
I (112) esp_image: segment 0: paddr=00010020 vaddr=3c020020 size=0c8bch ( 51388) map
I (126) esp_image: segment 1: paddr=0001c8e4 vaddr=3fc92e00 size=02dd8h ( 11736) load
I (130) esp_image: segment 2: paddr=0001f6c4 vaddr=40374000 size=00954h ( 2388) load
I (137) esp_image: segment 3: paddr=00020020 vaddr=42000020 size=1f274h (127604) map
I (160) esp_image: segment 4: paddr=0003f29c vaddr=40374954 size=0e3a4h ( 58276) load
I (175) boot: Loaded app from partition at offset 0x10000
I (176) boot: Disabling RNG early entropy source...
I (187) cpu_start: Multicore app
I (187) octal_psram: vendor id : 0x0d (AP)
I (187) octal_psram: dev id : 0x02 (generation 3)
I (190) octal_psram: density : 0x03 (64 Mbit)
I (196) octal_psram: good-die : 0x01 (Pass)
I (201) octal_psram: Latency : 0x01 (Fixed)
I (206) octal_psram: VCC : 0x01 (3V)
I (211) octal_psram: SRF : 0x01 (Fast Refresh)
I (217) octal_psram: BurstType : 0x01 (Hybrid Wrap)
I (223) octal_psram: BurstLen : 0x01 (32 Byte)
I (229) octal_psram: Readlatency : 0x02 (10 cycles@Fixed)
I (235) octal_psram: DriveStrength: 0x00 (1/1)
I (241) MSPI Timing: PSRAM timing tuning index: 4
I (245) esp_psram: Found 8MB PSRAM device
I (250) esp_psram: Speed: 80MHz
I (266) mmu_psram: Instructions copied and mapped to SPIRAM
I (272) mmu_psram: Read only data copied and mapped to SPIRAM
I (272) cpu_start: Pro cpu up.
I (272) cpu_start: Starting app cpu, entry point is 0x403753cc
0x403753cc: call_start_cpu1 at C:/Users/karun/ESP/esp-idf/components/esp_system/port/cpu_start.c:178
I (0) cpu_start: App cpu up.
I (553) esp_psram: SPI SRAM memory test OK
I (561) cpu_start: Pro cpu start user code
I (561) cpu_start: cpu freq: 240000000 Hz
I (562) cpu_start: Application information:
I (565) cpu_start: Project name: spi_slave_receiver
I (570) cpu_start: App version: 1af3222-dirty
I (576) cpu_start: Compile time: Dec 6 2024 12:04:08
I (582) cpu_start: ELF file SHA256: 6c52c8732...
I (587) cpu_start: ESP-IDF: v5.2-dev-2756-g2bc1f2f574-dirty
I (594) cpu_start: Min chip rev: v0.0
I (599) cpu_start: Max chip rev: v0.99
I (604) cpu_start: Chip rev: v0.2
I (609) heap_init: Initializing. RAM available for dynamic allocation:
I (616) heap_init: At 3FC964F8 len 00053218 (332 KiB): DRAM
I (622) heap_init: At 3FCE9710 len 00005724 (21 KiB): STACK/DRAM
I (629) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (635) heap_init: At 600FE010 len 00001FD8 (7 KiB): RTCRAM
I (641) esp_psram: Adding pool of 8000K of PSRAM memory to heap allocator
I (649) spi_flash: detected chip: gd
I (653) spi_flash: flash io: dio
I (657) sleep: Configure to isolate all GPIO pins in sleep state
I (664) sleep: Enable automatic switching of GPIO sleep configuration
I (671) app_start: Starting scheduler on CPU0
I (676) app_start: Starting scheduler on CPU1
I (676) main_task: Started on CPU0
I (686) main_task: Calling app_main()
I (690) gpio: GPIO[17]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:1
I (12548) peripheral_rx_Alpha: Starting DMA copy.
[b]E (12561) async_mcp.gdma: mcp_gdma_memcpy(363): buffer not aligned: 0x3fc99f40 -> 0x3c030a40, sz=4[/b]
ESP_ERROR_CHECK failed: esp_err_t 0x102 (ESP_ERR_INVALID_ARG) at 0x42008202
0x42008202: spi_receive_start at C:/Users/Alpha/ESP-IDF Peripherals - SPI slave example/receiver/main/app_main_receiver_Alpha.c:225 (discriminator 1)
file: "./main/app_main_receiver_Alpha.c" line 225
func: spi_receive_start
expression: esp_async_memcpy(async_memcpy_handle, new_mem, t.rx_buffer, sizeof(t.rx_buffer), &dmacpy_cb, semphr)
abort() was called at PC 0x4037ace7 on core 0
Backtrace: 0x40375ba6:0x3fc99e60 0x4037acf1:0x3fc99e80 0x40380a56:0x3fc99ea0 0x4037ace7:0x3fc99f10 0x42008202:0x3fc99f40 0x42007fa7:0x3fc9a0f0 0x4201e64f:0x3fc9a110
0x4037ace7: _esp_error_check_failed at C:/Users/Alpha/ESP/esp-idf/components/esp_system/esp_err.c:50
0x40375ba6: panic_abort at C:/Users/Alpha/ESP/esp-idf/components/esp_system/panic.c:452
0x4037acf1: esp_system_abort at C:/Users/Alpha/ESP/esp-idf/components/esp_system/port/esp_system_chip.c:93
0x40380a56: abort at C:/Users/Alpha/ESP/esp-idf/components/newlib/abort.c:38
0x4037ace7: _esp_error_check_failed at C:/Users/Alpha/ESP/esp-idf/components/esp_system/esp_err.c:50
0x42008202: spi_receive_start at C:/Users/Alpha/ESP-IDF Peripherals - SPI slave example/receiver/main/app_main_receiver_Alpha.c:225 (discriminator 1)
0x42007fa7: app_main at C:/Users/Alpha/ESP-IDF Peripherals - SPI slave example/receiver/main/main.c:4
0x4201e64f: main_task at C:/Users/Alpha/ESP/esp-idf/components/freertos/app_startup.c:208 (discriminator 13)