/************************************************************************** * * 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) Sean Nash * @date (last) 09-Nov-2024 * * @author (original) Sean Nash * @date (original) 09-Nov-2024 * ***************************************************************************/ #include "string.h" // for memset(), memcpy() #include "gio.h" // hal headers #include "sci.h" #include "sys_dma.h" #include "Comm.h" #include "Compatible.h" #include "FPGA.h" #include "Messaging.h" #include "OperationModes.h" #include "PersistentAlarm.h" #include "Timers.h" #include "Utilities.h" /** * @addtogroup FpgaRO * @{ */ // ********** private definitions ********** #define FPGA_EXPECTED_ID 0x01 ///< Expected ID for TD FPGA. #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 Sensors Record #pragma pack(push,1) /// Record structure for FPGA header read. typedef struct { U08 fpgaId; ///< Reg 0. FPGA ID code. Checked against expected value at power up to verify basic FPGA communication and operation. U08 fpgaRev; ///< Reg 1. FPGA revision (minor) being reported. U08 fpgaRevMajor; ///< Reg 2. FPGA revision (major) being reported. U08 fpgaRevLab; ///< Reg 3. FPGA revision (lab) being reported. } FPGA_HEADER_T; // Read only on FPGA /// Record structure for FPGA continuous priority reads. typedef struct { U16 compatibilityRev; ///< Reg 256. FPGA compatibility revision. U16 counterTimer1ms; ///< Reg 258. FPGA 1ms timer counter. U16 fpgaGenWrRd; ///< Reg 260. FPGA general read-back register (mirrored from a general write register in write page at addr 4). U08 errorCountProcessor; ///< Reg 262. Error count for processor communications. U08 errorCountPC; ///< Reg 263. Error count for TBD. S16 pressurePri; ///< Reg 264. PRi pressure data. U16 temperaturePri; ///< Reg 266. PRi temperature data. U08 readCountPri; ///< Reg 268. PRi read counter. U08 errorCountPri; ///< Reg 269. PRi error counter. S16 pressurePro; ///< Reg 270. PRo pressure data. U16 temperaturePro; ///< Reg 272. PRo temperature data. U08 readCountPro; ///< Reg 274. PRo read counter. U08 errorCountPro; ///< Reg 275. PRo error counter. S16 pressurePsi; ///< Reg 276. PSi pressure data. U16 temperaturePsi; ///< Reg 278. PSi temperature data. U08 readCountPsi; ///< Reg 280. PSi read counter. U08 errorCountPsi; ///< Reg 281. PSi error counter. S16 pressurePso; ///< Reg 282. PSo pressure data. U16 temperaturePso; ///< Reg 284. PSo temperature data. U08 readCountPso; ///< Reg 286. PSo read counter. U08 errorCountPso; ///< Reg 287. PSo error counter. S16 pressurePc1o; ///< Reg 288. PC1o pressure data. U16 temperaturePc1o; ///< Reg 290. PC1o temperature data. U08 readCountPc1o; ///< Reg 292. PC1o read counter. U08 errorCountPc1o; ///< Reg 293. PC1o error counter. S16 pressurePc2o; ///< Reg 294. PC2o pressure data. U16 temperaturePc2o; ///< Reg 296. PC2o temperature data. U08 readCountPc2o; ///< Reg 298. PC2o read counter. U08 errorCountPc2o; ///< Reg 299. PC2o error counter. S16 pressurePpo; ///< Reg 300. PPo pressure data. U16 temperaturePpo; ///< Reg 302. PPo temperature data. U08 readCountPpo; ///< Reg 304. PPo read counter. U08 errorCountPpo; ///< Reg 305. PPo error counter. S16 pressurePmp; ///< Reg 306. PMp pressure data. U16 temperaturePmp; ///< Reg 308. PMp temperature data. U08 readCountPmp; ///< Reg 310. PMp read counter. U08 errorCountPmp; ///< Reg 311. PMp error counter. S16 pressurePmc; ///< Reg 312. PMc pressure data. U16 temperaturePmc; ///< Reg 314. PMc temperature data. U08 readCountPmc; ///< Reg 316. PMc read counter. U08 errorCountPmc; ///< Reg 317. PMc error counter. S16 pressurePpi; ///< Reg 318. PPi pressure data. U16 temperaturePpi; ///< Reg 320. PPi temperature data. U08 readCountPpi; ///< Reg 322. PPi read counter. U08 errorCountPpi; ///< Reg 323. PPi error counter. S16 pressurePax1; ///< Reg 324. Pax1 pressure data. U16 temperaturePax1; ///< Reg 326. Pax1 temperature data. U08 readCountPax1; ///< Reg 328. Pax1 read counter. U08 errorCountPax1; ///< Reg 329. Pax1 error counter. S16 pressurePax2; ///< Reg 330. Pax2 pressure data. U16 temperaturePax2; ///< Reg 332. Pax2 temperature data. U08 readCountPax2; ///< Reg 334. Pax2 read counter. U08 errorCountPax2; ///< Reg 335. Pax2 error counter. U32 conductSensor1; ///< Reg 336. Conductivity sensor 1. U16 conductSensor1Data; ///< Reg 340. Conductivity sensor 1 data. U16 conductSensor1Temp; ///< Reg 342. Conductivity sensor 1 temperature. U08 conductSensor1ReadCount; ///< Reg 344. Conductivity sensor 1 read counter. U08 conductSensor1ErrorCount; ///< Reg 345. Conductivity sensor 1 error counter. U32 conductSensor2; ///< Reg 346. Conductivity sensor 2. U16 conductSensor2Data; ///< Reg 350. Conductivity sensor 2 data. U16 conductSensor2Temp; ///< Reg 352. Conductivity sensor 2 temperature. U08 conductSensor2ReadCount; ///< Reg 354. Conductivity sensor 2 read counter. U08 conductSensor2ErrorCount; ///< Reg 355. Conductivity sensor 2 error counter. U16 flowRateCountFmp; ///< Reg 356. FMP flow sensor pulse counter. U16 levelSwitch; ///< Reg 358. LRO1..3 level sensors. } FPGA_SENSORS_T; /// Record structure for FPGA continuous priority writes. typedef struct { U08 valveControl; ///< Reg 04. Valve control register. U08 valvePWMEnable; ///< Reg 05. Valve PWM enable register. U08 conductSensorControl1; ///< Reg 06. Conductivity sensor control register 1. U08 conductSensorControl2; ///< Reg 07. Conductivity sensor control register 2. U16 conductAddress1; ///< Reg 08. Conductivity sensor address register 1. U32 conductData1; ///< Reg 10. Conductivity sensor data in register 1. U16 conductAddress2; ///< Reg 14. Conductivity sensor address register 2. U32 conductData2; ///< Reg 16. Conductivity sensor data in register 2. U16 fpgaGenWrRd; ///< Reg 20. FPGA general write/read-back register (mirrored to a general read register in read page at addr 256). U16 descalePumpSpeed; ///< Reg 22. Descaler pump speed register. U08 descalePumpControl; ///< Reg 24. Descaler pump control register. U08 reserved1; ///< Reg 25. Reserved. U16 valveVwiPWMLow; ///< Reg 26. Valve VWi PWM low pulse period in 0.1 uSec. U16 valveVwiPWMPeriod; ///< Reg 28. Valve VWi PWM full period in 0.1 uSec. U16 valveVffPWMLow; ///< Reg 30. U16 valveVffPWMPeriod; ///< Reg 32. U16 valveVPiPWMLow; ///< Reg 34. U16 valveVPiPWMPeriod; ///< Reg 36. U16 valveVcrPWMLow; ///< Reg 38. U16 valveVcrPWMPeriod; ///< Reg 40. U16 valveVcmPWMLow; ///< Reg 42. U16 valveVcmPWMPeriod; ///< Reg 44. U16 valveVprPWMLow; ///< Reg 46. U16 valveVprPWMPeriod; ///< Reg 48. } FPGA_ACTUATORS_T; #pragma pack(pop) // ********** private data ********** // FPGA data static FPGA_HEADER_T fpgaHeader; ///< Record of last received FPGA header data. static FPGA_SENSORS_T fpgaSensorReadings; ///< Record of last received FPGA priority sensor data. static FPGA_ACTUATORS_T fpgaActuatorSetPoints; ///< Record of next transmitted FPGA priority actuator data. // FPGA Clock Speed Test static U16 currentFPGATimerCount_ms = 0; ///< Last read ms timer count from FPGA. static U32 currentTimerCount_ms = 0; ///< Last read ms timer count from processor. /*********************************************************************//** * @brief * The initFPGARO function initializes the RO FPGA unit. * @details \b Inputs: none * @details \b Outputs: RO FPGA unit initialized. * @return none *************************************************************************/ void initFPGARO( void ) { // Initialize fpga driver initFPGA( (U08*)&fpgaHeader, (U08*)&fpgaSensorReadings, (U08*)&fpgaActuatorSetPoints, sizeof(FPGA_HEADER_T), sizeof(FPGA_SENSORS_T), sizeof(FPGA_ACTUATORS_T) ); // Initialize fpga data structures memset( &fpgaHeader, 0, sizeof(FPGA_HEADER_T) ); memset( &fpgaSensorReadings, 0, sizeof(FPGA_SENSORS_T) ); memset( &fpgaActuatorSetPoints, 0, sizeof(FPGA_ACTUATORS_T) ); // 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); } /*********************************************************************//** * @brief * The execFPGATest function executes the FPGA self-test. * @details \b Alarm: ALARM_ID_RO_FPGA_POST_TEST_FAILED if self-test fails. * @details \b Inputs: fpgaHeader * @details \b Outputs: none * @return passed or failed *************************************************************************/ SELF_TEST_STATUS_T execFPGATest( void ) { SELF_TEST_STATUS_T result; // check FPGA reported correct ID if ( FPGA_EXPECTED_ID == fpgaHeader.fpgaId ) { // Check FPGA compatibility w/ firmware if ( TD_FPGA_COMPATIBILITY_REV == fpgaSensorReadings.compatibilityRev ) { result = SELF_TEST_STATUS_PASSED; } else { result = SELF_TEST_STATUS_FAILED; // TODO uncomment // SET_ALARM_WITH_2_U32_DATA( ALARM_ID_RO_FPGA_POST_TEST_FAILED, (U32)TD_FPGA_COMPATIBILITY_REV, (U32)fpgaSensorReadings.fpgaCompatibilityRev ) } } else { result = SELF_TEST_STATUS_FAILED; // TODO uncomment // SET_ALARM_WITH_1_U32_DATA( ALARM_ID_RO_FPGA_POST_TEST_FAILED, (U32)fpgaHeader.fpgaId ) } return result; } /*********************************************************************//** * @brief * The getFPGATimerCount function gets the latest FPGA timer millisecond count. * @details \b Inputs: fpgaSensorReadings * @details \b Outputs: none * @return last FPGA millisecond timer count *************************************************************************/ U16 getFPGATimerCount( void ) { return fpgaSensorReadings.counterTimer1ms; } /*********************************************************************//** * @brief * The execFPGAClockSpeedTest function verifies the processor clock speed * against the FPGA clock. * @details \b Alarm: ALARM_ID_RO_FPGA_CLOCK_SPEED_CHECK_FAILURE if test fails. * @details \b Inputs: fpgaSensorReadings.fpgaTimerCount_ms, msTimerCount, * currentFPGATimerCount_ms, currentTimerCount_ms * @details \b Outputs: currentFPGATimerCount_ms, currentTimerCount_ms * @return none *************************************************************************/ void execFPGAClockSpeedTest( void ) { // DEBUG WARNING // It may be necessary to comment out the following // code to prevent the alarm from occurring while // debugging. U16 newFPGATimerCount_ms = getFPGATimerCount(); U32 newTimerCount_ms = getMSTimerCount(); U32 diffFPGATimerCount = (U32)u16DiffWithWrap( currentFPGATimerCount_ms, newFPGATimerCount_ms ); U32 diffTimerCount = u32DiffWithWrap( currentTimerCount_ms, newTimerCount_ms ); if ( getCurrentOperationMode() != RO_MODE_INIT ) { if ( abs( diffFPGATimerCount - diffTimerCount ) > PROCESSOR_FPGA_CLOCK_DIFF_TOLERANCE ) { if ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_CLOCK_SPEED_ERROR ) ) { // TODO uncomment // SET_ALARM_WITH_2_U32_DATA( ALARM_ID_RO_FPGA_CLOCK_SPEED_CHECK_FAILURE, diffFPGATimerCount, diffTimerCount ); } } } currentFPGATimerCount_ms = newFPGATimerCount_ms; currentTimerCount_ms = newTimerCount_ms; } /*********************************************************************//** * @brief * The getFPGAVersions function gets the fpga version numbers. * @details \b Inputs: fpgaHeader * @details \b Outputs: Given version reference variables are populated. * @return none *************************************************************************/ void getFPGAVersions( U08 *Id, U08 *Maj, U08 *Min, U08 *Lab ) { *Id = fpgaHeader.fpgaId; *Min = fpgaHeader.fpgaRev; *Maj = fpgaHeader.fpgaRevMajor; *Lab = fpgaHeader.fpgaRevLab; } /*********************************************************************//** * @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 \b Inputs: none * @details \b Outputs: none * @return TRUE if windowed count exceeded, else false. *************************************************************************/ void checkFPGACommFailure( void ) { if ( getMSTimerCount() > MIN_POWER_ON_TIME_FOR_COMM_FAILS ) { if ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_COMM_FAILURES ) ) { // TODO uncomment // SET_ALARM_WITH_2_U32_DATA( ALARM_ID_RO_FPGA_COMM_TIMEOUT, MAX_FPGA_COMM_FAILURES, (U32)fpgaSensorReadings.errorCountProcessor ) } } } /*********************************************************************//** * @brief * The checkFPGAAFEOEFailure 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 \b Inputs: none * @details \b Outputs: none * @details \b Alarm: ALARM_ID_DD_FPGA_COMM_TIMEOUT when FPGA communication is * lost with the processor. * @return TRUE if windowed count exceeded, else false. *************************************************************************/ 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 ) ) { // TODO uncomment //SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_FPGA_COMM_TIMEOUT, MAX_FPGA_COMM_FAILURES, (U32)fpgaSensorReadings.fpgaIOErrorCntProcessor ) status = TRUE; } } } return status; } /*********************************************************************//** * @brief * The setFPGAValveStates function sets the RO valve states with an 8-bit * mask 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: * 0 - VFf.\n * 1 - VPi.\n * 2 - VLp.\n * 3 - VCr.\n * 4 - VCb.\n * 5 - VCd1.\n * 6 - VROd.\n * 7 - reserved or unused. * @details \b Inputs: none * @details \b Outputs: fpgaActuatorSetPoints.valveControl * @param valveStates bit mask for requested valve states * @return none *************************************************************************/ void setFPGAValveStates( U16 valveStates ) { fpgaActuatorSetPoints.valveControl = valveStates; } /*********************************************************************//** * @brief * The getFPGAValveStates function gets the RO valve commanded states with * an 8-bit mask representing the set of states with a 1 meaning "energized" * and a 0 meaning "de-energized". * @details \b Inputs: none * @details \b Outputs: fpgaSensorReadings.TBD * @return none *************************************************************************/ U08 getFPGAValveStates( void ) { // return fpgaSensorReadings.TBD; return 0; // TODO } /**@}*/