/************************************************************************** * * Copyright (c) 2021-2022 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 Voltages.c * * @author (last) Dara Navaei * @date (last) 02-May-2022 * * @author (original) Sean Nash * @date (original) 21-Apr-2021 * ***************************************************************************/ #include "AlarmMgmt.h" #include "InternalADC.h" #include "MessageSupport.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "Timers.h" #include "Voltages.h" #include "FPGA.h" /** * @addtogroup Voltages * @{ */ // ********** private definitions ********** #define VOLTAGES_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the voltages data is published on the CAN bus. #define VOLTAGES_ALARM_PERSISTENCE ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Alarm persistence period for voltage monitor alarms. #define DATA_PUBLISH_COUNTER_START_COUNT 1 ///< Data publish counter start count. #define SIZE_OF_ROLLING_AVG 16 ///< Number of DG FPGA ADC samples in rolling average calculations for each channel. #define ROLLING_AVG_SHIFT_DIVIDER 4 ///< Rolling average shift divider for DG FPGA ADC readings. #define FPGA_ADC_BITS_PER_CHANNEL 12 ///< DG FPGA ADC bits per channel. #define FPGA_ADC_FULL_SCALE_BITS ( ( 1 << FPGA_ADC_BITS_PER_CHANNEL ) - 1 ) ///< DG FPGA ADC full scale range. /// Defined states for the voltage monitor state machine. typedef enum Fpga_ADCs { FPGA_ADC_PRIM = 0, ///< Primary Voltage from FPGA. FPGA_ADC_PRIM_GND, ///< Primary Voltage GND from FPGA. NUM_OF_FPGA_ADCS ///< Number of Primary Voltage from FPGA. } FPGA_ADC_T; const F32 FPGA_ADC_READ_TO_UNITS[ NUM_OF_FPGA_ADCS ] = { 0.02783203125, ///< V - FPGA_ADC_PRIM conversion value 0.02783203125, ///< V - FPGA_ADC_PRIM_GND conversion value }; /// Defined states for the voltage monitor state machine. typedef enum Voltages_States { VOLTAGES_INIT_STATE = 0, ///< Initialization state. VOLTAGES_MONITOR_STATE, ///< Continuous read sensors state. NUM_OF_VOLTAGES_STATES ///< Number of voltage monitor states. } VOLTAGES_STATE_T; /// Maximum voltage/current level for each monitored signal. static const F32 MAX_VOLTAGES[ NUM_OF_MONITORED_LINES ] = { 26.4, // MONITORED_LINE_24V_MAIN 1.98, // MONITORED_LINE_1_8V_FPGA 1.1, // MONITORED_LINE_1V_FPGA 3.63, // MONITORED_LINE_3_3V_SENSORS 1.98, // MONITORED_LINE_1_8V_PROC 5.5, // MONITORED_LINE_5V_SENSORS 5.5, // MONITORED_LINE_5V_LOGIC 3.63, // MONITORED_LINE_3_3V 1.32, // MONITORED_LINE_1_2V_PROC 3.3, // MONITORED_LINE_V_REF 3.3, // MONITORED_LINE_EXT_ADC_1_REF_V 3.3, // MONITORED_LINE_EXT_ADC_2_REF_V 5.5, // MONITORED_LINE_PS_GATE_DRIVER_V 26.4, // MONITORED_LINE_24V_PRIM_HTR_V 26.4, // MONITORED_LINE_24V_PRIM_HTR_GND_V 26.4, // MONITORED_LINE_24V_SEC_HTR_V 26.4 // MONITORED_LINE_24V_TRIM_HTR_V }; /// Minimum voltage/current level for each monitored signal. static const F32 MIN_VOLTAGES[ NUM_OF_MONITORED_LINES ] = { 21.6, // MONITORED_LINE_24V_MAIN 1.62, // MONITORED_LINE_1_8V_FPGA 0.9, // MONITORED_LINE_1V_FPGA 2.97, // MONITORED_LINE_3_3V_SENSORS 1.62, // MONITORED_LINE_1_8V_PROC 4.5, // MONITORED_LINE_5V_SENSORS 4.5, // MONITORED_LINE_5V_LOGIC 2.97, // MONITORED_LINE_3_3V 1.08, // MONITORED_LINE_1_2V_PROC 2.7, // MONITORED_LINE_V_REF 2.7, // MONITORED_LINE_EXT_ADC_1_REF_V 2.7, // MONITORED_LINE_EXT_ADC_2_REF_V 4.5, // MONITORED_LINE_PS_GATE_DRIVER_V 0.0, // MONITORED_LINE_24V_PRIM_HTR_V 0.0, // MONITORED_LINE_24V_PRIM_HTR_GND_V 0.0, // MONITORED_LINE_24V_SEC_HTR_V 0.0 // MONITORED_LINE_24V_TRIM_HTR_V }; // ********** private data ********** static VOLTAGES_STATE_T voltagesState; ///< Current state of voltages monitor state machine. static U32 voltagesDataPublicationTimerCounter; ///< Used to schedule voltages monitor data publication to CAN bus. /// Interval (in ms) at which to publish voltages monitor data to CAN bus. static OVERRIDE_U32_T voltagesDataPublishInterval = { VOLTAGES_DATA_PUB_INTERVAL, VOLTAGES_DATA_PUB_INTERVAL, 0, 0 }; static OVERRIDE_F32_T voltages[ NUM_OF_MONITORED_LINES ]; ///< Monitored voltages and currents. static U32 voltageAlarmPersistenceCtr[ NUM_OF_MONITORED_LINES ]; ///< Alarm persistence counters for voltage check failures. static U16 adcReadings[ NUM_OF_FPGA_ADCS ][ SIZE_OF_ROLLING_AVG ]; ///< Buffer holds samples for each channel for a rolling average. static U32 adcReadingsIdx[ NUM_OF_FPGA_ADCS ]; ///< Index for next reading in each rolling average buffer. static U32 adcReadingsTotals[ NUM_OF_FPGA_ADCS ]; ///< Rolling sum for each ADC channel - used to calc average. static U32 adcReadingsAvgs[ NUM_OF_FPGA_ADCS ]; ///< Rolling average for each ADC channel. static F32 fpgaVoltage[ NUM_OF_FPGA_ADCS ]; ///< Converted Voltage from FPGA ADC values // ********** private function prototypes ********** static VOLTAGES_STATE_T handleVoltagesInitState( void ); static VOLTAGES_STATE_T handleVoltagesMonitorState( void ); static void checkVoltageRanges( void ); static void publishVoltagesData( void ); void getFpgaADC( void ); /*********************************************************************//** * @brief * The initVoltagesMonitor function initializes the Voltages module. * @details Inputs: none * @details Outputs: Voltages module initialized. * @return none *************************************************************************/ void initVoltagesMonitor( void ) { U32 i, r; voltagesState = VOLTAGES_INIT_STATE; voltagesDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; for ( i = 0; i < (U32)NUM_OF_MONITORED_LINES; i++ ) { voltages[i].data = 0.0; voltages[i].ovData = 0.0; voltages[i].ovInitData = 0.0; voltages[i].override = OVERRIDE_RESET; voltageAlarmPersistenceCtr[i] = 0; } for ( i = 0; i < (U32)NUM_OF_FPGA_ADCS; i++ ) { adcReadingsIdx[ i ] = 0; adcReadingsTotals[ i ] = 0; adcReadingsAvgs[ i ] = 0; fpgaVoltage[ i ] = 0.0F; for ( r = 0; r < SIZE_OF_ROLLING_AVG; r++ ) { adcReadings[ i ][ r ] = 0; } } } /*********************************************************************//** * @brief * The execVoltagesMonitor function executes the voltages monitor. * @details Inputs: voltagesState * @details Outputs: voltagesState * @return none *************************************************************************/ void execVoltagesMonitor( void ) { // State machine switch ( voltagesState ) { case VOLTAGES_INIT_STATE: voltagesState = handleVoltagesInitState(); break; case VOLTAGES_MONITOR_STATE: voltagesState = handleVoltagesMonitorState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, (U32)SW_FAULT_ID_INVALID_VOLTAGE_MONITOR_STATE, voltagesState ) break; } // Publish voltages data on interval publishVoltagesData(); } /*********************************************************************//** * @brief * The handleVoltagesInitState function handles the initialize state * of the voltages monitor state machine. * @details Inputs: none * @details Outputs: none * @return next state *************************************************************************/ static VOLTAGES_STATE_T handleVoltagesInitState( void ) { VOLTAGES_STATE_T result = VOLTAGES_MONITOR_STATE; return result; } /*********************************************************************//** * @brief * The handleVoltagesMonitorState function handles the monitor state * of the voltages monitor state machine. * @details Inputs: converted internal ADC readings * @details Outputs: alarm on failed check * @return next state *************************************************************************/ static VOLTAGES_STATE_T handleVoltagesMonitorState( void ) { VOLTAGES_STATE_T result = VOLTAGES_MONITOR_STATE; getFpgaADC(); // Get latest signal levels voltages[ MONITORED_LINE_24V_MAIN ].data = getIntADCVoltageConverted( INT_ADC_MAIN_24_VOLTS ); voltages[ MONITORED_LINE_1_8V_FPGA ].data = getIntADCVoltageConverted( INT_ADC_FPGA_1_8_VOLTS ); voltages[ MONITORED_LINE_1V_FPGA ].data = getIntADCVoltageConverted( INT_ADC_FPGA_1_VOLT ); voltages[ MONITORED_LINE_3_3V_SENSORS ].data = getIntADCVoltageConverted( INT_ADC_SENSORS_3_3_VOLTS ); voltages[ MONITORED_LINE_1_8V_PROC ].data = getIntADCVoltageConverted( INT_ADC_PROCESSOR_1_8_VOLTS ); voltages[ MONITORED_LINE_5V_SENSORS ].data = getIntADCVoltageConverted( INT_ADC_SENSORS_5_VOLTS ); voltages[ MONITORED_LINE_5V_LOGIC ].data = getIntADCVoltageConverted( INT_ADC_LOGIC_5_VOLTS ); voltages[ MONITORED_LINE_3_3V ].data = getIntADCVoltageConverted( INT_ADC_3_3_VOLTS ); voltages[ MONITORED_LINE_1_2V_PROC ].data = getIntADCVoltageConverted( INT_ADC_PROCESSOR_1_2_VOLTS ); voltages[ MONITORED_LINE_V_REF ].data = getIntADCVoltageConverted( INT_ADC_REFERENCE_VOLTAGE ); voltages[ MONITORED_LINE_EXT_ADC_1_REF_V ].data = getIntADCVoltageConverted( INT_ADC_REF_IN1 ); voltages[ MONITORED_LINE_EXT_ADC_2_REF_V ].data = getIntADCVoltageConverted( INT_ADC_REF_IN2 ); voltages[ MONITORED_LINE_PS_GATE_DRIVER_V ].data = getIntADCVoltageConverted( INT_ADC_POWER_SUPPLY_GATE_DRIVER ); voltages[ MONITORED_LINE_24V_PRIM_HTR_V ].data = fpgaVoltage[ FPGA_ADC_PRIM ]; voltages[ MONITORED_LINE_24V_PRIM_HTR_GND_V ].data = fpgaVoltage[ FPGA_ADC_PRIM_GND ]; voltages[ MONITORED_LINE_24V_SEC_HTR_V ].data = getIntADCVoltageConverted( INT_ADC_SECONDARY_HEATER_24_VOLTS ); voltages[ MONITORED_LINE_24V_TRIM_HTR_V ].data = getIntADCVoltageConverted( INT_ADC_TRIMMER_HEATER_24_VOLTS ); // Check voltage ranges checkVoltageRanges(); return result; } /*********************************************************************//** * @brief * The getFpgaADC function gets FPGA ADC values, calculate averages, convert to voltage. * @details Inputs: fpgaSensorReadings * @details Outputs: adcReadingsAvgs[], fpgaVoltage[] * @return none *************************************************************************/ void getFpgaADC( void ) { U16 ch; for ( ch = 0; ch < NUM_OF_FPGA_ADCS; ch++ ) { adcReadingsTotals[ ch ] -= adcReadings[ ch ][ adcReadingsIdx[ ch ] ]; switch ( ch ) { case FPGA_ADC_PRIM: adcReadings[ ch ][ adcReadingsIdx[ ch ] ] = getFPGAHeaterGateADC(); break; case FPGA_ADC_PRIM_GND: adcReadings[ ch ][ adcReadingsIdx[ ch ] ] = getFPGAHeaterGndADC(); break; #ifndef _VECTORCAST_ default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_INT_ADC_CHANNEL_NUMBER, ch ) break; #endif } adcReadingsTotals[ ch ] += adcReadings[ ch ][ adcReadingsIdx[ ch ] ]; adcReadingsAvgs[ ch ] = adcReadingsTotals[ ch ] >> ROLLING_AVG_SHIFT_DIVIDER; adcReadingsIdx[ ch ] = INC_WRAP( adcReadingsIdx[ ch ], 0, SIZE_OF_ROLLING_AVG - 1 ); fpgaVoltage[ ch ] = (F32)adcReadingsAvgs[ ch ] * FPGA_ADC_READ_TO_UNITS[ ch ]; } } /*********************************************************************//** * @brief * The checkVoltageRanges function checks each monitored voltage or current * against its minimum and maximum range. * @details Inputs: voltageAlarmPersistenceCtr, MAX_VOLTAGES[], MIN_VOLTAGES[], voltages[] * @details Outputs: voltageAlarmPersistenceCtr, alarm if out of range * @return none *************************************************************************/ static void checkVoltageRanges( void ) { U32 i; // Check range for ( i = 0; i <= MONITORED_LINE_LAST_RANGE_CHECKED_LINE; i++ ) { F32 volts = getMonitoredLineLevel( (MONITORED_VOLTAGES_T)i ); if ( volts > MAX_VOLTAGES[ i ] ) { if ( ++voltageAlarmPersistenceCtr[ i ] > VOLTAGES_ALARM_PERSISTENCE ) { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DG_VOLTAGE_OUT_OF_RANGE, (F32)i, volts ) } } else if ( volts < MIN_VOLTAGES[ i ] ) { if ( ++voltageAlarmPersistenceCtr[ i ] > VOLTAGES_ALARM_PERSISTENCE ) { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DG_VOLTAGE_OUT_OF_RANGE, (F32)i, volts ) } } else { voltageAlarmPersistenceCtr[ i ] = 0; } } // TODO - check heater voltages depending on current PWM level } /*********************************************************************//** * @brief * The getMonitoredLineLevel function gets the current voltage or current * level for a given signal. * @details Inputs: voltages[] * @details Outputs: none * @param signal the signal that is being asked for * @return the voltage/current for the given signal *************************************************************************/ F32 getMonitoredLineLevel( MONITORED_VOLTAGES_T signal ) { F32 result = 0.0; if ( signal < NUM_OF_MONITORED_LINES ) { result = getF32OverrideValue( &voltages[ signal ] ); } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, (U32)SW_FAULT_ID_INVALID_MONITORED_VOLTAGE_ID, (U32)signal ) } return result; } /*********************************************************************//** * @brief * The publishVoltagesData function publishes voltages monitor data at the * set interval. * @details Inputs: latest voltages and currents * @details Outputs: voltages monitor data are published to CAN bus. * @return none *************************************************************************/ static void publishVoltagesData( void ) { // Publish voltages monitor data on interval if ( ++voltagesDataPublicationTimerCounter >= getU32OverrideValue( &voltagesDataPublishInterval ) ) { VOLTAGES_DATA_PAYLOAD_T data; data.adc1VFPGA = getMonitoredLineLevel( MONITORED_LINE_1V_FPGA ); data.adc1_2VProc = getMonitoredLineLevel( MONITORED_LINE_1_2V_PROC ); data.adc1_8VProc = getMonitoredLineLevel( MONITORED_LINE_1_8V_PROC ); data.adc1_8VFPGA = getMonitoredLineLevel( MONITORED_LINE_1_8V_FPGA ); data.adc3VRef = getMonitoredLineLevel( MONITORED_LINE_V_REF ); data.adc3VExtADC1 = getMonitoredLineLevel( MONITORED_LINE_EXT_ADC_1_REF_V ); data.adc3VExtADC2 = getMonitoredLineLevel( MONITORED_LINE_EXT_ADC_2_REF_V ); data.adc3_3V = getMonitoredLineLevel( MONITORED_LINE_3_3V ); data.adc3_3VSensors = getMonitoredLineLevel( MONITORED_LINE_3_3V_SENSORS ); data.adc5VLogic = getMonitoredLineLevel( MONITORED_LINE_5V_LOGIC ); data.adc5VSensors = getMonitoredLineLevel( MONITORED_LINE_5V_SENSORS ); data.adc5VPSGateDriver = getMonitoredLineLevel( MONITORED_LINE_PS_GATE_DRIVER_V ); data.adc24V = getMonitoredLineLevel( MONITORED_LINE_24V_MAIN ); data.adc24VPrimaryHtr = getMonitoredLineLevel( MONITORED_LINE_24V_PRIM_HTR_V ); data.adc24VPrimaryHtrGnd = getMonitoredLineLevel( MONITORED_LINE_24V_PRIM_HTR_GND_V ); data.adc24VSecondaryHtr = getMonitoredLineLevel( MONITORED_LINE_24V_SEC_HTR_V ); data.adc24VTrimmerHtr = getMonitoredLineLevel( MONITORED_LINE_24V_TRIM_HTR_V ); broadcastData( MSG_ID_DG_VOLTAGES_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&data, sizeof( VOLTAGES_DATA_PAYLOAD_T ) ); voltagesDataPublicationTimerCounter = 0; } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testSetVoltagesDataPublishIntervalOverride function overrides the * monitored voltages data publish interval. * @details Inputs: none * @details Outputs: voltagesDataPublishInterval * @param value override monitored voltages data publish interval with (in ms) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetVoltagesDataPublishIntervalOverride( U32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { U32 intvl = value / TASK_GENERAL_INTERVAL; result = TRUE; voltagesDataPublishInterval.ovData = intvl; voltagesDataPublishInterval.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetVoltagesDataPublishIntervalOverride function resets the override * of the monitored voltages data publish interval. * @details Inputs: none * @details Outputs: voltagesDataPublishInterval * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetVoltagesDataPublishIntervalOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; voltagesDataPublishInterval.override = OVERRIDE_RESET; voltagesDataPublishInterval.ovData = voltagesDataPublishInterval.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetLineLevelOverride function overrides the given monitored voltage * or current. * @details Inputs: none * @details Outputs: voltages[] * @param signal the signal to override * @param value override signal level with this value * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetLineLevelOverride( U32 signal, F32 value ) { BOOL result = FALSE; if ( signal < NUM_OF_MONITORED_LINES ) { if ( TRUE == isTestingActivated() ) { result = TRUE; voltages[ signal ].ovData = value; voltages[ signal ].override = OVERRIDE_KEY; } } return result; } /*********************************************************************//** * @brief * The testResetLineLevelOverride function resets the override of the * given monitored voltage or current. * @details Inputs: none * @details Outputs: voltages[] * @param signal the signal to reset override * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetLineLevelOverride( U32 signal ) { BOOL result = FALSE; if ( signal < NUM_OF_MONITORED_LINES ) { if ( TRUE == isTestingActivated() ) { result = TRUE; voltages[ signal ].override = OVERRIDE_RESET; voltages[ signal ].ovData = voltages[ signal ].ovInitData; } } return result; } /**@}*/