## FSC For Dahuatech ## ### 參數 ### #### config.xml #### * AlgoPeriodMS: 1000 * PowerRecoveryTimeMS="15000" * DefaultProfile: 0 * PowerOffPWM: 0 #### SDR #### * FSC 相關的 SDR 位於 FCT.sdr * 屬性 * Record Type * FSC 相關的 SDR 其 Record Type 為 C0 * FSC Record type * 將 FSC 相關的 SDR 分為以下: * Fan Map * Main Domain * Step Header * Step Curve * Clamp Header * 其中,Main Domain 根據 Sub-Record Type 的不同,又可細分為: * Domain Configuration * Step Sub-Record * Clamp Sub-Record * Fan Fail Sub-Record * Fan Off Sub-Record * Domain Mask + Fan Profile Support * 描述哪些 Domain 中的哪些 Profile 可以參照該 SDR ### Domain 0 ### * 預設使用 Profile 0 * Profile 0 所參考的 SDR: * Step Header ID: 0x20 * Step Curve ID: 0x5B, 0x64 * Clamp Header ID: 0xB0, 0xB1, 0xB2, 0xB3, 0x20, 0x22, 0x23, 0x24, 0x25, 0x26, 0x29, 0x2A, 0x2B, 0x2D, 0x2F, 0x83, 0x84 * SDR 內容: * Step Header ID - 0x20 ![](https://imgur.com/lLTJ08y.png) * Step Curve ID - 0x5B ![](https://imgur.com/MryD7Ou.png) * Step Curve ID - 0x64 (Max. Step Control Rules) ![](https://imgur.com/WEuGwHg.png) * Clamp Header ID - 0x20 ![](https://imgur.com/SreHtnB.png) * Profile 0 的其他參數: * Normal Control Value: 20 % * Fan Fault Boost Value: 100% * Temperature Threshold Boost Value: 100% * Chassis Cover Boost Valu: 100% ### PWM 與溫度的關係 ### * 已知 Domain 0 使用 Profile 0,根據 SDR 內容,以 Sensor# 20 作為該 Domain 參考的 Temp Sensor。將定期讀取其溫度,再透過 INTC_FSC_domain_task_algo_temperature 運算後輸出 PWM。 * INTC_FSC_domain_task_algo_temperature 分別從 Profile0 的 units_step 和 units_clamp 選出其中最大 pwm_contrib。 * units_step 和 units_clamp 紀錄了 Profile0 包含了哪些 Step Header ID/Curve ID 和 Clamp Header ID,值得注意的是,只有 **合法** 的 unit 才會有 pwm_contrib。 * 考慮一種情況,若 Sensor# 20 上一次測量溫度為 90 °C,此次為 95 °C。假設,所選出最大 pwm_contrib 的 unit 其 Header ID/Curve ID 和 Clamp ID 分別是 0x20/0x5B 和 0x20。 那麼此時 PWM 會是多少呢? * 可分為以下兩個部份來探討: * 首先,分別算出 unit 的 pwm_contrib * 接著,將不同 unit 的 pwm_contrib 結合起來,將其稱為 pwm_composite,並考慮 pwm_limit 和 pwm_value_normal 的影響 #### pwm_contrib #### * 忽略 pwm_sleep 的影響 ##### Step ##### ```clike= INTC_FSC_domain_task_algo_temperature_step() { ... // Handle temperature sensor status rules. if (unit->status == NORMAL) { INTC_FSC_domain_task_algo_temperature_rule_step(unit); // compute the contribution from temperature ... } ... if (0 != (step_curve->sdr.point_cnt & DOMAIN_MAX_BIT)) { unit->pwm_limit = 100 - (UINT8)pwm; } else { unit->pwm_contrib = (UINT8)pwm; } } ``` * 結果: * 當 Sensor# 20 95°C,Curve ID 為 0x5B 的 unit 其 pwm_contrib 為 **78%**,pwm_limit 則為 0%。 * 值得注意的是,當 Sensor# 20 95°C,Curve ID 為 0x64 的 unit 其 pwm_contrib 為 0%, pwm_limit 也為 0%。 ##### Clamp ##### ```clike= INTC_FSC_domain_task_algo_temperature_rule_clamp() { ... if (temperature > (INT32)(UINT32)pclamp->isdr.sleep_hyst.hysteresis_pos) { temperature -= (INT32)(UINT32)pclamp->isdr.sleep_hyst.hysteresis_pos; } else if (temperature < -(INT32)(UINT32)pclamp->isdr.sleep_hyst.hysteresis_neg) { temperature += (INT32)(UINT32)pclamp->isdr.sleep_hyst.hysteresis_neg; } else { temperature = 0; } temperature_average = (unit->temperature_last + temperature) * 5; if ((pclamp->isdr.version == 3) && (temperature > 0) && (temperature > unit->temperature_last)) { ramp_coeff = pclamp->isdr.ramp_coeff_If; } else { ramp_coeff = pclamp->isdr.ramp_coeff_Is; } if (pclamp->isdr.version == 3) { // Add the derivative PWM contribution // Ramp has +3 decimal places, temp +0, time + 6. 3+0+6-(6-3) = 6 ramp_coeff = pclamp->isdr.ramp_coeff_D; if ((time_elapsed / 1000) > 0) { pwm_delta += (INT32)((INT64)ramp_coeff * ((INT64)temperature - (INT64)unit->temperature_last) * 1000LL); // PWM change computed in 1/1000000 of a % } } ... } ``` * 計算步驟: * diff_temp = sensor_temp - clamp_temp * temperature_average = ( temperature_last + diff_temp )*5 * pwm_delta = Fast Integral Coefficient * temperature_average/10000 (/10000 可看成 /10 * 1000) * pwm_delta = pwm_delta + (Derivative Coefficient *(diff_temp - temperature_last)) * 結果: * 當 Sensor# 20 95°C,而前一次溫度為 90 °C 的情況下,Clamp ID 為 0x20 的 unit 其pwm_contrib 為 **12%** 。 #### pwm_composite #### ```clike= INTC_FSC_domain_task_algo_temperature() { ... UINT8 pwm_step = profile->domain_info.pwm_value_normal; // 20% UINT8 pwm_clamp = 0; UINT8 pwm_limit = 100; for (idx = 0; idx < profile->units_step.cnt; idx++) { INTC_FSC_domain_unit_step_t *unit = &profile->units_step.units[idx]; if (pwm_step < unit->pwm_contrib) { pwm_step = unit->pwm_contrib; step_sensor = g_step_headers[unit->step_header_id].sdr.thermometer_nr; } pwm_limit = MIN(pwm_limit, 100 - unit->pwm_limit); } for (idx = 0; idx < profile->units_clamp.cnt; idx++) { INTC_FSC_domain_unit_clamp_t *unit = &profile->units_clamp.units[idx]; if (pwm_clamp < unit->pwm_contrib) { pwm_clamp = unit->pwm_contrib; clamp_sensor = g_clamp_headers[unit->clamp_header_id].isdr.thermometer_nr; } } ... pwm_composite = pwm_step; pwm_composite += pwm_clamp; if (domain->fault_detected == 0) { // Only enforce domain max if there is no fault condition active pwm_composite = MIN(pwm_composite, (INT64)(UINT64)pwm_limit); } pwm_composite = MAX(pwm_composite, profile->domain_info.pwm_value_normal); // enforce "no less than normal" rule after sleep is applied ... } ``` * 計算: * pwm_composite = MIN(pwm_step + pwm_clamp, pwm_limit) * pwm_composite = MAX(pwm_composite, pwm_value_normal) * 推論: * 若 pwm_limit < pwm_step + pwm_clamp,則 pwm_composite 等於 pwm_limit ;反之則為 pwm_step + pwm_clamp。總之,誰小則為誰。 * 但不能比 pwm_value_normal 規定的要來得小。 * 結果: * 當 Sensor# 20 95°C,首先,pwm_composite 等於 90 % (78 % + 12 %) * 而 pwm_composite 小於 pwm_limit 再加上大於 pwm_value_normal。 * 所以,**最終 pwm_composite 為 90 %**。 ## 參考資料 ## [Supervyse 3.0 FSC Settings HowTo](http://wiki.insyde.com/index.php/Supervyse_3.0_FSC_Settings_HowTo) [Supervyse 3.0 FSC Porting Guide](http://wiki.insyde.com/index.php/(Deprecated)_Supervyse_3.0_FSC_Porting_Guide) [Clamp Calculation](http://wiki.insyde.com/index.php/Supervyse_3.0_Dahuatech_Porting_Detail#Clamp_setting) *Mail: BMC 热策略细节沟通*