This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC2640R2F: NPI slave sends SPI data when MRDY is not asserted (follow up)

Part Number: CC2640R2F

It's been a while since I asked the related question, but has there been any update on this issue?  I'm using the simplelink SDK version 5.30.00.03.

What I see is that in the file "npi_tl.c" in the function "NPITL_writeTL()" the code calls transportWrite() immediately before SRDY_ENABLE().

The transportWrite() function which links to "NPITLSPI_writeTransport()" in "npi_tl_spi.c" sets up the SPI transaction and calls SPI_transfer() which means that as soon as the NPI Master starts toggling the CLK, the slave will start sending the SPI data over MISO.  Even if the MRDY line is not asserted.

This causes issues if trying to use a shared SPI bus because the Master will be talking to a different BLE module and yet this BLE module will still send data.

I'm struggling to modify the NPI files in a way that waits to set up the SPI transaction until after MRDY goes low.  There's just a lot of layers and events being called that sometimes my attempts will work for 1 transaction but then nothing will be sent after that.

Any help or ideas would be great, thanks!

  • I attempted a workaround that involves waiting for an MRDY event to setup the SPI transaction.

    I added a transportEnableWrite function to the top of npi_tl.h (line 7 here:)

    #elif defined(NPI_USE_SPI)
    #define transportInit NPITLSPI_initializeTransport
    #define transportRead NPITLSPI_readTransport
    #define transportWrite NPITLSPI_writeTransport
    #define transportStopTransfer NPITLSPI_stopTransfer
    #define transportMrdyEvent NPITLSPI_handleMrdyEvent
    #define transportEnableWrite NPITLSPI_enableWriteTransport
    #endif

    And called it from npi_tl.c in the NPITL_handleMrdyEvent function:

    void NPITL_handleMrdyEvent(void)
    {
        ICall_CSState key;
        key = ICall_enterCriticalSection();
    
        // Check to make sure this event is not occurring during the next packet
        // transmission
        if ( PIN_getInputValue(MRDY_PIN) == 0 ||
            (npiTxActive && mrdyPktStamp == txPktCount ) )
        {
            transportMrdyEvent();
            SRDY_ENABLE();
    
            if(npiTxActive)
            {
                //Set SPI count to correct length
                transportEnableWrite();
            }
        }
    
        ICall_leaveCriticalSection(key);
    }

    Then in npi_tl_spi.c I commented out the SPI_Transfer from NPITLSPI_writeTransport() and instead moved it to my new function NPITLSPI_enableWriteTransport()

    // -----------------------------------------------------------------------------
    //! \brief      This routine initializes and begins a SPI transaction
    //!
    //! \param[in]  len - Number of bytes to write.
    //!
    //! \return     uint8 - number of bytes written to transport
    // -----------------------------------------------------------------------------
    uint16 NPITLSPI_writeTransport(uint16 len)
    {
        int16 i = 0;
        ICall_CSState key;
    
        key = ICall_enterCriticalSection();
    
        TransportTxBufLen = len + SPI_TX_FIELD_LEN;
    
        // Shift TX message two bytes to give room for SPI header
        for( i = ( TransportTxBufLen - 1 ) ; i >= 0 ; i-- )
        {
          TransportTxBuf[i + SPI_TX_HDR_LEN] = TransportTxBuf[i];
        }
    
        // Add header (including a zero padding byte required by the SPI driver)
        TransportTxBuf[SPI_TX_ZERO_PAD_INDEX] = 0x00;
        TransportTxBuf[SPI_TX_SOF_INDEX] = SPI_SOF;
        TransportTxBuf[SPI_TX_LEN_INDEX] = len;
    
        // Calculate and append FCS at end of Frame
        TransportTxBuf[TransportTxBufLen - 1] =
            NPITLSPI_calcFCS(&TransportTxBuf[SPI_TX_LEN_INDEX],len + 1);
    
        // Clear DMA Rx buffer and clear extra Tx buffer bytes to ensure clean buffer
        //    for next RX/TX
        memset(TransportRxBuf, 0, NPI_TL_BUF_SIZE);
        memset(&TransportTxBuf[TransportTxBufLen], 0, NPI_TL_BUF_SIZE - TransportTxBufLen);
    
        // set up the SPI Transaction
        // Count set to 0 to avoid sending data before master is ready in a shared
        // SPI bus configuration
        spiTransaction.count = NPI_TL_BUF_SIZE;
        spiTransaction.txBuf = TransportTxBuf;
        spiTransaction.rxBuf = TransportRxBuf;
    
    //    // Check to see if transport is successful. If not, reset TxBufLen to allow
    //    // another write to be processed
    //    if( ! SPI_transfer(spiHandle, &spiTransaction) )
    //    {
    //      TransportTxBufLen = 0;
    //    }
    
        ICall_leaveCriticalSection(key);
    
        return TransportTxBufLen;
    }
    
    // -----------------------------------------------------------------------------
    //! \brief      This sets SPI TX count to the full buffer size. This is only
    //!             called once the MRDY pin has gone low to prevent data TX when
    //!             master is not ready.
    //!
    //! \return     void
    // -----------------------------------------------------------------------------
    void NPITLSPI_enableWriteTransport()
    {
        ICall_CSState key;
        key = ICall_enterCriticalSection();
    
        // Check to see if transport is successful. If not, reset TxBufLen to allow
        // another write to be processed
        if( ! SPI_transfer(spiHandle, &spiTransaction) )
        {
          TransportTxBufLen = 0;
        }
    
        ICall_leaveCriticalSection(key);
    }

    And of course added the prototype to npi_tl_spi.h

    // -----------------------------------------------------------------------------
    //! \brief      This sets SPI TX count to the full buffer size. This is only
    //!             called once the MRDY pin has gone low to prevent data TX when
    //!             master is not ready.
    //!
    //! \return     void
    // -----------------------------------------------------------------------------
    void NPITLSPI_enableWriteTransport(void);

    It seems like now the slave will lower SRDY when wanting to send data but now it will wait for a NPITL_handleMrdyEvent() in order to set up the SPI_Transfer rather than just sending the data out on MISO as soon as the clock starts toggling.  This way the master can talk to a 2nd slave module without this 1st module causing a collision of data.

    Does this seem like an OK modification to those of you more familiar with the code than me?  I've ran a few tests and both modules seem to behave according to the proper flow control now.

    Thanks, Erik

  • Hi Erik,

    The modifications you have made look okay to me at a glance. To ensure the modifications are proper and stable, I would encourage you to run some extended stress tests on the project to ensure it is working as expected in all cases. Thank you for sharing your workaround with the community!

    Best Regards,

    Jan