1.8.10 Multi Channel Serial Peripheral Interface (MCSPI)
The MCSPI PLIB can be configured in master or slave mode.
MCSPI master mode
In MCSPI master mode, the PLIB can be configured to run in blocking mode or non-blocking mode. In blocking mode the peripheral interrupt is disabled and the transfer API blocks until the transfer is complete. In non-blocking mode, the peripheral interrupt is enabled. The transfer API initiates the transfer and returns immediately. The transfer is completed from the peripheral interrupt. Application can either use a callback to get notified when the transfer is complete or can use the IsBusy API to check the completion status.
MCSPI slave mode
MCSPI slave mode enables peripheral interrupt for data transfers. The PLIB uses internal receive and transmit buffers. The receive buffer is used to hold the data received from the MCSPI master while the application data to be transmitted out is copied into the transmit buffer. The size of the transmit and receive buffers is configurable in MCC. Application must register a callback with the PLIB to receive event notifications. A callback is given when the chip select is de-asserted by the MCSPI master. The application must read out the received data in the callback, thereby clearing the PLIB's internal RX buffer.
The PLIB optionally supports busy signalling from MCSPI slave to MCSPI master. This option can be enabled to provide an indication to the MCSPI master on when the MCSPI slave will be ready to respond. In a typical implementation, to read data from MCSPI slave, the MCSPI master asserts the chip select line and then sends a MCSPI packet informing the slave about the memory address to read from and the number of bytes to read and then de-asserts the chip select line. The MCSPI master must then wait for the MCSPI slave to frame the response by waiting on the busy line. Once the MCSPI slave drives the busy signal to ready state, the MCSPI master can start reading the actual data by asserting the chip select line and sending dummy writes for the number of bytes to read. Finally, after the intended bytes are read, the chip select must be de-asserted by the MCSPI master.
If the busy signalling is not enabled, the MCSPI master must wait for sufficient duration to allow the MCSPI slave to become ready with the response.
MCSPI Master in blocking (peripheral interrupt disabled) mode
// Following code demonstrates MCSPI self loopback with the PLIB configured in blocking mode uint8_t txData[] = "SELF LOOPBACK FOR MCSPI!"; uint8_t rxData[sizeof(txData)]; int main ( void ) { /* Initialize all modules */ SYS_Initialize ( NULL ); /* MCSPI Write Read */ MCSPI1_WriteRead(&txData[0], sizeof(txData), &rxData[0], sizeof(rxData)); /* Compare received data with the transmitted data */ if ((memcmp(txData, rxData, sizeof(txData)) == 0)) { /* Pass: Received data is same as transmitted data */ } else { /* Fail: Received data is not same as transmitted data */ } while ( true ) { } /* Execution should not come here during normal operation */ return ( EXIT_FAILURE ); }
MCSPI Master in non-blocking (peripheral interrupt enabled) mode
// Following code demonstrates MCSPI self loopback with the PLIB configured in non-blocking mode uint8_t txData[] = "SELF LOOPBACK FOR MCSPI!"; uint8_t rxData[sizeof(txData)]; volatile bool transferStatus = false; /* This function will be called by MCSPI PLIB when transfer is completed */ void APP_MCSPI_Callback(uintptr_t context ) { transferStatus = true; } int main ( void ) { /* Initialize all modules */ SYS_Initialize ( NULL ); /* Register callback function */ MCSPI1_CallbackRegister(APP_MCSPI_Callback, 0); /* MCSPI Write Read */ MCSPI1_WriteRead(&txData[0], sizeof(txData), &rxData[0], sizeof(rxData)); while (1) { /* Perform other tasks here ...*/ /* Check if transfer has completed */ if(transferStatus == true) { /* Compare received data with the transmitted data */ if(memcmp(txData, rxData, sizeof(txData)) == 0) { /* Pass: Received data is same as transmitted data */ } else { /* Fail: Received data is not same as transmitted data */ } } } }
MCSPI slave mode
This example uses the MCSPI peripheral library in slave mode and allows reading and writing data from/to its internal buffer by a MCSPI master. The MCSPI master writes data by sending a write command followed by two bytes of memory address followed by the data to be written.
< WR_CMD > < ADDR_MSB > < ADDR_LSB > < DATA0 > ... < DATA n >
The MCSPI slave asserts the Busy line to indicate to the MCSPI master that it is busy. Once ready, the MCSPI slave de-asserts the Busy line. Once the MCSPI slave is ready, the MCSPI master reads the data by sending read command followed by two bytes of memory address and the number of bytes to read.
< RD_CMD > < ADDR_MSB > < ADDR_LSB > < NUM_BYTES >
The MCSPI slave responds by sending the data at the requested memory address.
/* * Protocol: * Master: [WR_CMD ADDR1 ADDR0 DATA0 DATA1 .. DATAN] ... ... ... ... ... ... [RD_CMD ADDR1 ADDR0] [DUMMY DUMMY .. DUMMY] * Slave: [DUMMY DUMMY DUMMY DUMMY DUMMY .. DUMMY] ... ... ... ... ... ... [DUMMY DUMMY DUMMY] [DATA0 DATA1 .. DATAN] * BUSY PIN: ---------------------------------------------------------------- * ____________| |____________________________________________ * * WR_CMD = 0x02 * RD_CMD = 0x03 * BUSY = 0x01 * READY = 0x00 */ typedef enum { APP_STATE_INITIALIZE, APP_STATE_READ, APP_STATE_WRITE, APP_STATE_IDLE, } APP_STATES; /* Commands */ #define APP_CMD_WRITE 0x02 #define APP_CMD_READ 0x03 #define APP_MEM_BUFFER_SIZE 512 #define APP_RX_BUFFER_SIZE 256 #define APP_TX_BUFFER_SIZE 256 typedef struct { uint8_t busy :1; uint8_t reserved :7; }STATUS; typedef struct { volatile APP_STATES state; volatile STATUS status; volatile uint8_t nBytesRead; volatile uint8_t nBytesToWrite; volatile uint8_t nBytesReadRequest; volatile uint16_t memAddr; }APP_DATA; APP_DATA appData; uint8_t APP_MemoryBuffer[APP_MEM_BUFFER_SIZE] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f, 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f, 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f, 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f, 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf, 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf, 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf, 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf, 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef, 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff, 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f, 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f, 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f, 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f, 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf, 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf, 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf, 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf, 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef, 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff }; uint8_t APP_RxData[APP_RX_BUFFER_SIZE]; uint8_t APP_TxData[APP_TX_BUFFER_SIZE]; void delay(uint32_t count) { uint32_t i; // 1 loop roughly provides 1us delay at 32MHz CPU frequency for (i = 0; i < count; i++) { asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP"); asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP"); asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP"); asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP"); } } void MCSPIEventHandler(uintptr_t context ) { if (MCSPI1_ErrorGet() == MCSPI_SLAVE_ERROR_NONE) { appData.nBytesRead = MCSPI1_Read(APP_RxData, MCSPI1_ReadCountGet()); switch(APP_RxData[0]) { case APP_CMD_WRITE: if (appData.status.busy == 0) { appData.status.busy = 1; appData.memAddr = ((APP_RxData[1] << 8) | (APP_RxData[2])); appData.nBytesToWrite = (appData.nBytesRead - 3); appData.state = APP_STATE_WRITE; } break; case APP_CMD_READ: appData.memAddr = ((APP_RxData[1] << 8) | (APP_RxData[2])); appData.nBytesReadRequest = APP_RxData[3]; if ((appData.memAddr + appData.nBytesReadRequest) <= APP_TX_BUFFER_SIZE) { memcpy(APP_TxData, &APP_MemoryBuffer[appData.memAddr], appData.nBytesReadRequest); MCSPI1_Write(APP_TxData, appData.nBytesReadRequest); } break; } if (appData.status.busy == 0) { /* Indicate to MCSPI Master that slave is ready for data transfer */ MCSPI1_Ready(); } } } int main ( void ) { /* Initialize all modules */ SYS_Initialize ( NULL ); appData.state = APP_STATE_INITIALIZE; while(1) { /* Check the application's current state. */ switch (appData.state) { case APP_STATE_INITIALIZE: MCSPI1_CallbackRegister(MCSPIEventHandler, (uintptr_t) 0); /* Wait for instructions from MCSPI master */ appData.state = APP_STATE_IDLE; break; case APP_STATE_WRITE: /* Adding delay to simulate busy condition */ delay(1000); /* Copy received data into Application memory buffer */ if ((appData.memAddr + appData.nBytesToWrite) <= APP_MEM_BUFFER_SIZE) { memcpy(&APP_MemoryBuffer[appData.memAddr], &APP_RxData[3], appData.nBytesToWrite); } appData.status.busy = 0; /* Indicate to MCSPI Master that slave is ready for data transfer */ MCSPI1_Ready(); appData.state = APP_STATE_IDLE; break; case APP_STATE_IDLE: break; default: break; } } }
Library Interface
MCSPI peripheral library provides the following interfaces:
Functions
Name | Description | Master (blocking/interrupt disabled) mode | Master (non-blocking/interrupt enabled) mode | Slave mode |
---|---|---|---|---|
MCSPIx_Initialize | Initializes MCSPI module of the device | Yes | Yes | Yes |
MCSPIx_TransferSetup | Configure MCSPI operational parameters at run time | Yes | Yes | No |
MCSPIx_WriteRead | Write and Read data on MCSPI peripheral | Yes | Yes | No |
MCSPIx_Write | Writes data to MCSPI peripheral | Yes | Yes | Yes |
MCSPIx_Read | Reads data on the MCSPI peripheral in master mode. Reads data from the PLIB's internal buffer to the application buffer in MCSPI slave mode | Yes | Yes | Yes |
MCSPIx_CallbackRegister | Allows application to register a callback with the PLIB | No | Yes | Yes |
MCSPIx_IsBusy | Returns transfer status of MCSPI | No | Yes | Yes |
MCSPIx_IsTransmitterBusy | Returns transfer status of MCSPI | Yes | No | No |
MCSPIx_ReadCountGet | Returns the number of bytes pending to be read out from the PLIB's internal buffer | No | No | Yes |
MCSPIx_ReadBufferSizeGet | Returns the size of the PLIB's internal receive buffer | No | No | Yes |
MCSPIx_WriteBufferSizeGet | Returns the size of the PLIB's internal transmit buffer | No | No | Yes |
MCSPIx_ErrorGet | Returns the error status of MCSPI transfer | No | No | Yes |
MCSPIx_Ready | Drives the MCSPI slave busy line to ready (not busy) state | No | No | Yes |
MCSPIx_ChipSelectSetup | Enables the specified hardware chip select | Yes | Yes | No |
Data types and constants
Name | Description | Master (blocking/interrupt disabled) mode | Master (non-blocking/interrupt enabled) mode | Slave mode |
---|---|---|---|---|
MCSPI_CLOCK_PHASE | Enum | Identifies MCSPI Clock Phase Options | Yes | Yes |
MCSPI_CLOCK_POLARITY | Enum | Identifies MCSPI Clock Polarity Options | Yes | Yes |
MCSPI_DATA_BITS | Enum | Identifies MCSPI bits per transfer | Yes | Yes |
MCSPI_CHIP_SELECT | Enum | Enumerator constants for MCSPI hardware chip select | Yes | Yes |
MCSPI_TRANSFER_SETUP | Struct | Data structure containing the MCSPI parameters which can be changed at run time | Yes | Yes |
MCSPI_CALLBACK | Typedef | Defines the data type and function signature for the MCSPI peripheral callback function | No | Yes |
MCSPI_SLAVE_CALLBACK | Typedef | Pointer to a MCSPI Call back function when MCSPI is configued in slave mode | No | No |
MCSPI_SLAVE_ERROR | Macros and Typedef | Defines the macros and typedef associated with MCSPI slave mode errors | No | No |