// Scan all of the DIMM temps and keep track of the hottest void update_hottest_dimm() { // Find/save the hottest DIMM temperature for the last set of readings uint8_t hottest = 0, hottest_loc = 0; int pIndex, dIndex; for (pIndex = 0; pIndex < G_maxDimmPorts; ++pIndex) { for (dIndex = 0; dIndex < NUM_DIMMS_PER_CENTAUR; ++dIndex) { if (g_amec->proc[0].memctl[pIndex].centaur.dimm_temps[dIndex].cur_temp > hottest) { hottest = g_amec->proc[0].memctl[pIndex].centaur.dimm_temps[dIndex].cur_temp; hottest_loc = (pIndex*8) + dIndex; } } } DIMM_DBG("update_hottest_dimm: hottest DIMM temp for this sample: %dC (loc=%d)", hottest, hottest_loc); if(hottest > g_amec->proc[0].memctl[0].centaur.tempdimmax.sample_max) { // Save hottest DIMM location ever sampled DIMM_DBG("update_hottest_dimm: Hottest DIMM ever sampled was DIMM%d %dC (prior %dC)", hottest_loc, hottest, g_amec->proc[0].memctl[0].centaur.tempdimmax.sample_max); sensor_update(&g_amec->proc[0].memctl[0].centaur.locdimmax, hottest_loc); } // Nimbus has no Centaurs, but store hottest temp in memctl[0] sensor_update(&g_amec->proc[0].memctl[0].centaur.tempdimmax, hottest); }
// Function Specification // // Name: amec_update_external_voltage // // Description: Measure actual external voltage // // Thread: RealTime Loop // // End Function Specification void amec_update_external_voltage() { /*------------------------------------------------------------------------*/ /* Local Variables */ /*------------------------------------------------------------------------*/ uint32_t l_data = 0; uint16_t l_temp = 0; uint16_t l_vdd = 0; uint16_t l_vcs = 0; /*------------------------------------------------------------------------*/ /* Code */ /*------------------------------------------------------------------------*/ // Collect the external voltage data l_data = in32(PMC_GLOBAL_ACTUAL_VOLTAGE_REG); // Extract the Vdd vid code and convert to voltage l_temp = (l_data & 0xFF000000) >>24; l_vdd = 16125 - ((uint32_t)l_temp * 625)/10; // Extract the Vcs vid code and convert to voltage l_temp = (l_data & 0x00FF0000) >>16; l_vcs = 16125 - ((uint32_t)l_temp * 625)/10; sensor_update( AMECSENSOR_PTR(VOLT250USP0V0), (uint16_t) l_vdd); sensor_update( AMECSENSOR_PTR(VOLT250USP0V1), (uint16_t) l_vcs); }
void state_normal_init(){ reset_fsm(); sensor_update(); post_timeout_end = set_timeout(millis() + POST_PERIOD_MS); post_res = NOT_POSTING; needs_to_post_room_changed = 0; returned_led_state = 1; #ifdef UPSIDE_DOWN util_timer_set_accel(1); #endif }
// 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_dps_partition_update_sensors // // Description: Update utilization sensors for a core group. // // End Function Specification void amec_dps_partition_update_sensors(const uint16_t i_part_id) { /*------------------------------------------------------------------------*/ /* Local Variables */ /*------------------------------------------------------------------------*/ amec_core_perf_counter_t* l_perf = NULL; uint16_t l_core_index = 0; uint8_t l_idx = 0; uint32_t l_cg_active_accumulator = 0; uint32_t l_cg_slack_accumulator = 0; uint16_t l_cg_util_slack_perc = 0; uint32_t l_divide32[2] = {0, 0}; /*------------------------------------------------------------------------*/ /* Code */ /*------------------------------------------------------------------------*/ for (l_idx=0; l_idx<g_amec->part_config.part_list[i_part_id].ncores; l_idx++) { l_core_index = g_amec->part_config.part_list[i_part_id].core_list[l_idx]; l_perf = &g_amec->proc[0].core[l_core_index % MAX_NUM_CORES].core_perf; // Sum accumulators for core group l_cg_active_accumulator += l_perf->util_active_accumulator; l_cg_slack_accumulator += l_perf->util_slack_accumulator; } if (l_cg_active_accumulator == 0) { // Check for divide by zero l_cg_util_slack_perc=16384; // if no active cores, set slack=100% } else { l_divide32[1]=(uint32_t)l_cg_active_accumulator; l_divide32[0]=(uint32_t)l_cg_slack_accumulator<<14; // *16384 because 16384=1.0 l_divide32[0] /= l_divide32[1]; l_cg_util_slack_perc=(uint16_t)(l_divide32[0]); } // Update the sensor of the utilization slack sensor_update(&g_amec->part_config.part_list[i_part_id].util2msslack, l_cg_util_slack_perc); }
// Function Specification // // Name: amec_update_current_sensor // // Description: Estimates Vdd output current based on input power and Vdd voltage setting. // Compute CUR250USVDD0 (current out of Vdd regulator) // // Flow: // // Thread: RealTime Loop // // Changedby: // // Task Flags: // // End Function Specification void amec_update_current_sensor(void) { uint32_t result32; //temporary result uint16_t l_pow_reg_input_dW = AMECSENSOR_PTR(PWR250USVDD0)->sample * 10; // convert to dW by *10. uint16_t l_vdd_reg = AMECSENSOR_PTR(VOLT250USP0V0)->sample; uint32_t l_pow_reg_output_mW; uint32_t l_curr_output; /* Step 1 */ // 1. Get PWR250USVDD0 (the input power to regulator) // 2. Look up efficiency using PWR250USVDD0 as index (and interpolate) // 3. Calculate output power = PWR250USVDD0 * efficiency // 4. Calculate output current = output power / Vdd set point /* Determine regulator efficiency */ // use 85% efficiency all the time result32 = 8500; // Compute regulator output power. out = in * efficiency // in: min=0W max=300W = 3000dW // eff: min=0 max=10000=100% (.01% units) // p_out: max=3000dW * 10000 = 30,000,000 (dW*0.0001) < 2^25, fits in 25 bits l_pow_reg_output_mW = (uint32_t)l_pow_reg_input_dW * (uint32_t)result32; // Scale up p_out by 10x to give better resolution for the following division step // p_out: max=30M (dW*0.0001) in 25 bits // * 10 = 300M (dW*0.00001) in 29 bits l_pow_reg_output_mW *= 10; // Compute current out of regulator. curr_out = power_out (*10 scaling factor) / voltage_out // p_out: max=300M (dW*0.00001) in 29 bits // v_out: min=5000 (0.0001 V) max=16000(0.0001 V) in 14 bits // i_out: max = 300M/5000 = 60000 (dW*0.00001/(0.0001V)= 0.01A), in 16 bits. // VOLT250USP0V0 in units of 0.0001 V = 0.1 mV. (multiply by 0.1 to get mV) l_curr_output = l_pow_reg_output_mW / l_vdd_reg; sensor_update(AMECSENSOR_PTR(CUR250USVDD0), l_curr_output); }
void int_cmt_cmt1(void) { cmt1_counter++; //各処理系/////////////////////////////////////////////////////////////////// // map_update(); //ジャイロと2つのエンコーダを用いてマップの更新(coordinate_omni) // gyro_map(); //ジャイロMAP状態の更新 sensor_update();//センサーの状態を確認(アームの状態等の取得) //プレステコンからの受信///////////////////////////////////////////////////// recieve_data_input(); //受信割り込みから受け取った値を格納(中でdutyも計算している) input_register_ctrl(); //dutyをレジスタに格納 //////////////////////////////////////////////////////////////////////////// //自動制御////////////////////////////////////////////////////////////////// // if(left_arm_auto_flag==1) // left_arm_ctrl(); //アーム自動制御 cmt1_counter=0; }
// Function Specification // // Name: amec_update_vrm_sensors // // Description: Updates sensors that use data from the VRMs // (e.g., VR_FAN, FANS_FULL_SPEED, VR_HOT). // // Thread: RealTime Loop // // End Function Specification void amec_update_vrm_sensors(void) { /*------------------------------------------------------------------------*/ /* Local Variables */ /*------------------------------------------------------------------------*/ int l_rc = 0; int l_vrfan = 0; int l_softoc = 0; int l_minus_np1_regmode = 0; int l_minus_n_regmode = 0; static uint8_t L_error_count = 0; uint8_t l_pin = 0; uint8_t l_pin_value = 1; // active low, so set default to high uint8_t l_vrhot_count = 0; errlHndl_t l_err = NULL; /*------------------------------------------------------------------------*/ /* Code */ /*------------------------------------------------------------------------*/ // Check if we have access to SPIVID. In DCMs only Master OCC has access to // the SPIVID. if (G_dcm_occ_role == OCC_DCM_MASTER) { // VR_FAN and SOFT_OC come from SPIVID l_rc = vrm_read_state(SPIVRM_PORT(0), &l_minus_np1_regmode, &l_minus_n_regmode, &l_vrfan, &l_softoc); if (l_rc == 0) { // Update the VR_FAN sensor sensor_update( AMECSENSOR_PTR(VRFAN250USPROC), (uint16_t)l_vrfan ); // Clear our error count and the 'read failure' flag (since we can // read VR_FAN signal) L_error_count = 0; G_thrm_fru_data[DATA_FRU_VRM].read_failure = 0; // Obtain the 'fan_full_speed' GPIO from APSS l_pin = G_sysConfigData.apss_gpio_map.fans_full_speed; // No longer reading gpio from APSS in GA1 due to instability in // APSS composite mode //apss_gpio_get(l_pin, &l_pin_value); // VR_HOT sensor is a counter of number of times the VRHOT signal // has been asserted l_vrhot_count = AMECSENSOR_PTR(VRHOT250USPROC)->sample; // Check if VR_FAN is asserted AND if 'fans_full_speed' GPIO is ON. // Note that this GPIO is active low. if (AMECSENSOR_PTR(VRFAN250USPROC)->sample && !(l_pin_value)) { // VR_FAN is asserted and 'fans_full_speed' GPIO is ON, // then increment our VR_HOT counter if (l_vrhot_count < g_amec->vrhotproc.setpoint) { l_vrhot_count++; } } else { // Reset our VR_HOT counter l_vrhot_count = 0; } sensor_update(AMECSENSOR_PTR(VRHOT250USPROC), l_vrhot_count); } else { // Increment our error count L_error_count++; // Don't allow the error count to wrap if (L_error_count == 0) { L_error_count = 0xFF; } // Log an error if we exceeded our number of fail-to-read sensor if ((L_error_count == g_amec->proc[0].vrfan_error_count) && (g_amec->proc[0].vrfan_error_count != 0xFF)) { TRAC_ERR("amec_update_vrm_sensors: Failed to read VR_FAN for %u consecutive times!", L_error_count); // Also, inform the thermal thread to send a cooling request G_thrm_fru_data[DATA_FRU_VRM].read_failure = 1; /* @ * @errortype * @moduleid AMEC_HEALTH_CHECK_VRFAN_TIMEOUT * @reasoncode VRM_VRFAN_TIMEOUT * @userdata1 timeout value * @userdata2 0 * @userdata4 OCC_NO_EXTENDED_RC * @devdesc Failed to read VR_FAN signal from regulator. * */ l_err = createErrl(AMEC_HEALTH_CHECK_VRFAN_TIMEOUT, //modId VRM_VRFAN_TIMEOUT, //reasoncode OCC_NO_EXTENDED_RC, //Extended reason code ERRL_SEV_PREDICTIVE, //Severity NULL, //Trace Buf DEFAULT_TRACE_SIZE, //Trace Size g_amec->thermaldimm.temp_timeout, //userdata1 0); //userdata2 // Callout backplane for this VRM error addCalloutToErrl(l_err, ERRL_CALLOUT_TYPE_HUID, G_sysConfigData.backplane_huid, ERRL_CALLOUT_PRIORITY_MED); // Commit the error commitErrl(&l_err); } } } if( 1 ) { sensor_update( AMECSENSOR_PTR(VRFAN250USMEM), 0 ); sensor_update( AMECSENSOR_PTR(VRHOT250USMEM), 0 ); } }
// 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. } }
void state_normal_play(){ // HACK do not allow all of these during posting until a clean way of aborting the FSM is coded. if (post_res == NOT_POSTING && usb_serial_get_nb_received() > 0){ uint8_t res; char t[32]; uint8_t c = usb_serial_get_byte(); switch(c){ case 'w': #ifdef WIFI state_set_next(&main_fsm, &state_config); #endif return; break; case 'e': DCALIB_PRINTF("HUM calib : %u\r\n", sensor_calib_HUM_is_done()); DCALIB_PRINTF("TEMP calib : %u\r\n", sensor_calib_TEMP_is_done()); DCALIB_PRINTF("PM calib : %u\r\n", sensor_calib_PM_is_done()); DCALIB_PRINTF("k_HUM : %u\r\n", eeprom_read_byte(calib_eeprom_k_hum_addr)); DCALIB_PRINTF("b_HUM : %li\r\n", (uint32_t) round(eeprom_read_float(calib_eeprom_b_hum_addr)*100)); DCALIB_PRINTF("k_TEMP : %u\r\n", eeprom_read_byte(calib_eeprom_k_temp_addr)); DCALIB_PRINTF("b_TEMP : %li\r\n", (int32_t) round(eeprom_read_float(calib_eeprom_b_temp_addr)*100)); DCALIB_PRINTF("k_PM : %u\r\n", eeprom_read_byte(calib_eeprom_k_pm_addr)); DCALIB_PRINTF("b_PM : %li\r\n", (int32_t) round(eeprom_read_float(calib_eeprom_b_pm_addr)*100)); break; case 'm': fprintf(&USBSerialStream, "MAC: %s\r\n", get_mac_str()); break; case 'g': #ifdef CALIBRATION sensor_calib_erase_calibration_k(); #endif break; case 'c': #ifdef CALIBRATION state_set_next(&main_fsm,&state_calibration); #endif break; case '-': println("Mem clear"); wifi_config_mem_clear(); error_set_post(POST_ERROR_WIFI_NO_CONFIG); default: break; } } if (error_post() != POST_ERROR_WIFI_NO_CONFIG){ util_timer_enable_interrupt(); // TODO update motor motor_set(180);// TEMP prev_post_res = post_res; // TODO integrate needs_to_post_room_changed to the flow to tell the backend that the room has changed... post_res = post_fsm(); // this runs the fsm until it stops then doesn't do anything until it's reset. uint32_t now = millis(); if (prev_post_res == POSTING && post_res == NOT_POSTING){ // just finished posting if (post_fsm_error()){ error_set_post(POST_ERROR_WIFI_NO_POST); } else { error_set_post(POST_ERROR_NO_ERROR); } DSENSOR_INFO_PRINTF("%lu, VOC, VOC_RAW, CO2, VZ87_VOC, VZ87_CO2, VZ87_RAW, SENSOR_1, SENSOR_2, PM*100, PM_Cal*100, TMP*100,PMP_Cal*100, HUM*100, HUM_Cal*100\r\n", now); sensor_update(); update_timeout_end = set_timeout(now + SENSOR_UPDATE_PERIOD_MS); needs_to_post_room_changed = 0; } // when a change of room is detected, the timer before next post is put to at least // 1 min to avoid posting old data to the new room. #ifdef UPSIDE_DOWN if ((post_res == NOT_POSTING) && upsidedown_detected ){ // posting must not be happening right now and an upside down condition must have been detected upsidedown_detected = 0; post_timeout_end = MAX(post_timeout_end, set_timeout(now + 60000)); needs_to_post_room_changed = 1; } #endif #ifdef DOUBLE_TAP_ENABLED if ((post_res == NOT_POSTING) && double_tap_detected){ reset_fsm(); } #endif if ( now > post_timeout_end && (post_res == NOT_POSTING)){ reset_fsm(); post_timeout_end = set_timeout(now + POST_PERIOD_MS); } else if (now > update_timeout_end && (post_res == NOT_POSTING)){ sensor_update(); update_timeout_end = set_timeout(now + SENSOR_UPDATE_PERIOD_MS); } } else { // The wifi has not been configured. This case is special since it makes it impossible to do anything interesting, // aside from configuring it. util_timer_disable_interrupt(); led_set(0, 0, 100); } }
// Function Specification // // Name: amec_update_proc_core_sensors // // Description: Update all the sensors for a given proc // // Thread: RealTime Loop // // End Function Specification void amec_update_proc_core_sensors(uint8_t i_core) { gpe_bulk_core_data_t * l_core_data_ptr; int i; uint16_t l_temp16 = 0; uint32_t l_temp32 = 0; // Make sure the core is present, and that it has updated data. if(CORE_PRESENT(i_core) && CORE_UPDATED(i_core)) { // Clear flag indicating core was updated by proc task CLEAR_CORE_UPDATED(i_core); // Get pointer to core data l_core_data_ptr = proc_get_bulk_core_data_ptr(i_core); //------------------------------------------------------- // Thermal Sensors & Calc //------------------------------------------------------- amec_calc_dts_sensors(l_core_data_ptr, i_core); //------------------------------------------------------- //CPM - Commented out as requested by Malcolm // ------------------------------------------------------ // amec_calc_cpm_sensors(l_core_data_ptr, i_core); //------------------------------------------------------- // Util / Freq //------------------------------------------------------- // Skip this update if there was an empath collection error if (!CORE_EMPATH_ERROR(i_core)) { amec_calc_freq_and_util_sensors(l_core_data_ptr,i_core); } //------------------------------------------------------- // Performance counter - This function should be called // after amec_calc_freq_and_util_sensors(). //------------------------------------------------------- amec_calc_dps_util_counters(i_core); //------------------------------------------------------- // IPS //------------------------------------------------------- // Skip this update if there was an empath collection error if (!CORE_EMPATH_ERROR(i_core)) { amec_calc_ips_sensors(l_core_data_ptr,i_core); } //------------------------------------------------------- // SPURR //------------------------------------------------------- amec_calc_spurr(i_core); // ------------------------------------------------------ // Update PREVIOUS values for next time // ------------------------------------------------------ g_amec->proc[0].core[i_core].prev_PC_RAW_Th_CYCLES = l_core_data_ptr->per_thread[0].raw_cycles; // Skip empath updates if there was an empath collection error on this core if (!CORE_EMPATH_ERROR(i_core)) { g_amec->proc[0].core[i_core].prev_PC_RAW_CYCLES = l_core_data_ptr->empath.raw_cycles; g_amec->proc[0].core[i_core].prev_PC_RUN_CYCLES = l_core_data_ptr->empath.run_cycles; g_amec->proc[0].core[i_core].prev_PC_COMPLETED = l_core_data_ptr->empath.completion; g_amec->proc[0].core[i_core].prev_PC_DISPATCH = l_core_data_ptr->empath.dispatch; g_amec->proc[0].core[i_core].prev_tod_2mhz = l_core_data_ptr->empath.tod_2mhz; g_amec->proc[0].core[i_core].prev_FREQ_SENS_BUSY = l_core_data_ptr->empath.freq_sens_busy; g_amec->proc[0].core[i_core].prev_FREQ_SENS_FINISH = l_core_data_ptr->empath.freq_sens_finish; } for(i=0; i<MAX_THREADS_PER_CORE; i++) { g_amec->proc[0].core[i_core].thread[i].prev_PC_RUN_Th_CYCLES = l_core_data_ptr->per_thread[i].run_cycles; } // Final step is to update TOD sensors // Extract 32 bits with 16usec resolution l_temp32 = (uint32_t)(G_dcom_slv_inbox_doorbell_rx.tod>>13); l_temp16 = (uint16_t)(l_temp32); // low 16 bits is 16usec resolution with 512MHz TOD clock sensor_update( AMECSENSOR_PTR(TODclock0), l_temp16); l_temp16 = (uint16_t)(l_temp32>>16); // mid 16 bits is 1.05sec resolution with 512MHz TOD clock sensor_update( AMECSENSOR_PTR(TODclock1), l_temp16); l_temp16 = (uint16_t)(G_dcom_slv_inbox_doorbell_rx.tod>>45); // hi 3 bits in 0.796 day resolution with 512MHz TOD clock sensor_update( AMECSENSOR_PTR(TODclock2), l_temp16); }
// Function Specification // // Name: amec_slv_voting_box // // Description: Slave OCC's voting box that decides the frequency request. // This function will run every tick. // // Thread: RealTime Loop // // Task Flags: // // End Function Specification void amec_slv_voting_box(void) { /*------------------------------------------------------------------------*/ /* Local Variables */ /*------------------------------------------------------------------------*/ uint16_t k = 0; uint16_t l_chip_fmax = g_amec->sys.fmax; uint16_t l_core_freq = 0; uint32_t l_chip_reason = 0; uint32_t l_core_reason = 0; uint8_t l_kvm_throt_reason = NO_THROTTLE; amec_part_t *l_part = NULL; bool l_freq_req_changed = FALSE; /*------------------------------------------------------------------------*/ /* Code */ /*------------------------------------------------------------------------*/ // Voting Box for CPU speed. // This function implements the voting box to decide which input gets the right // to actuate the system. //Reset the maximum core frequency requested prior to recalculation. g_amec->proc[0].core_max_freq = 0; // PPB_FMAX if(g_amec->proc[0].pwr_votes.ppb_fmax < l_chip_fmax) { l_chip_fmax = g_amec->proc[0].pwr_votes.ppb_fmax; l_chip_reason = AMEC_VOTING_REASON_PPB; l_kvm_throt_reason = POWERCAP; } // PMAX_CLIP_FREQ if(g_amec->proc[0].pwr_votes.pmax_clip_freq < l_chip_fmax) { l_chip_fmax = g_amec->proc[0].pwr_votes.pmax_clip_freq; l_chip_reason = AMEC_VOTING_REASON_PMAX; l_kvm_throt_reason = POWER_SUPPLY_FAILURE; } // Pmax_clip frequency request if there is an APSS failure if(g_amec->proc[0].pwr_votes.apss_pmax_clip_freq < l_chip_fmax) { l_chip_fmax = g_amec->proc[0].pwr_votes.apss_pmax_clip_freq; l_chip_reason = AMEC_VOTING_REASON_APSS_PMAX; l_kvm_throt_reason = POWER_SUPPLY_FAILURE; } //THERMALPROC.FREQ_REQUEST //Thermal controller input based on processor temperature if(g_amec->thermalproc.freq_request < l_chip_fmax) { l_chip_fmax = g_amec->thermalproc.freq_request; l_chip_reason = AMEC_VOTING_REASON_PROC_THRM; l_kvm_throt_reason = CPU_OVERTEMP; } // Controller request based on VRHOT signal from processor regulator if(g_amec->vrhotproc.freq_request < l_chip_fmax) { l_chip_fmax = g_amec->vrhotproc.freq_request; l_chip_reason = AMEC_VOTING_REASON_VRHOT_THRM; l_kvm_throt_reason = CPU_OVERTEMP; } // CONN_OC_VOTE if(g_amec->proc[0].pwr_votes.conn_oc_vote < l_chip_fmax) { l_chip_fmax = g_amec->proc[0].pwr_votes.conn_oc_vote; l_chip_reason = AMEC_VOTING_REASON_CONN_OC; l_kvm_throt_reason = OVERCURRENT; } for (k=0; k<MAX_NUM_CORES; k++) { if(CORE_PRESENT(k)) { l_core_freq = l_chip_fmax; l_core_reason = l_chip_reason; // Disable DPS in KVM if(!G_sysConfigData.system_type.kvm) { l_part = amec_part_find_by_core(&g_amec->part_config, k); // Check frequency request generated by DPS algorithms if(g_amec->proc[0].core[k].core_perf.dps_freq_request < l_core_freq) { l_core_freq = g_amec->proc[0].core[k].core_perf.dps_freq_request; l_core_reason = AMEC_VOTING_REASON_UTIL; } // Adjust frequency based on soft frequency boundaries if(l_part != NULL) { if(l_core_freq < l_part->soft_fmin) { // Before enforcing a soft Fmin, make sure we don't // have a thermal or power emergency if(!(l_chip_reason & (AMEC_VOTING_REASON_PROC_THRM | AMEC_VOTING_REASON_VRHOT_THRM | AMEC_VOTING_REASON_PPB | AMEC_VOTING_REASON_PMAX | AMEC_VOTING_REASON_CONN_OC))) { l_core_freq = l_part->soft_fmin; l_core_reason = AMEC_VOTING_REASON_SOFT_MIN; } } else if(l_core_freq > l_part->soft_fmax) { l_core_freq = l_part->soft_fmax; l_core_reason = AMEC_VOTING_REASON_SOFT_MAX; } } } if(CURRENT_MODE() == OCC_MODE_NOMINAL) { // PROC_PCAP_NOM_VOTE if(g_amec->proc[0].pwr_votes.proc_pcap_nom_vote < l_core_freq) { l_core_freq = g_amec->proc[0].pwr_votes.proc_pcap_nom_vote; l_core_reason = AMEC_VOTING_REASON_PWR; l_kvm_throt_reason = POWERCAP; } } else { // PROC_PCAP_VOTE if(g_amec->proc[0].pwr_votes.proc_pcap_vote < l_core_freq) { l_core_freq = g_amec->proc[0].pwr_votes.proc_pcap_vote; l_core_reason = AMEC_VOTING_REASON_PWR; l_kvm_throt_reason = POWERCAP; } } // Check IPS frequency request sent by Master OCC if(g_amec->slv_ips_freq_request != 0) { if(g_amec->slv_ips_freq_request < l_core_freq) { l_core_freq = g_amec->slv_ips_freq_request; l_core_reason = AMEC_VOTING_REASON_IPS; } } // Override frequency with request from Master OCC if(g_amec->foverride_enable) { if(g_amec->foverride != 0) { // Override the frequency on all cores if Master OCC sends // a non-zero request l_core_freq = g_amec->foverride; l_core_reason = AMEC_VOTING_REASON_OVERRIDE; } } if(g_amec->pstate_foverride_enable) { if(g_amec->pstate_foverride != 0) { // Override the frequency on all cores if the Global Pstate // table has been modified l_core_freq = g_amec->pstate_foverride; l_core_reason = AMEC_VOTING_REASON_OVERRIDE; } } //Make sure the frequency is not less then the system min if(l_core_freq < g_amec->sys.fmin) { l_core_freq = g_amec->sys.fmin; } // Override frequency via Amester parameter interface if (g_amec->proc[0].parm_f_override_enable && g_amec->proc[0].parm_f_override[k] > 0) { l_core_freq = g_amec->proc[0].parm_f_override[k]; l_core_reason = AMEC_VOTING_REASON_OVERRIDE_CORE; } // If frequency has changed, set the flag if ( (l_core_freq != g_amec->proc[0].core[k].f_request) || (l_core_freq != g_amec->sys.fmax)) { l_freq_req_changed = TRUE; } //STORE core frequency and reason g_amec->proc[0].core[k].f_request = l_core_freq; g_amec->proc[0].core[k].f_reason = l_core_reason; // Update the Amester parameter telling us the reason. Needed for // parameter array. g_amec->proc[0].parm_f_reason[k] = l_core_reason; //CURRENT_MODE() may be OCC_MODE_NOCHANGE because STATE change is processed //before MODE change if ((CURRENT_MODE() != OCC_MODE_DYN_POWER_SAVE) && (CURRENT_MODE() != OCC_MODE_DYN_POWER_SAVE_FP) && (CURRENT_MODE() != OCC_MODE_NOCHANGE) && (l_core_reason & NON_DPS_POWER_LIMITED)) { G_non_dps_power_limited = TRUE; } else { G_non_dps_power_limited = FALSE; } // Update the sensor telling us what the requested frequency is sensor_update( AMECSENSOR_ARRAY_PTR(FREQ250USP0C0,k), (uint16_t) g_amec->proc[0].core[k].f_request); #if 0 /// TODO: This can be deleted if deemed useless /// This trace that can be used to debug the voting /// box an control loops. It will trace the reason why a /// controller is lowering the freq, but will only do it once in a /// row for the specific freq it wants to control to. It assumes /// that all cores will be controlled to same freq. if(l_chip_fmax != g_amec->sys.fmax){ static uint16_t L_trace = 0; if(l_chip_fmax != L_trace){ L_trace = l_chip_fmax; TRAC_INFO("Core: %d, Freq: %d, Reason: %d",k,l_core_freq,l_core_reason); } } #endif if(l_core_freq > g_amec->proc[0].core_max_freq) { g_amec->proc[0].core_max_freq = l_core_freq; } } else { l_core_freq = 0; l_core_reason = 0; } }//End of for loop // Check if the frequency is going to be changing if( l_freq_req_changed == TRUE ) { G_time_until_freq_check = FREQ_CHG_CHECK_TIME; } else if (G_time_until_freq_check != 0) { G_time_until_freq_check--; } //convert POWERCAP reason to POWER_SUPPLY_FAILURE if ovs/failsafe is asserted if((l_kvm_throt_reason == POWERCAP) && (AMEC_INTF_GET_FAILSAFE() || AMEC_INTF_GET_OVERSUBSCRIPTION())) { l_kvm_throt_reason = POWER_SUPPLY_FAILURE; } //check if we need to update the throttle reason in homer if(G_sysConfigData.system_type.kvm && (l_kvm_throt_reason != G_amec_kvm_throt_reason)) { //Notify dcom thread to update the table G_amec_kvm_throt_reason = l_kvm_throt_reason; ssx_semaphore_post(&G_dcomThreadWakeupSem); } }
void state_calibration_play(){ uint8_t c; char t[6]; uint32_t now; value_sensor value_sensor_d; switch(calibration_fsm_state) { case CALFSM_STATE_CHOICE_DELAY: DCALIB_PRINT("\r\nPlease enter the delay between readings (in ms) : \r\n"); calibration_fsm_state=CALFSM_STATE_READING_DELAY; break; case CALFSM_STATE_READING_DELAY: c=usb_serial_get_byte(); if (c>=48 && c<=57) { fprintf(&USBSerialStream,"%c",c); Value_T[fillpos++]=c; } else if (c=='\r') { Value_T[fillpos++]=c; delay_between_readings=char_to_int(Value_T,0,fillpos-1); fillpos=0; calibration_fsm_state=CALFSM_STATE_INITIALIZING; } break; case CALFSM_STATE_INITIALIZING: DCALIB_PRINT("\r\nPlease chose the calibration type (1 for PM, 2 for temperature, 3 for Humidity) \r\n"); calibration_fsm_state=CALFSM_STATE_CHOICE_CALIB; break; case CALFSM_STATE_CHOICE_CALIB: c=usb_serial_get_byte(); if (c>48 && c<=51) { type_of_calib=c-'0'; calibration_fsm_state=CALFSM_STATE_READING_SENSOR; } break; case CALFSM_STATE_READING_SENSOR: sensor_update(); switch(type_of_calib) { case 1: Sensor_t[number_of_reading-1] = (int32_t) (sensors_acc.pm_instant*100); break; case 2: Sensor_t[number_of_reading-1] = (uint32_t) (sensors_acc.tmp_instant*100.0); break; case 3: Sensor_t[number_of_reading-1] = (uint32_t) (sensors_acc.hum_instant*100.0); break; } if (number_of_reading==1 || number_of_reading ==2) { number_of_reading++; now=millis(); waiting_end=set_timeout(now+delay_between_readings); calibration_fsm_state=CALFSM_STATE_WAITING; } else { DCALIB_PRINTF("T_0 : %lu, T_5 : %lu, T_10 : %lu \r\n", Sensor_t[0], Sensor_t[1], Sensor_t[2]); DCALIB_PRINT("Enter the reference values (ref_0;ref_5;ref_10) : \r\n"); number_of_reading=1; calibration_fsm_state=CALFSM_STATE_READING_VALUE_T; } break; case CALFSM_STATE_WAITING: //DCALIB_PRINTF("\r\n %li", (int32_t) (millis()-waiting_end)); if (millis()>waiting_end) { calibration_fsm_state=CALFSM_STATE_READING_SENSOR; } break; case CALFSM_STATE_READING_VALUE_T: c=usb_serial_get_byte(); if (c>=48 && c<=57 || c==';') { fprintf(&USBSerialStream,"%c",c); Value_T[fillpos++]=c; } else if (c=='\r') { Value_T[fillpos++]=c; value_sensor_d=parse_ref_value(Value_T,fillpos); Sensor_Ref_0=char_to_int(Value_T,0,value_sensor_d.length_S_0); Sensor_Ref_5=char_to_int(Value_T,value_sensor_d.length_S_0+1,value_sensor_d.length_S_5); Sensor_Ref_10=char_to_int(Value_T,value_sensor_d.length_S_5+1,value_sensor_d.length_S_10); //DCALIB_PRINTF("T_0 : %lu, T_5 : %lu, T_10 %lu\r\n",Sensor_Ref_0, Sensor_Ref_5 ,Sensor_Ref_10); fillpos=0; calibration_fsm_state=CALFSM_STATE_CALCULATE_K; } break; case CALFSM_STATE_CALCULATE_K: coef=calculate_k(Sensor_Ref_0, Sensor_t[0], Sensor_Ref_10, Sensor_t[2]); coef1=calculate_k(Sensor_Ref_0, Sensor_t[0], Sensor_Ref_5, Sensor_t[1]); coef2=calculate_k(Sensor_Ref_5, Sensor_t[1], Sensor_Ref_10, Sensor_t[2]); fprintf(&USBSerialStream,"\n\r 0-10 a : %u , b : %li , Calibrated_t_5 : %lu ",coef.a, coef.b, (uint32_t) round(((double)(Sensor_t[1]*coef.a+coef.b)/100))); fprintf(&USBSerialStream,"\n\r 0-5 a : %u , b : %li , Calibrated_t_10 : %lu ",coef1.a, coef1.b, (uint32_t) round(((double)(Sensor_t[2]*coef1.a+coef1.b)/100))); fprintf(&USBSerialStream,"\n\r 5-10 a : %u , b : %li , Calibrated_t_0 : %lu \r\n",coef2.a, coef2.b, (uint32_t) round(((double)(Sensor_t[0]*coef2.a+coef2.b)/100)) ); DCALIB_PRINT("Press 1, 2, 3 to save the corresponding coefficient. Press 0 to skip saving.\r\n"); calibration_fsm_state=CALFSM_STATE_CHOICE_SAVE; break; case CALFSM_STATE_CHOICE_SAVE: c=usb_serial_get_byte(); switch (c) { case '0': calibration_fsm_state=CALFSM_STATE_END; break; case '1': sensor_calib_set_k(coef.a,coef.b,SIGNIFICATIVE_DIGITS_K,type_of_calib); calibration_fsm_state=CALFSM_STATE_SAVE; break; case '2': sensor_calib_set_k(coef1.a,coef1.b,SIGNIFICATIVE_DIGITS_K,type_of_calib); calibration_fsm_state=CALFSM_STATE_SAVE; break; case '3': sensor_calib_set_k(coef2.a,coef2.b,SIGNIFICATIVE_DIGITS_K,type_of_calib); calibration_fsm_state=CALFSM_STATE_SAVE; break; case '-': DCALIB_PRINT("Enter the reference values (ref_0;ref_5;ref_10) : \r\n"); calibration_fsm_state=CALFSM_STATE_READING_VALUE_T; break; default : calibration_fsm_state=CALFSM_STATE_CHOICE_SAVE; break; } break; case CALFSM_STATE_SAVE: sensor_calib_save_k(type_of_calib); DCALIB_PRINT("Coefficients saved\r\n"); calibration_fsm_state=CALFSM_STATE_END; break; case CALFSM_STATE_END: state_set_next(&main_fsm, &state_normal); break; default: state_set_next(&main_fsm, &state_normal); break; } }
// Function Specification // // Name: amec_slv_proc_voting_box // // Description: Slave OCC's voting box that decides the frequency request. // This function will run every tick. // // Thread: RealTime Loop // // Task Flags: // // End Function Specification void amec_slv_proc_voting_box(void) { /*------------------------------------------------------------------------*/ /* Local Variables */ /*------------------------------------------------------------------------*/ uint16_t k = 0; uint16_t l_chip_fmax = g_amec->sys.fmax; uint16_t l_core_freq = 0; uint16_t l_core_freq_max = 0; // max freq across all cores uint16_t l_core_freq_min = g_amec->sys.fmax; // min freq across all cores uint32_t l_current_reason = 0; // used for debug purposes static uint32_t L_last_reason = 0; // used for debug purposes uint32_t l_chip_reason = 0; uint32_t l_core_reason = 0; amec_proc_voting_reason_t l_kvm_throt_reason = NO_THROTTLE; amec_part_t *l_part = NULL; // frequency threshold for reporting throttling uint16_t l_report_throttle_freq = G_sysConfigData.system_type.report_dvfs_nom ? G_sysConfigData.sys_mode_freq.table[OCC_MODE_NOMINAL] : G_sysConfigData.sys_mode_freq.table[OCC_MODE_TURBO]; /*------------------------------------------------------------------------*/ /* Code */ /*------------------------------------------------------------------------*/ if (!G_allowPstates) { // Don't allow pstates to be sent until after initial mode has been set if ( (CURRENT_MODE()) || (G_sysConfigData.system_type.kvm) ) { G_allowPstates = TRUE; } } // Voting Box for CPU speed. // This function implements the voting box to decide which input gets the right // to actuate the system. // check for oversubscription if redundant ps policy (oversubscription) is being enforced if (G_sysConfigData.system_type.non_redund_ps == false) { // If in oversubscription and there is a defined (non 0) OVERSUB frequency less than max then use it if( (AMEC_INTF_GET_OVERSUBSCRIPTION()) && (G_sysConfigData.sys_mode_freq.table[OCC_MODE_OVERSUB]) && (G_sysConfigData.sys_mode_freq.table[OCC_MODE_OVERSUB] < l_chip_fmax) ) { l_chip_fmax = G_sysConfigData.sys_mode_freq.table[OCC_MODE_OVERSUB]; l_chip_reason = AMEC_VOTING_REASON_OVERSUB; } } // If there is an active VRM fault and a defined (non 0) VRM N frequency less than max use it if( (g_amec->sys.vrm_fault_status) && (G_sysConfigData.sys_mode_freq.table[OCC_MODE_VRM_N]) && (G_sysConfigData.sys_mode_freq.table[OCC_MODE_VRM_N] < l_chip_fmax) ) { l_chip_fmax = G_sysConfigData.sys_mode_freq.table[OCC_MODE_VRM_N]; l_chip_reason = AMEC_VOTING_REASON_VRM_N; } // PPB_FMAX if(g_amec->proc[0].pwr_votes.ppb_fmax < l_chip_fmax) { l_chip_fmax = g_amec->proc[0].pwr_votes.ppb_fmax; l_chip_reason = AMEC_VOTING_REASON_PPB; if(l_report_throttle_freq <= l_chip_fmax) { l_kvm_throt_reason = PCAP_EXCEED_REPORT; } else { l_kvm_throt_reason = POWERCAP; } } // PMAX_CLIP_FREQ if(g_amec->proc[0].pwr_votes.pmax_clip_freq < l_chip_fmax) { l_chip_fmax = g_amec->proc[0].pwr_votes.pmax_clip_freq; l_chip_reason = AMEC_VOTING_REASON_PMAX; l_kvm_throt_reason = POWER_SUPPLY_FAILURE; } // Pmax_clip frequency request if there is an APSS failure if(g_amec->proc[0].pwr_votes.apss_pmax_clip_freq < l_chip_fmax) { l_chip_fmax = g_amec->proc[0].pwr_votes.apss_pmax_clip_freq; l_chip_reason = AMEC_VOTING_REASON_APSS_PMAX; l_kvm_throt_reason = POWER_SUPPLY_FAILURE; } //THERMALPROC.FREQ_REQUEST //Thermal controller input based on processor temperature if(g_amec->thermalproc.freq_request < l_chip_fmax) { l_chip_fmax = g_amec->thermalproc.freq_request; l_chip_reason = AMEC_VOTING_REASON_PROC_THRM; if( l_report_throttle_freq <= l_chip_fmax) { l_kvm_throt_reason = PROC_OVERTEMP_EXCEED_REPORT; } else { l_kvm_throt_reason = CPU_OVERTEMP; } } //Thermal controller input based on VRM Vdd temperature if(g_amec->thermalvdd.freq_request < l_chip_fmax) { l_chip_fmax = g_amec->thermalvdd.freq_request; l_chip_reason = AMEC_VOTING_REASON_VDD_THRM; if( l_report_throttle_freq <= l_chip_fmax) { l_kvm_throt_reason = VDD_OVERTEMP_EXCEED_REPORT; } else { l_kvm_throt_reason = VDD_OVERTEMP; } } for (k=0; k<MAX_NUM_CORES; k++) { if( CORE_PRESENT(k) && !CORE_OFFLINE(k) ) { l_core_freq = l_chip_fmax; l_core_reason = l_chip_reason; // Disable DPS in KVM if(!G_sysConfigData.system_type.kvm) { l_part = amec_part_find_by_core(&g_amec->part_config, k); // Check frequency request generated by DPS algorithms if(g_amec->proc[0].core[k].core_perf.dps_freq_request < l_core_freq) { l_core_freq = g_amec->proc[0].core[k].core_perf.dps_freq_request; l_core_reason = AMEC_VOTING_REASON_UTIL; } // Adjust frequency based on soft frequency boundaries if(l_part != NULL) { if(l_core_freq < l_part->soft_fmin) { // Before enforcing a soft Fmin, make sure we don't // have a thermal or power emergency if(!(l_chip_reason & (AMEC_VOTING_REASON_PROC_THRM | AMEC_VOTING_REASON_VDD_THRM | AMEC_VOTING_REASON_PPB | AMEC_VOTING_REASON_PMAX | AMEC_VOTING_REASON_CONN_OC))) { l_core_freq = l_part->soft_fmin; l_core_reason = AMEC_VOTING_REASON_SOFT_MIN; } } else if(l_core_freq > l_part->soft_fmax) { l_core_freq = l_part->soft_fmax; l_core_reason = AMEC_VOTING_REASON_SOFT_MAX; } } } if(CURRENT_MODE() == OCC_MODE_NOMINAL) { // PROC_PCAP_NOM_VOTE if(g_amec->proc[0].pwr_votes.proc_pcap_nom_vote < l_core_freq) { l_core_freq = g_amec->proc[0].pwr_votes.proc_pcap_nom_vote; l_core_reason = AMEC_VOTING_REASON_PWR; l_kvm_throt_reason = POWERCAP; } } else { // PROC_PCAP_VOTE if(g_amec->proc[0].pwr_votes.proc_pcap_vote < l_core_freq) { l_core_freq = g_amec->proc[0].pwr_votes.proc_pcap_vote; l_core_reason = AMEC_VOTING_REASON_PWR; if(l_report_throttle_freq <= l_core_freq) { l_kvm_throt_reason = PCAP_EXCEED_REPORT; } else { l_kvm_throt_reason = POWERCAP; } } } // Check IPS frequency request sent by Master OCC if(g_amec->slv_ips_freq_request != 0) { if(g_amec->slv_ips_freq_request < l_core_freq) { l_core_freq = g_amec->slv_ips_freq_request; l_core_reason = AMEC_VOTING_REASON_IPS; } } // Override frequency with request from Master OCC if(g_amec->foverride_enable) { if(g_amec->foverride != 0) { // Override the frequency on all cores if Master OCC sends // a non-zero request l_core_freq = g_amec->foverride; l_core_reason = AMEC_VOTING_REASON_OVERRIDE; } l_kvm_throt_reason = MANUFACTURING_OVERRIDE; } if(g_amec->pstate_foverride_enable) { if(g_amec->pstate_foverride != 0) { // Override the frequency on all cores if the Global Pstate // table has been modified l_core_freq = g_amec->pstate_foverride; l_core_reason = AMEC_VOTING_REASON_OVERRIDE; } } //Make sure the frequency is not less then the system min if(l_core_freq < g_amec->sys.fmin) { l_core_freq = g_amec->sys.fmin; } // Override frequency via Amester parameter interface if (g_amec->proc[0].parm_f_override_enable && g_amec->proc[0].parm_f_override[k] > 0) { l_core_freq = g_amec->proc[0].parm_f_override[k]; l_core_reason = AMEC_VOTING_REASON_OVERRIDE_CORE; } //STORE core frequency and reason g_amec->proc[0].core[k].f_request = l_core_freq; g_amec->proc[0].core[k].f_reason = l_core_reason; if(l_core_freq < l_core_freq_min) { // store the new lowest frequency and reason to be used after all cores checked l_core_freq_min = l_core_freq; l_current_reason = l_core_reason; } // Update the Amester parameter telling us the reason. Needed for // parameter array. g_amec->proc[0].parm_f_reason[k] = l_core_reason; //CURRENT_MODE() may be OCC_MODE_NOCHANGE because STATE change is processed //before MODE change if ((CURRENT_MODE() != OCC_MODE_DYN_POWER_SAVE) && (CURRENT_MODE() != OCC_MODE_DYN_POWER_SAVE_FP) && (CURRENT_MODE() != OCC_MODE_NOM_PERFORMANCE) && (CURRENT_MODE() != OCC_MODE_MAX_PERFORMANCE) && (CURRENT_MODE() != OCC_MODE_FMF) && (CURRENT_MODE() != OCC_MODE_NOCHANGE) && (l_core_reason & NON_DPS_POWER_LIMITED)) { G_non_dps_power_limited = TRUE; } else { G_non_dps_power_limited = FALSE; } // Update the sensor telling us what the requested frequency is sensor_update( AMECSENSOR_ARRAY_PTR(FREQREQC0,k), (uint16_t) g_amec->proc[0].core[k].f_request); #if DEBUG_PROC_VOTING_BOX /// This trace that can be used to debug the voting /// box and control loops. It will trace the reason why a /// controller is lowering the freq, but will only do it once in a /// row for the specific freq it wants to control to. It assumes /// that all cores will be controlled to same freq. if(l_chip_fmax != g_amec->sys.fmax){ static uint16_t L_trace = 0; if(l_chip_fmax != L_trace){ L_trace = l_chip_fmax; TRAC_INFO("Core: %d, Freq: %d, Reason: %d",k,l_core_freq,l_core_reason); } } #endif if(l_core_freq > l_core_freq_max) { l_core_freq_max = l_core_freq; } } // if core present and not offline else { //Set f_request to 0 so this core is ignored in amec_slv_freq_smh() g_amec->proc[0].core[k].f_request = 0; g_amec->proc[0].core[k].f_reason = 0; } }//End of for loop // update max core frequency if not 0 i.e. all cores offline (stop 2 or greater) // this is used by power capping alg, updating to 0 will cause power throttling when not needed if(l_core_freq_max) { g_amec->proc[0].core_max_freq = l_core_freq_max; // update the overall reason driving frequency across all cores g_amec->proc[0].f_reason = l_current_reason; } //check if there was a throttle reason change if(l_kvm_throt_reason != G_amec_opal_proc_throt_reason) { //Always update G_amec_opal_proc_throt_reason, this is used to set poll rsp bits for all system types G_amec_opal_proc_throt_reason = l_kvm_throt_reason; // Only if running OPAL need to notify dcom thread to update the table in HOMER for OPAL if(G_sysConfigData.system_type.kvm) { ssx_semaphore_post(&G_dcomThreadWakeupSem); } } // For debug... if lower than max update vars returned in poll response to give clipping reason g_amec->proc[0].core_min_freq = l_core_freq_min; if(l_core_freq_min < g_amec->sys.fmax) { if(l_current_reason == L_last_reason) { // same reason INC counter if(g_amec->proc[0].current_clip_count != 0xFF) { g_amec->proc[0].current_clip_count++; } } else { // new reason update history and set counter to 1 L_last_reason = l_current_reason; g_amec->proc[0].current_clip_count = 1; if( (g_amec->proc[0].chip_f_reason_history & l_current_reason) == 0) { g_amec->proc[0].chip_f_reason_history |= l_current_reason; TRAC_IMP("First time throttling for reason[0x%08X] History[0x%08X] freq = %d", l_current_reason, g_amec->proc[0].chip_f_reason_history, l_core_freq_min); } } } else // no active clipping { L_last_reason = 0; g_amec->proc[0].current_clip_count = 0; } }
int main(void) { system_init(); clock_init(); led_init(); led_set(0x01); //show life UART_Init(BAUD); UART_Write("\nInit"); //Show UART life motor_init(); adc_init(); //Enable Analog pins adc_enable(CHANNEL_SENSOR_LEFT); adc_enable(CHANNEL_SENSOR_RIGHT); adc_enable(CHANNEL_SENSOR_FRONT); //Sensor value variables uint16_t sensor_left_value = 0; uint16_t sensor_right_value = 0; uint16_t sensor_front_value = 0; //Analog inputSignal conditioning arrays circBuf_t left_buffer; circBuf_t right_buffer; circBuf_t front_buffer; //Initialise sensor averaging buffers initCircBuf(&left_buffer, ROLLING_AVERAGE_LENGTH); initCircBuf(&right_buffer, ROLLING_AVERAGE_LENGTH); initCircBuf(&front_buffer, ROLLING_AVERAGE_LENGTH); //UART output buffer char buffer[UART_BUFF_SIZE] = {0}; //=====Application specific variables===== //TODO: initialise circbuff circBuf_t sweep_times; initCircBuf(&sweep_times, SWEEP_TIME_MEMORY_LENGTH); short sweep_del_t_last = 0; short sweep_end_t_last = 0; //time when front sensor begins to see grey. uint32_t grey_time_start = 0; bool sweep_ended = FALSE; //set high if the front sensor crosses the line bool front_crossed_black = FALSE; //set high if front finds finish line bool front_crossed_grey = FALSE; bool sensor_update_serviced = TRUE; action current_action = IDLE; int16_t forward_speed = DEFAULT_FORWARD_SPEED; int16_t turn_speed = DEFAULT_SPEED; //Scheduler variables uint32_t t = 0; //Loop control time variables uint32_t maze_logic_t_last = 0; uint32_t sample_t_last = 0; uint32_t UART_t_last = 0; clock_set_ms(0); sei(); // Enable all interrupts UART_Write("ialized\n"); //wait for start command DDRD &= ~BIT(7); PORTD |= BIT(7); //motor_set(128, 128); while((PIND & BIT(7))) { continue; } while(1) { t = clock_get_ms(); //check if a sensor update has occured if ((sensor_update_serviced == FALSE) && (t%MAZE_LOGIC_PERIOD == 0) && (t != maze_logic_t_last)) { sensor_update_serviced = TRUE; // finishing condition is a grey read for a set period if(is_grey(sensor_front_value) && front_crossed_grey == FALSE) { front_crossed_grey = TRUE; grey_time_start = t; //TODO: adjust so that finishing condition is a 1/2 whole sweeps on grey line } else if (is_grey(sensor_front_value) && front_crossed_grey == TRUE) { // if ((grey_time_start + GREY_TIME) <= t ) { // Finish line found. Stop robot. maze_completed(); // wait for button push front_crossed_grey = FALSE; } } else { front_crossed_grey = FALSE; } //see if the front sensor crosses the line in case we run into a gap if(is_black(sensor_front_value)&&front_crossed_black == FALSE) { front_crossed_black = TRUE; //check for false finish line if(front_crossed_grey) front_crossed_grey = FALSE; //false alarm } // when both rear sensors go black, this indicates an intersection (turns included). // try turning left if(is_black(sensor_left_value) && is_black(sensor_right_value)) { sweep_ended = TRUE; motor_set(0, 255); PORTB |= BIT(3); PORTB |= BIT(4); } //when both sensors are completely white this indicates a dead end or a tape-gap else if (is_white(sensor_left_value) && is_white(sensor_right_value)) { sweep_ended = TRUE; PORTB &= ~BIT(3); PORTB &= ~BIT(4); //current_action = ON_WHITE; //Check if the front sensor is on black, or has been during the last sweep. if(is_black(sensor_front_value) | front_crossed_black) motor_set(255, 255); else if (is_white(sensor_front_value)) motor_set(-255, 255); } //sweep to the side that reads the darkest value else if (sensor_left_value + SENSOR_TOLLERANCE < sensor_right_value) { PORTB &= ~BIT(3); PORTB |= BIT(4); if (current_action == SWEEP_LEFT) sweep_ended = TRUE; current_action = SWEEP_RIGHT; motor_set(forward_speed + turn_speed, forward_speed); } else if(sensor_right_value + SENSOR_TOLLERANCE< sensor_left_value) { PORTB |= BIT(3); PORTB &= ~BIT(4); if (current_action == SWEEP_RIGHT) sweep_ended = TRUE; current_action = SWEEP_LEFT; motor_set(forward_speed, forward_speed+ turn_speed); } //If a new sweep started this cycle, find how long it took if (sweep_ended) { //reset front black crossing detection variable sweep_ended = FALSE; if (front_crossed_black) front_crossed_black = FALSE; //Calculate sweep time sweep_del_t_last = t - sweep_end_t_last; sweep_end_t_last = t; writeCircBuf(&sweep_times, sweep_del_t_last); //adjust turn_speed for battery level. if (sweep_del_t_last > IDEAL_SWEEP_TIME) { turn_speed += 5; } if (sweep_del_t_last < IDEAL_SWEEP_TIME) { turn_speed -= 5; } turn_speed = regulate_within(turn_speed, MIN_TURN_SPEED, MAX_TURN_SPEED); } } //Sensor value update if((t%SAMPLE_PERIOD == 0) & (t!=sample_t_last)) { sample_t_last = t; //read in analog values sensor_update(CHANNEL_SENSOR_LEFT, &left_buffer, &sensor_left_value ); sensor_update(CHANNEL_SENSOR_RIGHT, &right_buffer, &sensor_right_value ); sensor_update(CHANNEL_SENSOR_FRONT, &front_buffer, &sensor_front_value ); sensor_update_serviced = FALSE; } //display debug information if((t%UART_PERIOD == 0) & (t != UART_t_last) & UART_ENABLED) { UART_t_last = t; sprintf(buffer, "sweep_time: %u \n", sweep_del_t_last); UART_Write(buffer); sprintf(buffer, "L: %u F: %u R: %u", sensor_left_value, sensor_front_value, sensor_right_value); UART_Write(buffer); UART_Write("\n"); } } }
void amec_update_fw_sensors(void) { errlHndl_t l_err = NULL; int rc = 0; int rc2 = 0; static bool l_first_call = TRUE; bool l_gpe0_idle, l_gpe1_idle; static int L_consec_trace_count = 0; // ------------------------------------------------------ // Update OCC Firmware Sensors from last tick // ------------------------------------------------------ int l_last_state = G_fw_timing.amess_state; // RTLtickdur = duration of last tick's RTL ISR (max = 250us) sensor_update( AMECSENSOR_PTR(RTLtickdur), G_fw_timing.rtl_dur); // AMEintdur = duration of last tick's AMEC portion of RTL ISR sensor_update( AMECSENSOR_PTR(AMEintdur), G_fw_timing.ameint_dur); // AMESSdurX = duration of last tick's AMEC state if(l_last_state >= NUM_AMEC_SMH_STATES) { // Sanity check. Trace this out, even though it should never happen. TRAC_INFO("AMEC State Invalid, Sensor Not Updated"); } else { // AMESSdurX = duration of last tick's AMEC state sensor_update( AMECSENSOR_ARRAY_PTR(AMESSdur0, l_last_state), G_fw_timing.amess_dur); } // ------------------------------------------------------ // Kick off GPE programs to track WorstCase time in GPE // and update the sensors. // ------------------------------------------------------ if( (NULL != G_fw_timing.gpe0_timing_request) && (NULL != G_fw_timing.gpe1_timing_request) ) { //Check if both GPE engines were able to complete the last GPE job on //the queue within 1 tick. l_gpe0_idle = async_request_is_idle(&G_fw_timing.gpe0_timing_request->request); l_gpe1_idle = async_request_is_idle(&G_fw_timing.gpe1_timing_request->request); if(l_gpe0_idle && l_gpe1_idle) { //reset the consecutive trace count L_consec_trace_count = 0; //Both GPE engines finished on time. Now check if they were //successful too. if( async_request_completed(&(G_fw_timing.gpe0_timing_request->request)) && async_request_completed(&(G_fw_timing.gpe1_timing_request->request)) ) { // GPEtickdur0 = duration of last tick's PORE-GPE0 duration sensor_update( AMECSENSOR_PTR(GPEtickdur0), G_fw_timing.gpe_dur[0]); // GPEtickdur1 = duration of last tick's PORE-GPE1 duration sensor_update( AMECSENSOR_PTR(GPEtickdur1), G_fw_timing.gpe_dur[1]); } else { //This case is expected on the first call of the function. //After that, this should not happen. if(!l_first_call) { //Note: FFDC for this case is gathered by each task //responsible for a GPE job. TRAC_INFO("GPE task idle but GPE task did not complete"); } l_first_call = FALSE; } // Update Time used to measure GPE duration. G_fw_timing.rtl_start_gpe = G_fw_timing.rtl_start; // Schedule the GPE Routines that will run and update the worst // case timings (via callback) after they complete. These GPE // routines are the last GPE routines added to the queue // during the RTL tick. rc = pore_flex_schedule(G_fw_timing.gpe0_timing_request); rc2 = pore_flex_schedule(G_fw_timing.gpe1_timing_request); if(rc || rc2) { /* @ * @errortype * @moduleid AMEC_UPDATE_FW_SENSORS * @reasoncode SSX_GENERIC_FAILURE * @userdata1 return code - gpe0 * @userdata2 return code - gpe1 * @userdata4 OCC_NO_EXTENDED_RC * @devdesc Failure to schedule PORE-GPE poreFlex object for FW timing * analysis. */ l_err = createErrl( AMEC_UPDATE_FW_SENSORS, //modId SSX_GENERIC_FAILURE, //reasoncode OCC_NO_EXTENDED_RC, //Extended reason code ERRL_SEV_INFORMATIONAL, //Severity NULL, //Trace Buf DEFAULT_TRACE_SIZE, //Trace Size rc, //userdata1 rc2); //userdata2 // commit error log commitErrl( &l_err ); } } else if(L_consec_trace_count < MAX_CONSEC_TRACE) { uint64_t l_dbg1; // Reset will eventually be requested due to not having power measurement // data after X ticks, but add some additional FFDC to the trace that // will tell us what GPE job is currently executing. if(!l_gpe0_idle) { l_dbg1 = in64(PORE_GPE0_DBG1); TRAC_ERR("GPE0 programs did not complete within one tick. DBG1[0x%08x%08x]", l_dbg1 >> 32, l_dbg1 & 0x00000000ffffffffull); }