I have a small program to repeatedly send a buffer followed by receive a buffer via SPI2 with DMA enabled. If I disable the receiving part of the TRX function (by setting condition to "false" in second "if" statement), everything is fine, but otherwise only first time after boot-up the buffer will be sent correctly, all subsequent transmission will lead to transmit the first byte from the buffer so many times, that that long the buffer-to-send is:
Good transmission: Bad transmission: Basically it looks like the DMA engine "forgets" to increment the source address during sending the data out.
Code:
Code: Select all
static const spi_host_device_t SpiHost = SPI2_HOST; // SPI Host to use for communication to XXX chip
static const gpio_num_t XxxIrqPin = 5; // Irq pin
static const gpio_num_t XxxnCsPin = 4; // Chip select pin
static const size_t MaxTxBytesSpiTRxLen = 512; // Max SPI frame length
static const spi_bus_config_t SpiBusConfig = {
.mosi_io_num = 7,
.miso_io_num = 2,
.sclk_io_num = 6,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = MaxTxBytesSpiTRxLen,
.flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MISO |
SPICOMMON_BUSFLAG_MOSI,
.intr_flags = 0,
};
static const spi_device_interface_config_t spiConfig = {
.mode = 0,
.clock_speed_hz = SPI_MASTER_FREQ_8M,
.spics_io_num = -1,
.queue_size = 5,
.post_cb = NULL,
};
static const gpio_config_t IrqPinConfig = {
.pin_bit_mask = 1 << XxxIrqPin,
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_POSEDGE,
};
static const gpio_config_t IrqnCsConfig = {
.pin_bit_mask = 1 << XxxnCsPin,
.mode = GPIO_MODE_INPUT_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
struct hal{
uint8_t *spiBuf;
spi_device_handle_t spiDev;
} platform;
status_t TRx(struct hal *plat, uint8_t *txBuf[], size_t txLen[], size_t numTxBuffers,
uint8_t *rxBuf[], size_t *rxLen[], size_t numRxBuffers)
{
UNUSED(plat);
ESP_ERROR_CHECK(gpio_set_level(XxxnCsPin, 0)); // assert chip select
esp_task_wdt_reset();
size_t bufIdx = 0;
if (numTxBuffers && txBuf && txLen)
{
while (bufIdx < numTxBuffers)
{
spi_transaction_t txT;
const uint8_t *buf = txBuf[bufIdx];
assert(buf);
const size_t bufLen = txLen[bufIdx];
assert(bufLen < MaxTxBytesSpiTRxLen);
memset(&txT, 0, sizeof(txT));
txT.tx_buffer = buf;
txT.length = bufLen * 8;
// copy tx data to DMA capable memory
ESP_LOGD(__func__, "(%u) <<", bufLen);
dumpMemory("X", buf, bufLen);
ESP_ERROR_CHECK(spi_device_transmit(platform.spiDev, &txT));
bufIdx++;
}
}
irqState = false;
// Now receiving some data
if (true && numRxBuffers && rxBuf && rxLen)
{
bufIdx = 0;
while (bufIdx < numRxBuffers)
{
spi_transaction_t rxT;
uint8_t *buf = rxBuf[bufIdx];
assert(buf);
const size_t bufLen = *rxLen[bufIdx];
assert(bufLen < MaxTxBytesSpiTRxLen);
memset(platform.spiBuf, 0, bufLen);
memset(&rxT, 0, sizeof(rxT));
rxT.rx_buffer = platform.spiBuf;
rxT.length = bufLen * 8;
rxT.rxlength = 0;
ESP_ERROR_CHECK(spi_device_transmit(platform.spiDev, &rxT));
ESP_LOGD(__func__, "(%u) >>", bufLen);
dumpMemory(__func__, platform.spiBuf, bufLen);
// memcpy(buf, platform.spiBuf, bufLen);
bufIdx++;
}
}
ESP_ERROR_CHECK(gpio_set_level(XxxnCsPin, 1)); // de-assert chip select
return 0;
}
status_t Init()
{
memset(&platform, 0, sizeof(platform));
// XXX Irq pin
ESP_ERROR_CHECK(gpio_config(&IrqnCsConfig));
ESP_ERROR_CHECK(gpio_set_level(XxxnCsPin, 1));
ESP_ERROR_CHECK(gpio_config(&IrqPinConfig));
ESP_ERROR_CHECK(gpio_isr_handler_add(XxxIrqPin, &irqIsr, &platform));
// allocate DMA capable memory
platform.spiBuf = heap_caps_malloc(MaxTxBytesSpiTRxLen, MALLOC_CAP_DMA | MALLOC_CAP_32BIT);
assert(platform.spiBuf);
// init SPI driver
ESP_ERROR_CHECK(spi_bus_initialize(SpiHost, &SpiBusConfig, SPI_DMA_CH_AUTO));
ESP_ERROR_CHECK(spi_bus_add_device(SpiHost, &spiConfig, &platform.spiDev));
ESP_ERROR_CHECK(gpio_intr_enable(XxxIrqPin));
esp_log_level_set("*", ESP_LOG_VERBOSE);
ESP_LOGD(__func__, "done");
return 0;
}
void app_main(void)
{
uint8_t txBuf[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // data will be transmitted
uint8_t *tx[] = {txBuf};
size_t txL[] = {sizeof(txBuf)};
uint8_t rxBuf[128]; // receive buffer
uint8_t *rx[] = {rxBuf};
size_t rxLength = 2; // 2 bytes to receive
size_t *rxL[] = {&rxLength};
ESP_ERROR_CHECK(gpio_install_isr_service(ESP_INTR_FLAG_IRAM));
Init();
while (true)
{
TRx(plat, tx, txL, 1, rx, rxL, 1);
// TRx(plat, tx, txL, 1, NULL, NULL, 0);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
I am using almost the latest ESP-IDF cloned from GitHub with an ESP32-C3-DevKitM-1. I would be very happy if someone could help me finding the root cause and fixing the problem.
Thanks,
zolinux