How To Reduce Time Between SPI Transactions
Posted: Tue Apr 07, 2026 8:13 pm
Hello I am trying to sample a ADS131M06 at 32kHz but I am struggling to get the time between SPI transactions below 30us any suggestions?
Code: Select all
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "ads131m0x.h"
static const char *TAG = "MAIN";
static QueueHandle_t adc_queue = NULL;
// ─── Sampling task ────────────────────────────────────────────────────────────
// Runs on Core 1 at highest priority — just reads the ADC and queues the data.
static void sample_task(void *arg)
{
InitADC();
adc_channel_data result = {0};
toggleSYNC();
delay_us(1);
while (1)
{
if (waitForDRDYinterrupt(1000))
{
readData(&result);
xQueueSend(adc_queue, &result, 0); // non-blocking send
}
}
}
// ─── USB send task ────────────────────────────────────────────────────────────
// Runs on Core 0 — drains the queue and sends binary packets over USB CDC.
static void usb_task(void *arg)
{
adc_channel_data result = {0};
while (1)
{
if (xQueueReceive(adc_queue, &result, portMAX_DELAY))
{
}
}
}
// ─── App entry point ──────────────────────────────────────────────────────────
void app_main(void)
{
adc_queue = xQueueCreate(256, sizeof(adc_channel_data)); // bigger buffer at 32 kHz
xTaskCreatePinnedToCore(sample_task, "adc_sample", 4096, NULL, configMAX_PRIORITIES - 1, NULL, 1);
xTaskCreatePinnedToCore(usb_task,"Usb Send",4096,NULL,configMAX_PRIORITIES - 2,NULL,0);
}
Code: Select all
void InitSPI(void)
{
/* NOTE: The ADS131M06 operates in SPI mode 1 (CPOL = 0, CPHA = 1). */
spi_bus_config_t bus_cfg = {
.mosi_io_num = PIN_MOSI,
.miso_io_num = PIN_MISO,
.sclk_io_num = PIN_SCLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 64, /* Larger than the biggest frame we will ever send */
//.isr_cpu_id = 1,
};
esp_err_t ret = spi_bus_initialize(SPI_HOST_DEVICE, &bus_cfg, SPI_DMA_CH_AUTO);
if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE)
{
ESP_LOGE(TAG, "spi_bus_initialize failed: %s", esp_err_to_name(ret));
return;
}
spi_device_interface_config_t dev_cfg = {
.clock_speed_hz = SPI_CLOCK_HZ,
.mode = 1, /* CPOL=0, CPHA=1 */
.spics_io_num = PIN_CS,
.queue_size = 2,
.flags = SPI_DEVICE_NO_DUMMY,
//.input_delay_ns = 1,
.cs_ena_pretrans = 1,
//.cs_ena_posttrans = 2,
.clock_source = SPI_CLK_SRC_XTAL,
};
ret = spi_bus_add_device(SPI_HOST_DEVICE, &dev_cfg, &s_spi);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "spi_bus_add_device failed: %s", esp_err_to_name(ret));
}
}
Code: Select all
void spiSendReceiveArrays(const uint8_t dataTx[], uint8_t dataRx[], const uint8_t byteLength)
{
assert(dataTx && dataRx);
//spi_device_acquire_bus(s_spi,portMAX_DELAY);
t.length = (size_t) byteLength * 8;
t.tx_buffer = dataTx;
t.rx_buffer = dataRx;
spi_device_polling_transmit(s_spi, &t);
//spi_device_release_bus(s_spi);
}
Code: Select all
bool readData(adc_channel_data *DataStruct)
{
int i;
uint8_t crcTx[4] = { 0 };
uint8_t dataTx[24] = { 0 };
uint8_t dataRx[24] = { 0 };
uint8_t bytesPerWord = getWordByteLength();
#ifdef ENABLE_CRC_IN
// Build CRC word (only if "RX_CRC_EN" register bit is enabled)
uint16_t crcWordIn = calculateCRC(&DataTx[0], bytesPerWord * 2, 0xFFFF);
crcTx[0] = upperByte(crcWordIn);
crcTx[1] = lowerByte(crcWordIn);
#endif
/* Set the nCS pin LOW */
//setCS(LOW);
// Send NULL word, receive response word
uint16_t opcodes[7] = {0};
opcodes[0] = OPCODE_NULL;
uint8_t numberOfBytes = buildSPIarray(opcodes, 7, dataTx);
// Send the opcode (and crc word, if enabled)
spiSendReceiveArrays(dataTx,dataRx,numberOfBytes);
DataStruct->response = combineBytes(dataRx[0], dataRx[1]);
// (OPTIONAL) Do something with the response (STATUS) word.
// ...Here we only use the response for calculating the CRC-OUT
//uint16_t crcWord = calculateCRC(&dataRx[0], bytesPerWord, 0xFFFF);
// (OPTIONAL) Ignore CRC error checking
uint16_t crcWord = 0;
DataStruct->channel0 = signExtend(&dataRx[3]);
#if (CHANNEL_COUNT > 1)
DataStruct->channel1 = signExtend(&dataRx[6]);
#endif
#if (CHANNEL_COUNT > 2)
DataStruct->channel2 = signExtend(&dataRx[9]);
#endif
#if (CHANNEL_COUNT > 3)
DataStruct->channel3 = signExtend(&dataRx[12]);
#endif
#if (CHANNEL_COUNT > 4)
DataStruct->channel4 = signExtend(&dataRx[15]);
#endif
#if (CHANNEL_COUNT > 5)
DataStruct->channel5 = signExtend(&dataRx[18]);
#endif
#if (CHANNEL_COUNT > 6)
DataStruct->channel6 = signExtend(&dataRx[21]);
#endif
#if (CHANNEL_COUNT > 7)
DataStruct->channel7 = signExtend(&dataRx[24]);
#endif
uint8_t crcOffset = (CHANNEL_COUNT + 1) * bytesPerWord;
DataStruct->crc = combineBytes(dataRx[crcOffset], dataRx[crcOffset + 1]);
/* NOTE: If we continue calculating the CRC with a matching CRC, the result should be zero.
* Any non-zero result will indicate a mismatch.
*/
//crcWord = calculateCRC(&dataRx[0], bytesPerWord, crcWord);
/* Set the nCS pin HIGH */
//setCS(HIGH);
// Returns true when a CRC error occurs
return ((bool) crcWord);
}