summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorVic Yang <victoryang@chromium.org>2012-02-15 15:38:06 -0800
committerVic Yang <victoryang@chromium.org>2012-02-18 13:37:53 +0800
commit0fefd25c0c7d6517f47aac2da974495f72312014 (patch)
treed67e0071040aa53f3b3922f2ca39cce6ed4e4617 /common
parent737fbbd032ef937b37f2e5e833fa52455aa19c64 (diff)
downloadchrome-ec-0fefd25c0c7d6517f47aac2da974495f72312014.tar.gz
Temperature polling and temporal correction
A temperature polling task is added to achieve temporal correction and also reduce the latency of reading temperature. Factor out sensor specific part to keep code clean. Signed-off-by: Vic Yang <victoryang@chromium.org> BUG=chrome-os-partner:7801 TEST=On link, 'temps' shows all temperature readings. Cover each sensor with hand and see object temperature rise. Compilation succeeded on bds/adv/daisy/discovery. Change-Id: I3c44c8b2e3ab2aa9ce640d3fc25e7fba56534b86
Diffstat (limited to 'common')
-rw-r--r--common/build.mk1
-rw-r--r--common/main.c1
-rw-r--r--common/temp_sensor.c236
-rw-r--r--common/tmp006.c253
4 files changed, 274 insertions, 217 deletions
diff --git a/common/build.mk b/common/build.mk
index a04fe3c11a..b6e32dfd73 100644
--- a/common/build.mk
+++ b/common/build.mk
@@ -16,6 +16,7 @@ common-$(CONFIG_TASK_GAIAPOWER)+=gaia_power.o
common-$(CONFIG_FLASH)+=flash_commands.o
common-$(CONFIG_PWM)+=pwm_commands.o
common-$(CONFIG_TEMP_SENSOR)+=temp_sensor.o temp_sensor_commands.o
+common-$(CONFIG_TMP006)+=tmp006.o
common-$(CONFIG_LIGHTBAR)+=leds.o
# Board driver modules
diff --git a/common/main.c b/common/main.c
index 7058aad009..f342bad9a0 100644
--- a/common/main.c
+++ b/common/main.c
@@ -30,6 +30,7 @@
#include "system.h"
#include "task.h"
#include "temp_sensor.h"
+#include "tmp006.h"
#include "timer.h"
#include "uart.h"
#include "usb_charge.h"
diff --git a/common/temp_sensor.c b/common/temp_sensor.c
index 9313623213..cc7dc25599 100644
--- a/common/temp_sensor.c
+++ b/common/temp_sensor.c
@@ -11,9 +11,10 @@
#include "util.h"
#include "console.h"
#include "board.h"
+#include "peci.h"
+#include "tmp006.h"
#include "task.h"
-#include "fpu.h"
-#include "math.h"
+#include "chip_temp_sensor.h"
/* Defined in board_temp_sensor.c. Must be in the same order as
* in enum temp_sensor_id.
@@ -27,171 +28,31 @@ int temp_sensor_read(enum temp_sensor_id id)
if (id < 0 || id >= TEMP_SENSOR_COUNT)
return -1;
sensor = temp_sensors + id;
- return sensor->read(sensor);
+ return sensor->read(sensor->idx);
}
-int temp_sensor_tmp006_read_die_temp(const struct temp_sensor_t* sensor)
+void poll_all_sensors(void)
{
- int traw, t;
- int rv;
- int addr = sensor->addr;
-
- rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x01, &traw);
- if (rv)
- return -1;
- t = (int)(int16_t)traw / 128;
- return t + 273;
-}
-
-/* Calculate the remote object temperature.
- * Parameters:
- * Tdie: Die temperature in 1/100 K.
- * Vobj: Voltage read from register 0. In nV.
- * S0: Sensitivity factor in 1e-17.
- * Return:
- * Object temperature in 1/100 K.
- */
-int temp_sensor_tmp006_calculate_object_temp(int Tdie_i, int Vobj_i, int S0_i)
-{
-#ifdef CONFIG_FPU
- float Tdie, Vobj, S0;
- float Tx, S, Vos, Vx, fv, Tobj, T4;
- int Tobj_i;
-
- enable_fpu();
-
- Tdie = (float)Tdie_i * 1e-2f;
- Vobj = (float)Vobj_i * 1e-9f;
- S0 = (float)S0_i * 1e-17f;
-
- /* Calculate according to TMP006 users guide. */
- Tx = Tdie - 298.15f;
- /* S is the sensitivity */
- S = S0 * (1.0f + 1.75e-3f * Tx - 1.678e-5f * Tx * Tx);
- /* Vos is the offset voltage */
- Vos = -2.94e-5f - 5.7e-7f * Tx + 4.63e-9f * Tx * Tx;
- Vx = Vobj - Vos;
- /* fv is Seebeck coefficient f(Vobj) */
- fv = Vx + 13.4f * Vx * Vx;
-
- T4 = Tdie * Tdie * Tdie * Tdie + fv / S;
- Tobj = sqrtf(sqrtf(T4));
- Tobj_i = (int32_t)(Tobj * 100.0f);
-
- disable_fpu(Tobj_i);
-
- return Tobj_i;
-#else
- /* This is the fixed-point version of object temperature calculation.
- * Should be accurate but it is hard to prevent and debug
- * overflow/underflow problem. Only use this version if there is no
- * FPU support.
- * Division is delayed when possible to preserve precision, but should
- * not cause overflow.
- * Assuming Tdie is between 200K and 400K, and S0 between 3e-14 and
- * 9e-14, the maximum value during the calculation should be less than
- * (1 << 30), which fits in int32_t.
- */
- int32_t Tx, S19, Vos, Vx, fv9, ub, lb;
-
- Tx = Tdie - 29815;
- /* S19 is the sensitivity multipled by 1e19 */
- S19 = S0 * (100000 + 175 * Tx / 100 -
- 1678 * Tx / 100 * Tx / 100000) / 1000;
- /* Vos is the offset voltage in nV */
- Vos = -29400 - 570 * Tx / 100 + 463 * Tx / 100 * Tx / 10000;
- Vx = Vobj - Vos;
- /* fv9 is Seebeck coefficient f(Vobj) multipled by 1e9 */
- fv9 = Vx + 134 * Vx / 100000 * Vx / 100000;
-
- /* The last step in the calculation involves square root, so we use
- * binary search.
- * Assuming the object temperature is between 200K and 400K, the search
- * should take at most 14 iterations.
- */
- ub = 40000;
- lb = 20000;
- while (lb != ub) {
- int32_t t, rhs, lhs;
-
- t = (ub + lb) / 2;
- lhs = t / 100 * t / 10000 * t / 10000 * (S19/100) / 1000 * t;
- rhs = Tdie / 100 * Tdie / 10000 * Tdie / 10000 * (S19/100) /
- 1000 * Tdie + fv9 * 1000;
- if (lhs > rhs)
- ub = t;
- else
- lb = t + 1;
- }
-
- return ub;
+#ifdef CONFIG_TMP006
+ tmp006_poll();
+#endif
+#ifdef CONFIG_PECI
+ peci_temp_sensor_poll();
+#endif
+#ifdef CHIP_lm4
+ chip_temp_sensor_poll();
#endif
}
-int temp_sensor_tmp006_read_object_temp(const struct temp_sensor_t* sensor)
-{
- int traw, t;
- int vraw, v;
- int rv;
- int addr = sensor->addr;
-
- rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x01, &traw);
- if (rv)
- return -1;
- t = (int)(int16_t)traw / 128 + 273;
-
- rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x00, &vraw);
- if (rv)
- return -1;
- v = ((int)(int16_t)vraw * 15625) / 100;
-
- return temp_sensor_tmp006_calculate_object_temp(t * 100, v, 6400);
-}
-
-void temp_sensor_tmp006_config(const struct temp_sensor_t* sensor)
+void temp_sensor_task(void)
{
- int addr = sensor->addr;
-
- /* Configure the sensor:
- * 0x7000 = bits 14:12 = continuous conversion
- * 0x0400 = bits 11:9 = ADC conversion rate (1/sec)
- * 0x0100 = bit 8 = DRDY pin enabled */
-
- /* TODO: support shutdown mode for power-saving? */
- i2c_write16(TMP006_PORT(addr), TMP006_REG(addr), 0x02, 0x7500);
+ while (1) {
+ poll_all_sensors();
+ /* Wait 1s */
+ task_wait_msg(1000000);
+ }
}
-int temp_sensor_tmp006_print(const struct temp_sensor_t* sensor)
-{
- int vraw, v;
- int traw, t;
- int rv;
- int d;
- int addr = sensor->addr;
-
- uart_printf("Debug data from %s:\n", sensor->name);
- rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0xfe, &d);
- if (rv)
- return rv;
- uart_printf(" Manufacturer ID: 0x%04x\n", d);
-
- rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0xff, &d);
- uart_printf(" Device ID: 0x%04x\n", d);
-
- rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x02, &d);
- uart_printf(" Config: 0x%04x\n", d);
-
- rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x00, &vraw);
- v = ((int)(int16_t)vraw * 15625) / 100;
- uart_printf(" Voltage: 0x%04x = %d nV\n", vraw, v);
-
- rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x01, &traw);
- t = ((int)(int16_t)traw * 100) / 128;
- uart_printf(" Temperature: 0x%04x = %d.%02d C\n",
- traw, t / 100, t > 0 ? t % 100 : 100 - (t % 100));
-
- return EC_SUCCESS;
-}
/*****************************************************************************/
/* Console commands */
@@ -221,65 +82,6 @@ static int command_temps(int argc, char **argv)
}
DECLARE_CONSOLE_COMMAND(temps, command_temps);
-static int command_sensor_info(int argc, char **argv)
-{
- int i;
- int rv, rv1;
- const struct temp_sensor_t* sensor;
-
- rv1 = EC_SUCCESS;
- for (i = 0; i < TEMP_SENSOR_COUNT; ++i) {
- sensor = temp_sensors + i;
- if (sensor->print == TEMP_SENSOR_NO_PRINT)
- continue;
- rv = sensor->print(sensor);
- if (rv != EC_SUCCESS)
- rv1 = rv;
- }
-
- return rv1;
-}
-DECLARE_CONSOLE_COMMAND(tempsinfo, command_sensor_info);
-
-/* TMP006 object temperature calculation command.
- * TODO: This command is only for debugging. Remove it when temporal correciton
- * is done.
- */
-static int command_sensor_remote(int argc, char **argv)
-{
- char *e;
- int32_t Td2, Vobj9, Sm03;
-
- if (argc != 4) {
- uart_puts("Usage: tempcorrect <Tdie*100> <Vobj*10^9> <S0*10^11>\n");
- return EC_ERROR_UNKNOWN;
- }
-
- Td2 = strtoi(argv[1], &e, 0);
- if (e && *e) {
- uart_puts("Bad Tdie.\n");
- return EC_ERROR_UNKNOWN;
- }
-
- Vobj9 = strtoi(argv[2], &e, 0);
- if (e && *e) {
- uart_puts("Bad Vobj.\n");
- return EC_ERROR_UNKNOWN;
- }
-
- Sm03 = strtoi(argv[3], &e, 0);
- if (e && *e) {
- uart_puts("Bad S0.\n");
- return EC_ERROR_UNKNOWN;
- }
-
- uart_printf("%d\n",
- temp_sensor_tmp006_calculate_object_temp(Td2, Vobj9, Sm03));
-
- return EC_SUCCESS;
-}
-DECLARE_CONSOLE_COMMAND(tempremote, command_sensor_remote);
-
/*****************************************************************************/
/* Initialization */
diff --git a/common/tmp006.c b/common/tmp006.c
new file mode 100644
index 0000000000..70ad0eb688
--- /dev/null
+++ b/common/tmp006.c
@@ -0,0 +1,253 @@
+/* Copyright (c) 2012 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.
+ */
+
+/* TMP006 temperature sensor module for Chrome EC */
+
+#include "tmp006.h"
+#include "temp_sensor.h"
+#include "board.h"
+#include "uart.h"
+#include "util.h"
+#include "console.h"
+#include "task.h"
+#include "fpu.h"
+#include "math.h"
+#include "i2c.h"
+
+/* Defined in board_temp_sensor.c. */
+extern const struct tmp006_t tmp006_sensors[TMP006_COUNT];
+
+struct tmp006_data_t {
+ /* Object voltage */
+ int v;
+ /* The last four die temperature value. Used as a circular buffer. */
+ int t[4];
+ /* The index of the current value in the dir temperature array. */
+ int tidx;
+};
+
+static struct tmp006_data_t tmp006_data[TMP006_COUNT];
+
+static int tmp006_read_die_temp(int idx)
+{
+ int pidx = (tmp006_data[idx].tidx - 1) & 0x3;
+ return tmp006_data[idx].t[pidx] / 100;
+}
+
+/* Calculate the remote object temperature.
+ * Parameters:
+ * Tdie: Die temperature in 1/100 K.
+ * Vobj: Voltage read from register 0. In nV.
+ * S0: Sensitivity factor in 1e-17.
+ * Return:
+ * Object temperature in 1/100 K.
+ */
+static int tmp006_calculate_object_temp(int Tdie_i, int Vobj_i, int S0_i)
+{
+ float Tdie, Vobj, S0;
+ float Tx, S, Vos, Vx, fv, Tobj, T4;
+ int Tobj_i;
+
+ enable_fpu();
+
+ Tdie = (float)Tdie_i * 1e-2f;
+ Vobj = (float)Vobj_i * 1e-9f;
+ S0 = (float)S0_i * 1e-17f;
+
+ /* Calculate according to TMP006 users guide. */
+ Tx = Tdie - 298.15f;
+ /* S is the sensitivity */
+ S = S0 * (1.0f + 1.75e-3f * Tx - 1.678e-5f * Tx * Tx);
+ /* Vos is the offset voltage */
+ Vos = -2.94e-5f - 5.7e-7f * Tx + 4.63e-9f * Tx * Tx;
+ Vx = Vobj - Vos;
+ /* fv is Seebeck coefficient f(Vobj) */
+ fv = Vx + 13.4f * Vx * Vx;
+
+ T4 = Tdie * Tdie * Tdie * Tdie + fv / S;
+ Tobj = sqrtf(sqrtf(T4));
+ Tobj_i = (int32_t)(Tobj * 100.0f);
+
+ disable_fpu(Tobj_i);
+
+ return Tobj_i;
+}
+
+/* Temporal Correction
+ * Parameters:
+ * T1-T4: Four die temperature readings separated by 1s in 1/100K.
+ * v: Voltage read from register 0. In nV.
+ * Return:
+ * Corrected object voltage in 1/100K.
+ */
+static int tmp006_correct_object_voltage(int T1,
+ int T2,
+ int T3,
+ int T4,
+ int Vobj)
+{
+ int Tslope = 3 * T1 + T2 - T3 - 3 * T4;
+ return Vobj + 296 * Tslope;
+}
+
+static int tmp006_read_object_temp(int idx)
+{
+ int pidx = (tmp006_data[idx].tidx - 1) & 0x3;
+ int t = tmp006_data[idx].t[pidx];
+ int v = tmp006_data[idx].v;
+
+ v = tmp006_correct_object_voltage(
+ t,
+ tmp006_data[idx].t[(pidx + 3) & 3],
+ tmp006_data[idx].t[(pidx + 2) & 3],
+ tmp006_data[idx].t[(pidx + 1) & 3],
+ v);
+
+ /* TODO: Calibrate the sensitivity factor. */
+ return tmp006_calculate_object_temp(t, v, 6400) / 100;
+}
+
+static int tmp006_poll_sensor(int sensor_id)
+{
+ int traw, t;
+ int vraw, v;
+ int rv;
+ int addr = tmp006_sensors[sensor_id].addr;
+ int idx;
+
+ rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x01, &traw);
+ if (rv)
+ return EC_ERROR_UNKNOWN;
+ t = ((int)(int16_t)traw * 100) / 128 + 27300;
+
+ rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x00, &vraw);
+ if (rv)
+ return EC_ERROR_UNKNOWN;
+ v = ((int)(int16_t)vraw * 15625) / 100;
+
+ idx = tmp006_data[sensor_id].tidx;
+ tmp006_data[sensor_id].t[idx] = t;
+ tmp006_data[sensor_id].v = v;
+ tmp006_data[sensor_id].tidx = (idx + 1) & 3;
+
+ return EC_SUCCESS;
+}
+
+static int tmp006_print(int idx)
+{
+ int vraw, v;
+ int traw, t;
+ int rv;
+ int d;
+ int addr = tmp006_sensors[idx].addr;
+
+ uart_printf("Debug data from %s:\n", tmp006_sensors[idx].name);
+ rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0xfe, &d);
+ if (rv)
+ return rv;
+ uart_printf(" Manufacturer ID: 0x%04x\n", d);
+
+ rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0xff, &d);
+ uart_printf(" Device ID: 0x%04x\n", d);
+
+ rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x02, &d);
+ uart_printf(" Config: 0x%04x\n", d);
+
+ rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x00, &vraw);
+ v = ((int)(int16_t)vraw * 15625) / 100;
+ uart_printf(" Voltage: 0x%04x = %d nV\n", vraw, v);
+
+ rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x01, &traw);
+ t = ((int)(int16_t)traw * 100) / 128;
+ uart_printf(" Temperature: 0x%04x = %d.%02d C\n",
+ traw, t / 100, t > 0 ? t % 100 : 100 - (t % 100));
+
+ return EC_SUCCESS;
+}
+
+
+int tmp006_get_val(int idx)
+{
+ /* Check the low bit to determine which temperature to read. */
+ if ((idx & 0x1) == 0)
+ return tmp006_read_die_temp(idx >> 1);
+ else
+ return tmp006_read_object_temp(idx >> 1);
+}
+
+
+int tmp006_poll(void)
+{
+ int i;
+ int rv;
+ int rv1 = EC_SUCCESS;
+
+ for (i = 0; i < TMP006_COUNT; ++i) {
+ rv = tmp006_poll_sensor(i);
+ if (rv != EC_SUCCESS)
+ rv1 = rv;
+ }
+
+ return rv1;
+}
+
+
+/*****************************************************************************/
+/* Console commands */
+
+/* TMP006 object temperature calculation command.
+ * TODO: This command is only for debugging. Remove it when temporal correciton
+ * is done.
+ */
+static int command_sensor_remote(int argc, char **argv)
+{
+ char *e;
+ int32_t Td2, Vobj9, Sm03;
+
+ if (argc != 4) {
+ uart_puts("Usage: tempcorrect <Tdie*100> <Vobj*10^9> <S0*10^11>\n");
+ return EC_ERROR_UNKNOWN;
+ }
+
+ Td2 = strtoi(argv[1], &e, 0);
+ if (e && *e) {
+ uart_puts("Bad Tdie.\n");
+ return EC_ERROR_UNKNOWN;
+ }
+
+ Vobj9 = strtoi(argv[2], &e, 0);
+ if (e && *e) {
+ uart_puts("Bad Vobj.\n");
+ return EC_ERROR_UNKNOWN;
+ }
+
+ Sm03 = strtoi(argv[3], &e, 0);
+ if (e && *e) {
+ uart_puts("Bad S0.\n");
+ return EC_ERROR_UNKNOWN;
+ }
+
+ uart_printf("%d\n",
+ tmp006_calculate_object_temp(Td2, Vobj9, Sm03));
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(tempremote, command_sensor_remote);
+
+static int command_sensor_info(int argc, char **argv)
+{
+ int i;
+ int rv, rv1;
+
+ rv1 = EC_SUCCESS;
+ for (i = 0; i < TMP006_COUNT; ++i) {
+ rv = tmp006_print(i);
+ if (rv != EC_SUCCESS)
+ rv1 = rv;
+ }
+
+ return rv1;
+}
+DECLARE_CONSOLE_COMMAND(tmp006, command_sensor_info);