nrfx_spim_xfer function and thread-safe

Hello guys

We have a problem with the SPI bus driver on the nRF9160 MCU.
In our project, we use SPI1 and SPI3 instances.

When I send a package in some of these SPI busses I use the following code:

        static bool SpiNrf_sOperation(const SpiIdx_t kIdx, uint8_t* const pTx,
                const uint16_t kTxSize, uint8_t* const pRx, const uint16_t kRxSize,
                const bool kNeedAwait)
        {
            SPI_XFER oper;
            // Prepare an operation structure.
            if (pTx && pRx) { // Transmiting and receiving operation.
                SPI_XFER txRx = NRFX_SPIM_XFER_TRX(pTx, kTxSize, pRx, kRxSize);
                memcpy(&oper, &txRx, sizeof(SPI_XFER));
            } else if (pTx) { // Transmiting-only operation.
                SPI_XFER tx = NRFX_SPIM_XFER_TX(pTx, kTxSize);
                memcpy(&oper, &tx, sizeof(SPI_XFER));
            } else {          // Receiving-only operation.
                SPI_XFER rx = NRFX_SPIM_XFER_RX(pRx, kRxSize);
                memcpy(&oper, &rx, sizeof(SPI_XFER));
            }
            // Select between awaiting or non-awaiting operations.
            if (!kNeedAwait) { // Just sent and do not wait until the data is received:
                               // data receiving will be driven from SPI event
                               // callback.
                return (nrfx_spim_xfer(&sSpi[kIdx].periph, &oper, 0) == NRFX_SUCCESS);
            } else { // Run the SPI operation and await until it is finished.
                sSpi[kIdx].isBusy = true;
                int status = nrfx_spim_xfer(&sSpi[kIdx].periph, &oper, 0);
                if (status == NRFX_SUCCESS) {
                    if (SpiNrf_sWaitUntilReady(kIdx)) {
                        return true;
                    }
                }
                sSpi[kIdx].isBusy = false;
                LOG_E("failed to xfer data - %d\n", status);
                return false;
            }
        }

Where the kNeedAwait flag is always true.

Inside of the SpiNrf_sWaitUntilReady function I wait for sSpi[kIdx].isBusy == false condition:

        static bool SpiNrf_sWaitUntilReady(const SpiIdx_t kIdx)
        {
            while (sSpi[kIdx].isBusy == true) {
            }

            return true;
        }

It reaches by catching callbacks from the SPI driver. For example:

static void Spi1_sDfltClbk(nrfx_spim_evt_t const* pEvent, void* pContext)
{
    if (pEvent->type == NRFX_SPIM_EVENT_DONE) {
        sSpi[kSpi1].isBusy = false;
    }
}

The isBusy flag is declared with the volatile specifier:

        typedef struct {
            bool          isInit;       // Initialization flag
            bool          isActive;     // Activity flag
            volatile bool isBusy;       // Business flag.
            SPI_INS       periph;       // Instance object
            SPI_CFG       config;       // Instance configuration object
            pSpiClbk      pClbk;        // Pointer to an external interrupt processing function
        } SpiNrf_t;

The problem comes when I try to send two transactions and each one is issued from separate threads.
For example one transaction (from thread #1) to the WIFI chip on the SPI1 bus and another transaction (from thread #2) to the external flash memory on the SPI3 bus. I have looked at the nrfx driver implementation and it looks very good.
As a solution to this problem, I used a mutex to access the nrfx driver. In this case, everything works fine. Could this be a hardware issue for this type of MCU, or should I be using the nrfx driver in some other way?

If you need to clarify the details on this issue, so I am ready to provide them.

Thanks in advance for your reply.

  • Hi,

    There is no HW reason why you cannot use the two instances at once, and I am not able to see anything in the driver that should cause problems either. Could it rather be that the problem here is related to your mutex handling, or some other condition that happens when you do this in parallel (one thread waiting for something from the other thread, etc?). I do not have insight into your code (and it could be difficult to see in any case), but that seems like the first think to investigate.

Related