/************************************************************************** * * Copyright (c) 2024-2024 Diality Inc. - All Rights Reserved. * * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * @file FPGA.c * * @author (last) Sean Nash * @date (last) 31-Jul-2024 * * @author (original) Sean Nash * @date (original) 31-Jul-2024 * ***************************************************************************/ #include // For memset(), memcpy() #include "sci.h" #include "sys_dma.h" #include "Comm.h" #include "Compatible.h" #include "FPGA.h" #ifdef _TD_ #include "FpgaTD.h" #include "OperationModes.h" #endif #ifdef _DD_ #include "FpgaDD.h" #include "OperationModes.h" #include "FPOperationModes.h" #endif #include "Messaging.h" #include "PersistentAlarm.h" #include "Timers.h" #include "Utilities.h" /** * @addtogroup FPGA * @{ */ // ********** private definitions ********** /// Enumeration of FPGA states. typedef enum FPGA_States { FPGA_STATE_START = 0, ///< Start state for the FPGA. FPGA_STATE_READ_HEADER, ///< Read header command state for the FPGA. FPGA_STATE_RCV_HEADER, ///< Receive header state for the FPGA. FPGA_STATE_WRITE_ALL_ACTUATORS, ///< Write actuators command state for the FPGA. FPGA_STATE_RCV_ALL_SENSORS, ///< Receive sensors state for the FPGA. FPGA_STATE_FAILED, ///< Failed state for the FPGA. NUM_OF_FPGA_STATES ///< Number of FPGA states. } FPGA_STATE_T; #define FPGA_PAGE_SIZE 512 ///< FPGA register pages are 256 bytes. #define FPGA_HEADER_START_ADDR 0x0000 ///< Start address for FPGA header data. #define FPGA_BULK_WRITE_START_ADDR 0x0004 ///< Start address for FPGA continuous priority writes. #define FPGA_BULK_READ_START_ADDR 0x0100 ///< Start address for FPGA continuous priority reads. #define FPGA_WRITE_CMD_BUFFER_LEN (FPGA_PAGE_SIZE+8) ///< FPGA write command buffer byte length. #define FPGA_READ_CMD_BUFFER_LEN 8 ///< FPGA read command buffer byte length. #define FPGA_WRITE_RSP_BUFFER_LEN 8 ///< FPGA write command response buffer byte length. #define FPGA_READ_RSP_BUFFER_LEN (FPGA_PAGE_SIZE+8) ///< FPGA read command response buffer byte length. #define FPGA_WRITE_CMD_CODE 0x55 ///< FPGA write command code. #define FPGA_READ_CMD_CODE 0x5A ///< FPGA read command code. #define FPGA_WRITE_CMD_ACK 0xA5 ///< FPGA write command ACK code. #define FPGA_READ_CMD_ACK 0xAA ///< FPGA read command ACK code. #define FPGA_CMD_NAK 0xEE ///< FPGA command NAK code. #define FPGA_CRC_LEN 2 ///< FPGA CRC byte length. #define FPGA_WRITE_CMD_HDR_LEN 4 ///< FPGA write command header byte length. #define FPGA_READ_CMD_HDR_LEN 4 ///< FPGA read command header byte length. #define FPGA_WRITE_RSP_HDR_LEN 3 ///< FPGA write command response header byte length. #define FPGA_READ_RSP_HDR_LEN 3 ///< FPGA read command response header byte length. #define SCI2_RECEIVE_DMA_REQUEST 28 ///< Serial port 2 receive DMA request line. #define SCI2_TRANSMIT_DMA_REQUEST 29 ///< Serial port 2 transmit DMA request line. #define FPGA_ADC1_AUTO_READ_ENABLE 0x01 ///< Auto-read enable bit for ADC1 control register. #define FPGA_BLOOD_LEAK_STATUS_MASK 0x1000 ///< Bit mask for blood leak detector. #define FPGA_BLOOD_LEAK_ST_BIT_INDEX 12 ///< Bit index for the blood leak self test status bit. #define FPGA_BLOOD_LEAK_ZERO_STATE_MASK 0x2000 ///< Bit mask for blood leak detector zero. #define FPAG_BLOOD_LEAK_ZERO_BIT_INDEX 13 ///< Bit index for the blood leak zero status bit. #define FPGA_BLOOD_LEAK_ZERO_CMD 0x02 ///< Bit for blood leak detector zero command. #define FPGA_BLOOD_LEAK_SELF_TEST_CMD 0x01 ///< Bit for blood leak detector self test command. // ********** private data ********** // FPGA state static FPGA_STATE_T fpgaState = FPGA_STATE_START; ///< Current FPGA state. static U32 fpgaReceiptCounter = 0; ///< FPGA response receipt counter. static U32 fpgaTransmitCounter = 0; ///< FPGA command transmit counter. static BOOL fpgaWriteCommandInProgress = FALSE; ///< Flag indicating an FPGA write command is in progress. static BOOL fpgaReadCommandInProgress = FALSE; ///< Flag indicating an FPGA read command is in progress. static BOOL fpgaBulkWriteAndReadInProgress = FALSE; ///< Flag indicating an FPGA bulk write and read command are in progress. static BOOL fpgaWriteCommandResponseReceived = FALSE; ///< Flag indicating a response to an FPGA write command has been received. static BOOL fpgaReadCommandResponseReceived = FALSE; ///< Flag indicating a response to an FPGA read command has been received. // FPGA comm buffers static U08 fpgaWriteCmdBuffer[ FPGA_WRITE_CMD_BUFFER_LEN ]; ///< FPGA write command buffer. Holds the next FPGA write command to be transmitted. static U08 fpgaReadCmdBuffer[ FPGA_READ_CMD_BUFFER_LEN ]; ///< FPGA read command buffer. Holds the next FPGA read command to be transmitted. static U08 fpgaWriteResponseBuffer[ FPGA_WRITE_RSP_BUFFER_LEN ]; ///< FPGA write command response buffer. Memory reserved to capture the response to the last FPGA write command. static U08 fpgaReadResponseBuffer[ FPGA_READ_RSP_BUFFER_LEN ]; ///< FPGA read command response buffer. Memory reserved to capture the response to the last FPGA read command. // DMA control records static g_dmaCTRL fpgaDMAWriteControlRecord; ///< DMA record for controlling a DMA write command transmission from buffer. static g_dmaCTRL fpgaDMAWriteRespControlRecord; ///< DMA record for controlling a DMA write command reception to buffer. static g_dmaCTRL fpgaDMAReadControlRecord; ///< DMA record for controlling a DMA read command transmission from buffer. static g_dmaCTRL fpgaDMAReadRespControlRecord; ///< DMA record for controlling a DMA read command reception to buffer. // FPGA data static U08* fpgaHeaderPtr; ///< Record of last received FPGA header data. static U08* fpgaSensorReadingsPtr; ///< Record of last received FPGA priority sensor data. static U08* fpgaActuatorSetPointsPtr; ///< Record of next transmitted FPGA priority actuator data. static U32 fpgaHeaderSize; ///< FPGA header record byte size. static U32 fpgaSensorReadingsSize; ///< FPGA sensor readings record byte size. static U32 fpgaActuatorSetPointsSize; ///< FPGA actuator set points record byte size. // ********** private function prototypes ********** static FPGA_STATE_T handleFPGAReadHeaderState( void ); static FPGA_STATE_T handleFPGAReceiveHeaderState( void ); static FPGA_STATE_T handleFPGAWriteAllActuatorsState( void ); static FPGA_STATE_T handleFPGAReceiveAllSensorsState( void ); static void resetFPGACommFlags( void ); static void setupDMAForWriteCmd( U32 bytes2Transmit ); static void startDMAWriteCmd( void ); static void setupDMAForWriteResp( U32 bytes2Receive ); static void startDMAReceiptOfWriteResp( void ); static void setupDMAForReadCmd( U32 bytes2Transmit ); static void startDMAReadCmd( void ); static void setupDMAForReadResp( U32 bytes2Receive ); static void startDMAReceiptOfReadResp( void ); static void consumeUnexpectedData( void ); static void monitorFPGAPowerStatus( void ); /*********************************************************************//** * @brief * The initFPGA function initializes the FPGA unit. * @details \b Inputs: none * @details \b Outputs: FPGA unit initialized. * @param hdr Pointer to the FPGA header register I/O map record. * @param sen Pointer to the FPGA sensor register I/O map record. * @param act Pointer to the FPGA actuator register I/O map record. * @param hdrSize Size (in bytes) of the FPGA header register I/O map record. * @param senSize Size (in bytes) of the FPGA sensor register I/O map record. * @param actSize Size (in bytes) of the FPGA actuator register I/O map record. * @return none *************************************************************************/ void initFPGA( U08* hdr, U08* sen, U08* act, U32 hdrSize, U32 senSize, U32 actSize ) { // Initialize fpga data structure pointers fpgaHeaderPtr = hdr; fpgaSensorReadingsPtr = sen; fpgaActuatorSetPointsPtr = act; fpgaHeaderSize = hdrSize; fpgaSensorReadingsSize = senSize; fpgaActuatorSetPointsSize = actSize; // initialize fpga comm buffers memset( &fpgaWriteCmdBuffer, 0, FPGA_WRITE_CMD_BUFFER_LEN ); memset( &fpgaReadCmdBuffer, 0, FPGA_READ_CMD_BUFFER_LEN ); memset( &fpgaWriteResponseBuffer, 0, FPGA_WRITE_RSP_BUFFER_LEN ); memset( &fpgaReadResponseBuffer, 0, FPGA_READ_RSP_BUFFER_LEN ); // Enable interrupt notifications for FPGA serial port sciEnableNotification( scilinREG, SCI_OE_INT | SCI_FE_INT ); // Assign DMA channels to h/w DMA requests dmaReqAssign( DMA_CH0, SCI2_RECEIVE_DMA_REQUEST ); dmaReqAssign( DMA_CH2, SCI2_TRANSMIT_DMA_REQUEST ); // Set DMA channel priorities dmaSetPriority( DMA_CH0, HIGHPRIORITY ); dmaSetPriority( DMA_CH2, LOWPRIORITY ); // Enable DMA block transfer complete interrupts dmaEnableInterrupt( DMA_CH0, BTC ); dmaEnableInterrupt( DMA_CH2, BTC ); // Initialize FPGA DMA Write Control Record fpgaDMAWriteControlRecord.PORTASGN = 4; // Port B (only choice per datasheet) fpgaDMAWriteControlRecord.SADD = (U32)fpgaWriteCmdBuffer; // Transfer source address fpgaDMAWriteControlRecord.DADD = (U32)(&(scilinREG->TD)); // Dest. is SCI2 xmit register fpgaDMAWriteControlRecord.CHCTRL = 0; // No chaining fpgaDMAWriteControlRecord.ELCNT = 1; // Frame is 1 element fpgaDMAWriteControlRecord.FRCNT = 0; // Block is TBD frames - will be populated later when known fpgaDMAWriteControlRecord.RDSIZE = ACCESS_8_BIT; // Element size is 1 byte for read fpgaDMAWriteControlRecord.WRSIZE = ACCESS_8_BIT; // Element size is 1 byte for write fpgaDMAWriteControlRecord.TTYPE = FRAME_TRANSFER; // Transfer type is block transfer fpgaDMAWriteControlRecord.ADDMODERD = ADDR_INC1; // Source addressing mode is post-increment fpgaDMAWriteControlRecord.ADDMODEWR = ADDR_FIXED; // Dest. addressing mode is fixed fpgaDMAWriteControlRecord.AUTOINIT = AUTOINIT_OFF; // Auto-init off fpgaDMAWriteControlRecord.ELSOFFSET = 0; // Not used fpgaDMAWriteControlRecord.ELDOFFSET = 0; // Not used fpgaDMAWriteControlRecord.FRSOFFSET = 0; // Not used fpgaDMAWriteControlRecord.FRDOFFSET = 0; // Not used // Initialize FPGA DMA Write Response Control Record fpgaDMAWriteRespControlRecord.PORTASGN = 4; // Port B (only choice per datasheet) fpgaDMAWriteRespControlRecord.SADD = (U32)(&(scilinREG->RD));// Source is SCI2 recv register fpgaDMAWriteRespControlRecord.DADD = (U32)fpgaWriteResponseBuffer; // Transfer destination address fpgaDMAWriteRespControlRecord.CHCTRL = 0; // No chaining fpgaDMAWriteRespControlRecord.ELCNT = 1; // Frame is 1 element fpgaDMAWriteRespControlRecord.FRCNT = 0; // Block is TBD frames - will be populated later when known fpgaDMAWriteRespControlRecord.RDSIZE = ACCESS_8_BIT; // Element size is 1 byte fpgaDMAWriteRespControlRecord.WRSIZE = ACCESS_8_BIT; // fpgaDMAWriteRespControlRecord.TTYPE = FRAME_TRANSFER; // Transfer type is block transfer fpgaDMAWriteRespControlRecord.ADDMODERD = ADDR_FIXED; // Source addressing mode is fixed fpgaDMAWriteRespControlRecord.ADDMODEWR = ADDR_INC1; // Dest. addressing mode is post-increment fpgaDMAWriteRespControlRecord.AUTOINIT = AUTOINIT_OFF; // Auto-init off fpgaDMAWriteRespControlRecord.ELDOFFSET = 0; // Not used fpgaDMAWriteRespControlRecord.ELSOFFSET = 0; // Not used fpgaDMAWriteRespControlRecord.FRDOFFSET = 0; // Not used fpgaDMAWriteRespControlRecord.FRSOFFSET = 0; // Not used // Initialize FPGA DMA Read Control Record fpgaDMAReadControlRecord.PORTASGN = 4; // Port B (only choice per datasheet) fpgaDMAReadControlRecord.SADD = (U32)fpgaReadCmdBuffer; // Transfer source address fpgaDMAReadControlRecord.DADD = (U32)(&(scilinREG->TD)); // Dest. is SCI2 xmit register fpgaDMAReadControlRecord.CHCTRL = 0; // No chaining fpgaDMAReadControlRecord.ELCNT = 1; // Frame is 1 element fpgaDMAReadControlRecord.FRCNT = 0; // Block is TBD frames - will be populated later when known fpgaDMAReadControlRecord.RDSIZE = ACCESS_8_BIT; // Element size is 1 byte fpgaDMAReadControlRecord.WRSIZE = ACCESS_8_BIT; // fpgaDMAReadControlRecord.TTYPE = FRAME_TRANSFER; // Transfer type is block transfer fpgaDMAReadControlRecord.ADDMODERD = ADDR_INC1; // Source addressing mode is post-increment fpgaDMAReadControlRecord.ADDMODEWR = ADDR_FIXED; // Dest. addressing mode is fixed fpgaDMAReadControlRecord.AUTOINIT = AUTOINIT_OFF; // Auto-init off fpgaDMAReadControlRecord.ELSOFFSET = 0; // Not used fpgaDMAReadControlRecord.ELDOFFSET = 0; // Not used fpgaDMAReadControlRecord.FRSOFFSET = 0; // Not used fpgaDMAReadControlRecord.FRDOFFSET = 0; // Not used // Initialize FPGA DMA Read Response Control Record fpgaDMAReadRespControlRecord.PORTASGN = 4; // Port B (only choice per datasheet) fpgaDMAReadRespControlRecord.SADD = (U32)(&(scilinREG->RD)); // Source is SCI2 recv register fpgaDMAReadRespControlRecord.DADD = (U32)fpgaReadResponseBuffer; // Transfer destination address fpgaDMAReadRespControlRecord.CHCTRL = 0; // No chaining fpgaDMAReadRespControlRecord.ELCNT = 1; // Frame is 1 element fpgaDMAReadRespControlRecord.FRCNT = 0; // Block is TBD frames - will be populated later when known fpgaDMAReadRespControlRecord.RDSIZE = ACCESS_8_BIT; // Element size is 1 byte fpgaDMAReadRespControlRecord.WRSIZE = ACCESS_8_BIT; // fpgaDMAReadRespControlRecord.TTYPE = FRAME_TRANSFER; // Transfer type is block transfer fpgaDMAReadRespControlRecord.ADDMODERD = ADDR_FIXED; // Source addressing mode is fixed fpgaDMAReadRespControlRecord.ADDMODEWR = ADDR_INC1; // Dest. addressing mode is post-increment fpgaDMAReadRespControlRecord.AUTOINIT = AUTOINIT_OFF; // Auto-init off fpgaDMAReadRespControlRecord.ELDOFFSET = 0; // Not used fpgaDMAReadRespControlRecord.ELSOFFSET = 0; // Not used fpgaDMAReadRespControlRecord.FRDOFFSET = 0; // Not used fpgaDMAReadRespControlRecord.FRSOFFSET = 0; // Not used // There should not be any data pending yet consumeUnexpectedData(); } /*********************************************************************//** * @brief * The resetFPGACommFlags function resets the various fpga comm flags and * counters. * @details \b Inputs: none * @details \b Outputs: fpga comm flags and counters reset * @return none *************************************************************************/ static void resetFPGACommFlags( void ) { fpgaWriteCommandResponseReceived = FALSE; fpgaReadCommandResponseReceived = FALSE; fpgaWriteCommandInProgress = FALSE; fpgaReadCommandInProgress = FALSE; fpgaBulkWriteAndReadInProgress = FALSE; fpgaTransmitCounter = 0; fpgaReceiptCounter = 0; } /*********************************************************************//** * @brief * The signalFPGAReceiptCompleted function increments a counter to indicate * that another DMA receipt from the FPGA has completed and sets comm flags * indicating pending response from FPGA is completed. * @details \b Inputs: none * @details \b Outputs: fpgaReceiptCounter, fpgaWriteCommandInProgress, * fpgaWriteCommandResponseReceived, fpgaReadCommandInProgress, * fpgaReadCommandResponseReceived, fpgaBulkWriteAndReadInProgress * @return none *************************************************************************/ void signalFPGAReceiptCompleted( void ) { fpgaReceiptCounter++; // Did FPGA Ack last command? if ( TRUE == fpgaWriteCommandInProgress ) { fpgaWriteCommandInProgress = FALSE; fpgaWriteCommandResponseReceived = TRUE; } else if ( TRUE == fpgaReadCommandInProgress ) { fpgaReadCommandInProgress = FALSE; fpgaReadCommandResponseReceived = TRUE; } // See if we want to follow up with a bulk read command if ( TRUE == fpgaBulkWriteAndReadInProgress ) { fpgaBulkWriteAndReadInProgress = FALSE; fpgaReadCommandInProgress = TRUE; // Initiate bulk read command startDMAReceiptOfReadResp(); startDMAReadCmd(); } } /*********************************************************************//** * @brief * The signalFPGATransmitCompleted function increments a counter to indicate * that another DMA transmit to the FPGA has completed. * @details \b Inputs: none * @details \b Outputs: fpgaTransmitCounter * @return none *************************************************************************/ void signalFPGATransmitCompleted( void ) { fpgaTransmitCounter++; } /*********************************************************************//** * @brief * The execFPGA function manages incoming data exchanges with the FPGA. * @details \b Alarm: ALARM_ID_XX_SOFTWARE_FAULT if current FPGA state is invalid. * @details \b Inputs: fpgaState * @details \b Outputs: fpgaState * @param in Flag indicating whether we are executing the in or out cycle of the state machine. * @return none *************************************************************************/ void execFPGA( BOOL in ) { if ( TRUE == in ) { // Check if FE or OE error has occurred checkFPGAFEOEFailure(); } // FPGA incoming state machine switch ( fpgaState ) { case FPGA_STATE_START: fpgaState = FPGA_STATE_READ_HEADER; break; case FPGA_STATE_RCV_HEADER: fpgaState = handleFPGAReceiveHeaderState(); break; case FPGA_STATE_RCV_ALL_SENSORS: fpgaState = handleFPGAReceiveAllSensorsState(); break; case FPGA_STATE_READ_HEADER: fpgaState = handleFPGAReadHeaderState(); break; case FPGA_STATE_WRITE_ALL_ACTUATORS: fpgaState = handleFPGAWriteAllActuatorsState(); break; case FPGA_STATE_FAILED: // Do nothing - we will be stuck here break; default: #ifdef _TD_ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_INVALID_STATE, fpgaState ) #endif #ifdef _DD_ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_INVALID_STATE, fpgaState ) #endif break; } if ( TRUE == in ) { // Reset comm flags after processing incoming responses resetFPGACommFlags(); // Monitor the power status monitorFPGAPowerStatus(); } } /*********************************************************************//** * @brief * The handleFPGAReadHeaderState function handles the FPGA state where * the read FPGA header registers command is sent to the FPGA. * @details \b Inputs: none * @details \b Outputs: read header command transmit to FPGA is initiated * @return next FPGA state *************************************************************************/ static FPGA_STATE_T handleFPGAReadHeaderState( void ) { FPGA_STATE_T result = FPGA_STATE_RCV_HEADER; U16 crc; // Construct read command to read 3 registers starting at address 0 fpgaReadCmdBuffer[ 0 ] = FPGA_READ_CMD_CODE; fpgaReadCmdBuffer[ 1 ] = GET_LSB_OF_WORD( FPGA_HEADER_START_ADDR ); fpgaReadCmdBuffer[ 2 ] = GET_MSB_OF_WORD( FPGA_HEADER_START_ADDR ); fpgaReadCmdBuffer[ 3 ] = fpgaHeaderSize; crc = crc16( fpgaReadCmdBuffer, FPGA_READ_CMD_HDR_LEN ); fpgaReadCmdBuffer[ 4 ] = GET_MSB_OF_WORD( crc ); fpgaReadCmdBuffer[ 5 ] = GET_LSB_OF_WORD( crc ); // Prep DMA for sending the read cmd and receiving the response fpgaReadCommandInProgress = TRUE; setupDMAForReadResp( FPGA_READ_RSP_HDR_LEN + fpgaHeaderSize + FPGA_CRC_LEN ); setupDMAForReadCmd( FPGA_READ_CMD_HDR_LEN + FPGA_CRC_LEN ); startDMAReceiptOfReadResp(); startDMAReadCmd(); return result; } /*********************************************************************//** * @brief * The handleFPGAReceiveHeaderState function handles the FPGA state * where the header registers read response should be ready to take in. * @details \b Inputs: fpgaReadCommandResponseReceived, fpgaReadResponseBuffer[] * @details \b Outputs: header register values updated * @return next FPGA state *************************************************************************/ static FPGA_STATE_T handleFPGAReceiveHeaderState( void ) { FPGA_STATE_T result = FPGA_STATE_READ_HEADER; // Did we get an FPGA response? if ( TRUE == fpgaReadCommandResponseReceived ) { // Did FPGA Ack the read command? if ( fpgaReadResponseBuffer[ 0 ] == FPGA_READ_CMD_ACK ) { U32 rspSize = FPGA_READ_RSP_HDR_LEN + fpgaHeaderSize; U32 crcPos = rspSize; U16 crc = MAKE_WORD_OF_BYTES( fpgaReadResponseBuffer[ crcPos ], fpgaReadResponseBuffer[ crcPos + 1 ] ); // Does the FPGA response CRC check out? if ( crc == crc16( fpgaReadResponseBuffer, rspSize ) ) { // Capture the read values memcpy( fpgaHeaderPtr, &fpgaReadResponseBuffer[ FPGA_READ_RSP_HDR_LEN ], fpgaHeaderSize ); result = FPGA_STATE_WRITE_ALL_ACTUATORS; } else { checkFPGACommFailure(); } } else // Header read was NAK'd { checkFPGACommFailure(); } } else // No response to read command { checkFPGACommFailure(); } // Should not be any data received at this time consumeUnexpectedData(); return result; } /*********************************************************************//** * @brief * The handleFPGAWriteAllActuatorsState function handles the FPGA state * where the bulk write and read commands are setup for DMA and the bulk * write command transmit to FPGA is initiated. * @details \b Inputs: actuator set points * @details \b Outputs: fpgaWriteCmdBuffer[], fpgaReadCmdBuffer[] * @return next FPGA state *************************************************************************/ static FPGA_STATE_T handleFPGAWriteAllActuatorsState( void ) { FPGA_STATE_T result = FPGA_STATE_RCV_ALL_SENSORS; U16 crc; // Construct bulk write command to write actuator data registers starting at address 3 (TODO - change address later) fpgaWriteCmdBuffer[ 0 ] = FPGA_WRITE_CMD_CODE; fpgaWriteCmdBuffer[ 1 ] = GET_LSB_OF_WORD( FPGA_BULK_WRITE_START_ADDR ); fpgaWriteCmdBuffer[ 2 ] = GET_MSB_OF_WORD( FPGA_BULK_WRITE_START_ADDR ); fpgaWriteCmdBuffer[ 3 ] = fpgaActuatorSetPointsSize; memcpy( &( fpgaWriteCmdBuffer[ FPGA_WRITE_CMD_HDR_LEN ] ), fpgaActuatorSetPointsPtr, fpgaActuatorSetPointsSize ); crc = crc16( fpgaWriteCmdBuffer, FPGA_WRITE_CMD_HDR_LEN + fpgaActuatorSetPointsSize ); fpgaWriteCmdBuffer[ FPGA_WRITE_CMD_HDR_LEN + fpgaActuatorSetPointsSize ] = GET_MSB_OF_WORD( crc ); fpgaWriteCmdBuffer[ FPGA_WRITE_CMD_HDR_LEN + fpgaActuatorSetPointsSize + 1 ] = GET_LSB_OF_WORD( crc ); #ifdef _TD_ // reset transitory commands once they're copied to buffer for transmit to FPGA fpgaResetTransitoryCmds(); #endif // Construct bulk read command to read sensor data registers starting at address 8 fpgaReadCmdBuffer[ 0 ] = FPGA_READ_CMD_CODE; fpgaReadCmdBuffer[ 1 ] = GET_LSB_OF_WORD( FPGA_BULK_READ_START_ADDR ); fpgaReadCmdBuffer[ 2 ] = GET_MSB_OF_WORD( FPGA_BULK_READ_START_ADDR ); fpgaReadCmdBuffer[ 3 ] = fpgaSensorReadingsSize; crc = crc16( fpgaReadCmdBuffer, FPGA_READ_CMD_HDR_LEN ); fpgaReadCmdBuffer[ 4 ] = GET_MSB_OF_WORD( crc ); fpgaReadCmdBuffer[ 5 ] = GET_LSB_OF_WORD( crc ); // Prep DMA for sending the bulk write cmd and receiving its response setupDMAForWriteCmd( FPGA_WRITE_CMD_HDR_LEN + fpgaActuatorSetPointsSize + FPGA_CRC_LEN ); setupDMAForWriteResp( FPGA_WRITE_RSP_HDR_LEN + FPGA_CRC_LEN ); // Prep DMA for sending the bulk read cmd and receiving its response setupDMAForReadCmd( FPGA_READ_CMD_HDR_LEN + FPGA_CRC_LEN ); setupDMAForReadResp( FPGA_READ_RSP_HDR_LEN + fpgaSensorReadingsSize + FPGA_CRC_LEN ); // Set fpga comm flags for bulk write cmd and follow-up bulk read command fpgaWriteCommandInProgress = TRUE; fpgaBulkWriteAndReadInProgress = TRUE; // Initiate bulk write command and its receipt - read will follow startDMAReceiptOfWriteResp(); startDMAWriteCmd(); return result; } /*********************************************************************//** * @brief * The handleFPGAReceiveAllSensorsState function handles the FPGA state * where the bulk write and read responses should be ready to parse. The * bulk write command response is checked to ensure FPGA acknowledged it. * The bulk read command response is CRC checked and registers updated. * @details \b Inputs: fpgaWriteCommandResponseReceived, fpgaWriteResponseBuffer[], * fpgaReadCommandResponseReceived, fpgaReadResponseBuffer[] * @details \b Outputs: Register (sensor) values updated * @return next FPGA state *************************************************************************/ static FPGA_STATE_T handleFPGAReceiveAllSensorsState( void ) { FPGA_STATE_T result = FPGA_STATE_WRITE_ALL_ACTUATORS; // check bulk write command success if ( TRUE == fpgaWriteCommandResponseReceived ) { // The write command completed so check for validity if ( fpgaWriteResponseBuffer[ 0 ] == FPGA_WRITE_CMD_ACK) { // Message is an ack - check CRC U32 rspSize = FPGA_READ_RSP_HDR_LEN; U32 crcPos = rspSize; U16 crc = MAKE_WORD_OF_BYTES( fpgaWriteResponseBuffer[ crcPos ], fpgaWriteResponseBuffer[ crcPos + 1 ] ); // Does the FPGA response CRC checkout? if ( crc != crc16( fpgaWriteResponseBuffer, rspSize ) ) { // CRC failed checkFPGACommFailure(); } } else { // Not an ACK checkFPGACommFailure(); } } else { // Timeout - communication error checkFPGACommFailure(); } /* If the write command response (ACK) was not received, the read response * was not issued. If this is the case the read response will also * timeout. For FPGA V&V testing this will cause two timeouts to occur. * The V&V expectation is that when the timeout test is executed a * single timeout will occur. */ if ( TRUE == fpgaWriteCommandResponseReceived ) { // if bulk read command is ACK'd, collect the readings if ( TRUE == fpgaReadCommandResponseReceived ) { // did FPGA ACK the read command? if ( fpgaReadResponseBuffer[ 0 ] == FPGA_READ_CMD_ACK ) { U32 rspSize = FPGA_READ_RSP_HDR_LEN + fpgaSensorReadingsSize; U32 crcPos = rspSize; U16 crc = MAKE_WORD_OF_BYTES( fpgaReadResponseBuffer[ crcPos ], fpgaReadResponseBuffer[ crcPos + 1 ] ); // does the FPGA response CRC check out? if ( crc == crc16( fpgaReadResponseBuffer, rspSize ) ) { // capture the read values memcpy( fpgaSensorReadingsPtr, &fpgaReadResponseBuffer[ FPGA_READ_RSP_HDR_LEN ], fpgaSensorReadingsSize ); result = FPGA_STATE_WRITE_ALL_ACTUATORS; } else // bad CRC { checkFPGACommFailure(); } } else // read command was NAK'd { checkFPGACommFailure(); } } else // no response to read command { checkFPGACommFailure(); } } // There should not be any data received at this time consumeUnexpectedData(); return result; } /*********************************************************************//** * @brief * The consumeUnexpectedData function checks to see if a byte is sitting in * the SCI2 received data register and consumes the byte if found. * @details \b Inputs: SCI FLR register * @details \b Outputs: SCI errors cleared, unexpected byte consumed * @return none *************************************************************************/ static void consumeUnexpectedData( void ) { // Clear any errors sciRxError( scilinREG ); // If a byte is pending read, read it if ( sciIsRxReady( scilinREG ) != 0 ) { sciReceiveByte( scilinREG ); } } /*********************************************************************//** * @brief * The monitorFPGAPowerStatus function monitors the status of the FPGA power source. * @details \b Inputs: TBD * @details \b Outputs: TBD * @return none *************************************************************************/ static void monitorFPGAPowerStatus( void ) { // TODO Figure out the status of the power source from FPGA from NOE and Kai. } /*********************************************************************//** * @brief * The setupDMAForWriteCmd function sets the byte count for the next DMA * write command to the FPGA. * @details \b Inputs: none * @details \b Outputs: number of bytes for next FPGA write command is set * @param bytes2Transmit number of bytes to be transmitted via DMA to the FPGA * @return none *************************************************************************/ static void setupDMAForWriteCmd( U32 bytes2Transmit ) { // Verify # of bytes does not exceed buffer length if ( bytes2Transmit <= FPGA_WRITE_CMD_BUFFER_LEN ) { fpgaDMAWriteControlRecord.FRCNT = bytes2Transmit; } else { #ifdef _TD_ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_WRITE_CMD_TOO_MUCH_DATA, bytes2Transmit ) #endif #ifdef _DD_ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_WRITE_CMD_TOO_MUCH_DATA, bytes2Transmit ); #endif } } /*********************************************************************//** * @brief * The startDMAWriteCmd function initiates the DMA transmit for the next * DMA write command to the FPGA. * @details \b Inputs: fpgaDMAWriteControlRecord * @details \b Outputs: DMA write command to FPGA is initiated * @return none *************************************************************************/ static void startDMAWriteCmd( void ) { dmaSetCtrlPacket( DMA_CH2, fpgaDMAWriteControlRecord ); dmaSetChEnable( DMA_CH2, DMA_HW ); setSCI2DMATransmitInterrupt(); } /*********************************************************************//** * @brief * The setupDMAForWriteResp function sets the expected byte count for the * next DMA write command response from the FPGA. * @details \b Alarm: ALARM_ID_XX_SOFTWARE_FAULT if byte count exceeds buffer size. * @details \b Inputs: none * @details \b Outputs: fpgaDMAWriteRespControlRecord * @param bytes2Receive number of bytes expected to be transmitted via DMA from the FPGA * @return none *************************************************************************/ static void setupDMAForWriteResp( U32 bytes2Receive ) { // Verify # of bytes does not exceed buffer length if ( bytes2Receive <= FPGA_WRITE_RSP_BUFFER_LEN ) { fpgaDMAWriteRespControlRecord.FRCNT = bytes2Receive; } else { #ifdef _TD_ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_WRITE_RSP_TOO_MUCH_DATA, bytes2Receive ) #endif #ifdef _DD_ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_WRITE_RSP_TOO_MUCH_DATA, bytes2Receive ) #endif } } /*********************************************************************//** * @brief * The startDMAReceiptOfWriteResp function initiates readiness of the DMA * receiver for the next DMA write command response from the FPGA. * @details \b Inputs: fpgaDMAWriteRespControlRecord * @details \b Outputs: DMA write command response is made ready to be received from the FPGA * @return none *************************************************************************/ static void startDMAReceiptOfWriteResp( void ) { dmaSetCtrlPacket( DMA_CH0, fpgaDMAWriteRespControlRecord ); dmaSetChEnable( DMA_CH0, DMA_HW ); setSCI2DMAReceiveInterrupt(); } /*********************************************************************//** * @brief * The setupDMAForReadCmd function sets the byte count for the next DMA * read command to the FPGA. * @details \b Alarm: ALARM_ID_XX_SOFTWARE_FAULT if byte count exceeds buffer size. * @details \b Inputs: none * @details \b Outputs: fpgaDMAReadControlRecord * @param bytes2Transmit number of bytes to be transmitted via DMA to the FPGA * @return none *************************************************************************/ static void setupDMAForReadCmd( U32 bytes2Transmit ) { // Verify # of bytes does not exceed buffer length if ( bytes2Transmit <= FPGA_READ_CMD_BUFFER_LEN ) { fpgaDMAReadControlRecord.FRCNT = bytes2Transmit; } else { #ifdef _TD_ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_READ_CMD_TOO_MUCH_DATA, bytes2Transmit ) #endif #ifdef _DD_ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_READ_CMD_TOO_MUCH_DATA, bytes2Transmit ) #endif } } /*********************************************************************//** * @brief * The startDMAReadCmd function initiates the DMA transmit for the next * DMA read command to the FPGA. * @details \b Inputs: fpgaDMAReadControlRecord * @details \b Outputs: DMA read command to FPGA is initiated * @return none *************************************************************************/ static void startDMAReadCmd( void ) { dmaSetCtrlPacket( DMA_CH2, fpgaDMAReadControlRecord ); dmaSetChEnable( DMA_CH2, DMA_HW ); setSCI2DMATransmitInterrupt(); } /*********************************************************************//** * @brief * The setupDMAForReadResp function sets the expected byte count for the * next DMA read command response from the FPGA. * @details \b Alarm: ALARM_ID_XX_SOFTWARE_FAULT if byte count exceeds buffer size. * @details \b Inputs: none * @details \b Outputs: fpgaDMAReadRespControlRecord * @param bytes2Receive number of expected bytes to be transmitted via DMA from the FPGA * @return none *************************************************************************/ static void setupDMAForReadResp( U32 bytes2Receive ) { // Verify # of bytes does not exceed buffer length if ( bytes2Receive <= FPGA_READ_RSP_BUFFER_LEN ) { fpgaDMAReadRespControlRecord.FRCNT = bytes2Receive; } else { #ifdef _TD_ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_READ_RSP_TOO_MUCH_DATA, bytes2Receive ) #endif #ifdef _DD_ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_READ_RSP_TOO_MUCH_DATA, bytes2Receive ) #endif } } /*********************************************************************//** * @brief * The startDMAReceiptOfReadResp function initiates readiness of the DMA * receiver for the next DMA read command response from the FPGA. * @details \b Inputs: fpgaDMAReadRespControlRecord * @details \b Outputs: DMA read command response is ready to be received from the FPGA * @return none *************************************************************************/ static void startDMAReceiptOfReadResp( void ) { dmaSetCtrlPacket( DMA_CH0, fpgaDMAReadRespControlRecord ); dmaSetChEnable( DMA_CH0, DMA_HW ); setSCI2DMAReceiveInterrupt(); } /**@}*/