1. 硬件原理分析
在我的板子上客户提出了检测电池温度的需求,为了满足需求同时减少成本,我们的硬件工程师将电池的NTC直接连接到了rk817这快PMIC的TS脚上,并且没有串联任何的电阻,在我们的一贯思维里一般都是串联一个电阻,然后在电阻跟NTC之间拉条线作为检测口,但是这个项目却并非如此,于是我们查阅rk817的手册我们可以了解到TS脚作为GPIO/模拟功能的描述如下:
TS_FUN
TS_FUN: TS pin function selection
0:source current to TS pin
1:external voltage input directly
根据手册我们可以知道TS脚作为模拟口的时候可选择是从外部输入电压还是从内部输出电流来检测,而我们则选择的是从内部输出电流到TS脚位,然后在NTC上产生电压,再通过TS脚采集AD值计算相应的电阻值
2.软件实现
2.1修改rk817相关的寄存器配置
2.1.1 gas_gauge_ADC_CONFIG0寄存器
该寄存器上的TS_ADC_EN位要配置为1,源码里面已经完成了配置:
rk817_bat_field_write(battery, TS_ADC_EN, ENABLE);
2.1.2 gas_gauge_ADC_CONFIG1寄存器
该寄存器上的VOL_ADC_TSCUR_SEL确保这一位描述了从TS脚输出的电流大小,规格书描述如下:
VOL_ADC_TSCUR_SEL
VOL_ADC_TSCUR_SEL: TS pin flow out
current in active state
00:10uA 01:20uA 10:30uA 11:40uA
在这里我们选择的是默认的也就是10uA
2.1.3 CODEC_AREF_RTCFG1寄存器
通过该寄存器上的REF_ADC_SEL位我们可以知道ADC的参考电压是多少,描述如下:
REF_ADC_SEL
Select the ADC reference voltage
0: 1.2V 1: 1.5V
我们选择的是默认值,也就是1.2v
2.2 添加自己的温度检测函数
首先我们找到rk817采集电池温度的位置,如下:
static int rk817_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct rk817_battery_device *battery = power_supply_get_drvdata(psy);
switch (psp) {
.... //---------------------------------------此处为了篇幅我省略了部分代码
case POWER_SUPPLY_PROP_TEMP:
if(bat_ntc_count >= 100)
{
val->intval = battery_read_temp()/100;
}
if (battery->pdata->bat_mode == MODE_VIRTUAL)
val->intval = VIRTUAL_TEMPERATURE;
break;
.... //---------------------------------------此处为了篇幅我省略了部分代码
default:
return -EINVAL;
}
return 0;
}
在这里是通过 val->intval = battery_read_temp()/100;,来获取温度的我们将这里注释掉,添加成我们集编写的函数,我们自己编写的函数如下:
struct temp_data {
int tempR;
int tempC;
};
static const struct temp_data bat_temp_table[] = {
{1956520, -40}, {1849171, -39}, {1748452, -38}, {1653910, -37}, {1565125, -36},
{1481710, -35}, {1403304, -34}, {1329576, -33}, {1260215, -32}, {1194936, -31},
{1133471, -30}, {1075649, -29}, {1021155, -28}, {969776, -27}, {921315, -26},
{875588, -25}, {832424, -24}, {791663, -23}, {753157, -22}, {716768, -21},
{682367, -20}, {649907, -19}, {619190, -18}, {590113, -17}, {562579, -16},
{536496, -15}, {511779, -14}, {488349, -13}, {466132, -12}, {445058, -11},
{425062, -10}, {405997, -9}, {387905, -8}, {370729, -7}, {354417, -6},
{338922, -5}, {324197, -4}, {310200, -3}, {296890, -2}, {284231, -1},
{272186, 0}, {260760, 1}, {249877, 2}, {239509, 3}, {229629, 4},
{220211, 5}, {211230, 6}, {202666, 7}, {194495, 8}, {186698, 9},
{179255, 10}, {172139, 11}, {165344, 12}, {158856, 13}, {152658, 14},
{146735, 15}, {141075, 16}, {135664, 17}, {130489, 18}, {125540, 19},
{120805, 20}, {116281, 21}, {111947, 22}, {107795, 23}, {103815, 24},
{100000, 25}, {96342, 26}, {92835, 27}, {89470, 28}, {86242, 29},
{83145, 30}, {80181, 31}, {77337, 32}, {74609, 33}, {71991, 34},
{69479, 35}, {67067, 36}, {64751, 37}, {62526, 38}, {60390, 39},
{58336, 40}, {56357, 41}, {54454, 42}, {52623, 43}, {50863, 44},
{49169, 45}, {47539, 46}, {45971, 47}, {44461, 48}, {43008, 49},
{41609, 50}, {40262, 51}, {38964, 52}, {37714, 53}, {36510, 54},
{35350, 55}, {34231, 56}, {33152, 57}, {32113, 58}, {31110, 59},
{30143, 60}, {29224, 61}, {28337, 62}, {27482, 63}, {26657, 64},
{25861, 65}, {25093, 66}, {24351, 67}, {23635, 68}, {22943, 69},
{22275, 70}, {21627, 71}, {21001, 72}, {20396, 73}, {19811, 74},
{19245, 75}, {18698, 76}, {18170, 77}, {17658, 78}, {17164, 79},
{16685, 80}, {16224, 81}, {15777, 82}, {15345, 83}, {14927, 84},
{14521, 85}, {14129, 86}, {13749, 87}, {13381, 88}, {13025, 89},
{12680, 90}, {12343, 91}, {12016, 92}, {11700, 93}, {11393, 94},
{11096, 95}, {10807, 96}, {10528, 97}, {10256, 98}, {9993, 99},
{9738, 100}, {9492, 101}, {9254, 102}, {9022, 103}, {8798, 104},
};
#define BAT_TEMP_TEBLE_NUM (sizeof(bat_temp_table) / sizeof(bat_temp_table[0]))
int vt_get_battery_temp(struct rk817_battery_device *battery)
{
int val = 0, res = 0, i= 0,ret = 0;
val = rk817_bat_field_read(battery, BAT_TS_H) << 8;
val |= rk817_bat_field_read(battery, BAT_TS_L);
//cur = rk817_bat_field_read(battery,VOL_ADC_TSCUR_SEL); //TS out current select 参考电压选择
//val = (1200*val)/65536; //
//res = val*100;///(10/1000);
//res = res *10; //扩大10倍
val = val*18; //
res = val; //扩大10倍
//printk("Vantron print Ntc RValue is: %d -----------------------------------------rn",res);
for(i = 0; i < BAT_TEMP_TEBLE_NUM-1;i++)
{
if ((res > bat_temp_table[i + 1].tempR) && (res <= bat_temp_table[i].tempR))
{
ret = bat_temp_table[i].tempC;
break;
}
}
//printk("Vantron print Ntc CValue is: %d -----------------------------------------rn",ret);
// return (ret*10);
return ret;
}
我们将温度所对应的电阻值做成一个表方便查找,在rk817_battery_get_property的调用如下:
static int rk817_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct rk817_battery_device *battery = power_supply_get_drvdata(psy);
static int bat_ntc_count = 0;
bat_ntc_count++;
switch (psp) {
.... //---------------------------------------此处为了篇幅我省略了部分代码
case POWER_SUPPLY_PROP_TEMP:
if(bat_ntc_count >= 100)
{
//val->intval = battery_read_temp()/100;
val->intval = vt_get_battery_temp(battery);///100; // 20220322--k.li
}
if (battery->pdata->bat_mode == MODE_VIRTUAL)
val->intval = VIRTUAL_TEMPERATURE;
break;
.... //------------------------------------------此处为了篇幅我省略了部分代码
default:
return -EINVAL;
}
return 0;
}
编译烧录到我们的板子中,然后就可以通过cat 命令查看我们的电池温度了,命令如下:
rk66_gnrc:/sys/class/power_supply/battery $ ls
capacity charge_counter charge_full_design device online status temp type voltage_now
capacity_level charge_full current_now health power subsystem time_to_full_now uevent wakeup6
rk66_gnrc:/sys/class/power_supply/battery $ cat temp
22
rk66_gnrc:/sys/class/power_supply/battery $
可以看到电池温度为22摄氏度。
原作者:lkdcom
|