1.1.9.2 Using the Library
The SPI driver builds on top of the SPI Peripheral Library (PLIB) and provides write, read and write-read APIs in Blocking and Non-blocking mode.
SPI Driver Features:
- Provides Write, Read and Write followed by Read APIs.
- Supports multiple clients 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 MCC.
- 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; } }
