ESP32-S3 - Can't send SPI transaction of more than one DMA max payload size?
Posted: Wed Jan 03, 2024 1:47 pm
I want to be able to send an SPI 8-bit transaction of about 32kBytes (so 4000 bits in parallel), but the ESP32-S3 doesn't ever send more than one DMA linked list's worth of data?
If I create an spi_transaction_t of 32k, I only ever get about one DMA max payload lengths worth of data?
Is there some bug in the IDF?
If I create an spi_transaction_t of 32k, I only ever get about one DMA max payload lengths worth of data?
Is there some bug in the IDF?
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <inttypes.h>
- #include "freertos/FreeRTOS.h"
- #include "freertos/task.h"
- #include "esp_system.h"
- #include "driver/spi_master.h"
- #include "driver/gpio.h"
- #include "hal/gpio_types.h"
- #include "soc/spi_reg.h"
- #include "soc/spi_struct.h"
- // SPI2 on ESP32-S3 supports 8-bit Octal SPI mode
- #define LCD_HOST SPI2_HOST
- void spi_post_transfer_callback(spi_transaction_t *t)
- {
- }
- static void send_lines(spi_device_handle_t spi, int ypos, uint8_t *linedata)
- {
- esp_err_t ret;
- int x;
- //Transaction descriptors. Declared static so they're not allocated on the stack; we need this memory even when this
- //function is finished because the SPI driver needs access to it even while we're already calculating the next line.
- static spi_transaction_t trans_msg;
- trans_msg.flags = SPI_TRANS_MODE_OCT;
- trans_msg.tx_buffer = linedata; //finally send the line data
- trans_msg.length = 31000; //Data length, in bits
- // ret = spi_device_queue_trans(spi, &trans_msg, portMAX_DELAY);
- // assert(ret == ESP_OK);
- ret = spi_device_polling_transmit(spi, &trans_msg); // Transmit!
- assert(ret == ESP_OK); // Should have had no issues.
- }
- void setup() {
- // put your setup code here, to run once:
- esp_err_t ret;
- spi_device_handle_t spi;
- spi_bus_config_t buscfg = {
- .data0_io_num = 5, // A
- .data1_io_num = 4, // B
- .sclk_io_num = 42, // C
- .data2_io_num = 7, // D
- .data3_io_num = 41, // E
- .data4_io_num = 1, // oe
- .data5_io_num = 6, // lat
- .data6_io_num = 2, // clk
- .data7_io_num = 48, // sr
- .max_transfer_sz = 32768, // ESP32 S3 max size is 64Kbytes
- .flags = (SPICOMMON_BUSFLAG_OCTAL | SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_GPIO_PINS), // kinda important
- };
- //Configure SPI Device
- spi_device_interface_config_t devcfg = {
- .command_bits = 0,
- .address_bits = 0,
- .dummy_bits = 0,
- .mode = 0, // SPI mode 0
- .duty_cycle_pos = 0,
- .cs_ena_pretrans = 0,
- .cs_ena_posttrans = 0,
- .clock_speed_hz = SPI_MASTER_FREQ_8M, // Clock out at 10 MHz
- .input_delay_ns = 0,
- .spics_io_num = -1, // CS pin
- // SPI_DEVICE_NO_RETURN_RESULT = Don't care abut result
- //.flags = (SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_NO_RETURN_RESULT),
- .flags = (SPI_DEVICE_HALFDUPLEX ),
- .queue_size = 10,
- .pre_cb = 0, // Not used
- .post_cb = spi_post_transfer_callback,
- };
- //Initialize the SPI bus
- ret = spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO);
- ESP_ERROR_CHECK(ret);
- //Attach the LCD to the SPI bus
- ret = spi_bus_add_device(LCD_HOST, &devcfg, &spi);
- ESP_ERROR_CHECK(ret);
- size_t max_trans_bytes = 0;
- ret = spi_bus_get_max_transaction_len(LCD_HOST, &max_trans_bytes);
- assert(ret == ESP_OK);
- ESP_LOGI("S3", "Max transfer size is %u", (uint32_t)max_trans_bytes);
- uint8_t *output_data;
- output_data = (uint8_t *) heap_caps_malloc(31000 * sizeof(uint8_t), MALLOC_CAP_DMA);
- assert(output_data != NULL);
- // Doesn't send data after about the 4096 boundary?
- int offset = 4096;
- memset(output_data, (uint8_t)0x00, 31000);
- memset(output_data+offset, (uint8_t)0xff, 31000-offset); // overwrite from offset with 0xff
- while (1)
- {
- send_lines(spi, 0, output_data);
- }
- } // setup
- void loop() {
- // put your main code here, to run repeatedly:
- }