Jump to main content

##

# 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;
        }
    }