/*! * @brief Fill up the TX FIFO with data. * This function fills up the TX FIFO with initial data for start of transfers where it will * first clear the transfer count. Otherwise, if the TX FIFO fill is part of an ongoing transfer * then do not clear the transfer count. The param "isInitialData" is used to determine if this * is an initial data fill. * This is not a public API as it is called from other driver functions. */ static void DSPI_DRV_MasterFillupTxFifo(uint32_t instance) { /* instantiate local variable of type dspi_master_state_t and point to global state */ dspi_master_state_t * dspiState = (dspi_master_state_t *)g_dspiStatePtr[instance]; SPI_Type *base = g_dspiBase[instance]; dspi_command_config_t command; /* create an instance of the data command struct*/ uint32_t cmd; /* Command word to be OR'd with data word */ uint16_t wordToSend = 0; /* Declare variables for storing volatile data later in the code */ uint32_t remainingReceiveByteCount, remainingSendByteCount; /* Before sending the data, we first need to initialize the data command struct * Configure the data command attributes for the desired PCS, CTAR, and continuous PCS * which are derived from the run-time state struct */ command.whichPcs = dspiState->whichPcs; command.whichCtar = dspiState->whichCtar; command.isChipSelectContinuous = dspiState->isChipSelectContinuous; command.isEndOfQueue = 0; command.clearTransferCount = 0; /* "Build" the command word. Only do this once since the commad word members don't * change until the last word sent (which is when the end of queue flag gets set). */ cmd = DSPI_HAL_GetFormattedCommand(base, &command); /* Store the DSPI state struct volatile member variables into temporary * non-volatile variables to allow for MISRA compliant calculations */ remainingSendByteCount = dspiState->remainingSendByteCount; remainingReceiveByteCount = dspiState->remainingReceiveByteCount; /* Architectural note: When developing the TX FIFO fill functionality, it was found that to * achieve more efficient run-time performance, it was better to first check the bits/frame * setting and then proceed with the FIFO fill management process, rather than to clutter the * FIFO fill process with continual checks of the bits/frame setting. */ /* If bits/frame is greater than one byte */ if (dspiState->bitsPerFrame > 8) { /* Fill the fifo until it is full or until the send word count is 0 or until the difference * between the remainingReceiveByteCount and remainingSendByteCount equals the FIFO depth. * The reason for checking the difference is to ensure we only send as much as the * RX FIFO can receive. * For this case where bitsPerFrame > 8, each entry in the FIFO contains 2 bytes of the * send data, hence the difference between the remainingReceiveByteCount and * remainingSendByteCount must be divided by 2 to convert this difference into a * 16-bit (2 byte) value. */ while((DSPI_HAL_GetStatusFlag(base, kDspiTxFifoFillRequest) == 1) && ((remainingReceiveByteCount - remainingSendByteCount)/2 < g_dspiFifoSize[instance])) { /* On the last word to be sent, set the end of queue flag in the data command struct * and ensure that the CONT bit in the PUSHR is also cleared even if it was cleared to * begin with. If CONT is set it means continuous chip select operation and to ensure * the chip select is de-asserted, this bit must be cleared on the last data word. */ if (dspiState->remainingSendByteCount == 2) { command.isEndOfQueue = 1; command.isChipSelectContinuous = 0; cmd = DSPI_HAL_GetFormattedCommand(base, &command); /* If there is an extra byte to send due to an odd byte count, prepare the final * wordToSend here */ if (dspiState->sendBuffer) { if (dspiState->extraByte) { wordToSend = *(dspiState->sendBuffer); } else { wordToSend = *(dspiState->sendBuffer); ++dspiState->sendBuffer; /* increment to next data byte */ wordToSend |= (unsigned)(*(dspiState->sendBuffer)) << 8U; } } } /* For all words except the last word */ else { /* If a send buffer was provided, the word comes from there. Otherwise we just send * a zero (initialized above). */ if (dspiState->sendBuffer) { wordToSend = *(dspiState->sendBuffer); ++dspiState->sendBuffer; /* increment to next data byte */ wordToSend |= (unsigned)(*(dspiState->sendBuffer)) << 8U; ++dspiState->sendBuffer; /* increment to next data byte */ } } DSPI_HAL_WriteCmdDataMastermode(base, cmd|wordToSend); /* Try to clear the TFFF; if the TX FIFO is full this will clear */ DSPI_HAL_ClearStatusFlag(base, kDspiTxFifoFillRequest); dspiState->remainingSendByteCount -= 2; /* decrement remainingSendByteCount by 2 */ /* exit loop if send count is zero, else update local variables for next loop */ if (dspiState->remainingSendByteCount == 0) { break; } else { /* Store the DSPI state struct volatile member variables into temporary * non-volatile variables to allow for MISRA compliant calculations */ remainingSendByteCount = dspiState->remainingSendByteCount; } } /* End of TX FIFO fill while loop */ } /* Optimized for bits/frame less than or equal to one byte. */ else { /* Fill the fifo until it is full or until the send word count is 0 or until the difference * between the remainingReceiveByteCount and remainingSendByteCount equals the FIFO depth. * The reason for checking the difference is to ensure we only send as much as the * RX FIFO can receive. */ while((DSPI_HAL_GetStatusFlag(base, kDspiTxFifoFillRequest) == 1) && ((remainingReceiveByteCount - remainingSendByteCount) < g_dspiFifoSize[instance])) { /* On the last word to be sent, set the end of queue flag in the data command struct * and ensure that the CONT bit in the PUSHR is also cleared even if it was cleared to * begin with. If CONT is set it means continuous chip select operation and to ensure * the chip select is de-asserted, this bit must be cleared on the last data word. */ if (dspiState->remainingSendByteCount == 1) { command.isEndOfQueue = 1; command.isChipSelectContinuous = 0; cmd = DSPI_HAL_GetFormattedCommand(base, &command); } /* If a send buffer was provided, the word comes from there. Otherwise we just send * a zero (initialized above). */ if (dspiState->sendBuffer) { wordToSend = *(dspiState->sendBuffer); ++dspiState->sendBuffer; /* increment to next data word*/ } DSPI_HAL_WriteCmdDataMastermode(base, cmd|wordToSend); /* Try to clear the TFFF; if the TX FIFO is full this will clear */ DSPI_HAL_ClearStatusFlag(base, kDspiTxFifoFillRequest); --dspiState->remainingSendByteCount; /* decrement remainingSendByteCount*/ /* exit loop if send count is zero, else update local variables for next loop */ if (dspiState->remainingSendByteCount == 0) { break; } else { /* Store the DSPI state struct volatile member variables into temporary * non-volatile variables to allow for MISRA compliant calculations */ remainingSendByteCount = dspiState->remainingSendByteCount; } } /* End of TX FIFO fill while loop */ } }
uint16_t SpiInOut(Spi_t *obj, uint16_t outData) { uint16_t data = 0x00; if ((obj == NULL) || (obj->Spi) == NULL) { while (1) ; } if (obj->isSlave) { } else { dspi_command_config_t commandConfig = { .isChipSelectContinuous = false, .whichCtar = kDspiCtar0, .whichPcs = kDspiPcs0, .clearTransferCount = true, .isEndOfQueue = false }; if (outData != 0x00) { // Restart the transfer by stop then start again, this will clear out the shift register DSPI_HAL_StopTransfer(obj->Spi); // Flush the FIFOs DSPI_HAL_SetFlushFifoCmd(obj->Spi, true, true); // Clear status flags that may have been set from previous transfers. DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiTxComplete); DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiEndOfQueue); DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiTxFifoUnderflow); DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiTxFifoFillRequest); DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiRxFifoOverflow); DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiRxFifoDrainRequest); // Clear the transfer count. DSPI_HAL_PresetTransferCount(obj->Spi, 0); // Start the transfer process in the hardware DSPI_HAL_StartTransfer(obj->Spi); // Send the data to slave. // Write data to PUSHR DSPI_HAL_WriteDataMastermode(obj->Spi, &commandConfig, outData); } else { // Restart the transfer by stop then start again, this will clear out the shift register DSPI_HAL_StopTransfer(obj->Spi); // Flush the FIFOs DSPI_HAL_SetFlushFifoCmd(obj->Spi, true, true); //Clear status flags that may have been set from previous transfers. DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiTxComplete); DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiEndOfQueue); DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiTxFifoUnderflow); DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiTxFifoFillRequest); DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiRxFifoOverflow); DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiRxFifoDrainRequest); // Clear the transfer count. DSPI_HAL_PresetTransferCount(obj->Spi, 0); // Start the transfer process in the hardware DSPI_HAL_StartTransfer(obj->Spi); // Write command to PUSHR. DSPI_HAL_WriteDataMastermode(obj->Spi, &commandConfig, 0); // Check RFDR flag while (DSPI_HAL_GetStatusFlag(obj->Spi, kDspiRxFifoDrainRequest) == false) { } // Read data from POPR data = DSPI_HAL_ReadData(obj->Spi); // Clear RFDR flag DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiRxFifoDrainRequest); } } return data; }
/*! * @brief Initiate (start) a transfer. This is not a public API as it is called from other * driver functions */ static dspi_status_t DSPI_DRV_MasterStartTransfer(uint32_t instance, const dspi_device_t * device) { /* instantiate local variable of type dspi_master_state_t and point to global state */ dspi_master_state_t * dspiState = (dspi_master_state_t *)g_dspiStatePtr[instance]; SPI_Type *base = g_dspiBase[instance]; uint32_t calculatedBaudRate; /* Check that we're not busy.*/ if (dspiState->isTransferInProgress) { return kStatus_DSPI_Busy; } /* Configure bus for this device. If NULL is passed, we assume the caller has * preconfigured the bus using DSPI_DRV_MasterConfigureBus(). * Do nothing for calculatedBaudRate. If the user wants to know the calculatedBaudRate * then they can call this function separately. */ if (device) { DSPI_DRV_MasterConfigureBus(instance, device, &calculatedBaudRate); dspiState->bitsPerFrame = device->dataBusConfig.bitsPerFrame;/*update dspiState bits/frame*/ } /* Check the transfer byte count. If bits/frame > 8, meaning 2 bytes and if * the transfer byte count is an odd count we'll have to increase the transfer byte count * by one and assert a flag to indicate to the send and receive functions that it will * need to handle an extra byte. */ if ((dspiState->bitsPerFrame > 8) && (dspiState->remainingSendByteCount & 1UL)) { dspiState->remainingSendByteCount += 1; dspiState->remainingReceiveByteCount += 1; dspiState->extraByte = true; } else { dspiState->extraByte = false; } /* Save information about the transfer for use by the ISR.*/ dspiState->isTransferInProgress = true; /* Restart the transfer by stop then start again, this will clear out the shift register */ DSPI_HAL_StopTransfer(base); /* flush the fifos*/ DSPI_HAL_SetFlushFifoCmd(base, true, true); /* Clear status flags that may have been set from previous transfers */ DSPI_HAL_ClearStatusFlag(base, kDspiTxComplete); DSPI_HAL_ClearStatusFlag(base, kDspiEndOfQueue); DSPI_HAL_ClearStatusFlag(base, kDspiTxFifoUnderflow); DSPI_HAL_ClearStatusFlag(base, kDspiTxFifoFillRequest); DSPI_HAL_ClearStatusFlag(base, kDspiRxFifoOverflow); DSPI_HAL_ClearStatusFlag(base, kDspiRxFifoDrainRequest); /* Clear the transfer count */ DSPI_HAL_PresetTransferCount(base, 0); /* Start the transfer, make sure to do this before filling the FIFO */ DSPI_HAL_StartTransfer(base); /* Fill up the DSPI FIFO (even if one word deep, data still written to data buffer) */ DSPI_DRV_MasterFillupTxFifo(instance); /* RX FIFO Drain request: RFDF_RE to enable RFDF interrupt * Since SPI is a synchronous interface, we only need to enable the RX interrupt. * The IRQ handler will get the status of RX and TX interrupt flags. */ DSPI_HAL_SetRxFifoDrainDmaIntMode(base, kDspiGenerateIntReq, true); return kStatus_DSPI_Success; }
/*FUNCTION********************************************************************** * * Function Name : DSPI_DRV_SlaveIRQHandler * Description : DSPI Slave Generic IRQ handler. * * This handler check errors of driver and it puts data into Tx FIFO, gets data * from Rx FIFO whenever data transmitting/received. * *END**************************************************************************/ void DSPI_DRV_SlaveIRQHandler(uint32_t instance) { SPI_Type *base = g_dspiBase[instance]; dspi_slave_state_t *dspiState = (dspi_slave_state_t *)g_dspiStatePtr[instance]; uint8_t nBytes; /* Calculate number of bytes in a frame */ nBytes = dspiState->bitsPerFrame >> 3; /* Number of bytes is bits/frame divide 8 */ if ((dspiState->bitsPerFrame & 0x07) != 0) /* Bits/frame module 8 is not zero */ { nBytes += 1; } /* Because SPI protocol is synchronous, the number of bytes that that slave received from the * master is the actual number of bytes that the slave transmitted to the master. So we only * monitor the received size to know when the transfer is complete. */ if (dspiState->remainingReceiveByteCount > 0) { /* Read data if remaining receive byte > 0 */ uint32_t dataReceived; uint32_t dataSend = 0; while (DSPI_HAL_GetStatusFlag(base, kDspiRxFifoDrainRequest)) { /* Have received data in the buffer. */ dataReceived = DSPI_HAL_ReadData(base); /* clear the rx fifo drain request, needed for non-DMA applications as this flag * will remain set even if the rx fifo is empty. By manually clearing this flag, it * either remain clear if no more data is in the fifo, or it will set if there is * more data in the fifo. */ DSPI_HAL_ClearStatusFlag(base, kDspiRxFifoDrainRequest); /* If bits/frame is one byte */ if (nBytes == 1) { if (dspiState->receiveBuffer) { /* Receive buffer is not null, store data into it */ *dspiState->receiveBuffer = dataReceived; ++dspiState->receiveBuffer; } if (dspiState->sendBuffer) { dataSend = *dspiState->sendBuffer; ++dspiState->sendBuffer; } /* Descrease remaining receive byte count */ --dspiState->remainingReceiveByteCount; --dspiState->remainingSendByteCount; } /* If bits/frame is 2 bytes */ else { /* With multibytes frame receiving, we only receive till the received size * matches user request. Other bytes will be ignored. */ if (dspiState->receiveBuffer) { /* Receive buffer is not null, store first byte into it */ *dspiState->receiveBuffer = dataReceived; ++dspiState->receiveBuffer; if (--dspiState->remainingReceiveByteCount > 0) { /* Receive buffer is not null, store second byte into it */ *dspiState->receiveBuffer = dataReceived >> 8; ++dspiState->receiveBuffer; } /* Decrease remaining receive byte count */ --dspiState->remainingReceiveByteCount; } else {