Skip to content

Instantly share code, notes, and snippets.

@DavidJRobertson
Created March 9, 2022 01:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DavidJRobertson/3d077b55dce744c4c87ae6c49d0fc2cb to your computer and use it in GitHub Desktop.
Save DavidJRobertson/3d077b55dce744c4c87ae6c49d0fc2cb to your computer and use it in GitHub Desktop.
Example of workaround for 9-bit SPI data corruption on ESP32-S3
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
#include "esp_log.h"
#ifdef CONFIG_IDF_TARGET_ESP32
# define SPI_HOST HSPI_HOST
# define PIN_NUM_MISO 18
# define PIN_NUM_MOSI 23
# define PIN_NUM_CLK 19
# define PIN_NUM_CS 13
#elif CONFIG_IDF_TARGET_ESP32S3
# define SPI_HOST SPI2_HOST
# define PIN_NUM_MISO 13
# define PIN_NUM_MOSI 11
# define PIN_NUM_CLK 12
# define PIN_NUM_CS 10
#endif
static const char TAG[] = "main";
// Just send the data normally.
// This fails on ESP32-S3 if sizeBits is 8n+1 (last bit will be sent as 0 always)
void send_without_workaround(spi_device_handle_t device, uint8_t *buf, size_t sizeBits) {
spi_transaction_t transaction = {
.flags = 0,
.cmd = 0,
.addr = 0,
.length = sizeBits,
.rxlength = 0,
.tx_buffer = buf,
};
ESP_ERROR_CHECK(spi_device_transmit(device, &transaction));
}
void send_with_workaround(spi_device_handle_t device, uint8_t *buf, size_t sizeBits) {
if (sizeBits == 1) {
// Can't handle this case. You could bit-bang if really necessary.
assert(false);
} else if ((sizeBits % 8) != 1) {
// Normal case where workaround is not necessary.
send_without_workaround(device, buf, sizeBits);
} else {
// Need to work around bug on ESP32S3 by splitting transfer
ESP_ERROR_CHECK(spi_device_acquire_bus(device, portMAX_DELAY));
// Send all but last 2 bits
spi_transaction_t transaction1 = {
.flags = SPI_TRANS_CS_KEEP_ACTIVE,
.cmd = 0,
.addr = 0,
.length = sizeBits - 2,
.rxlength = 0,
.tx_buffer = buf,
};
ESP_ERROR_CHECK(spi_device_transmit(device, &transaction1));
// Send last 2 bits
uint8_t lastBits = (buf[(sizeBits/8)-1] << 7) | (buf[sizeBits/8] >> 1);
spi_transaction_t transaction2 = {
.flags = 0,
.cmd = 0,
.addr = 0,
.length = 2,
.rxlength = 0,
.tx_buffer = &lastBits,
};
ESP_ERROR_CHECK(spi_device_transmit(device, &transaction2));
spi_device_release_bus(device);
}
}
void test_send(spi_device_handle_t device, uint8_t *buf, size_t sizeBits) {
send_without_workaround(device, buf, sizeBits);
send_with_workaround(device, buf, sizeBits);
vTaskDelay(1);
}
void app_main(void)
{
esp_err_t ret;
// Initialise bus
ESP_LOGI(TAG, "Initializing bus SPI%d...", SPI_HOST+1);
spi_bus_config_t buscfg={
.miso_io_num = PIN_NUM_MISO,
.mosi_io_num = PIN_NUM_MOSI,
.sclk_io_num = PIN_NUM_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 32,
};
ret = spi_bus_initialize(SPI_HOST, &buscfg, SPI_DMA_CH_AUTO);
ESP_ERROR_CHECK(ret);
// Initialise device
ESP_LOGI(TAG, "Initializing device");
spi_device_handle_t spiDevice;
spi_device_interface_config_t deviceConfig = {
.command_bits = 0,
.address_bits = 0,
.dummy_bits = 0,
.mode = 0,
.duty_cycle_pos = 0,
.cs_ena_pretrans = 0,
.cs_ena_posttrans = 0,
.clock_speed_hz = 100000,
.input_delay_ns = 0,
.spics_io_num = PIN_NUM_CS,
.flags = 0,
.queue_size = 200,
};
ESP_ERROR_CHECK(spi_bus_add_device(SPI_HOST, &deviceConfig, &spiDevice));
// Send test data
uint8_t testData[3] = {0xff, 0xff, 0xff};
test_send(spiDevice, testData, 9);
test_send(spiDevice, testData, 17);
while (1) {
// Add your main loop handling code here.
vTaskDelay(1);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment