temp_sensor: Separate ADC interface and thermistor maths

Separate the bd99992gw ADC interface from the NCP15WB thermistor
adc-to-temp maths so that the thermistor can be used with various
other interfaces.

BUG=chrome-os-partner:44764
TEST=make buildall -j
Manual on Glados. Boot to S0, run "temps".
Verify that temperatures start around 28C and begin to increase after
system is powered-on for a long duration.
BRANCH=None

Change-Id: I3e72e9f390feebaac2440dbe722485f8d1cf8c56
Signed-off-by: Wonjoon Lee <woojoo.lee@samsung.com>
Reviewed-on: https://chromium-review.googlesource.com/296871
Reviewed-by: Shawn N <shawnn@chromium.org>
This commit is contained in:
Wonjoon Lee
2015-09-01 21:33:56 +09:00
committed by chrome-bot
parent 3f2dc44158
commit 502dc50f04
8 changed files with 142 additions and 96 deletions

View File

@@ -71,6 +71,7 @@
#define CONFIG_TEMP_SENSOR
#define CONFIG_TEMP_SENSOR_BD99992GW
#define CONFIG_THERMISTOR_NCP15WB
/*
* Allow dangerous commands.

View File

@@ -58,6 +58,9 @@ driver-$(CONFIG_TEMP_SENSOR_G781)+=temp_sensor/g781.o
driver-$(CONFIG_TEMP_SENSOR_TMP006)+=temp_sensor/tmp006.o
driver-$(CONFIG_TEMP_SENSOR_TMP432)+=temp_sensor/tmp432.o
# Thermistors
driver-$(CONFIG_THERMISTOR_NCP15WB)+=temp_sensor/thermistor_ncp15wb.o
# Type-C port controller (TCPC) drivers
driver-$(CONFIG_USB_PD_TCPM_STUB)+=tcpm/stub.o
driver-$(CONFIG_USB_PD_TCPM_TCPCI)+=tcpm/tcpci.o

View File

@@ -17,6 +17,7 @@
#include "hooks.h"
#include "i2c.h"
#include "temp_sensor.h"
#include "thermistor.h"
#include "timer.h"
#include "util.h"
@@ -35,46 +36,6 @@ static enum bd99992gw_adc_channel
*/
#define ADC_LOOP_PERIOD BD99992GW_ADC1CNTL1_SLP27MS
/*
* ADC-to-temp conversion assumes recommended thermistor / resistor
* configuration specified in datasheet (NCP15WB* / 24.9K).
* For 50C through 100C, use linear interpolation from discreet points
* in table below. For temps < 50C, use a simplified linear function.
*/
#define ADC_DISCREET_RANGE_START_TEMP 50
/* 10 bit ADC result corresponding to START_TEMP */
#define ADC_DISCREET_RANGE_START_RESULT 407
#define ADC_DISCREET_RANGE_LIMIT_TEMP 100
/* 10 bit ADC result corresponding to LIMIT_TEMP */
#define ADC_DISCREET_RANGE_LIMIT_RESULT 107
/* Table entries in steppings of 5C */
#define ADC_DISCREET_RANGE_STEP 5
/* Discreet range ADC results (9 bit) per temperature, in 5 degree steps */
static const uint8_t adc_result[] = {
203, /* 50 C */
178, /* 55 C */
157, /* 60 C */
138, /* 65 C */
121, /* 70 C */
106, /* 75 C */
93, /* 80 C */
81, /* 85 C */
70, /* 90 C */
61, /* 95 C */
53, /* 100 C */
};
/*
* From 20C (reasonable lower limit of temperatures we care about accuracy)
* to 50C, the temperature curve is roughly linear, so we don't need to include
* data points in our table.
*/
#define adc_to_temp(result) (ADC_DISCREET_RANGE_START_TEMP - \
(((result) - ADC_DISCREET_RANGE_START_RESULT) * 3 + 16) / 32)
static int raw_read8(const int offset, int *data_ptr)
{
int ret;
@@ -143,55 +104,14 @@ DECLARE_HOOK(HOOK_INIT, bd99992gw_init, HOOK_PRIO_DEFAULT);
DECLARE_HOOK(HOOK_CHIPSET_RESUME, bd99992gw_init, HOOK_PRIO_DEFAULT);
/* Convert ADC result to temperature in celsius */
test_export_static int bd99992gw_get_temp(uint16_t adc)
static int bd99992gw_get_temp(uint16_t adc)
{
int temp;
int head, tail, mid;
uint8_t delta, step;
/* Is ADC result in linear range? */
if (adc >= ADC_DISCREET_RANGE_START_RESULT) {
temp = adc_to_temp(adc);
}
/* Hotter than our discreet range limit? */
else if (adc <= ADC_DISCREET_RANGE_LIMIT_RESULT) {
temp = ADC_DISCREET_RANGE_LIMIT_TEMP;
}
/* We're in the discreet range */
else {
/* Table uses 9 bit ADC values */
adc /= 2;
/* Binary search to find proper table entry */
head = 0;
tail = ARRAY_SIZE(adc_result) - 1;
while (head != tail) {
mid = (head + tail) / 2;
if (adc_result[mid] >= adc &&
adc_result[mid+1] < adc)
break;
if (adc_result[mid] > adc)
head = mid + 1;
else
tail = mid;
}
/* Now fit between table entries using linear interpolation. */
if (head != tail) {
delta = adc_result[mid] - adc_result[mid + 1];
step = ((adc_result[mid] - adc) *
ADC_DISCREET_RANGE_STEP + delta / 2) / delta;
} else {
/* Edge case where adc = max */
mid = head;
step = 0;
}
temp = ADC_DISCREET_RANGE_START_TEMP +
ADC_DISCREET_RANGE_STEP * mid + step;
}
return temp;
#ifdef CONFIG_THERMISTOR_NCP15WB
return ncp15wb_calculate_temp(adc);
#else
#error "Unknown thermistor for bd99992gw"
return 0;
#endif
}
/* Get temperature from requested sensor */

View File

@@ -0,0 +1,20 @@
/* Copyright 2015 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* Thermistor module for Chrome EC */
#ifndef __CROS_EC_TEMP_SENSOR_THERMISTOR_H
#define __CROS_EC_TEMP_SENSOR_THERMISTOR_H
/**
* ncp15wb temperature conversion routine.
*
* @param adc 10bit raw data on adc.
*
* @return temperature in C.
*/
int ncp15wb_calculate_temp(uint16_t adc);
#endif /* __CROS_EC_TEMP_SENSOR_THERMISTOR_NCP15WB_H */

View File

@@ -0,0 +1,100 @@
/* Copyright 2015 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* NCP15WB thermistor module for Chrome EC */
#include "common.h"
#include "thermistor.h"
#include "util.h"
/*
* ADC-to-temp conversion assumes recommended thermistor / resistor
* configuration (NCP15WB* / 24.9K) with a 10-bit ADC.
* For 50C through 100C, use linear interpolation from discreet points
* in table below. For temps < 50C, use a simplified linear function.
*/
#define ADC_DISCREET_RANGE_START_TEMP 50
/* 10 bit ADC result corresponding to START_TEMP */
#define ADC_DISCREET_RANGE_START_RESULT 407
#define ADC_DISCREET_RANGE_LIMIT_TEMP 100
/* 10 bit ADC result corresponding to LIMIT_TEMP */
#define ADC_DISCREET_RANGE_LIMIT_RESULT 107
/* Table entries in steppings of 5C */
#define ADC_DISCREET_RANGE_STEP 5
/* Discreet range ADC results (9 bit) per temperature, in 5 degree steps */
static const uint8_t adc_result[] = {
203, /* 50 C */
178, /* 55 C */
157, /* 60 C */
138, /* 65 C */
121, /* 70 C */
106, /* 75 C */
93, /* 80 C */
81, /* 85 C */
70, /* 90 C */
61, /* 95 C */
53, /* 100 C */
};
/*
* From 20C (reasonable lower limit of temperatures we care about accuracy)
* to 50C, the temperature curve is roughly linear, so we don't need to include
* data points in our table.
*/
#define adc_to_temp(result) (ADC_DISCREET_RANGE_START_TEMP - \
(((result) - ADC_DISCREET_RANGE_START_RESULT) * 3 + 16) / 32)
/* Convert ADC result (10 bit) to temperature in celsius */
int ncp15wb_calculate_temp(uint16_t adc)
{
int temp;
int head, tail, mid;
uint8_t delta, step;
/* Is ADC result in linear range? */
if (adc >= ADC_DISCREET_RANGE_START_RESULT)
temp = adc_to_temp(adc);
/* Hotter than our discreet range limit? */
else if (adc <= ADC_DISCREET_RANGE_LIMIT_RESULT)
temp = ADC_DISCREET_RANGE_LIMIT_TEMP;
/* We're in the discreet range */
else {
/* Table uses 9 bit ADC values */
adc /= 2;
/* Binary search to find proper table entry */
head = 0;
tail = ARRAY_SIZE(adc_result) - 1;
while (head != tail) {
mid = (head + tail) / 2;
if (adc_result[mid] >= adc &&
adc_result[mid+1] < adc)
break;
if (adc_result[mid] > adc)
head = mid + 1;
else
tail = mid;
}
/* Now fit between table entries using linear interpolation. */
if (head != tail) {
delta = adc_result[mid] - adc_result[mid + 1];
step = ((adc_result[mid] - adc) *
ADC_DISCREET_RANGE_STEP + delta / 2) / delta;
} else {
/* Edge case where adc = max */
mid = head;
step = 0;
}
temp = ADC_DISCREET_RANGE_START_TEMP +
ADC_DISCREET_RANGE_STEP * mid + step;
}
return temp;
}

View File

@@ -1497,6 +1497,8 @@
#undef CONFIG_TEMP_SENSOR_TMP006 /* TI TMP006 sensor, on I2C bus */
#undef CONFIG_TEMP_SENSOR_TMP432 /* TI TMP432 sensor, on I2C bus */
#undef CONFIG_THERMISTOR_NCP15WB /* NCP15WB thermistor */
/*
* If defined, active-high GPIO which indicates temperature sensor chips are
* powered. If not defined, temperature sensors are assumed to be always

View File

@@ -78,9 +78,9 @@ int board_discharge_on_ac(int enabled);
#define CONFIG_CHIPSET_CAN_THROTTLE
#define CONFIG_FANS 1
#define CONFIG_TEMP_SENSOR
#define CONFIG_TEMP_SENSOR_BD99992GW
#define CONFIG_THERMISTOR_NCP15WB
#define I2C_PORT_THERMAL 1
int bd99992gw_get_temp(uint16_t adc);
int ncp15wb_calculate_temp(uint16_t adc);
#endif
#ifdef TEST_FAN

View File

@@ -480,11 +480,11 @@ static int test_several_limits(void)
return EC_SUCCESS;
}
/* Tests for bd99992gw temperature sensor ADC-to-temp calculation */
/* Tests for ncp15wb thermistor ADC-to-temp calculation */
#define LOW_ADC_TEST_VALUE 887 /* 0 C */
#define HIGH_ADC_TEST_VALUE 100 /* > 100C */
static int test_bd99992_adc_to_temp(void)
static int test_ncp15wb_adc_to_temp(void)
{
int i;
uint8_t temp;
@@ -513,10 +513,10 @@ static int test_bd99992_adc_to_temp(void)
* decrease.
*/
i = LOW_ADC_TEST_VALUE;
temp = bd99992gw_get_temp(i);
temp = ncp15wb_calculate_temp(i);
while (--i > HIGH_ADC_TEST_VALUE) {
new_temp = bd99992gw_get_temp(i);
new_temp = ncp15wb_calculate_temp(i);
TEST_ASSERT(new_temp == temp ||
new_temp == temp + 1);
temp = new_temp;
@@ -524,7 +524,7 @@ static int test_bd99992_adc_to_temp(void)
/* Verify several datapoints are within 1C accuracy */
for (i = 0; i < ARRAY_SIZE(adc_temp_datapoints); ++i) {
temp = bd99992gw_get_temp(adc_temp_datapoints[i].adc);
temp = ncp15wb_calculate_temp(adc_temp_datapoints[i].adc);
ASSERT(temp >= adc_temp_datapoints[i].temp - 1 &&
temp <= adc_temp_datapoints[i].temp + 1);
}
@@ -544,6 +544,6 @@ void run_test(void)
RUN_TEST(test_one_limit);
RUN_TEST(test_several_limits);
RUN_TEST(test_bd99992_adc_to_temp);
RUN_TEST(test_ncp15wb_adc_to_temp);
test_print_result();
}