Index: firmware/App/Services/FPGA.c =================================================================== diff -u -rb36964ca0398c4a4eefd07f334f09b043a5e2b8b -r7d4711edd7b40cd3e29f43e766f79a8a09586fe9 --- firmware/App/Services/FPGA.c (.../FPGA.c) (revision b36964ca0398c4a4eefd07f334f09b043a5e2b8b) +++ firmware/App/Services/FPGA.c (.../FPGA.c) (revision 7d4711edd7b40cd3e29f43e766f79a8a09586fe9) @@ -1,15 +1,15 @@ /************************************************************************** * -* Copyright (c) 2019-2022 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-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) Dara Navaei -* @date (last) 10-Nov-2022 +* @date (last) 26-Sep-2023 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -107,6 +107,10 @@ #define PROCESSOR_FPGA_CLOCK_DIFF_TOLERANCE 1 ///< Tolerance for processor clock speed check against FPGA clock. +#define MAX_FPGA_COMM_FAILURES_WINDOW_MS ( 1 * SEC_PER_MIN * MS_PER_SECOND ) ///< FPGA comm failures window +#define MAX_FPGA_COMM_FAILURES 3 ///< FPGA maximum comm failures per MAX_FPGA_COMM_FAILURES_WINDOW_MS +#define MIN_POWER_ON_TIME_FOR_COMM_FAILS ( 1 * MS_PER_SECOND ) ///< Allow FPGA comm errors for first second after power-up + // FPGA header struct. #pragma pack(push,1) typedef struct @@ -320,15 +324,14 @@ U16 fpgaDACRegFIn; ///< Reg 126. Debug DAC channel F output U16 fpgaDACRegGIn; ///< Reg 128. Debug DAC channel G output U16 fpgaDACRegHIn; ///< Reg 130. Debug DAC channel H output - U08 fgpaNewCP2Control; ///< Reg 132. Concentrate pump 2 control + U08 fpgaNewCP2Control; ///< Reg 132. Concentrate pump 2 control U08 fpgaNewCP1Control; ///< Reg 133. Concentrate pump 1 control } FPGA_ACTUATORS_T; #pragma pack(pop) // ********** private data ********** static FPGA_STATE_T fpgaState = FPGA_STATE_START; ///< FPGA current state. -static U32 fpgaCommRetryCount = 0; ///< FPGA communication retry count. static U32 fpgaReceiptCounter = 0; ///< FPGA receipt completed counter. static U32 fpgaTransmitCounter = 0; ///< FPGA transmit completed counter. static BOOL fpgaWriteCommandInProgress = FALSE; ///< Flag indicates whether a FPGA write command is in progress. @@ -353,11 +356,6 @@ static FPGA_HEADER_T fpgaHeader; ///< FPGA header structure. static DG_FPGA_SENSORS_T fpgaSensorReadings; ///< DG FPGA sensors structure. static FPGA_ACTUATORS_T fpgaActuatorSetPoints; ///< FPGA actuator set points structure. -static U08 fpgaReadByteSize; ///< FPGA read byte size. -#ifndef DEBUG_ENABLED -static U16 currentFPGATimerCount_ms; ///< Current FPGA timer count in ms. -static U32 currentTimerCount_ms; ///< Current processor timer count in ms. -#endif // ********** private function prototypes ********** @@ -377,8 +375,10 @@ static void startDMAReceiptOfReadResp( void ); static void consumeUnexpectedData( void ); -static void monitorFPGAPowerStatus( void ); +static BOOL checkFPGACommFailure( void ); +static BOOL checkFPGAFEOEFailure( void ); + /*********************************************************************//** * @brief * The initFPGA function initializes the FPGA module. @@ -495,8 +495,9 @@ // there shouldn't be any data pending yet consumeUnexpectedData(); - // Initialize the persistent alarm for FPGA power out - initPersistentAlarm( ALARM_ID_DG_FPGA_POWER_OUT_TIMEOUT, FPGA_POWER_OUT_TIMEOUT_MS, FPGA_POWER_OUT_TIMEOUT_MS ); + // initialize FPGA clock speed error time windowed count + initTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_COMM_FAILURES, MAX_FPGA_COMM_FAILURES, MAX_FPGA_COMM_FAILURES_WINDOW_MS); + } /*********************************************************************//** @@ -573,15 +574,9 @@ *************************************************************************/ void execFPGAIn( void ) { - fpgaReadByteSize = sizeof( DG_FPGA_SENSORS_T ); + // Check if FE or OE error has occurred + checkFPGAFEOEFailure(); -#ifndef _RELEASE_ - if ( ( HW_CONFIG_BETA == getHardwareConfigStatus() ) || ( DG_MODE_INIT == getCurrentOperationMode() ) ) - { - fpgaReadByteSize = FPGA_SIZE_OF_V3_READ_BYTES; - } -#endif - // FPGA incoming state machine switch ( fpgaState ) { @@ -613,22 +608,9 @@ break; } - // if retries for commands exceeds limit or FPGA reports comm error, fault - if ( ( fpgaCommRetryCount > MAX_COMM_ERROR_RETRIES ) -#ifdef _RELEASE_ - || ( fpgaSensorReadings.fpgaIOErrorCntProcessor > MAX_COMM_ERROR_RETRIES ) ) -#else - ) -#endif - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_FPGA_COMM_TIMEOUT, fpgaCommRetryCount, (U32)fpgaSensorReadings.fpgaIOErrorCntProcessor ) - } - // reset comm flags after processing incoming responses resetFPGACommFlags(); - // Check the FPGA power status - monitorFPGAPowerStatus(); } /*********************************************************************//** @@ -640,15 +622,6 @@ *************************************************************************/ void execFPGAOut( void ) { - fpgaReadByteSize = sizeof( DG_FPGA_SENSORS_T ); - -#ifndef _RELEASE_ - if ( ( HW_CONFIG_BETA == getHardwareConfigStatus() ) || ( DG_MODE_INIT == getCurrentOperationMode() ) ) - { - fpgaReadByteSize = FPGA_SIZE_OF_V3_READ_BYTES; - } -#endif - // FPGA outgoing state machine switch ( fpgaState ) { @@ -733,24 +706,23 @@ // 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++; + checkFPGACommFailure(); } } else // header read was NAK'd { - fpgaCommRetryCount++; + checkFPGACommFailure(); } } else // no response to read command { - fpgaCommRetryCount++; + checkFPGACommFailure(); } // There should not be any data received at this time @@ -784,15 +756,15 @@ // reset one-time sets after actuator set points xmit message created fpgaActuatorSetPoints.fpgaNewCP1Control &= ~FPGA_CONC_PUMP_PARK_COMMAND; // clear concentrate pump park command bits - fpgaActuatorSetPoints.fgpaNewCP2Control &= ~FPGA_CONC_PUMP_PARK_COMMAND; + fpgaActuatorSetPoints.fpgaNewCP2Control &= ~FPGA_CONC_PUMP_PARK_COMMAND; fpgaActuatorSetPoints.fpgaCP1Control &= ~FPGA_CONC_PUMP_PARK_COMMAND; fpgaActuatorSetPoints.fpgaCP2Control &= ~FPGA_CONC_PUMP_PARK_COMMAND; // 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 ] = fpgaReadByteSize; + 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 ); @@ -803,7 +775,7 @@ // 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 + fpgaReadByteSize + 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; @@ -828,43 +800,75 @@ FPGA_STATE_T result = FPGA_STATE_WRITE_ALL_ACTUATORS; // check bulk write command success - if ( ( FALSE == fpgaWriteCommandResponseReceived ) || ( fpgaWriteResponseBuffer[ 0 ] != FPGA_WRITE_CMD_ACK ) ) + if ( TRUE == fpgaWriteCommandResponseReceived ) { - fpgaCommRetryCount++; + // 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 bulk read command is ACK'd, collect the readings - if ( TRUE == fpgaReadCommandResponseReceived ) + /* 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 ) { - // did FPGA Ack the read command? - if ( fpgaReadResponseBuffer[ 0 ] == FPGA_READ_CMD_ACK ) + // if bulk read command is ACK'd, collect the readings + if ( TRUE == fpgaReadCommandResponseReceived ) { - U32 rspSize = FPGA_READ_RSP_HDR_LEN + fpgaReadByteSize; - 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 ) ) + // did FPGA ACK the read command? + if ( fpgaReadResponseBuffer[ 0 ] == FPGA_READ_CMD_ACK ) { - fpgaCommRetryCount = 0; - // capture the read values - memcpy( &fpgaSensorReadings, &fpgaReadResponseBuffer[ FPGA_READ_RSP_HDR_LEN ], fpgaReadByteSize ); - result = FPGA_STATE_WRITE_ALL_ACTUATORS; + 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 ) ) + { + // 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 + { + checkFPGACommFailure(); + } } - else // bad CRC + else // read command was NAK'd { - fpgaCommRetryCount++; + checkFPGACommFailure(); } } - else // read command was NAK'd + else // no response to read command { - fpgaCommRetryCount++; + checkFPGACommFailure(); } } - else // no response to read command - { - fpgaCommRetryCount++; - } // There should not be any data received at this time consumeUnexpectedData(); @@ -910,17 +914,26 @@ * @brief * The execFPGAClockSpeedTest function verifies the processor clock speed * against the FPGA clock. - * @details Inputs: fpgaHeader + * @details Inputs: fpgaHeader, + * window timer TIME_WINDOWED_COUNT_FPGA_CLOCK_SPEED_ERROR * @details Outputs: none - * @return passed, or failed + * @return: none *************************************************************************/ void execFPGAClockSpeedTest( void ) { -#ifndef DEBUG_ENABLED + /* DEBUG WARNING + * It may be necessary to comment out the following + * code to prevent the alarm from occurring while + * debugging. + */ + + static U16 currentFPGATimerCount_ms = 0; + static U32 currentTimerCount_ms = 0; + U16 const newFPGATimerCount_ms = getFPGATimerCount(); - U32 const newTimerCount_ms = getMSTimerCount(); - U32 const diffFPGATimerCount = (U32)u16DiffWithWrap( currentFPGATimerCount_ms, newFPGATimerCount_ms ); - U32 const diffTimerCount = u32DiffWithWrap( currentTimerCount_ms, newTimerCount_ms ); + U32 const newTimerCount_ms = getMSTimerCount(); + U32 const diffFPGATimerCount = (U32)u16DiffWithWrap( currentFPGATimerCount_ms, newFPGATimerCount_ms ); + U32 const diffTimerCount = u32DiffWithWrap( currentTimerCount_ms, newTimerCount_ms ); if ( getCurrentOperationMode() != DG_MODE_INIT ) { @@ -934,8 +947,7 @@ } currentFPGATimerCount_ms = newFPGATimerCount_ms; - currentTimerCount_ms = newTimerCount_ms; -#endif + currentTimerCount_ms = newTimerCount_ms; } /*********************************************************************//** @@ -1107,22 +1119,6 @@ /*********************************************************************//** * @brief - * The monitorFPGAPowerStatus function monitors the status of the FPGA power source. - * @details Inputs: none - * @details Outputs: none - * @return none - *************************************************************************/ -static void monitorFPGAPowerStatus( void ) -{ - // If the GIO bit returned a 0 it mean the power is out, otherwise the power is not out - BOOL isPowerOut = ( TRUE == (BOOL)gioGetBit( gioPORTA, FPGA_GPIO_POWER_STATUS_PIN ) ? FALSE : TRUE ); - - // TODO check to make sure alarm is not raised when the power is good - checkPersistentAlarm( ALARM_ID_DG_FPGA_POWER_OUT_TIMEOUT, isPowerOut, 0, FPGA_POWER_OUT_TIMEOUT_MS ); -} - -/*********************************************************************//** - * @brief * The setFPGAValveStates function sets the DG valve states with a 16-bit * set of states - one bit per valve, with a 1 meaning "energized" and a 0 * meaning "de-energized". The bit positions for these bit states are as follows: @@ -1303,6 +1299,25 @@ /*********************************************************************//** * @brief + * The getFPGAAcidPumpControlStatus function gets the status of the + * acid pump control status bits. + * bit 7: Park (set in different function) + * bit 6: nSleep + * bit 5: nReset + * bit 4: nEnable + * bit 3: Direction (1=Fwd, 0=Rev) + * bit 0-2: Microstepping resolution + * @details Inputs: none + * @details Outputs: fpgaActuatorSetPoints.fpgaNewCP1Control + * @return Acid pump control status bit + *************************************************************************/ +U08 getFPGAAcidPumpControlStatus( void ) +{ + return fpgaActuatorSetPoints.fpgaNewCP1Control; +} + +/*********************************************************************//** + * @brief * The setFPGABicarbPumpControl function sets the DVT concentrate pump 2 * (bicarb pump) control mode. * bit 7: Park (set in different function) @@ -1312,18 +1327,37 @@ * bit 3: Direction (1=Fwd, 0=Rev) * bit 0-2: Microstepping resolution * @details Inputs: none - * @details Outputs: fpgaActuatorSetPoints.fgpaNewCP2Control + * @details Outputs: fpgaActuatorSetPoints.fpgaNewCP2Control * @param control Concentrate pump control set * @return none *************************************************************************/ void setFPGABicarbPumpControl( U08 control ) { - fpgaActuatorSetPoints.fgpaNewCP2Control &= FPGA_CONC_PUMP_PARK_COMMAND; // preserve msb (park command bit) - fpgaActuatorSetPoints.fgpaNewCP2Control |= control; + fpgaActuatorSetPoints.fpgaNewCP2Control &= FPGA_CONC_PUMP_PARK_COMMAND; // preserve msb (park command bit) + fpgaActuatorSetPoints.fpgaNewCP2Control |= control; } /*********************************************************************//** * @brief + * The getFPGABicarbPumpControlStatus function gets the DVT concentrate pump 2 + * (bicarb pump) control mode. + * bit 7: Park (set in different function) + * bit 6: nSleep + * bit 5: nReset + * bit 4: nEnable + * bit 3: Direction (1=Fwd, 0=Rev) + * bit 0-2: Microstepping resolution + * @details Inputs: none + * @details Outputs: fpgaActuatorSetPoints.fpgaNewCP2Control + * @return Bicarb pump control status bit + *************************************************************************/ +U08 getFPGABicarbPumpControlStatus( void ) +{ + return fpgaActuatorSetPoints.fpgaNewCP2Control; +} + +/*********************************************************************//** + * @brief * The setFPGAAcidPumpParkCmd function sets the DVT concentrate pump 1 * (acid pump) park command bit. * bit 7: Park command bit @@ -1345,13 +1379,13 @@ * bit 7: Park command bit * bit 0-6: Other pump control bits (set in different function) * @details Inputs: none - * @details Outputs: fpgaActuatorSetPoints.fgpaNewCP2Control + * @details Outputs: fpgaActuatorSetPoints.fpgaNewCP2Control * @param Park command bit set * @return none *************************************************************************/ void setFPGABicarbPumpParkCmd( void ) { - fpgaActuatorSetPoints.fgpaNewCP2Control |= FPGA_CONC_PUMP_PARK_COMMAND; // this bit must be cleared after next transmit to prevent continuous park commands + fpgaActuatorSetPoints.fpgaNewCP2Control |= FPGA_CONC_PUMP_PARK_COMMAND; // this bit must be cleared after next transmit to prevent continuous park commands } /*********************************************************************//** @@ -2686,4 +2720,74 @@ return fpgaSensorReadings.fpgaOnBoardThermistor; } +/*********************************************************************//** + * @brief + * The getFPGAPowerSupply2ThermistorCount function returns the + * Power Supply 2 thermistor + * count. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return onboard thermistor + *************************************************************************/ +U16 getFPGAPowerSupply2ThermistorCount( void ) +{ + return fpgaSensorReadings.fpgaPowerSupply2; +} + +/*********************************************************************//** + * @brief + * The checkFPGACommFailure function increments the FPGA comm failure + * windowed timer and returns whether or not the number of failures in + * the window have been reached. + * @details Inputs: none + * @details Outputs: none + * @return TRUE if windowed count exceeded, else false. + *************************************************************************/ +BOOL checkFPGACommFailure( void ) +{ + BOOL status = FALSE; + + if ( getMSTimerCount() > MIN_POWER_ON_TIME_FOR_COMM_FAILS ) + { + if ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_COMM_FAILURES ) ) + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_FPGA_COMM_TIMEOUT, MAX_FPGA_COMM_FAILURES, (U32)fpgaSensorReadings.fpgaIOErrorCntProcessor ) + status = TRUE; + } + } + + return status; + +} + +/*********************************************************************//** + * @brief + * The checkFPGACommFailure function increments the FPGA comm failure + * windowed timer if an FE or OE error has occurred and returns whether + * or not the number of failures in + * the window have been reached. + * @details Inputs: none + * @details Outputs: none + * @return TRUE if windowed count exceeded, else false. + *************************************************************************/ +static BOOL checkFPGAFEOEFailure( void ) +{ + BOOL status = FALSE; + BOOL FPGAFEOEError = getSci2FEOEError(); + + if ( TRUE == FPGAFEOEError) + { + if ( getMSTimerCount() > MIN_POWER_ON_TIME_FOR_COMM_FAILS ) + { + if ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_COMM_FAILURES ) ) + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_FPGA_COMM_TIMEOUT, MAX_FPGA_COMM_FAILURES, (U32)fpgaSensorReadings.fpgaIOErrorCntProcessor ) + status = TRUE; + } + } + } + + return status; +} + /**@}*/