// Function Specification // // Name: amec_update_channel_sensor // // Description: Updates the APSS channel sensors only. Used to calculate power based // on raw data obtained from APSS // // End Function Specification void amec_update_channel_sensor(const uint8_t i_channel) { if (i_channel < MAX_APSS_ADC_CHANNELS) { if(AMECSENSOR_PTR(PWRAPSSCH0 + i_channel)->ipmi_sid != 0) { uint32_t l_bulk_voltage = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.sense_12v); uint32_t l_temp32 = ADC_CONVERTED_VALUE(i_channel); l_temp32 = ((l_temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; sensor_update(AMECSENSOR_PTR(PWRAPSSCH0 + i_channel), (uint16_t) l_temp32); } } }
// Function Specification // // Name: amec_update_apss_sensors // // Description: Calculates sensor from raw ADC value // // Thread: RealTime Loop // // End Function Specification void amec_update_apss_sensors(void) { /* * Removed fake apss config data, do not reuse, the old hardcoded * values will not work with the new code used in processing APSS channel * data. * Code is in place to receive command code 0x21 SET CONFIG DATA * which should popluate the ADC and GPIO maps as well as the APSS * calibration data for all 16 ADC channels. */ // ------------------------------------------------------ // APSS Data Collection & Sensorization // ------------------------------------------------------ // Need to check to make sure APSS data has been received // via slave inbox first if(G_slv_inbox_received) { uint8_t l_proc = G_pob_id.module_id; uint32_t temp32 = 0; uint8_t l_idx = 0; uint32_t l_bulk_current_sum = 0; // ---------------------------------------------------- // Convert all ADC Channels immediately // ---------------------------------------------------- for(l_idx=0; l_idx < MAX_APSS_ADC_CHANNELS; l_idx++) { // These values returned are gain adjusted. The APSS readings for // the remote ground and 12V sense are returned in mVs, all other // readings are treated as mAs. G_lastValidAdcValue[l_idx] = amec_value_from_apss_adc(l_idx); // Add up all channels now, we will subtract ones later that don't // count towards the system power l_bulk_current_sum += G_lastValidAdcValue[l_idx]; } // -------------------------------------------------------------- // Convert 12Vsense into interim value - this has to happen first // -------------------------------------------------------------- uint32_t l_bulk_voltage = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.sense_12v); // ---------------------------------------------------------- // Convert Raw Vdd/Vcs/Vio/Vpcie Power from APSS into sensors // ---------------------------------------------------------- // Some sensor values are in Watts so after getting the mA readings we // multiply by the bulk voltage (mVs) which requires us to then divide // by 1000000 to get W (A.V), ie. // divide by 1000 to get it back to milliUnits (0.001) // divide by 10000 to get it to centiUnits (0.01) // divide by 100000 to get it to deciUnits (0.1) // divide by 1000000 to get it to Units (1) #define ADCMULT_TO_UNITS 1000000 #define ADCMULT_ROUND ADCMULT_TO_UNITS/2 uint32_t l_vdd = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.vdd[l_proc]); uint32_t l_vcs_vio_vpcie = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.vcs_vio_vpcie[l_proc]); temp32 = ((l_vcs_vio_vpcie + l_vdd) * l_bulk_voltage)/ADCMULT_TO_UNITS; sensor_update(AMECSENSOR_PTR(PWR250USP0), (uint16_t) temp32); // Save off the combined power from all modules for (l_idx=0; l_idx < MAX_NUM_CHIP_MODULES; l_idx++) { uint32_t l_vd = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.vdd[l_idx]); uint32_t l_vpcie = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.vcs_vio_vpcie[l_idx]); g_amec->proc_snr_pwr[l_idx] = ((l_vpcie + l_vd) * l_bulk_voltage)/ADCMULT_TO_UNITS; } // All readings from APSS come back as milliUnits, so if we want // to convert one, we need to // divide by 1 to get it back to milliUnits (0.001) // divide by 10 to get it to centiUnits (0.01) // divide by 100 to get it to deciUnits (0.1) // divide by 1000 to get it to Units (1) #define ADCSINGLE_TO_CENTIUNITS 100 // Vdd has both a power and a current sensor, we convert the Vdd power // to Watts and the current to centiAmps temp32 = ((l_vdd * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; sensor_update( AMECSENSOR_PTR(PWR250USVDD0), (uint16_t)temp32); temp32 = (l_vdd)/ADCSINGLE_TO_CENTIUNITS; // Current is in 0.01 Amps, sensor_update( AMECSENSOR_PTR(CUR250USVDD0), l_vdd); temp32 = ((l_vcs_vio_vpcie * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; sensor_update( AMECSENSOR_PTR(PWR250USVCS0), (uint16_t)temp32); // ---------------------------------------------------- // Convert Other Raw Misc Power from APSS into sensors // ---------------------------------------------------- // Fans temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.fans[0]); temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.fans[1]); temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; sensor_update( AMECSENSOR_PTR(PWR250USFAN), (uint16_t)temp32); // I/O temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.io[0]); temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.io[1]); temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.io[2]); temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; sensor_update( AMECSENSOR_PTR(PWR250USIO), (uint16_t)temp32); // Memory temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_proc]); temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; sensor_update( AMECSENSOR_PTR(PWR250USMEM0), (uint16_t)temp32); // Save off the combined power from all memory for (l_idx=0; l_idx < MAX_NUM_CHIP_MODULES; l_idx++) { uint32_t l_temp = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_idx]); g_amec->mem_snr_pwr[l_idx] = ((l_temp * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; } // Storage/Media temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.storage_media[0]); temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.storage_media[1]); temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; sensor_update( AMECSENSOR_PTR(PWR250USSTORE), (uint16_t)temp32); // GPU adapter temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.gpu); temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; sensor_update( AMECSENSOR_PTR(PWR250USGPU), (uint16_t)temp32); // ---------------------------------------------------- // Convert Raw Bulk Power from APSS into sensors // ---------------------------------------------------- // We don't get this adc channel in some systems, we have to add it manually. // With valid sysconfig data the code here should automatically use what // is provided by the APSS if it is available, or manually sum it up if not. temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.total_current_12v); temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; // To calculated the total 12V current based on a sum of all ADC channels, // Subract adc channels that don't measure power l_bulk_current_sum -= ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.sense_12v); l_bulk_current_sum -= ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.remote_gnd); // If we don't have a ADC channel that measures the bulk 12v power, use // the ADC sum instead if(0 == temp32) { temp32 = ((l_bulk_current_sum * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; } sensor_update(AMECSENSOR_PTR(PWR250US), (uint16_t)temp32); // Calculate average frequency of all OCCs. uint32_t l_allOccAvgFreqOver250us = 0; uint8_t l_presentOCCs = 0; uint8_t l_occCount = 0; // Add up the average freq from all OCCs. for (l_occCount = 0; l_occCount < MAX_OCCS; l_occCount++) { if (G_sysConfigData.is_occ_present & (1<< l_occCount)) { l_allOccAvgFreqOver250us += G_dcom_slv_outbox_rx[l_occCount].freqa2msp0; l_presentOCCs++; } } //Calculate average of all the OCCs. l_allOccAvgFreqOver250us /= l_presentOCCs; // Save the max and min pwr250us sensors and keep an accumulator of the // average frequency over 30 seconds. if (g_pwr250us_over30sec.count == 0) { //The counter has been reset, therefore initialize the stored values. g_pwr250us_over30sec.max = (uint16_t) temp32; g_pwr250us_over30sec.min = (uint16_t) temp32; g_pwr250us_over30sec.freqaAccum = l_allOccAvgFreqOver250us; } else { //Check for max. if (temp32 > g_pwr250us_over30sec.max) { g_pwr250us_over30sec.max = (uint16_t) temp32; } //Check for min. if (temp32 < g_pwr250us_over30sec.min) { g_pwr250us_over30sec.min = (uint16_t) temp32; } //Average frequency accumulator. g_pwr250us_over30sec.freqaAccum += l_allOccAvgFreqOver250us; } //Count of number of updates. g_pwr250us_over30sec.count++; // ---------------------------------------------------- // Clear Flag to indicate that AMEC has received the data. // ---------------------------------------------------- G_slv_inbox_received = FALSE; } else { // Skip it...AMEC Health Monitor will figure out we didn't // update this sensor. } }