/************************************************************************** * * Copyright (c) 2019-2020 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 * * @date 21-Oct-2019 * @author S. Nash * * @brief FPGA interface service module. Provides an interface to the FPGA. \n * Various sensor readings are gathered and get functions provided for them. \n * Various actuator settings are sent and set functions provided for them. * **************************************************************************/ #include // for memset(), memcpy() #include "sci.h" #include "sys_dma.h" #include "FPGA.h" #include "Comm.h" #include "SystemCommMessages.h" #include "Utilities.h" // ********** private definitions ********** typedef enum FPGA_States { FPGA_STATE_START = 0, FPGA_STATE_READ_HEADER, FPGA_STATE_RCV_HEADER, FPGA_STATE_WRITE_ALL_ACTUATORS, FPGA_STATE_RCV_ALL_SENSORS, FPGA_STATE_FAILED, NUM_OF_FPGA_STATES } FPGA_STATE_T; #define FPGA_PAGE_SIZE 256 #define FPGA_EXPECTED_ID 0x59 #define FPGA_HEADER_START_ADDR 256 // update these after re-arranging w/ Randy #define FPGA_BULK_READ_START_ADDR 262 #define FPGA_BULK_WRITE_START_ADDR 2 #define FPGA_WRITE_CMD_BUFFER_LEN (FPGA_PAGE_SIZE+8) #define FPGA_READ_CMD_BUFFER_LEN 8 #define FPGA_WRITE_RSP_BUFFER_LEN 8 #define FPGA_READ_RSP_BUFFER_LEN (FPGA_PAGE_SIZE+8) #define FPGA_WRITE_CMD_CODE 0x55 #define FPGA_READ_CMD_CODE 0x5A #define FPGA_WRITE_CMD_ACK 0xA5 #define FPGA_READ_CMD_ACK 0xAA #define FPGA_CMD_NAK 0xEE #define FPGA_CRC_LEN 2 #define FPGA_WRITE_CMD_HDR_LEN 4 #define FPGA_READ_CMD_HDR_LEN 4 #define FPGA_WRITE_RSP_HDR_LEN 3 #define FPGA_READ_RSP_HDR_LEN 3 #define SCI2_RECEIVE_DMA_REQUEST 28 #define SCI2_TRANSMIT_DMA_REQUEST 29 #define MAX_COMM_ERROR_RETRIES 5 // FPGA Sensors Record #pragma pack(push,1) typedef struct { U08 fpgaId; U08 fpgaRev; U16 fpgaControl; U16 fpgaStatus; } FPGA_HEADER_T; // read only on FPGA typedef struct // TODO - add all sensor readings to this structure per FPGA register map { U32 LCA1; U32 LCA2; U32 LCB1; U32 LCB2; //U08 bloodFlowMeterDataPktCount; //U08 bloodFlowMeterSlowPktCounts; //U08 bloodFlowMeterDeviceStatus; //U08 bloodFlowMeterResponse; //F32 bloodFlowLast; //U08 dialysateFlowMeterDataPktCount; //U08 dialysateFlowMeterSlowPckCounts; //U08 dialysateFlowMeterDeviceStatus; //U08 dialysateFlowMeterResponse; //F32 dialysateFlowLast; U08 bloodFlowMeterErrorCount; U08 dialysateFlowMeterErrorCount; U16 bloodOcclusionData; U08 bloodOcclusionReadCount; U08 bloodOcclusionErrorCount; U16 dialysateInOcclusionData; U08 dialysateInOcclusionReadCount; U08 dialysateInOcclusionErrorCount; U16 dialysateOutOcclusionData; U08 dialysateOutOcclusionReadCount; U08 dialysateOutOcclusionErrorCount; U16 arterialPressureData; U08 arterialPressureReadCount; U08 arterialPressureErrorCount; U16 dialysateTempPrimaryData; U16 dialysateTempBackupData; } DG_FPGA_SENSORS_T; typedef struct // TODO - add all sensor readings to this structure per FPGA register map { U08 bloodFlowMeterDataPktCount; U08 bloodFlowMeterSlowPktCounts; U08 bloodFlowMeterDeviceStatus; U08 bloodFlowMeterResponse; F32 bloodFlowLast; U08 dialysateFlowMeterDataPktCount; U08 dialysateFlowMeterSlowPckCounts; U08 dialysateFlowMeterDeviceStatus; U08 dialysateFlowMeterResponse; F32 dialysateFlowLast; U08 bloodFlowMeterErrorCount; U08 dialysateFlowMeterErrorCount; U16 bloodOcclusionData; U08 bloodOcclusionReadCount; U08 bloodOcclusionErrorCount; U16 dialysateInOcclusionData; U08 dialysateInOcclusionReadCount; U08 dialysateInOcclusionErrorCount; U16 dialysateOutOcclusionData; U08 dialysateOutOcclusionReadCount; U08 dialysateOutOcclusionErrorCount; U16 arterialPressureData; U08 arterialPressureReadCount; U08 arterialPressureErrorCount; U16 dialysateTempPrimaryData; U16 dialysateTempBackupData; } FPGA_SENSORS_T; typedef struct // TODO - add all actuator set points to this structure per FPGA register map { U08 bloodValveSetState; } FPGA_ACTUATORS_T; #pragma pack(pop) // ********** private data ********** // FPGA state static FPGA_STATE_T fpgaState = FPGA_STATE_START; static U32 fpgaCommRetryCount = 0; static U32 fpgaReceiptCounter = 0; static U32 fpgaTransmitCounter = 0; static BOOL fpgaWriteCommandInProgress = FALSE; static BOOL fpgaReadCommandInProgress = FALSE; static BOOL fpgaBulkWriteAndReadInProgress = FALSE; static BOOL fpgaWriteCommandResponseReceived = FALSE; static BOOL fpgaReadCommandResponseReceived = FALSE; // FPGA comm buffers static U08 fpgaWriteCmdBuffer[ FPGA_WRITE_CMD_BUFFER_LEN ]; static U08 fpgaReadCmdBuffer[ FPGA_READ_CMD_BUFFER_LEN ]; static U08 fpgaWriteResponseBuffer[ FPGA_WRITE_RSP_BUFFER_LEN ]; static U08 fpgaReadResponseBuffer[ FPGA_READ_RSP_BUFFER_LEN ]; // DMA control records static g_dmaCTRL fpgaDMAWriteControlRecord; static g_dmaCTRL fpgaDMAWriteRespControlRecord; static g_dmaCTRL fpgaDMAReadControlRecord; static g_dmaCTRL fpgaDMAReadRespControlRecord; // FPGA data static FPGA_HEADER_T fpgaHeader; static DG_FPGA_SENSORS_T fpgaSensorReadings; static FPGA_ACTUATORS_T fpgaActuatorSetPoints; // ********** 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 ); /************************************************************************* * @brief initFPGA * The initFPGA function initializes the FPGA module. * @details * Inputs : none * Outputs : FPGA module initialized. * @param none * @return none *************************************************************************/ void initFPGA( void ) { // initialize fpga data structures memset( &fpgaHeader, 0, sizeof(FPGA_HEADER_T) ); memset( &fpgaSensorReadings, 0, sizeof(DG_FPGA_SENSORS_T) ); memset( &fpgaActuatorSetPoints, 0, sizeof(FPGA_ACTUATORS_T) ); // 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 fpgaDMAWriteControlRecord.WRSIZE = ACCESS_8_BIT; // 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 shouldn't be any data pending yet consumeUnexpectedData(); } /************************************************************************* * @brief resetFPGACommFlags * The resetFPGACommFlags function resets the various fpga comm flags and \n * counters. * @details * Inputs : none * Outputs : fpga comm flags & counters reset * @param none * @return none *************************************************************************/ static void resetFPGACommFlags( void ) { fpgaWriteCommandResponseReceived = FALSE; fpgaReadCommandResponseReceived = FALSE; fpgaWriteCommandInProgress = FALSE; fpgaReadCommandInProgress = FALSE; fpgaBulkWriteAndReadInProgress = FALSE; fpgaTransmitCounter = 0; fpgaReceiptCounter = 0; } /************************************************************************* * @brief signalFPGAReceiptCompleted * The signalFPGAReceiptCompleted function increments a counter to indicate \n * that another DMA receipt from the FPGA has completed. * @details * Inputs : none * Outputs : fpgaReceiptCounter * @param none * @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 signalFPGATransmitCompleted * The signalFPGATransmitCompleted function increments a counter to indicate \n * that another DMA transmit to the FPGA has completed. * @details * Inputs : none * Outputs : fpgaReceiptCounter * @param none * @return none *************************************************************************/ void signalFPGATransmitCompleted( void ) { fpgaTransmitCounter++; } /************************************************************************* * @brief execFPGAIn * The execFPGA function manages incoming data exchanges with the FPGA. * @details * Inputs : fpgaState * Outputs : fpgaState * @param none * @return none *************************************************************************/ void execFPGAIn( void ) { // FPGA incoming state machine switch ( fpgaState ) { case FPGA_STATE_START: fpgaState = FPGA_STATE_READ_HEADER; break; case FPGA_STATE_RCV_HEADER: fpgaState = handleFPGAReceiveHeaderState(); break; // TODO - sensor/ADC init/configuration states case FPGA_STATE_RCV_ALL_SENSORS: fpgaState = handleFPGAReceiveAllSensorsState(); break; case FPGA_STATE_FAILED: // do nothing - we'll be stuck here break; default: if ( fpgaState >= NUM_OF_FPGA_STATES ) { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_INVALID_IN_STATE, fpgaState ) } else { // ok, some states handled in the outgoing state machine } break; } // if retries for commands exceeds limit, fault if ( fpgaCommRetryCount > MAX_COMM_ERROR_RETRIES ) { // TODO - FPGA comm fault } // reset comm flags after processing incoming responses resetFPGACommFlags(); } /************************************************************************* * @brief execFPGAOut * The execFPGAOut function manages outgoing data exchanges with the FPGA. * @details * Inputs : fpgaState * Outputs : fpgaState * @param none * @return none *************************************************************************/ void execFPGAOut( void ) { // FPGA outgoing state machine switch ( fpgaState ) { case FPGA_STATE_READ_HEADER: fpgaState = handleFPGAReadHeaderState(); break; // TODO - sensor/ADC init/configuration states case FPGA_STATE_WRITE_ALL_ACTUATORS: fpgaState = handleFPGAWriteAllActuatorsState(); break; case FPGA_STATE_FAILED: // do nothing - we'll be stuck here break; default: if ( fpgaState >= NUM_OF_FPGA_STATES ) { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_INVALID_OUT_STATE, fpgaState ) } else { // ok, some states handled in the incoming state machine } break; } } /************************************************************************* * @brief handleFPGAReadHeaderState * The handleFPGAReadHeaderState function handles the FPGA state where \n * the read header registers command is sent to the FPGA. * @details * Inputs : none * Outputs : read command sent to FPGA * @param none * @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 ] = 0x00; // start at FPGA address 0 fpgaReadCmdBuffer[ 2 ] = 0x00; fpgaReadCmdBuffer[ 3 ] = sizeof(FPGA_HEADER_T); 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 + sizeof(FPGA_HEADER_T) + FPGA_CRC_LEN ); setupDMAForReadCmd( FPGA_READ_CMD_HDR_LEN + FPGA_CRC_LEN ); startDMAReceiptOfReadResp(); startDMAReadCmd(); return result; } /************************************************************************* * @brief handleFPGAReceiveHeaderState * The handleFPGAReceiveHeaderState function handles the FPGA state \n * where the header registers read response should be ready to take in. * @details * Inputs : none * Outputs : header register values updated * @param none * @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 + sizeof(FPGA_HEADER_T); 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 ) ) { fpgaCommRetryCount = 0; // capture the read values memcpy( &fpgaHeader, &fpgaReadResponseBuffer[ FPGA_READ_RSP_HDR_LEN ], sizeof( FPGA_HEADER_T ) ); result = FPGA_STATE_WRITE_ALL_ACTUATORS; } else { fpgaCommRetryCount++; } } else // header read was NAK'd { fpgaCommRetryCount++; } } else // no response to read command { fpgaCommRetryCount++; } // shouldn't be any data received at this time consumeUnexpectedData(); return result; } /************************************************************************* * @brief handleFPGAWriteAllActuatorsState * The handleFPGAWriteAllActuatorsState function handles the FPGA state \n * where the bulk write command is sent to the FPGA. * @details * Inputs : actuator set points * Outputs : actuator set points sent to FPGA * @param none * @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 ] = 0x08; // start at FPGA address 8 fpgaWriteCmdBuffer[ 2 ] = 0x00; fpgaWriteCmdBuffer[ 3 ] = sizeof(FPGA_ACTUATORS_T); memcpy( &( fpgaWriteCmdBuffer[ FPGA_WRITE_CMD_HDR_LEN ] ), &fpgaActuatorSetPoints, sizeof( FPGA_ACTUATORS_T ) ); crc = crc16( fpgaWriteCmdBuffer, FPGA_WRITE_CMD_HDR_LEN + sizeof( FPGA_ACTUATORS_T ) ); fpgaWriteCmdBuffer[ FPGA_WRITE_CMD_HDR_LEN + sizeof( FPGA_ACTUATORS_T ) ] = GET_MSB_OF_WORD( crc ); fpgaWriteCmdBuffer[ FPGA_WRITE_CMD_HDR_LEN + sizeof( FPGA_ACTUATORS_T ) + 1 ] = GET_LSB_OF_WORD( crc ); // construct bulk read command to read sensor data registers starting at address 8 fpgaReadCmdBuffer[ 0 ] = FPGA_READ_CMD_CODE; fpgaReadCmdBuffer[ 1 ] = 0x08; // start at FPGA address 0x108 (264) fpgaReadCmdBuffer[ 2 ] = 0x01; fpgaReadCmdBuffer[ 3 ] = sizeof(DG_FPGA_SENSORS_T); 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 + sizeof( FPGA_ACTUATORS_T ) + 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 + sizeof( DG_FPGA_SENSORS_T ) + 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 it's receipt - read will follow startDMAReceiptOfWriteResp(); startDMAWriteCmd(); return result; } /************************************************************************* * @brief handleFPGAReceiveAllSensorsState * The handleFPGAReceiveAllSensorsState function handles the FPGA state \n * where the bulk read response should be ready to parse. * @details * Inputs : none * Outputs : sensor values updated * @param none * @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 ( ( FALSE == fpgaWriteCommandResponseReceived ) || ( fpgaWriteResponseBuffer[ 0 ] != FPGA_WRITE_CMD_ACK ) ) { fpgaCommRetryCount++; } // 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 + sizeof(DG_FPGA_SENSORS_T); 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 ) ) { fpgaCommRetryCount = 0; // capture the read values memcpy( &fpgaSensorReadings, &fpgaReadResponseBuffer[ FPGA_READ_RSP_HDR_LEN ], sizeof( DG_FPGA_SENSORS_T ) ); result = FPGA_STATE_WRITE_ALL_ACTUATORS; } else // bad CRC { fpgaCommRetryCount++; } } else // read command was NAK'd { fpgaCommRetryCount++; } } else // no response to read command { fpgaCommRetryCount++; } // shouldn't be any data received at this time consumeUnexpectedData(); return result; } /************************************************************************* * @brief execFPGATest * The execFPGATest function executes the FPGA self-test. \n * @details * Inputs : fpgaHeader * Outputs : none * @param none * @return passed, or failed *************************************************************************/ SELF_TEST_STATUS_T execFPGATest( void ) { SELF_TEST_STATUS_T result; // check FPGA reported correct ID #ifndef RM46_EVAL_BOARD_TARGET if ( FPGA_EXPECTED_ID == fpgaHeader.fpgaId ) #else if ( 1 ) #endif { result = SELF_TEST_STATUS_PASSED; } else { result = SELF_TEST_STATUS_FAILED; SET_ALARM_WITH_1_U32_DATA( ALARM_ID_FPGA_POST_TEST_FAILED, (U32)fpgaHeader.fpgaId ) } return result; } /************************************************************************* * @brief setupDMAForWriteCmd * The setupDMAForWriteCmd function sets the byte count for the next DMA \n * write command to the FPGA. * @details * Inputs : none * Outputs : # of bytes for next FPGA write command is set * @param bytes2Transmit : # 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 { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_WRITE_CMD_TOO_MUCH_DATA, bytes2Transmit ) } } /************************************************************************* * @brief startDMAWriteCmd * The startDMAWriteCmd function initiates the DMA transmit for the next \n * DMA write command to the FPGA. * @details * Inputs : none * Outputs : DMA write command to FPGA is initiated * @param none * @return none *************************************************************************/ static void startDMAWriteCmd( void ) { dmaSetCtrlPacket( DMA_CH2, fpgaDMAWriteControlRecord ); dmaSetChEnable( DMA_CH2, DMA_HW ); setSCI2DMATransmitInterrupt(); } /************************************************************************* * @brief setupDMAForWriteResp * The setupDMAForWriteResp function sets the expected byte count for the \n * next DMA write command response from the FPGA. * @details * Inputs : none * Outputs : # of expected bytes for next FPGA write command response is set * @param bytes2Receive : # 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 { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_WRITE_RSP_TOO_MUCH_DATA, bytes2Receive ) } } /************************************************************************* * @brief startDMAReceiptOfWriteResp * The startDMAReceiptOfWriteResp function initiates readiness of the DMA \n * receiver for the next DMA write command response from the FPGA. * @details * Inputs : none * Outputs : DMA write command response is ready to be received from the FPGA * @param none * @return none *************************************************************************/ static void startDMAReceiptOfWriteResp( void ) { dmaSetCtrlPacket( DMA_CH0, fpgaDMAWriteRespControlRecord ); dmaSetChEnable( DMA_CH0, DMA_HW ); setSCI2DMAReceiveInterrupt(); } /************************************************************************* * @brief setupDMAForReadCmd * The setupDMAForReadCmd function sets the byte count for the next DMA \n * read command to the FPGA. * @details * Inputs : none * Outputs : # of bytes for next FPGA read command is set * @param bytes2Transmit : # 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 { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_READ_CMD_TOO_MUCH_DATA, bytes2Transmit ) } } /************************************************************************* * @brief startDMAReadCmd * The startDMAReadCmd function initiates the DMA transmit for the next \n * DMA read command to the FPGA. * @details * Inputs : none * Outputs : DMA read command to FPGA is initiated * @param none * @return none *************************************************************************/ static void startDMAReadCmd( void ) { dmaSetCtrlPacket( DMA_CH2, fpgaDMAReadControlRecord ); dmaSetChEnable( DMA_CH2, DMA_HW ); setSCI2DMATransmitInterrupt(); } /************************************************************************* * @brief setupDMAForReadResp * The setupDMAForReadResp function sets the expected byte count for the \n * next DMA read command response from the FPGA. * @details * Inputs : none * Outputs : # of expected bytes for next FPGA read command response is set * @param bytes2Receive : # 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 { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_READ_RSP_TOO_MUCH_DATA, bytes2Receive ) } } /************************************************************************* * @brief startDMAReceiptOfReadResp * The startDMAReceiptOfReadResp function initiates readiness of the DMA \n * receiver for the next DMA read command response from the FPGA. * @details * Inputs : none * Outputs : DMA read command response is ready to be received from the FPGA * @param none * @return none *************************************************************************/ static void startDMAReceiptOfReadResp( void ) { dmaSetCtrlPacket( DMA_CH0, fpgaDMAReadRespControlRecord ); dmaSetChEnable( DMA_CH0, DMA_HW ); setSCI2DMAReceiveInterrupt(); } /************************************************************************* * @brief getFPGAId * The getFPGAId function gets the version read from the Id register \n * of the FPGA. * @details * Inputs : fpgaHeader * Outputs : none * @param none * @return Id *************************************************************************/ U08 getFPGAId( void ) { return fpgaHeader.fpgaId; } /************************************************************************* * @brief getFPGARev * The getFPGARev function gets the revision read from the Rev register \n * of the FPGA. * @details * Inputs : fpgaHeader * Outputs : none * @param none * @return Revision *************************************************************************/ U08 getFPGARev( void ) { return fpgaHeader.fpgaRev; } /************************************************************************* * @brief getFPGAStatus * The getFPGAStatus function gets the version read from the diagnostic register \n * of the FPGA. * @details * Inputs : fpgaHeader * Outputs : none * @param none * @return fpgaHeader.fpgaStatus *************************************************************************/ U16 getFPGAStatus( void ) { return fpgaHeader.fpgaStatus; } /************************************************************************* * @brief getFPGADiag * The getFPGADiag function sets the diagnostic register of the FPGA. * @details * Inputs : fpgaHeader * Outputs : none * @param ctrl : value to write to diagnostic register * @return none *************************************************************************/ void setFPGAControl( U16 ctrl ) { fpgaHeader.fpgaControl = ctrl; } /************************************************************************* * @brief getFPGALoadCellA1 * The getFPGALoadCellA1 function gets the latest load cell A 1 reading. * @details * Inputs : fpgaSensorReadings * Outputs : none * @param none * @return last load cell A 1 reading *************************************************************************/ U32 getFPGALoadCellA1( void ) { return fpgaSensorReadings.LCA1; } /************************************************************************* * @brief getFPGALoadCellA2 * The getFPGALoadCellA2 function gets the latest load cell A 2 reading. * @details * Inputs : fpgaSensorReadings * Outputs : none * @param none * @return last load cell A 2 reading *************************************************************************/ U32 getFPGALoadCellA2( void ) { return fpgaSensorReadings.LCA2; } /************************************************************************* * @brief getFPGALoadCellB1 * The getFPGALoadCellB1 function gets the latest load cell B 1 reading. * @details * Inputs : fpgaSensorReadings * Outputs : none * @param none * @return last load cell B 1 reading *************************************************************************/ U32 getFPGALoadCellB1( void ) { return fpgaSensorReadings.LCB1; } /************************************************************************* * @brief getFPGALoadCellB2 * The getFPGALoadCellB2 function gets the latest load cell B 2 reading. * @details * Inputs : fpgaSensorReadings * Outputs : none * @param none * @return last load cell B 2 reading *************************************************************************/ U32 getFPGALoadCellB2( void ) { return fpgaSensorReadings.LCB2; } /************************************************************************* * @brief getFPGABloodPumpOcclusion * The getFPGABloodPumpOcclusion function gets the latest blood occlusion reading. * @details * Inputs : fpgaSensorReadings * Outputs : none * @param none * @return last blood occlusion reading *************************************************************************/ U16 getFPGABloodPumpOcclusion( void ) { return fpgaSensorReadings.bloodOcclusionData; } /************************************************************************* * @brief getFPGADialInPumpOcclusion * The getFPGADialInPumpOcclusion function gets the latest dialysate \n * inlet occlusion reading. * @details * Inputs : fpgaSensorReadings * Outputs : none * @param none * @return last dialysate inlet occlusion reading *************************************************************************/ U16 getFPGADialInPumpOcclusion( void ) { #ifdef DEBUG_ENABLED // { // // TODO - temporary debug code - remove later // char debugOccStr[ 60 ]; // S32 dat = fpgaSensorReadings.dialysateInOcclusionData; // S32 rct = fpgaSensorReadings.dialysateInOcclusionReadCount; // S32 ect = fpgaSensorReadings.dialysateInOcclusionErrorCount; // // sprintf( debugOccStr, "Data %5d Reads %5d Errors %5d\n", dat, rct, ect ); // sendDebugData( (U08*)debugOccStr, strlen(debugOccStr) ); // } #endif return fpgaSensorReadings.dialysateInOcclusionData; } /************************************************************************* * @brief getFPGADialOutPumpOcclusion * The getFPGADialOutPumpOcclusion function gets the latest dialysate \n * outlet occlusion reading. * @details * Inputs : fpgaSensorReadings * Outputs : none * @param none * @return last dialysate outlet occlusion reading *************************************************************************/ U16 getFPGADialOutPumpOcclusion( void ) { return fpgaSensorReadings.dialysateOutOcclusionData; } /************************************************************************* * @brief getFPGAArterialPressure * The getFPGAArterialPressure function gets the latest arterial pressure reading. * @details * Inputs : fpgaSensorReadings * Outputs : none * @param none * @return last arterial pressure reading *************************************************************************/ U16 getFPGAArterialPressure( void ) { return fpgaSensorReadings.arterialPressureData; } /************************************************************************* * @brief getFPGAVenousPressure * The getFPGAVenousPressure function gets the venous arterial pressure reading. * @details * Inputs : fpgaSensorReadings * Outputs : none * @param none * @return last venous pressure reading *************************************************************************/ U16 getFPGAVenousPressure( void ) { return 0; // TODO - return reading when available } /************************************************************************* * @brief consumeUnexpectedData * The consumeUnexpectedData function checks to see if a byte is sitting in \n * the SCI2 received data register. * @details * Inputs : fpgaHeader * Outputs : none * @param none * @return fpgaDiag *************************************************************************/ static void consumeUnexpectedData( void ) { // clear any errors sciRxError( scilinREG ); // if a byte is pending read, read it if ( sciIsRxReady( scilinREG ) != 0 ) { sciReceiveByte( scilinREG ); } }