diff --git a/board/glados/board.h b/board/glados/board.h index 836894e759..f2b1dc0434 100644 --- a/board/glados/board.h +++ b/board/glados/board.h @@ -71,6 +71,7 @@ #define CONFIG_TEMP_SENSOR #define CONFIG_TEMP_SENSOR_BD99992GW +#define CONFIG_THERMISTOR_NCP15WB /* * Allow dangerous commands. diff --git a/driver/build.mk b/driver/build.mk index b617033977..70745ae07d 100644 --- a/driver/build.mk +++ b/driver/build.mk @@ -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 diff --git a/driver/temp_sensor/bd99992gw.c b/driver/temp_sensor/bd99992gw.c index b46d8512fe..f2a48eb2d5 100644 --- a/driver/temp_sensor/bd99992gw.c +++ b/driver/temp_sensor/bd99992gw.c @@ -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 */ diff --git a/driver/temp_sensor/thermistor.h b/driver/temp_sensor/thermistor.h new file mode 100644 index 0000000000..3bb5335ddd --- /dev/null +++ b/driver/temp_sensor/thermistor.h @@ -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 */ diff --git a/driver/temp_sensor/thermistor_ncp15wb.c b/driver/temp_sensor/thermistor_ncp15wb.c new file mode 100644 index 0000000000..51e884ed35 --- /dev/null +++ b/driver/temp_sensor/thermistor_ncp15wb.c @@ -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; +} diff --git a/include/config.h b/include/config.h index 2ca35f73d6..e301633315 100644 --- a/include/config.h +++ b/include/config.h @@ -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 diff --git a/test/test_config.h b/test/test_config.h index 93f9f4b072..4b49c699df 100644 --- a/test/test_config.h +++ b/test/test_config.h @@ -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 diff --git a/test/thermal.c b/test/thermal.c index 761dc9358d..6e95d37f83 100644 --- a/test/thermal.c +++ b/test/thermal.c @@ -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(); }