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?
Code: Untitled.c Select all
#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:
}