First SPI Transaction is Wrong

Ryker LabJack
Posts: 2
Joined: Fri Dec 06, 2024 9:23 pm

First SPI Transaction is Wrong

Postby Ryker LabJack » Fri Dec 06, 2024 10:17 pm

Hello Everyone!

I have been developing a program with a ESP32-C6 DevKitC-1(WROOM-1) and ESP-IDF v5.3.1 and have encountered an odd issue with SPI.
With the ESP configured as a slave, and restarting it, its first SPI transaction it receives is "wrong".
The data received is wrong, and the data it transmit is wrong.
All subsequent transactions have no problems receiving or sending.
Both the master and slave are transmitting 4 0x33 bytes.
After investigating with the logic analyzer, the only problem seems to be the firs transaction's MISO data.
All other transactions look fine on the logic analyzer.

I have attached a minimal example code that reproduces this: (SPI clk is 10MHz)

Code: Select all

#include <stdio.h>
#include <string.h>
#include "esp_err.h"
#include "esp_log.h"
#include "driver/spi_slave.h"
#include "driver/gpio.h"
#include "freertos/task.h"


// Logging Tag
static const char* TAG = "TEST";

// Define SPI pins
#define GPIO_MISO 20
#define GPIO_MOSI 19
#define GPIO_CLK  18
#define GPIO_CS   9

// Transaction buffer size
#define TRANSACTION_SIZE 4 // bytes


// Task for handling SPI transactions
void spi_task(void* parameters) {
    ESP_LOGI(TAG, "SPI Task Start");

    // Send and recieve buffers
    uint8_t rx_buffer[TRANSACTION_SIZE];
    uint8_t tx_buffer[TRANSACTION_SIZE];

    // spi transaction struct
    spi_slave_transaction_t trans;
    memset(&trans, 0, sizeof(trans));

    while (true) {
        ESP_LOGI(TAG, "SPI Loop Start");

        // Initialize transmit buffer
        tx_buffer[0] = 0x33;
        tx_buffer[1] = 0x33;
        tx_buffer[2] = 0x33;
        tx_buffer[3] = 0x33;

        // Initialize receive buffer
        memset(rx_buffer, 0, TRANSACTION_SIZE);

        // Prepare the transaction
        trans.length = TRANSACTION_SIZE * 8; // Transaction length in bits
        trans.rx_buffer = rx_buffer;
        trans.tx_buffer = tx_buffer;

        // Wait for a transaction from the master
        ESP_ERROR_CHECK(spi_slave_transmit(SPI2_HOST, &trans, portMAX_DELAY));
        ESP_LOGI(TAG, "SPI Transaction Completed");
        
        // Print the received data
        printf("Received data: ");
        for (int i = 0; i < TRANSACTION_SIZE; i++) {
            printf("0x%02X ", rx_buffer[i]);
        }
        printf("\n");
    }

    ESP_LOGI(TAG, "SPI Task End");
}


void app_main(void) {
    ESP_LOGI(TAG, "App Main Start");

    // Setup GPIO
    gpio_set_pull_mode(GPIO_MOSI, GPIO_PULLUP_ONLY);
    gpio_set_pull_mode(GPIO_CLK, GPIO_PULLUP_ONLY);
    gpio_set_pull_mode(GPIO_CS, GPIO_PULLUP_ONLY);

    // Configuration for SPI slave interface
    spi_bus_config_t spi_bus_cfg = {
        .mosi_io_num = GPIO_MOSI,
        .miso_io_num = GPIO_MISO,
        .sclk_io_num = GPIO_CLK,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        //.max_transfer_sz = TRANSACTION_SIZE,
        .flags = SPICOMMON_BUSFLAG_SLAVE,
    };

    spi_slave_interface_config_t spi_slave_cfg = {
        .mode = 2,
        .spics_io_num = GPIO_CS,
        .queue_size = 1,
        .flags = 0,
    };

    // Initialize SPI slave
    ESP_ERROR_CHECK(spi_slave_initialize(SPI2_HOST, &spi_bus_cfg, &spi_slave_cfg, SPI_DMA_CH_AUTO));

    // Start SPI Task
    BaseType_t task_status = xTaskCreate(spi_task, "SPI_TASK", 4096, (void*)1, 2, NULL);
    if (task_status != pdPASS) {
        ESP_LOGE(TAG, "SPI Task Creation Failed");
        abort();
    }

    ESP_LOGI(TAG, "App Main End");
}
Here is the ESP32 Log: (Master Log Level set to DEBUG)
D (320) spi_flash: trying chip: generic
I ESP-ROM:esp32c6-20220919
Build:Sep 19 2022
rst:0x15 (USB_UART_HPSYS),boot:0x1c (SPI_FAST_FLASH_BOOT)
Saved PC:0x400294a6
--- 0x400294a6: uart_hal_get_txfifo_count in ROM

SPIWP:0xee
mode:DIO, clock div:2
load:0x40875720,len:0x1338
load:0x4086c110,len:0xc70
load:0x4086e610,len:0x2c18
entry 0x4086c110
I (49) cpu_start: Unicore app
D (49) cpu_start: Pro cpu up
--- Error: ClearCommError failed (PermissionError(13, 'The device does not recognize the command.', None, 22))
--- Waiting for the device to reconnect
D (502) intr_alloc: Connected src 72 to int 11 (cpu 0)
I (502) TEST: SPI Task Start
I (512) TEST: SPI Loop Start
I (512) TEST: App Main End
I (512) main_task: Returned from app_main()
I (16062) TEST: SPI Transaction Completed
Received data: 0x66 0x66 0x66 0x33
I (16062) TEST: SPI Loop Start
I (17022) TEST: SPI Transaction Completed
Received data: 0x33 0x33 0x33 0x33
I (17022) TEST: SPI Loop Start
I (18062) TEST: SPI Transaction Completed
Received data: 0x33 0x33 0x33 0x33
I (18062) TEST: SPI Loop Start
And here are the three SPI transactions on the logic analyzer:

First Transaction:
first_transaction.png
First SPI Transaction
first_transaction.png (30.93 KiB) Viewed 3194 times
Second Transaction:
second_transaction.png
Second SPI Transaction
second_transaction.png (33.24 KiB) Viewed 3194 times
Third Transaction:
third_transaction.png
Third SPI Transaction
third_transaction.png (32.88 KiB) Viewed 3194 times
Any ideas or recommendations would be appreciated.

username
Posts: 556
Joined: Thu May 03, 2018 1:18 pm

Re: First SPI Transaction is Wrong

Postby username » Sun Dec 08, 2024 6:05 am

Does this change anything if you do this.

gpio_reset_pin(GPIO_CS); gpio_set_direction(GPIO_CS, GPIO_MODE_INPUT); gpio_pullup_en(GPIO_CS);
gpio_reset_pin(GPIO_CLK); gpio_set_direction(GPIO_CLK, GPIO_MODE_INPUT); gpio_pullup_en(GPIO_CLK);
gpio_reset_pin(GPIO_MOSI); gpio_set_direction(GPIO_MOSI, GPIO_MODE_INPUT); gpio_pullup_en(GPIO_MOSI);

Ryker LabJack
Posts: 2
Joined: Fri Dec 06, 2024 9:23 pm

Re: First SPI Transaction is Wrong

Postby Ryker LabJack » Sun Dec 08, 2024 5:50 pm

I replaced line 71 (//Setup GPIO) with the recommended changes.

There were no changes.

I also included gpio_set_pull_mode(GPIO_*, GPIO_PULLUP_ONLY) like was recommended in the spi_slave example here: https://github.com/espressif/esp-idf/bl ... app_main.c

That also had no effect.

I tried similar changes to the GPIO_MSIO pin but instead set the direction to GPIO_MODE_OUTPUT.

This also had no effect.

I tried dropping the SPI CLK down to 5MHz, but that did not change anything.

I have another DevKit of the same chip, but had the same problem.

I dont think this problem is related to the master, since this problem occurs only when the ESP32 slave is restarted, and I dont see any changes when restarting the master.

The only other thing I have noticed is that the last byte received on the slave's first spi transaction seems correct.
I tried to see if there is any correlation to length, but increasing the transaction length has the same effect.
All bytes are incorrect except the last one.

I attempted to post my sdkconfig, but it was to long for the forum.
If there is a part you would like to see let me know.

Let me know if you have any other ideas.
Im trying to avoid setting up a use case where the first transaction has to be ignored.

Who is online

Users browsing this forum: No registered users and 57 guests