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