嵌入式功耗問題調試日誌

  1. mh公司功耗要求:整機(包括所有外設)在飛行模式滅屏下,待機電流在5ma以內  
      
    一、功耗問題一般調試辦法 - 【逐個去掉】  
        1. 外接精確電源(實驗室有),電腦端有一個連接電源的軟件(龍旗電流檢測工具),可以查看實時電流與平均電流  
        2. 切換爲飛行模式 - 排查modem的影響  
            10ma 以上 -> 查看mtklog中的kernel_log看是否有休眠"suspend"  
            10ma 以下 -> 逐個去掉外設: lcm/tp/camera/fingerprint/sensor/小板(直接拔除), 看哪裏漏電  
          
    二、常見外設功耗:  
            注:除了tp帶手勢,其他均爲詢問FAE得知,均未驗證  
            lcm                 : uA級  
            tp                  : uA級  
            tp 帶手勢喚醒        : 1mA  
            camera              : uA級  
            sensor              : uA級  
            fingerprint         : uA級  
            省晶體(節省gps晶體)也會導致電流較大 - 約1mA  
            每增大1G RAM 電流會增大: 約1mA  
      
    三、如何確實中斷喚醒源:  
        (1)打開irq-mt-eic.c中的EINT_DEBUG宏,重新抓取kernel log       // 實測80_c_m.git 不報錯,7.0都報錯  
        (2)在log中w“ake up by EINT”之後,查找EINT_STA的值  
               EINT_STA的值是中斷狀態寄存器,每個bit對應一個EINT channel,  
               所以EINT_STA的值就是0x1<<index(index即EINT channel)  
               eg:比如EINT_STA=0x200,對應的EINT channel就是9  
        (3)查看cust_eint.h,跟據EINT channel確定是哪個模塊  
       
        至於log中“wake up by EINT (0x20)(0x4)”的0x20指的是EINT wakesrc的index,是WAKE_SRC_EINT這個宏的值  
              
          
    四、常見外設功耗不符合要求原因及解決辦法:  
        lcm :  
            案例一:  lcm沒有完全休眠:  
            原因: lcm驅動中使用SET_RESET_PIN(0)在休眠時對reset進行拉低,實際上LCM的reset並未拉低,拉低後又會被拉高。  
                  而很多顯示屏在休眠下去時是要將LCM的reset的拉低,顯示屏的待機電流才能正常的uA級別。  
            解決: 改用這種方式將reset拉低:  
                android5.1: (不支持dts)  
                    由老的 SET_RESET_PIN()  改爲 lcd_rst_en()  
                    驅動中:  
                     #include <mach/mt_gpio.h>        // mt_set_gpio_mode()函數包含  
                     static void lcd_rst_en(int enabled){  
                        if(1 == enabled){  
                            mt_set_gpio_mode(GPIO_LCM_RST, GPIO_MODE_00);  
      
                            mt_set_gpio_dir(GPIO_LCM_RST, GPIO_DIR_OUT);  
                            mt_set_gpio_out(GPIO_LCM_RST, GPIO_OUT_ONE);  
                        }else{  
                            mt_set_gpio_mode(GPIO_LCM_RST, GPIO_MODE_00);  
      
                            mt_set_gpio_dir(GPIO_LCM_RST, GPIO_DIR_OUT);  
                            mt_set_gpio_out(GPIO_LCM_RST, GPIO_OUT_ZERO);  
                        }  
                    }  
                     static void lcm_init(void)  
                    {  
                        lcd_rst_en(1);//SET_RESET_PIN(1);  
                        MDELAY(2);  
                        lcd_rst_en(0);//SET_RESET_PIN(0);  
                        MDELAY(2);  
                        lcd_rst_en(1);//SET_RESET_PIN(1);  
                        MDELAY(120);  
      
                        push_table(lcm_initialization_setting, sizeof(lcm_initialization_setting) / sizeof(struct LCM_setting_table), 1);  
                    }  
                    static void lcm_suspend(void)  
                    {  
                        push_table(lcm_sleep_in_setting, sizeof(lcm_sleep_in_setting) / sizeof(struct LCM_setting_table), 1);  
                        MDELAY(10);  
                        lcd_rst_en(0);      // 新增這一句  
                    }  
                    static unsigned int lcm_compare_id(void)  
                    {  
                        ...  
                        lcd_rst_en(1);  
                        MDELAY(25);  
                        lcd_rst_en(0);  
                        MDELAY(25);  
                        lcd_rst_en(1);  
                        MDELAY(50);  
                        ...  
                        read_reg_v2(0xbf, buffer, 5);  
                        ...  
                        return (0x3350 == id)?1:0;  
                    }  
                       
                android6/7:  
                    1.修改dts: 添加reset引腳的配置,方便驅動中使用  
                        /* DISPSYS GPIO standardization */  
                        &pio {  
                            ...  
                            mtkfb_pins_lcm_reset0: lcm_rst_out0_gpio {  
                                pins_cmd_dat {  
                                    pins = <PINMUX_GPIO70__FUNC_LCM_RST>;  
                                    slew-rate = <1>;  
                                    output-low;  
                                };  
                            };  
                            mtkfb_pins_lcm_reset1: lcm_rst_out1_gpio {  
                                pins_cmd_dat {  
                                    pins = <PINMUX_GPIO70__FUNC_LCM_RST>;  
                                    slew-rate = <1>;  
                                    output-high;  
                                };  
                            };  
                            ...  
                        }  
                              
                        &mtkfb {  
                            ...  
                            pinctrl-3 = <&mtkfb_pins_lcm_reset0>;  
                            pinctrl-4 = <&mtkfb_pins_lcm_reset1>;  
                        }  
                      
                    2.驅動中: (kernel中才能用dts)  
                        #include "disp_dts_gpio.h"  // mt_lcm_rst_set_gpio()函數包含  
                        static void lcm_init(void)  
                        {  
                            mt_lcm_rst_set_gpio(1);  
                            MDELAY(10);  
                            mt_lcm_rst_set_gpio(0);  
                            MDELAY(10);  
                            mt_lcm_rst_set_gpio(1);  
                            MDELAY(200);  
      
                            push_table(lcm_initialization_setting,  
                                      sizeof(lcm_initialization_setting) /  
                                      sizeof(struct LCM_setting_table), 1);  
                        }  
                        static void lcm_suspend(void)  
                        {  
                            push_table(lcm_sleep_in_setting, sizeof(lcm_sleep_in_setting) / sizeof(struct LCM_setting_table), 1);  
                            MDELAY(10);  
                            mt_lcm_rst_set_gpio(0);  
                        }  
                        static unsigned int lcm_compare_id(void)  
                        {  
                            ...  
                            mt_lcm_rst_set_gpio(1);  
                            MDELAY(25);  
                            mt_lcm_rst_set_gpio(0);  
                            MDELAY(25);  
                            mt_lcm_rst_set_gpio(1);  
                            MDELAY(50);  
                            ...  
                            read_reg_v2(0xbf, buffer, 5);  
                            ...  
                            return (0x3350 == id)?1:0;  
                        }  
      
        tp  :  
            案例一: 固件原因  
                原因: 固件  
                解決: 安排FAE來優化固件  
                示例: v618_p300項目,tp電流爲1.5mA  
                      ->FAE優化下發參數之後,約爲1mA  
              
        camera:   
        案例一 : 待機電流過大(18ma) - 後副攝沒有休眠 - 掉電時序  
            現象  : 整機待機電流正常(7ma),攝像頭打開再關閉滅屏後整機待機電流過大(18ma)  
            平臺  : androidN,MTK6737  
            排查過程: 1. 一個有後副攝,一個沒有後副攝對照,發現無後副攝的機器電流正常  
                    
                  2. 引出後副攝的RST 與PDN腳,用萬用表測量打開載關閉滅屏之後的電平 - 低   
                    
                  3. 對照gc0310的芯片手冊 - PDN腳爲高時休眠  
                       
                  4. 掉電時序中將PDN腳拉高  
                    -   mtkcam_gpio_set(pinSetIdx, CAMPDN, pinSet[pinSetIdx][IDX_PS_CMPDN + IDX_PS_ON]);    // 拉低 前面進行翻轉  
                    +   mtkcam_gpio_set(pinSetIdx, CAMPDN, pinSet[pinSetIdx][IDX_PS_CMPDN + IDX_PS_OFF]);   // 拉高  
                    
                  5. 改掉電時序之後還是一樣電流大,懷疑沒跑到,修改的代碼中添加log -> log沒打印  
                     詢問姜工後,修改alps\kernel-3.18\drivers\misc\mediatek\imgsensor\src\mt6735m\kd_sensorlist.c:  
                     在kd_MultiSensorClose()函數中,打開後副攝掉電時序:  
                       
                    -   #ifdef CONFIG_KST_DUAL_CAM_YUV0  
                    +   #if ((defined CONFIG_KST_DUAL_CAM_YUV0) || (defined CONFIG_KST_BOARD_V666))  
                      
                  6. log還是沒打印,修改掉電時序中: (均打印得知:後副攝 pinSetIdx == 2)  
                    -   if((pinSetIdx == 0)&&(currSensorName && (0 == strcmp(SENSOR_DRVNAME_GC0310_MIPI_YUV, currSensorName))))  
                    +   if((pinSetIdx == 2)&&(currSensorName && (0 == strcmp(SENSOR_DRVNAME_GC0310_MIPI_YUV, currSensorName))))  
                    
        處理方案: 修改掉電時序  
      
        sensor:   
            案例一: 待機電流過大(6.6ma) - gsensor 中斷腳漏電  
                原因: 原理圖中gsensor的中斷腳接了10k的上拉電阻,上拉到PMU1.8v 高電平, 而dws中沒有配置GPIO60爲中斷模式,  
                處理: 1. 配置dws中的pin腳模式 與中斷的觸發方式  
                    dws配置pin腳:  
                            EintMode|Def.Mode   M0|M1|M2|M3|M4|M5|M6|M7|InPull En|InPull SelHigh|Def.Dir|In|Out|OutHigh|VarName1  
                -   GPIO60          0:GPIO80    1  0  0  1  1  0  1  0  1         0              OUT     0  1   0         
                +   GPIO60  1       0:GPIO80                            1         1              IN                     GPIO_GSE_1_EINT_PIN   
                  
                    dws配置EINT:  
                            EINTVar|Debounce Time(ms)|Polarity|Sensitive_Level|Debounce En    
                -   EINT60  NC      0  
                +   EINT60  GSE_1   0                   High    Level           Disable  
                      
                      2. 或者在硬件中去掉上拉電阻,也就是將gsensor的中斷腳NC掉  
                        
                      ==> 配置dws後 功耗正常(小於5ma)  
                        
            案例二: 待機電流過大(8ma)去掉gsensor後5ma  
                原因: gsensor(qma6981)的第10腳只能懸空或接1.8v,而實際接到了2.8v  
                處理: 1. 查看log,休眠與喚醒函數都正常跑到了  
                      
                      2. 對比相同mtk6737 android7.0的其他項目。不同主板的gsensor 6981功耗正常。==>對比電路原理圖  
                        發現qma6981的第10腳接的電壓不一樣,正常主板接的是1.8v,問題主板接到2.8v。  
                      
                      3. 諮詢fae後得知:[此芯片的Pin10 爲VDDIO 電壓域1.8v,當接入2.8V電壓時會產生電壓差導致待機電流偏大4-5mA,且無法通過軟件改善] ,第10腳只能懸空或接1.8v  
                        
                      4. 嘗試將正常主板的第10腳接到2.8v,功耗就變大了3個ma(正常主板原理圖上做了1.8v/2.8v兼容,將接到1.8v的電阻挪到接2.8v的位置即可)  
                        
                      ==> 硬件改版(問題主板沒做1.8v/2.8v兼容) or 更換gsensor爲3433(3433 芯片內部兼容1.8v/2.8v)  
                        
                      5. 也就是說3433與6981並不完全pin對pin  
                        
            案例三 : gsensor兼容(3433 & 6981)導致功耗大(70ma)  
                平臺: androidN,MTK6737  
                步驟: 1. 休眠時候打log: adb shell dmesg > e:gsensor_3433_6981.log  
                        log顯示由於設備(2-004c - mc3433)休眠失敗,導致系統休眠失敗,重新喚醒,  
                        系統一直處於: 休眠->休眠失敗->喚醒 ->休眠的循環中  
                        [  207.629520]  (1)[1066:system_server]qma6981_suspend 2894 : liuzhigou 20171018 qma6981_suspend start   
                        [  207.635164]  (1)[1066:system_server]qma6981_suspend 2914 : liuzhigou 20171018 qma6981_suspend end   
                        [  207.635254]  (1)[1066:system_server]liuzhigou 20171018 mc3xxx_suspend start   
                        [  207.635291]  (1)[1066:system_server]dpm_run_callback(): i2c_device_pm_suspend+0x0/0x38 returns -22  
                        [  207.635324]  (1)[1066:system_server]PM: Device 2-004c failed to suspend: error -22  
                        [  207.635352]  (1)[1066:system_server][name:suspend&]PM: Some devices failed to suspend, or early wake event detected  
          
                      2. 在mc3433的休眠函數中,添加打印log:  
                        static int mc3xxx_suspend(struct i2c_client *client, pm_message_t msg)  
                        {  
                            struct mc3xxx_i2c_data *obj = i2c_get_clientdata(client);  
                            int err = 0;  
                            if(msg.event == PM_EVENT_SUSPEND)   {  
                                if(obj == NULL) {  
                        +               GSE_ERR("liuzhigou 20171025 %s obj == NULL\n",__FUNCTION__);  
                                        return -EINVAL;  
                                    }  
                                  
                        [  116.917907]  (0)[1150:system_server]liuzhigou 20171018 mc3xxx_suspend start   
                        [  116.917926]  (0)[1150:system_server]liuzhigou 20171018 mc3xxx_suspend msg.event == PM_EVENT_SUSPEND   
                        [  116.917943]  (0)[1150:system_server]liuzhigou 20171018 mc3xxx_suspend obj == NULL   
                        [  116.917974]  (0)[1150:system_server]dpm_run_callback(): i2c_device_pm_suspend+0x0/0x38 returns -22  
                        [  116.917996]  (0)[1150:system_server]PM: Device 2-004c failed to suspend: error -22  
                        [  116.918016]  (0)[1150:system_server]PM: Some devices failed to suspend, or early wake event detected  
                            根據log,obj爲空指針,出錯判斷後返回錯誤值  
                    
                      3. 根據標誌位添加出錯判斷,如果沒加載3433就直接return 0(成功),終止3433的休眠函數  
                        static int mc3xxx_suspend(struct i2c_client *client, pm_message_t msg)  
                        {  
                            struct mc3xxx_i2c_data *obj = i2c_get_clientdata(client);  
                            int err = 0;  
                            if(msg.event == PM_EVENT_SUSPEND)   {  
                                if(obj == NULL) {  
                            +       if (MC3XXX_INIT_FAIL == s_nInitFlag){  
                            +           GSE_ERR("liuzhigou 20171025 %s obj == NULL MC3XXX_INIT_FAIL == s_nInitFlag \n",__FUNCTION__);  
                            +           return 0;  
                            +       }  
                            +       else{  
                            +           GSE_ERR("liuzhigou 20171025 %s obj == NULL MC3XXX_INIT_FAIL != s_nInitFlag \n",__FUNCTION__);  
                                        return -EINVAL;  
                                    }  
                                }  
                                  
        總結  :   此log爲正常狀態: 0x4000爲pmu中斷  
                    [  147.732936] -(0)[1066:system_server][name:mt_spm_internal&][SPM] wake up byEINT, timer_out = 18724959, r13 = 0x10001000, debug_flag = 0x9f  
                    [  147.732936] -(0)[1066:system_server][name:mt_spm_internal&][SPM] r12 = 0x20, raw_sta = 0x20, idle_sta = 0x9fa, event_reg = 0x90100000, isr = 0x0  
                    [  147.732936] -(0)[1066:system_server][name:mt_spm_sleep&][SPM] suspend dormant state = 0, md32_flag = 0x0, md32_flag2 = 0  
                    [  147.732936] -(0)[1066:system_server][name:mt_spm_sleep&][SPM] log_wakesta_index = 5  
                    [  147.732936] -(0)[1066:system_server][name:irq_mt_eic&]EINT_STA:  
                    [  147.732936] -(0)[1066:system_server][name:irq_mt_eic&]EINT Module - index:192,EINT_STA = 0x4000  
                    [  147.732936] -(0)[1066:system_server][name:irq_mt_eic&]EINT 206 is pending  
                    [  147.732936] -(0)[1066:system_server][name:irq_mt_eic&]  
                    [  147.732988] -(0)[1066:system_server][name:ccci&][ccci1/mcd]Resume cldma pdn register ...11  
                    [  147.733070] -(0)[1066:system_server][name:irq_mt_eic&]EINT Module - expires:4294952066, jiffies:4294952065, deb_in_jiffies:1,   
                    [  147.733091] -(0)[1066:system_server][name:irq_mt_eic&]deb:1000, in mt_eint_set_timer_event  
                    [  147.733270]  (0)[1066:system_server][name:cpu&]Enabling non-boot CPUs ...  
                    [  147.733571] -(1)[0:swapper/1]CPU1: Booted secondary processor  
              
        fingerprint:  
            案例一: 指紋功耗約爲2mA,不符合要求  
                原因: 沒有休眠,指紋的休眠需要hal層下發休眠命令  
                處理: 添加相關hal層代碼  
                實例: v618_p300項目(去掉上層mmi修改的測功耗版本),指紋電流爲2mA  
                      ->由於指紋沒有收到休眠命令導致,添加上層mmi修改之後正常  
                    
        充電IC:  
            案例一: 每隔30s左右會有一次大電流脈衝,導致平均功耗十幾個毫安  
                現象: 30s一次大電流脈衝  
                原因: 1. mtklog中顯示wake up by PCM_TIMER提示,但還是定位不到問題,只好git回退,  
                      2. 通過git版本回退發現:對alps\kernel-3.18\drivers\power\mediatek\battery_meter.c中的獲取電池電壓  
                      函數battery_meter_get_battery_voltage()做了【讀取20次,求平均值的操作】  
                      導致,30s一次大電流脈衝  
                處理: 去掉讀取20次操作,還原爲mtk默認即只讀一次  
                存疑: 添加log得知,本函數每隔10s被調用一次,爲何脈衝是是30s一次?  
                log:  [cat /proc/kmsg | grep "20170713"]  
                     [489.332438] 20170713 battery_meter_get_battery_voltage()  
                     [489.503921] 20170713 battery_meter_get_battery_voltage()  
                     [499.331495] 20170713 battery_meter_get_battery_voltage()  
                     [499.503337] 20170713 battery_meter_get_battery_voltage()  
                     [509.331463] 20170713 battery_meter_get_battery_voltage()  
                     [509.502923] 20170713 battery_meter_get_battery_voltage()  
              
        主板功耗:  
            案例一: 雙卡實網待機電流過大(標準需要小於12ma,實測約15ma)  
            原因: 谷歌服務  
            處理: 1. 測試的時候關閉:這種方式只能【關閉部分】谷歌服務  
                    setting -> apps -> google play servicer 點擊disable關閉  
                      
                    這樣測出來的電流是15ma  
                      
                  2. 編譯的時候在update\alps\system_conf.sh 【徹底關閉】(微掌客製化)  
                    BUILD_GMS=no  
                      
                    這樣測出來的電流是11.5ma(合格)  
              
            注意: 1. 雙卡待機,數據只能開一卡,聯通卡(CU)網絡待機功耗較大,以移動卡(CMCC)網絡待機爲準  
                  2. 切換:setting -> sim cards ->cellular data 點擊選擇sim卡 :CMCC 移動 / CU 聯通  
                  3. 打開數據:下滑菜單 打開 :CMCC/CU -> cellular data 打開  
              
              


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章