1.1.8.2 Using The Library

The SPI driver builds on top of the SPI peripheral library (PLIB) and provides write, read and write-read API's in blocking and non-blocking mode.

  • Provides Write, Read and Write followed by Read API's.

  • Supports multiple slaves connected to the same SPI peripheral instance (multi-client mode).

  • In asynchronous (non-blocking) mode, application can either register a callback to get notified once the data transfer is complete or can poll the status of the data transfer using the status APIs

  • In asynchronous mode, application can queue more than one transmit/receive requests without waiting for the previous request to be completed. The number of transmit/receive requests that can be queued depends on the depth of the transfer queue configured using the MHC

  • The asynchronous mode is supported in both bare-metal and RTOS environment

  • The synchronous (blocking) mode of the driver is supported only in an RTOS environment

  • The synchronous mode of the driver does not support callback or queuing multiple requests. This is because the implementation is blocking in nature

  • Supports DMA for Transfer/Receive in both asynchronous and synchronous mode

Example application to Read and Write from SPI EEPROM in Asynchronous mode

/* EEPROM Commands */
#define EEPROM_CMD_WREN                       0x06
#define EEPROM_CMD_WRITE                      0x02
#define EEPROM_CMD_RDSR                       0x05
#define EEPROM_CMD_READ                       0x03
#define EEPROM_START_ADDRESS                  0x000000
#define EEPROM_STATUS_BUSY_BIT                0x01

static APP_EEPROM_DATA app_eepromData;

static const uint8_t EEPROM_MSG_STR[] = "WRITING AND READING DATA ON EEPROM SLAVE";

/* On devices with cache, the array size has to be of multiple of cache line size and aligned to 
 * cache line boundary */
static uint8_t CACHE_ALIGN eepromTxData[64];
static uint8_t CACHE_ALIGN eepromRxData[64];

static void SPI_EEEPROM_EventHandler(
    DRV_SPI_TRANSFER_EVENT event,
    DRV_SPI_TRANSFER_HANDLE transferHandle,
    uintptr_t context
)
{
    if (event == DRV_SPI_TRANSFER_EVENT_COMPLETE)
    {
         app_eepromData.isTransferComplete = true;
    }
    else
    {
        app_eepromData.isTransferComplete = false;
        app_eepromData.state = APP_EEPROM_STATE_ERROR;
    }
}

void APP_EEPROM_Initialize ( void )
{
    /* Place the App state machine in its initial state. */
    app_eepromData.state               = APP_EEPROM_STATE_DATA_INIT;
    app_eepromData.drvSPIHandle        = DRV_HANDLE_INVALID;
    app_eepromData.transferStatus      = APP_ERROR;
    app_eepromData.isTransferComplete  = false;        

    memset(eepromTxData, 0, sizeof(eepromTxData));
    memset(eepromRxData, 0, sizeof(eepromRxData));

    APP_EEPROM_CS_Set();

    /* As EEPROM WP and HOLD pins are already latched high from
     * Pin Configuration, no need to set both pins high again.
     */
}

void APP_EEPROM_Tasks ( void )
{
    uint32_t eepromAddr = EEPROM_START_ADDRESS;

    /* Check the application's current state. */
    switch ( app_eepromData.state )
    {
        /* Application's initial state. */
        case APP_EEPROM_STATE_DATA_INIT:

            /* Setup SPI for client 1 which is EEPROM 1 */
            app_eepromData.setup.baudRateInHz  = 600000;
            app_eepromData.setup.clockPhase    = DRV_SPI_CLOCK_PHASE_VALID_LEADING_EDGE;
            app_eepromData.setup.clockPolarity = DRV_SPI_CLOCK_POLARITY_IDLE_LOW;
            app_eepromData.setup.dataBits      = DRV_SPI_DATA_BITS_8;
            app_eepromData.setup.chipSelect    = (SYS_PORT_PIN)APP_EEPROM_CS_PIN;
            app_eepromData.setup.csPolarity    = DRV_SPI_CS_POLARITY_ACTIVE_LOW;
            app_eepromData.state               = APP_EEPROM_STATE_DRIVER_SETUP;
            break;

        case APP_EEPROM_STATE_DRIVER_SETUP:

            /* Open the SPI Driver for client 1 */
            app_eepromData.drvSPIHandle = DRV_SPI_Open( DRV_SPI_INDEX_0, DRV_IO_INTENT_READWRITE );
            if(app_eepromData.drvSPIHandle != DRV_HANDLE_INVALID)
            {
                if(DRV_SPI_TransferSetup(app_eepromData.drvSPIHandle, &app_eepromData.setup) == true)
                {
                    DRV_SPI_TransferEventHandlerSet(app_eepromData.drvSPIHandle, SPI_EEEPROM_EventHandler, (uintptr_t)0);
                    app_eepromData.state = APP_EEPROM_STATE_WRITE_ENABLE;
                }
                else
                {
                    app_eepromData.state = APP_EEPROM_STATE_ERROR;
                }
            }
            else
            {
                app_eepromData.state = APP_EEPROM_STATE_ERROR;
            }
            break;

        case APP_EEPROM_STATE_WRITE_ENABLE:

            /* Set the next state first as callback may be fired before the state
             * is changed; potentially over-writing error state set from the callback */
            
            app_eepromData.state = APP_EEPROM_STATE_WRITE;
            
            eepromTxData[0] = EEPROM_CMD_WREN;

            DRV_SPI_WriteTransferAdd(app_eepromData.drvSPIHandle, eepromTxData, 1, &app_eepromData.transferHandle);

            if(app_eepromData.transferHandle == DRV_SPI_TRANSFER_HANDLE_INVALID)
            {
                app_eepromData.state = APP_EEPROM_STATE_ERROR;
            }
            break;

        case APP_EEPROM_STATE_WRITE:
            if (app_eepromData.isTransferComplete == true)
            {
                app_eepromData.isTransferComplete = false;

                // Write to EEPROM
                eepromTxData[0] = EEPROM_CMD_WRITE;
                eepromTxData[1] = (uint8_t)(eepromAddr>>16);
                eepromTxData[2] = (uint8_t)(eepromAddr>>8);
                eepromTxData[3] = (uint8_t)(eepromAddr);

                memcpy(&eepromTxData[4], EEPROM_MSG_STR, strlen((const char*)EEPROM_MSG_STR));

                app_eepromData.state = APP_EEPROM_STATE_WAIT_FOR_WRITE_COMPLETE;

                DRV_SPI_WriteTransferAdd(app_eepromData.drvSPIHandle, eepromTxData, (4 + strlen((const char*)EEPROM_MSG_STR)), &app_eepromData.transferHandle );

                if(app_eepromData.transferHandle == DRV_SPI_TRANSFER_HANDLE_INVALID)
                {
                    app_eepromData.state = APP_EEPROM_STATE_ERROR;
                }
            }
            break;

        case APP_EEPROM_STATE_WAIT_FOR_WRITE_COMPLETE:

            if (app_eepromData.isTransferComplete == true)
            {
                app_eepromData.isTransferComplete = false;
                
                eepromTxData[0] = EEPROM_CMD_RDSR;

                app_eepromData.state = APP_EEPROM_STATE_CHECK_STATUS;

                DRV_SPI_WriteReadTransferAdd(app_eepromData.drvSPIHandle, eepromTxData, 1, eepromRxData, 2, &app_eepromData.transferHandle);

                if(app_eepromData.transferHandle == DRV_SPI_TRANSFER_HANDLE_INVALID)
                {
                    app_eepromData.state = APP_EEPROM_STATE_ERROR;
                }
            }
            break;

        case APP_EEPROM_STATE_CHECK_STATUS:
            if (app_eepromData.isTransferComplete == true)
            {
                app_eepromData.isTransferComplete = false;
                if((eepromRxData[1] & EEPROM_STATUS_BUSY_BIT) == 0x00)
                {
                    app_eepromData.state = APP_EEPROM_STATE_READ;
                }
                else
                {
                    /* EEPROM is still busy. Keep checking the status. */
                    DRV_SPI_WriteReadTransferAdd(app_eepromData.drvSPIHandle, eepromTxData, 1, eepromRxData, 2, &app_eepromData.transferHandle);
                    if(app_eepromData.transferHandle == DRV_SPI_TRANSFER_HANDLE_INVALID)
                    {
                        app_eepromData.state = APP_EEPROM_STATE_ERROR;
                    }
                }
            }
            break;

        case APP_EEPROM_STATE_READ:

            // Read from EEPROM
            eepromTxData[0] = EEPROM_CMD_READ;
            eepromTxData[1] = (uint8_t)(eepromAddr>>16);
            eepromTxData[2] = (uint8_t)(eepromAddr>>8);
            eepromTxData[3] = (uint8_t)(eepromAddr);

            app_eepromData.state = APP_EEPROM_STATE_DATA_COMPARISON;

            DRV_SPI_WriteReadTransferAdd(app_eepromData.drvSPIHandle, eepromTxData, 4, eepromRxData, (4 + strlen((const char*)EEPROM_MSG_STR)), &app_eepromData.transferHandle);

            if(app_eepromData.transferHandle == DRV_SPI_TRANSFER_HANDLE_INVALID)
            {
                app_eepromData.state = APP_EEPROM_STATE_ERROR;
            }
            break;

        case APP_EEPROM_STATE_DATA_COMPARISON:
            if (app_eepromData.isTransferComplete == true)
            {
                app_eepromData.isTransferComplete = false;
                if (memcmp(&eepromRxData[4], EEPROM_MSG_STR, strlen((const char*)EEPROM_MSG_STR)) == 0)
                {                    
                    app_eepromData.state = APP_EEPROM_STATE_SUCCESS;
                }
                else
                {
                    app_eepromData.state = APP_EEPROM_STATE_ERROR;
                }                
            }
            break;

        case APP_EEPROM_STATE_SUCCESS:
            app_eepromData.transferStatus = APP_SUCCESS;
            app_eepromData.state = APP_EEPROM_STATE_IDLE;
            break;

        case APP_EEPROM_STATE_ERROR:
            app_eepromData.transferStatus = APP_ERROR;
            app_eepromData.state = APP_EEPROM_STATE_IDLE;
            break;

        case APP_EEPROM_STATE_IDLE:
        default:
            break;
    }
}