Skip to content

SPI.beginTransaction is not thread safe #6404

Closed
@smarq8

Description

@smarq8

Board

ESP32

Device Description

custom board based on esp32-wroom

Hardware Configuration

const int VMOSI_PIN = 23;
const int VMISO_PIN = 19;
const int VSCLK_PIN = 18;

const int ADXL355_MOSI = VMOSI_PIN;
const int ADXL355_MISO = VMISO_PIN;
const int ADXL355_SCLK = VSCLK_PIN;
const int ADXL355_CSEL = 21;
const int ADXL355_DRDY = 22;

#define TFT_BL 2 // LED back-light control pin
#define TFT_MISO VMISO_PIN
#define TFT_MOSI VMOSI_PIN
#define TFT_SCLK VSCLK_PIN
#define TFT_CS 32 // Chip select control pin
#define TFT_DC 25 // Data Command control pin
#define TFT_RST 33 // Reset pin (could connect to RST pin)

Version

latest master

IDE Name

platformio

Operating System

Windows 10

Flash frequency

40mhz

PSRAM enabled

no

Upload speed

2000000

Description

before beginTransaction() reach its mutex then other threads can easily owervrite input parameters as they are stored as class members.
My board have several deviced connected to VMOSI (sensor,display,etc). In my case sensors data are corrupted by display thread which randomly overwrite SPI settings, as you can see in the picture while sensor transaction (CSEL low) then it run at my display settings - 40mhz instead of 10mhz (max spec of sensor)
I can fix it at my code by putting mutex around any spi transaction but its not solve any library issue or I move for a test beginTransaction() internal mutex to be executed just before any other code. It seems work but it need better implementation.

I can not reproduce any demonstration. For me it reveal in my main project after several months only under certain setting, threads load etc.
screenshot 1646841341

Sketch

illustrative code


void SPIClass::beginTransaction(SPISettings settings)
{
    spiLock(_spi); // <-- putting mutex here sole all problems
//check if last freq changed
    uint32_t cdiv = spiGetClockDiv(_spi);
    if(_freq != settings._clock || _div != cdiv) {
        _freq = settings._clock;
        _div = spiFrequencyToClockDiv(_freq);
    }
// <--- before sensor reach SPI_MUTEX_LOCK() then other thread might overwrite parameters
    // spiLock(_spi); // as inside spiTransaction() cause problem
    spiTransaction(_spi, _div, settings._dataMode, settings._bitOrder); // SPI_MUTEX_LOCK() removed
    _inTransaction = true;
}

void SPIClass::endTransaction()
{
    if(_inTransaction){
        _inTransaction = false;
        spiEndTransaction(_spi); // SPI_MUTEX_UNLOCK() removed
        spiUnlock(_spi);
    }
}

void spiLock(spi_t * spi){
    if(!spi) {
        return;
    }
    SPI_MUTEX_LOCK();
}
void spiUnlock(spi_t * spi){
    if(!spi) {
        return;
    }
    SPI_MUTEX_UNLOCK();
}

Debug Message

none

Other Steps to Reproduce

No response

I have checked existing issues, online documentation and the Troubleshooting Guide

  • I confirm I have checked existing issues, online documentation and Troubleshooting guide.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions