int Spi::sync() { uint32_t timer; int res = 0; if (!m_autoSlaveSelect) return 0; SSP_IntConfig(LPC_SSP1, SSP_INTCFG_RX, DISABLE); setTimer(&timer); while(1) { if(checkIdle()) { res = 1; break; } if (getTimer(timer)>500000) // timeout .5 seconds break; } SSP_IntConfig(LPC_SSP1, SSP_INTCFG_RX, ENABLE); return res; }
Spi::Spi(SerialCallback callback) : m_rq(SPI_RECEIVEBUF_SIZE), m_tq(SPI_TRANSMITBUF_SIZE, callback) { uint32_t i; volatile uint32_t d; SSP_CFG_Type configStruct; configStruct.CPHA = SSP_CPHA_FIRST; configStruct.CPOL = SSP_CPOL_HI; configStruct.ClockRate = 204000000; configStruct.Databit = SSP_DATABIT_16; configStruct.Mode = SSP_SLAVE_MODE; configStruct.FrameFormat = SSP_FRAME_SPI; // Initialize SSP peripheral with parameter given in structure above SSP_Init(LPC_SSP1, &configStruct); // clear receive fifo for (i=0; i<8; i++) d = LPC_SSP1->DR; // Enable SSP peripheral SSP_Cmd(LPC_SSP1, ENABLE); SSP_ClearIntPending(LPC_SSP1, SSP_INTCFG_RX); SSP_IntConfig(LPC_SSP1, SSP_INTCFG_RX, ENABLE); NVIC_SetPriority(SSP1_IRQn, 0); // high priority interrupt m_sync = false; m_recvCounter = 0; m_lastRecvCounter = 0; m_syncCounter = 0; setAutoSlaveSelect(false); }
void spi_init() { uint32_t i; volatile uint32_t d; SSP_CFG_Type configStruct; g_receive.m_buf = new uint16_t[SPI_RECEIVEBUF_SIZE]; g_receive.m_read = 0; g_receive.m_write = 0; g_receive.m_produced = 0; g_receive.m_consumed = 0; g_transmit.m_buf = new uint16_t[SPI_TRANSMITBUF_SIZE]; g_transmit.m_read = 0; g_transmit.m_len = 0; g_transmit.m_callback = (TransmitCallback)NULL; configStruct.CPHA = SSP_CPHA_FIRST; configStruct.CPOL = SSP_CPOL_HI; configStruct.ClockRate = 204000000; configStruct.Databit = SSP_DATABIT_16; configStruct.Mode = SSP_SLAVE_MODE; configStruct.FrameFormat = SSP_FRAME_SPI; // Initialize SSP peripheral with parameter given in structure above SSP_Init(LPC_SSP1, &configStruct); // clear receive fifo for (i=0; i<8; i++) d = LPC_SSP1->DR; // Enable SSP peripheral SSP_Cmd(LPC_SSP1, ENABLE); SSP_ClearIntPending(LPC_SSP1, SSP_INTCFG_RT); SSP_IntConfig(LPC_SSP1, SSP_INTCFG_RT, ENABLE); // sync spi_sync(); // enable interrupt NVIC_SetPriority(SSP1_IRQn, 0); // high priority interrupt NVIC_EnableIRQ(SSP1_IRQn); }
portBASE_TYPE FreeRTOS_SSP_ioctl( Peripheral_Descriptor_t const pxPeripheral, uint32_t ulRequest, void *pvValue ) { Peripheral_Control_t * const pxPeripheralControl = ( Peripheral_Control_t * const ) pxPeripheral; uint32_t ulValue = ( uint32_t ) pvValue, ulInitSSP = pdFALSE; const int8_t cPeripheralNumber = diGET_PERIPHERAL_NUMBER( ( ( Peripheral_Control_t * const ) pxPeripheral ) ); LPC_SSP_TypeDef * pxSSP = ( LPC_SSP_TypeDef * ) diGET_PERIPHERAL_BASE_ADDRESS( ( ( Peripheral_Control_t * const ) pxPeripheral ) ); taskENTER_CRITICAL(); { switch( ulRequest ) { case ioctlUSE_INTERRUPTS : /* Sanity check the array index. */ configASSERT( cPeripheralNumber < ( int8_t ) ( sizeof( xIRQ ) / sizeof( IRQn_Type ) ) ); if( ulValue == pdFALSE ) { NVIC_DisableIRQ( xIRQ[ cPeripheralNumber ] ); } else { /* Enable the Rx interrupts only. New data is sent if an Rx interrupt makes space in the FIFO, so Tx interrupts are not required. */ SSP_IntConfig( LPC_SSP1, SSP_INTCFG_TX, DISABLE ); SSP_IntConfig( pxSSP, sspALL_SSP_RX_INTERRUPTS, ENABLE ); /* Enable the interrupt and set its priority to the minimum interrupt priority. A separate command can be issued to raise the priority if desired. */ NVIC_SetPriority( xIRQ[ cPeripheralNumber ], configSPI_INTERRUPT_PRIORITY ); NVIC_EnableIRQ( xIRQ[ cPeripheralNumber ] ); /* If the Rx is configured to use interrupts, remember the transfer control structure that should be used. A reference to the Tx transfer control structure is taken when a write() operation is actually performed. */ pxRxTransferControlStructs[ cPeripheralNumber ] = pxPeripheralControl->pxRxControl; } break; case ioctlSET_INTERRUPT_PRIORITY : /* The ISR uses ISR safe FreeRTOS API functions, so the priority being set must be lower than (ie numerically larger than) configMAX_LIBRARY_INTERRUPT_PRIORITY. */ configASSERT( ulValue < configMAX_LIBRARY_INTERRUPT_PRIORITY ); NVIC_SetPriority( xIRQ[ cPeripheralNumber ], ulValue ); break; case ioctlSET_SPEED : /* In Hz. */ xSSPConfigurations[ cPeripheralNumber ].ClockRate = ulValue; ulInitSSP = pdTRUE; break; case ioctlSET_SPI_DATA_BITS : /* 4 to 16. */ xSSPConfigurations[ cPeripheralNumber ].Databit = ulValue; ulInitSSP = pdTRUE; break; case ioctlSET_SPI_CLOCK_PHASE : /* SSP_CPHA_FIRST or SSPCPHA_SECOND */ xSSPConfigurations[ cPeripheralNumber ].CPHA = ulValue; ulInitSSP = pdTRUE; break; case ioctlSET_SPI_CLOCK_POLARITY : /* SSP_CPOL_HI or SSP_CPOL_LO. */ xSSPConfigurations[ cPeripheralNumber ].CPOL = ulValue; break; case ioctlSET_SPI_MODE : /* SSP_MASTER_MODE or SSP_SLAVE_MODE. */ xSSPConfigurations[ cPeripheralNumber ].Mode = ulValue; break; case ioctlSET_SSP_FRAME_FORMAT : /* SSP_FRAME_SPI or SSP_FRAME_TI or SSP_FRAME_MICROWIRE. */ xSSPConfigurations[ cPeripheralNumber ].FrameFormat = ulValue; break; } if( ulInitSSP == pdTRUE ) { SSP_Cmd( pxSSP, DISABLE ); SSP_DeInit( pxSSP ); SSP_Init( pxSSP, &( xSSPConfigurations[ cPeripheralNumber ] ) ); SSP_Cmd( pxSSP, ENABLE ); } } taskEXIT_CRITICAL(); return pdPASS; }
size_t FreeRTOS_SSP_read( Peripheral_Descriptor_t const pxPeripheral, void * const pvBuffer, const size_t xBytes ) { Peripheral_Control_t * const pxPeripheralControl = ( Peripheral_Control_t * const ) pxPeripheral; size_t xReturn = 0U; LPC_SSP_TypeDef * const pxSSP = ( LPC_SSP_TypeDef * const ) diGET_PERIPHERAL_BASE_ADDRESS( ( ( Peripheral_Control_t * const ) pxPeripheral ) ); SSP_DATA_SETUP_Type *pxSSPTransferDefinition; const int8_t cPeripheralNumber = diGET_PERIPHERAL_NUMBER( ( ( Peripheral_Control_t * const ) pxPeripheral ) ); /* Sanity check the array index. */ configASSERT( cPeripheralNumber < ( int8_t ) ( sizeof( xIRQ ) / sizeof( IRQn_Type ) ) ); switch( diGET_RX_TRANSFER_TYPE( pxPeripheralControl ) ) { case ioctlUSE_POLLED_RX : #if ioconfigUSE_SSP_POLLED_RX == 1 { /* Configure the transfer data. No semaphore or queue is used here, so the application must ensure only one task attempts to make a polling read at a time. *NOTE* the Tx transfer state is used, as the SSP requires a Tx to occur for any data to be received. */ pxSSPTransferDefinition = ( SSP_DATA_SETUP_Type * ) diGET_TX_TRANSFER_STATE( pxPeripheralControl ); configASSERT( pxSSPTransferDefinition ); pxSSPTransferDefinition->tx_data = NULL; pxSSPTransferDefinition->rx_data = ( void * ) pvBuffer; pxSSPTransferDefinition->length = ( uint32_t ) xBytes; xReturn = SSP_ReadWrite( pxSSP, pxSSPTransferDefinition, SSP_TRANSFER_POLLING ); } #endif /* ioconfigUSE_SSP_POLLED_RX */ break; case ioctlUSE_CIRCULAR_BUFFER_RX : /* _RB_ This relies on Tx being configured to zero copy mode. */ #if ioconfigUSE_SSP_CIRCULAR_BUFFER_RX == 1 { /* There is nothing to prevent multiple tasks attempting to read the circular buffer at any one time. The implementation of the circular buffer uses a semaphore to indicate when new data is available, and the semaphore will ensure that only the highest priority task that is attempting a read will actually receive bytes. */ /* A write is performed first, to generate the clock required to clock the data in. NULL is passed as the source buffer as there isn't actually any data to send, and NULL will just result in 0xff being sent. When the data written to the FIFO has been transmitted an Rx interrupt will copy the received data into the circular buffer, and check to see if there is more data to be written. */ /* Ensure the last Tx has completed. */ xReturn = xIOUtilsGetZeroCopyWriteMutex( pxPeripheralControl, ioctlOBTAIN_WRITE_MUTEX, ioutilsDEFAULT_ZERO_COPY_TX_MUTEX_BLOCK_TIME ); configASSERT( xReturn ); if( xReturn == pdPASS ) { /* Empty whatever is lingering in the Rx buffer (there shouldn't be any. */ vIOUtilsClearRxCircularBuffer( pxPeripheralControl ); /* Data should be received during the following write. */ ulReceiveActive[ cPeripheralNumber ] = pdTRUE; /* Write to solicit received data. */ FreeRTOS_SSP_write( pxPeripheralControl, NULL, xBytes ); /* This macro will continuously wait on the new data mutex, reading bytes from the circular buffer each time it receives it, until the desired number of bytes have been read. */ ioutilsRECEIVE_CHARS_FROM_CIRCULAR_BUFFER ( pxPeripheralControl, SSP_IntConfig( pxSSP, sspRX_DATA_AVAILABLE_INTERRUPTS, DISABLE ), /* Disable interrupt. */ SSP_IntConfig( pxSSP, sspRX_DATA_AVAILABLE_INTERRUPTS, ENABLE ), /* Enable interrupt. */ ( ( uint8_t * ) pvBuffer ), /* Data destination. */ xBytes, /* Bytes to read. */ xReturn /* Number of bytes read. */ ); /* Not expecting any more Rx data now, so just junk anything that is received until the next explicit read is performed. */ ulReceiveActive[ cPeripheralNumber ] = pdFALSE; } } #endif break; case ioctlUSE_CHARACTER_QUEUE_RX : /* The queue allows multiple tasks to attempt to read bytes, but ensures only the highest priority of these tasks will actually receive bytes. If two tasks of equal priority attempt to read simultaneously, then the application must ensure mutual exclusion, as time slicing could result in the string being received being partially received by each task. */ #if ioconfigUSE_SSP_RX_CHAR_QUEUE == 1 { /* Ensure the last Tx has completed. */ xIOUtilsWaitTxQueueEmpty( pxPeripheralControl, boardDEFAULT_READ_MUTEX_TIMEOUT ); /* Clear any residual data - there shouldn't be any! */ xIOUtilsClearRxCharQueue( pxPeripheralControl ); /* Data should be received during the following write. */ ulReceiveActive[ cPeripheralNumber ] = pdTRUE; /* Write to solicit received data. */ FreeRTOS_SSP_write( pxPeripheralControl, NULL, xBytes ); /* Read the received data placed in the Rx queue by the interrupt. */ xReturn = xIOUtilsReceiveCharsFromRxQueue( pxPeripheralControl, ( uint8_t * ) pvBuffer, xBytes ); /* Not expecting any more Rx data now, so just junk anything that is received until the next explicit read is performed. */ ulReceiveActive[ cPeripheralNumber ] = pdFALSE; } #endif break; default : /* Other methods can be implemented here. */ configASSERT( xReturn ); /* Prevent compiler warnings when the configuration is set such that the following parameters are not used. */ ( void ) pvBuffer; ( void ) xBytes; ( void ) pxSSP; ( void ) pxSSPTransferDefinition; ( void ) cPeripheralNumber; break; } return xReturn; }
size_t FreeRTOS_SSP_write( Peripheral_Descriptor_t const pxPeripheral, const void *pvBuffer, const size_t xBytes ) { Peripheral_Control_t * const pxPeripheralControl = ( Peripheral_Control_t * const ) pxPeripheral; size_t xReturn = 0U; LPC_SSP_TypeDef * const pxSSP = ( LPC_SSP_TypeDef * const ) diGET_PERIPHERAL_BASE_ADDRESS( ( ( Peripheral_Control_t * const ) pxPeripheral ) ); SSP_DATA_SETUP_Type *pxSSPTransferDefinition; const uint32_t ulPeripheralNumber = ( uint32_t ) diGET_PERIPHERAL_NUMBER( ( ( Peripheral_Control_t * const ) pxPeripheral ) ); /* Remember which transfer control structure is being used, so if an interrupt is being used, it can continue the same transfer until all data has been transmitted. */ pxTxTransferControlStructs[ ulPeripheralNumber ] = diGET_TX_TRANSFER_STRUCT( pxPeripheralControl ); switch( diGET_TX_TRANSFER_TYPE( pxPeripheralControl ) ) { case ioctlUSE_POLLED_TX : #if ioconfigUSE_SSP_POLLED_TX == 1 { /* Configure the transfer data. No semaphore or queue is used here, so the application must ensure only one task attempts to make a polling write at a time. */ pxSSPTransferDefinition = ( SSP_DATA_SETUP_Type * ) diGET_TX_TRANSFER_STATE( pxPeripheralControl ); configASSERT( pxSSPTransferDefinition ); pxSSPTransferDefinition->tx_data = ( void * ) pvBuffer; pxSSPTransferDefinition->rx_data = NULL; pxSSPTransferDefinition->length = ( uint32_t ) xBytes; xReturn = SSP_ReadWrite( pxSSP, pxSSPTransferDefinition, SSP_TRANSFER_POLLING ); } #endif /* ioconfigUSE_SSP_POLLED_TX */ /* The transfer struct is set back to NULL as the Tx is complete before the above call to SSP_ReadWrite() completes. */ pxTxTransferControlStructs[ ulPeripheralNumber ] = NULL; break; case ioctlUSE_ZERO_COPY_TX : #if ioconfigUSE_SSP_ZERO_COPY_TX == 1 { /* The implementation of the zero copy write uses a semaphore to indicate whether a write is complete (and so the buffer being written free again) or not. The semantics of using a zero copy write dictate that a zero copy write can only be attempted by a task, once the semaphore has been successfully obtained by that task. This ensure that only one task can perform a zero copy write at any one time. Ensure the semaphore is not currently available, if this function has been called without it being obtained first then it is an error. */ configASSERT( xIOUtilsGetZeroCopyWriteMutex( pxPeripheralControl, ioctlOBTAIN_WRITE_MUTEX, 0U ) == 0 ); xReturn = xBytes; ioutilsINITIATE_ZERO_COPY_TX ( pxPeripheralControl, SSP_IntConfig( pxSSP, sspRX_DATA_AVAILABLE_INTERRUPTS, DISABLE ), /* Disable interrupt. */ SSP_IntConfig( pxSSP, sspRX_DATA_AVAILABLE_INTERRUPTS, ENABLE ), /* Enable interrupt. */ prvFillFifoFromBuffer( pxSSP, ( uint8_t ** ) &( pvBuffer ), xBytes ), /* Write to peripheral function. The buffer is passed in by address as the pointer is incremented. */ pvBuffer, /* Data source. */ xReturn /* Number of bytes to be written. This will get set to zero if the write mutex is not held. */ ); } #endif /* ioconfigUSE_SSP_ZERO_COPY_TX */ /* Remove compiler warnings in case the above is #defined out. */ ( void ) prvFillFifoFromBuffer; break; case ioctlUSE_CHARACTER_QUEUE_TX : #if ioconfigUSE_SSP_TX_CHAR_QUEUE == 1 { /* The queue allows multiple tasks to attempt to write bytes, but ensures only the highest priority of these tasks will actually succeed. If two tasks of equal priority attempt to write simultaneously, then the application must ensure mutual exclusion, as time slicing could result in the strings being sent to the queue becoming interleaved. */ xReturn = xIOUtilsSendCharsToTxQueue( pxPeripheralControl, ( ( uint8_t * ) pvBuffer ), xBytes ); ioutilsFILL_FIFO_FROM_TX_QUEUE( pxPeripheralControl, SSP_IntConfig( pxSSP, sspRX_DATA_AVAILABLE_INTERRUPTS, DISABLE ), /* Disable Rx interrupt. */ SSP_IntConfig( pxSSP, sspRX_DATA_AVAILABLE_INTERRUPTS, ENABLE ), /* Enable Rx interrupt. */ sspMAX_FIFO_DEPTH, /* Bytes to write to the FIFO. */ ( pxSSP->SR & SSP_STAT_TXFIFO_NOTFULL ) != 0UL, /* FIFO not full. */ pxSSP->DR = SSP_DR_BITMASK( ucChar ) ); /* Tx function. */ } #endif /* ioconfigUSE_SSP_RX_CHAR_QUEUE */ break; default : /* Other methods can be implemented here. For now, set the stored Tx structure back to NULL as nothing is being sent. */ pxTxTransferControlStructs[ ulPeripheralNumber ] = NULL; configASSERT( xReturn ); /* Prevent compiler warnings when the configuration is set such that the following parameters are not used. */ ( void ) pvBuffer; ( void ) xBytes; ( void ) pxSSP; ( void ) pxSSPTransferDefinition; break; } return xReturn; }
/*********************************************************************//** * @brief SSP0 Interrupt used for reading and writing handler * @param None * @return None ***********************************************************************/ void SSP0_IRQHandler(void) { SSP_DATA_SETUP_Type *xf_setup; uint16_t tmp; uint8_t dataword; // Disable all SSP interrupts SSP_IntConfig(LPC_SSP0, SSP_INTCFG_ROR|SSP_INTCFG_RT|SSP_INTCFG_RX|SSP_INTCFG_TX, DISABLE); if(SSP_GetDataSize(LPC_SSP0)>8) dataword = 1; else dataword = 0; xf_setup = &xferConfig; // save status tmp = SSP_GetRawIntStatusReg(LPC_SSP0); xf_setup->status = tmp; // Check overrun error if (tmp & SSP_RIS_ROR){ // Clear interrupt SSP_ClearIntPending(LPC_SSP0, SSP_INTCLR_ROR); // update status xf_setup->status |= SSP_STAT_ERROR; // Set Complete Flag complete = SET; return; } if ((xf_setup->tx_cnt != xf_setup->length) || (xf_setup->rx_cnt != xf_setup->length)){ /* check if RX FIFO contains data */ while ((SSP_GetStatus(LPC_SSP0, SSP_STAT_RXFIFO_NOTEMPTY)) && (xf_setup->rx_cnt != xf_setup->length)){ // Read data from SSP data tmp = SSP_ReceiveData(LPC_SSP0); // Store data to destination if (xf_setup->rx_data != NULL) { if (dataword == 0){ *(uint8_t *)((uint32_t)xf_setup->rx_data + xf_setup->rx_cnt) = (uint8_t) tmp; } else { *(uint16_t *)((uint32_t)xf_setup->rx_data + xf_setup->rx_cnt) = (uint16_t) tmp; } } // Increase counter if (dataword == 0){ xf_setup->rx_cnt++; } else { xf_setup->rx_cnt += 2; } } while ((SSP_GetStatus(LPC_SSP0, SSP_STAT_TXFIFO_NOTFULL)) && (xf_setup->tx_cnt != xf_setup->length)){ // Write data to buffer if(xf_setup->tx_data == NULL){ if (dataword == 0){ SSP_SendData(LPC_SSP0, 0xFF); xf_setup->tx_cnt++; } else { SSP_SendData(LPC_SSP0, 0xFFFF); xf_setup->tx_cnt += 2; } } else { if (dataword == 0){ SSP_SendData(LPC_SSP0, (*(uint8_t *)((uint32_t)xf_setup->tx_data + xf_setup->tx_cnt))); xf_setup->tx_cnt++; } else { SSP_SendData(LPC_SSP0, (*(uint16_t *)((uint32_t)xf_setup->tx_data + xf_setup->tx_cnt))); xf_setup->tx_cnt += 2; } } // Check overrun error if (SSP_GetRawIntStatus(LPC_SSP0, SSP_INTSTAT_RAW_ROR)){ // update status xf_setup->status |= SSP_STAT_ERROR; // Set Complete Flag complete = SET; return; } // Check for any data available in RX FIFO while ((SSP_GetStatus(LPC_SSP0, SSP_STAT_RXFIFO_NOTEMPTY)) && (xf_setup->rx_cnt != xf_setup->length)){ // Read data from SSP data tmp = SSP_ReceiveData(LPC_SSP0); // Store data to destination if (xf_setup->rx_data != NULL) { if (dataword == 0){ *(uint8_t *)((uint32_t)xf_setup->rx_data + xf_setup->rx_cnt) = (uint8_t) tmp; } else { *(uint16_t *)((uint32_t)xf_setup->rx_data + xf_setup->rx_cnt) = (uint16_t) tmp; } } // Increase counter if (dataword == 0){ xf_setup->rx_cnt++; } else { xf_setup->rx_cnt += 2; } } } } // If there more data to sent or receive if ((xf_setup->rx_cnt != xf_setup->length) || (xf_setup->tx_cnt != xf_setup->length)){ // Enable all interrupt SSP_IntConfig(LPC_SSP0, SSP_INTCFG_ROR|SSP_INTCFG_RT|SSP_INTCFG_RX|SSP_INTCFG_TX, ENABLE); } else { // Save status xf_setup->status = SSP_STAT_DONE; // Set Complete Flag complete = SET; } }
/*********************************************************************//** * @brief SSP Slave Interrupt sub-routine used for reading * and writing handler * @param None * @return None ***********************************************************************/ void ssp_Slave_IntHandler(void) { uint16_t tmp; /* Clear all interrupt */ SSP_ClearIntPending(SSPDEV_S, SSP_INTCLR_ROR); SSP_ClearIntPending(SSPDEV_S, SSP_INTCLR_RT); /* check if RX FIFO contains data */ while (SSP_GetStatus(SSPDEV_S, SSP_STAT_RXFIFO_NOTEMPTY) == SET) { tmp = SSP_ReceiveData(SSPDEV_S); if ((pRdBuf_S!= NULL) && (RdIdx_S < DatLen_S)) { *(pRdBuf_S + RdIdx_S) = (uint8_t) tmp; } RdIdx_S++; } /* Check if TX FIFO is not full */ while ((SSP_GetStatus(SSPDEV_S, SSP_STAT_TXFIFO_NOTFULL) == SET) && (WrIdx_S < DatLen_S)) { /* check if RX FIFO contains data */ while (SSP_GetStatus(SSPDEV_S, SSP_STAT_RXFIFO_NOTEMPTY) == SET) { tmp = SSP_ReceiveData(SSPDEV_S); if ((pRdBuf_S!= NULL) && (RdIdx_S < DatLen_S)) { *(pRdBuf_S + RdIdx_S) = (uint8_t) tmp; } RdIdx_S++; } if (pWrBuf_S != NULL) { SSP_SendData(SSPDEV_S, (uint16_t)(*(pWrBuf_S + WrIdx_S))); } else { SSP_SendData(SSPDEV_S, IDLE_CHAR); } WrIdx_S++; } /* There're more data to send */ if (WrIdx_S < DatLen_S) { SSP_IntConfig(SSPDEV_S, SSP_INTCFG_TX, ENABLE); } /* Otherwise */ else { SSP_IntConfig(SSPDEV_S, SSP_INTCFG_TX, DISABLE); } /* There're more data to receive */ if (RdIdx_S < DatLen_S) { SSP_IntConfig(SSPDEV_S, SSP_INTCFG_ROR, ENABLE); SSP_IntConfig(SSPDEV_S, SSP_INTCFG_RT, ENABLE); SSP_IntConfig(SSPDEV_S, SSP_INTCFG_RX, ENABLE); } /* Otherwise */ else { SSP_IntConfig(SSPDEV_S, SSP_INTCFG_ROR, DISABLE); SSP_IntConfig(SSPDEV_S, SSP_INTCFG_RT, DISABLE); SSP_IntConfig(SSPDEV_S, SSP_INTCFG_RX, DISABLE); } /* Set Flag if both Read and Write completed */ if ((WrIdx_S == DatLen_S) && (RdIdx_S == DatLen_S)) { complete_S = TRUE; } }