diff --git a/drivers/sensor/mcp9808/mcp9808.c b/drivers/sensor/mcp9808/mcp9808.c index 434aeddd587..3b19dae3612 100644 --- a/drivers/sensor/mcp9808/mcp9808.c +++ b/drivers/sensor/mcp9808/mcp9808.c @@ -1,6 +1,5 @@ -/* sensor_mcp9808.c - Driver for MCP9808 temperature sensor */ - /* + * Copyright (c) 2019 Peter Bigot Consulting, LLC * Copyright (c) 2016 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 @@ -19,9 +18,11 @@ LOG_MODULE_REGISTER(MCP9808, CONFIG_SENSOR_LOG_LEVEL); -int mcp9808_reg_read(struct mcp9808_data *data, u8_t reg, u16_t *val) +int mcp9808_reg_read(struct device *dev, u8_t reg, u16_t *val) { - int rc = i2c_write_read(data->i2c_master, data->i2c_slave_addr, + const struct mcp9808_data *data = dev->driver_data; + const struct mcp9808_config *cfg = dev->config->config_info; + int rc = i2c_write_read(data->i2c_master, cfg->i2c_addr, ®, sizeof(reg), val, sizeof(*val)); @@ -38,24 +39,21 @@ static int mcp9808_sample_fetch(struct device *dev, enum sensor_channel chan) __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_AMBIENT_TEMP); - return mcp9808_reg_read(data, MCP9808_REG_TEMP_AMB, &data->reg_val); + return mcp9808_reg_read(dev, MCP9808_REG_TEMP_AMB, &data->reg_val); } static int mcp9808_channel_get(struct device *dev, enum sensor_channel chan, struct sensor_value *val) { - struct mcp9808_data *data = dev->driver_data; + const struct mcp9808_data *data = dev->driver_data; + int temp = mcp9808_temp_signed_from_reg(data->reg_val); __ASSERT_NO_MSG(chan == SENSOR_CHAN_AMBIENT_TEMP); - val->val1 = (data->reg_val & MCP9808_TEMP_INT_MASK) >> - MCP9808_TEMP_INT_SHIFT; - val->val2 = (data->reg_val & MCP9808_TEMP_FRAC_MASK) * 62500U; - - if (data->reg_val & MCP9808_SIGN_BIT) { - val->val1 -= 256; - } + val->val1 = temp / MCP9808_TEMP_SCALE_CEL; + temp -= val->val1 * MCP9808_TEMP_SCALE_CEL; + val->val2 = (temp * 1000000) / MCP9808_TEMP_SCALE_CEL; return 0; } @@ -63,31 +61,42 @@ static int mcp9808_channel_get(struct device *dev, static const struct sensor_driver_api mcp9808_api_funcs = { .sample_fetch = mcp9808_sample_fetch, .channel_get = mcp9808_channel_get, +#ifdef CONFIG_MCP9808_TRIGGER .attr_set = mcp9808_attr_set, .trigger_set = mcp9808_trigger_set, +#endif /* CONFIG_MCP9808_TRIGGER */ }; int mcp9808_init(struct device *dev) { struct mcp9808_data *data = dev->driver_data; + const struct mcp9808_config *cfg = dev->config->config_info; + int rc = 0; - data->i2c_master = - device_get_binding(DT_INST_0_MICROCHIP_MCP9808_BUS_NAME); + data->i2c_master = device_get_binding(cfg->i2c_bus); if (!data->i2c_master) { - LOG_DBG("mcp9808: i2c master not found: %s", - DT_INST_0_MICROCHIP_MCP9808_BUS_NAME); + LOG_DBG("mcp9808: i2c master not found: %s", cfg->i2c_bus); return -EINVAL; } - data->i2c_slave_addr = DT_INST_0_MICROCHIP_MCP9808_BASE_ADDRESS; +#ifdef CONFIG_MCP9808_TRIGGER + rc = mcp9808_setup_interrupt(dev); +#endif /* CONFIG_MCP9808_TRIGGER */ - mcp9808_setup_interrupt(dev); - - return 0; + return rc; } -struct mcp9808_data mcp9808_data; +static struct mcp9808_data mcp9808_data; +static const struct mcp9808_config mcp9808_cfg = { + .i2c_bus = DT_INST_0_MICROCHIP_MCP9808_BUS_NAME, + .i2c_addr = DT_INST_0_MICROCHIP_MCP9808_BASE_ADDRESS, +#ifdef CONFIG_MCP9808_TRIGGER + .alert_pin = DT_INST_0_MICROCHIP_MCP9808_INT_GPIOS_PIN, + .alert_flags = DT_INST_0_MICROCHIP_MCP9808_INT_GPIOS_FLAGS, + .alert_controller = DT_INST_0_MICROCHIP_MCP9808_INT_GPIOS_CONTROLLER, +#endif /* CONFIG_MCP9808_TRIGGER */ +}; DEVICE_AND_API_INIT(mcp9808, DT_INST_0_MICROCHIP_MCP9808_LABEL, mcp9808_init, - &mcp9808_data, NULL, POST_KERNEL, + &mcp9808_data, &mcp9808_cfg, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, &mcp9808_api_funcs); diff --git a/drivers/sensor/mcp9808/mcp9808.h b/drivers/sensor/mcp9808/mcp9808.h index 0bd684f75fa..5ee2791400a 100644 --- a/drivers/sensor/mcp9808/mcp9808.h +++ b/drivers/sensor/mcp9808/mcp9808.h @@ -1,4 +1,5 @@ /* + * Copyright (c) 2019 Peter Bigot Consulting, LLC * Copyright (c) 2016 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 @@ -21,24 +22,53 @@ #define MCP9808_REG_CRITICAL 0x04 #define MCP9808_REG_TEMP_AMB 0x05 -#define MCP9808_ALERT_INT BIT(0) -#define MCP9808_ALERT_CNT BIT(3) -#define MCP9808_INT_CLEAR BIT(5) +/* 16 bits control configuration and state. + * + * * Bit 0 controls alert signal output mode + * * Bit 1 controls interrupt polarity + * * Bit 2 disables upper and lower threshold checking + * * Bit 3 enables alert signal output + * * Bit 4 records alert status + * * Bit 5 records interrupt status + * * Bit 6 locks the upper/lower window registers + * * Bit 7 locks the critical register + * * Bit 8 enters shutdown mode + * * Bits 9-10 control threshold hysteresis + */ +#define MCP9808_CFG_ALERT_MODE_INT BIT(0) +#define MCP9808_CFG_ALERT_ENA BIT(3) +#define MCP9808_CFG_ALERT_STATE BIT(4) +#define MCP9808_CFG_INT_CLEAR BIT(5) -#define MCP9808_SIGN_BIT BIT(12) -#define MCP9808_TEMP_INT_MASK 0x0ff0 -#define MCP9808_TEMP_INT_SHIFT 4 -#define MCP9808_TEMP_FRAC_MASK 0x000f - -#define MCP9808_TEMP_MAX 0xffc +/* 16 bits are used for temperature and state encoding: + * * Bits 0..11 encode the temperature in a 2s complement signed value + * in Celsius with 1/16 Cel resolution + * * Bit 12 is set to indicate a negative temperature + * * Bit 13 is set to indicate a temperature below the lower threshold + * * Bit 14 is set to indicate a temperature above the upper threshold + * * Bit 15 is set to indicate a temperature above the critical threshold + */ +#define MCP9808_TEMP_SCALE_CEL 16 /* signed */ +#define MCP9808_TEMP_SIGN_BIT BIT(12) +#define MCP9808_TEMP_ABS_MASK ((u16_t)(MCP9808_TEMP_SIGN_BIT - 1U)) +#define MCP9808_TEMP_LWR_BIT BIT(13) +#define MCP9808_TEMP_UPR_BIT BIT(14) +#define MCP9808_TEMP_CRT_BIT BIT(15) struct mcp9808_data { struct device *i2c_master; - u16_t i2c_slave_addr; u16_t reg_val; - struct gpio_callback gpio_cb; +#ifdef CONFIG_MCP9808_TRIGGER + struct device *alert_gpio; + struct gpio_callback alert_cb; + + struct device *dev; + + struct sensor_trigger trig; + sensor_trigger_handler_t trigger_handler; +#endif #ifdef CONFIG_MCP9808_TRIGGER_OWN_THREAD struct k_sem sem; @@ -46,16 +76,20 @@ struct mcp9808_data { #ifdef CONFIG_MCP9808_TRIGGER_GLOBAL_THREAD struct k_work work; - struct device *dev; -#endif - -#ifdef CONFIG_MCP9808_TRIGGER - struct sensor_trigger trig; - sensor_trigger_handler_t trigger_handler; #endif }; -int mcp9808_reg_read(struct mcp9808_data *data, u8_t reg, u16_t *val); +struct mcp9808_config { + const char *i2c_bus; + u16_t i2c_addr; +#ifdef CONFIG_MCP9808_TRIGGER + u8_t alert_pin; + u8_t alert_flags; + const char *alert_controller; +#endif /* CONFIG_MCP9808_TRIGGER */ +}; + +int mcp9808_reg_read(struct device *dev, u8_t reg, u16_t *val); #ifdef CONFIG_MCP9808_TRIGGER int mcp9808_attr_set(struct device *dev, enum sensor_channel chan, @@ -64,26 +98,37 @@ int mcp9808_attr_set(struct device *dev, enum sensor_channel chan, int mcp9808_trigger_set(struct device *dev, const struct sensor_trigger *trig, sensor_trigger_handler_t handler); -void mcp9808_setup_interrupt(struct device *dev); -#else -static inline int mcp9808_attr_set(struct device *dev, - enum sensor_channel chan, - enum sensor_attribute attr, - const struct sensor_value *val) -{ - return -ENOTSUP; -} - -static inline int mcp9808_trigger_set(struct device *dev, - const struct sensor_trigger *trig, - sensor_trigger_handler_t handler) -{ - return -ENOTSUP; -} - -static void mcp9808_setup_interrupt(struct device *dev) -{ -} +int mcp9808_setup_interrupt(struct device *dev); #endif /* CONFIG_MCP9808_TRIGGER */ +/* Encode a signed temperature in scaled Celsius to the format used in + * register values. + */ +static inline u16_t mcp9808_temp_reg_from_signed(int temp) +{ + /* Get the 12-bit 2s complement value */ + u16_t rv = temp & MCP9808_TEMP_ABS_MASK; + + if (temp < 0) { + rv |= MCP9808_TEMP_SIGN_BIT; + } + return rv; +} + +/* Decode a register temperature value to a signed temperature in + * scaled Celsius. + */ +static inline int mcp9808_temp_signed_from_reg(u16_t reg) +{ + int rv = reg & MCP9808_TEMP_ABS_MASK; + + if (reg & MCP9808_TEMP_SIGN_BIT) { + /* Convert 12-bit 2s complement to signed negative + * value. + */ + rv = -(1U + (rv ^ MCP9808_TEMP_ABS_MASK)); + } + return rv; +} + #endif /* ZEPHYR_DRIVERS_SENSOR_MCP9808_MCP9808_H_ */ diff --git a/drivers/sensor/mcp9808/mcp9808_trigger.c b/drivers/sensor/mcp9808/mcp9808_trigger.c index 3f0f774cf88..12eaae36c8b 100644 --- a/drivers/sensor/mcp9808/mcp9808_trigger.c +++ b/drivers/sensor/mcp9808/mcp9808_trigger.c @@ -1,7 +1,5 @@ -/* sensor_mcp9808_trigger.c - Trigger support for MCP9808 */ - /* - * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2019 Peter Bigot Consulting, LLC * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,54 +14,28 @@ LOG_MODULE_DECLARE(MCP9808, CONFIG_SENSOR_LOG_LEVEL); -static int mcp9808_reg_write(struct mcp9808_data *data, u8_t reg, u16_t val) +static int mcp9808_reg_write(struct device *dev, u8_t reg, u16_t val) { + const struct mcp9808_data *data = dev->driver_data; + const struct mcp9808_config *cfg = dev->config->config_info; u8_t buf[3] = { reg, val >> 8, /* big-endian register storage */ val & 0xFF, }; - return i2c_write(data->i2c_master, buf, sizeof(buf), data->i2c_slave_addr); -} - -static int mcp9808_reg_update(struct mcp9808_data *data, u8_t reg, - u16_t mask, u16_t val) -{ - u16_t old_val, new_val; - - if (mcp9808_reg_read(data, reg, &old_val) < 0) { - return -EIO; - } - - new_val = old_val & ~mask; - new_val |= val; - - if (new_val == old_val) { - return 0; - } - - return mcp9808_reg_write(data, reg, new_val); + return i2c_write(data->i2c_master, buf, sizeof(buf), cfg->i2c_addr); } int mcp9808_attr_set(struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, const struct sensor_value *val) { - struct mcp9808_data *data = dev->driver_data; - u16_t reg_val = 0U; u8_t reg_addr; - s32_t val2; + int temp; __ASSERT_NO_MSG(chan == SENSOR_CHAN_AMBIENT_TEMP); - val2 = val->val2; - while (val2 > 0) { - reg_val += (1 << 2); - val2 -= 250000; - } - reg_val |= val->val1 << 4; - switch (attr) { case SENSOR_ATTR_LOWER_THRESH: reg_addr = MCP9808_REG_LOWER_LIMIT; @@ -75,7 +47,53 @@ int mcp9808_attr_set(struct device *dev, enum sensor_channel chan, return -EINVAL; } - return mcp9808_reg_write(data, reg_addr, reg_val); + /* Convert temperature to a signed scaled value, then write + * the 12-bit 2s complement-plus-sign-bit register value. + */ + temp = val->val1 * MCP9808_TEMP_SCALE_CEL; + temp += (MCP9808_TEMP_SCALE_CEL * val->val2) / 1000000; + + return mcp9808_reg_write(dev, reg_addr, + mcp9808_temp_reg_from_signed(temp)); +} + +static inline void setup_int(struct device *dev, + bool enable) +{ + const struct mcp9808_data *data = dev->driver_data; + const struct mcp9808_config *cfg = dev->config->config_info; + + if (enable) { + gpio_pin_enable_callback(data->alert_gpio, cfg->alert_pin); + } else { + gpio_pin_disable_callback(data->alert_gpio, cfg->alert_pin); + } +} + +static void handle_int(struct device *dev) +{ + struct mcp9808_data *data = dev->driver_data; + + setup_int(dev, false); + +#if defined(CONFIG_MCP9808_TRIGGER_OWN_THREAD) + k_sem_give(&data->sem); +#elif defined(CONFIG_MCP9808_TRIGGER_GLOBAL_THREAD) + k_work_submit(&data->work); +#endif +} + +static void process_int(struct device *dev) +{ + struct mcp9808_data *data = dev->driver_data; + + if (data->trigger_handler) { + data->trigger_handler(dev, &data->trig); + } + + if (data->trigger_handler) { + setup_int(dev, true); + } } int mcp9808_trigger_set(struct device *dev, @@ -83,27 +101,40 @@ int mcp9808_trigger_set(struct device *dev, sensor_trigger_handler_t handler) { struct mcp9808_data *data = dev->driver_data; + const struct mcp9808_config *cfg = dev->config->config_info; + int rv = 0; + + setup_int(dev, false); data->trig = *trig; data->trigger_handler = handler; - return mcp9808_reg_update(data, MCP9808_REG_CONFIG, MCP9808_ALERT_CNT, - handler == NULL ? 0 : MCP9808_ALERT_CNT); + if (handler != NULL) { + u32_t val; + + setup_int(dev, true); + + rv = gpio_pin_read(data->alert_gpio, cfg->alert_pin, &val); + if ((rv == 0) && (val == 0)) { + handle_int(dev); + } + } + + return rv; } -#ifdef CONFIG_MCP9808_TRIGGER_OWN_THREAD - -static void mcp9808_gpio_cb(struct device *dev, - struct gpio_callback *cb, u32_t pins) +static void alert_cb(struct device *dev, struct gpio_callback *cb, u32_t pins) { struct mcp9808_data *data = - CONTAINER_OF(cb, struct mcp9808_data, gpio_cb); + CONTAINER_OF(cb, struct mcp9808_data, alert_cb); ARG_UNUSED(pins); - k_sem_give(&data->sem); + handle_int(data->dev); } +#ifdef CONFIG_MCP9808_TRIGGER_OWN_THREAD + static void mcp9808_thread_main(int arg1, int arg2) { struct device *dev = INT_TO_POINTER(arg1); @@ -111,11 +142,9 @@ static void mcp9808_thread_main(int arg1, int arg2) ARG_UNUSED(arg2); - while (1) { + while (true) { k_sem_take(&data->sem, K_FOREVER); - data->trigger_handler(dev, &data->trig); - mcp9808_reg_update(data, MCP9808_REG_CONFIG, - MCP9808_INT_CLEAR, MCP9808_INT_CLEAR); + process_int(dev); } } @@ -123,40 +152,29 @@ static K_THREAD_STACK_DEFINE(mcp9808_thread_stack, CONFIG_MCP9808_THREAD_STACK_S static struct k_thread mcp9808_thread; #else /* CONFIG_MCP9808_TRIGGER_GLOBAL_THREAD */ -static void mcp9808_gpio_cb(struct device *dev, - struct gpio_callback *cb, u32_t pins) -{ - struct mcp9808_data *data = - CONTAINER_OF(cb, struct mcp9808_data, gpio_cb); - - ARG_UNUSED(pins); - - k_work_submit(&data->work); -} - static void mcp9808_gpio_thread_cb(struct k_work *work) { struct mcp9808_data *data = CONTAINER_OF(work, struct mcp9808_data, work); - struct device *dev = data->dev; - data->trigger_handler(dev, &data->trig); - mcp9808_reg_update(data, MCP9808_REG_CONFIG, - MCP9808_INT_CLEAR, MCP9808_INT_CLEAR); + process_int(data->dev); } #endif /* CONFIG_MCP9808_TRIGGER_GLOBAL_THREAD */ -void mcp9808_setup_interrupt(struct device *dev) +int mcp9808_setup_interrupt(struct device *dev) { struct mcp9808_data *data = dev->driver_data; + const struct mcp9808_config *cfg = dev->config->config_info; struct device *gpio; + int rc = mcp9808_reg_write(dev, MCP9808_REG_CRITICAL, + MCP9808_TEMP_ABS_MASK); + if (rc == 0) { + rc = mcp9808_reg_write(dev, MCP9808_REG_CONFIG, + MCP9808_CFG_ALERT_ENA); + } - mcp9808_reg_update(data, MCP9808_REG_CONFIG, MCP9808_ALERT_INT, - MCP9808_ALERT_INT); - mcp9808_reg_write(data, MCP9808_REG_CRITICAL, MCP9808_TEMP_MAX); - mcp9808_reg_update(data, MCP9808_REG_CONFIG, MCP9808_INT_CLEAR, - MCP9808_INT_CLEAR); + data->dev = dev; #ifdef CONFIG_MCP9808_TRIGGER_OWN_THREAD k_sem_init(&data->sem, 0, UINT_MAX); @@ -167,18 +185,27 @@ void mcp9808_setup_interrupt(struct device *dev) K_PRIO_COOP(CONFIG_MCP9808_THREAD_PRIORITY), 0, K_NO_WAIT); #else /* CONFIG_MCP9808_TRIGGER_GLOBAL_THREAD */ data->work.handler = mcp9808_gpio_thread_cb; - data->dev = dev; -#endif +#endif /* trigger type */ - gpio = device_get_binding(DT_INST_0_MICROCHIP_MCP9808_INT_GPIOS_CONTROLLER); - gpio_pin_configure(gpio, DT_INST_0_MICROCHIP_MCP9808_INT_GPIOS_PIN, - GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | - GPIO_INT_ACTIVE_LOW | GPIO_INT_DEBOUNCE); + gpio = device_get_binding(cfg->alert_controller); + if (gpio != NULL) { + data->alert_gpio = gpio; + } else { + rc = -ENOENT; + } - gpio_init_callback(&data->gpio_cb, - mcp9808_gpio_cb, - BIT(DT_INST_0_MICROCHIP_MCP9808_INT_GPIOS_PIN)); + if (rc == 0) { + rc = gpio_pin_configure(gpio, cfg->alert_pin, + GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | + GPIO_PUD_PULL_UP | + GPIO_INT_ACTIVE_LOW | GPIO_INT_DEBOUNCE); + } - gpio_add_callback(gpio, &data->gpio_cb); - gpio_pin_enable_callback(gpio, DT_INST_0_MICROCHIP_MCP9808_INT_GPIOS_PIN); + if (rc == 0) { + gpio_init_callback(&data->alert_cb, alert_cb, BIT(cfg->alert_pin)); + + rc = gpio_add_callback(gpio, &data->alert_cb); + } + + return rc; } diff --git a/samples/sensor/mcp9808/README.rst b/samples/sensor/mcp9808/README.rst index 4c7baa42f51..3901b5e40d7 100644 --- a/samples/sensor/mcp9808/README.rst +++ b/samples/sensor/mcp9808/README.rst @@ -6,42 +6,68 @@ MCP9808 Temperature Sensor Overview ******** -Sample application that periodically reads temperature from the MCP9808 sensor. +This sample application periodically (0.5 Hz) measures the ambient +temperature. The result is written to the console. +If triggered measurements are enabled the sample initializes and +maintains a |plusminus| 2 |deg| C window around the current temperature. +When the temperature moves outside the window an alert is given, and the +window is moved to center on the new temperature. Requirements ************ The MCP9808 digital temperature sensor converts temperatures between -20 |deg| C and +100 |deg| C to a digital word with |plusminus| 0.5 |deg| C (max.) -accuracy. It is I2C compatible and -supports up to 16 devices on the bus. We do not require pullup resistors on the -data or clock signals as they are already installed on the breakout board. - -The MCP9808 is available in a discrete component form but it is much easier to -use it mounted on a breakout board. We used the Adafruit breakout board. - -- `MCP9808 Sensor`_ - -This sample uses the sensor APIs and the provided driver for the MCP9808 sensor. +accuracy. It is I2C compatible and supports up to 16 devices on the bus. Wiring ******* -The MCP9808 requires 2 wires for the I2C bus plus power and ground. The power -can be either 5V or 3.3V. - -We connect the Data and clock wires to Analog ports A4 and A5 which is the I2C -pins on Arduino compatible boards. - -In this hookup we are only connecting one device to one of the supported boards. -It reads the temperature and displays it on the console. - - -References -*********** - -- http://www.microchip.com/wwwproducts/en/en556182 - +The MCP9808 is available in a discrete component form but it is much easier to +use it mounted on a breakout board. We used the Adafruit `MCP9808 +Sensor`_ breakout board. .. _`MCP9808 Sensor`: https://www.adafruit.com/product/1782 + +Building and Running +******************** + +After providing a devicetree overlay that specifies the sensor I2C bus +and alert GPIO, build this sample app using: + +.. zephyr-app-commands:: + :zephyr-app: samples/sensor/mcp9808 + :board: particle_xenon + :goals: build flash + +Sample Output +============= + +Note that in the capture below output from the trigger callback and the +main thread are interleaved. + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-v2.1.0-537-gbbdeaa1ae5bb *** + Alert on temp outside [24500, 25500] milli-Celsius + Trtrigger fired 1, temp 15.9375 C + iggAlert on temp outside [15437, 16437] milli-Celsius + er set got 0 + 0:00:00.017: 15.9375 C + 0:00:02.020: 16 C + 0:00:04.022: 16.125 C + 0:00:06.024: 16.1875 C + trigger fired 2, temp 16.3125 C + Alert on temp outside [15812, 16812] milli-Celsius + 0:00:08.027: 16.3125 C + 0:00:10.029: 16.375 C + 0:00:12.032: 16.5 C + 0:00:14.034: 16.5625 C + 0:00:16.037: 16.5625 C + 0:00:18.039: 16.625 C + 0:00:20.042: 16.6875 C + trigger fired 3, temp 16.8125 C + Alert on temp outside [16312, 17312] milli-Celsius + 0:00:22.044: 16.8125 C + 0:00:24.047: 16.875 C diff --git a/samples/sensor/mcp9808/prj.conf b/samples/sensor/mcp9808/prj.conf index 03c6d388cc3..f5524b5c9f7 100644 --- a/samples/sensor/mcp9808/prj.conf +++ b/samples/sensor/mcp9808/prj.conf @@ -3,4 +3,6 @@ CONFIG_I2C=y CONFIG_GPIO=y CONFIG_SENSOR=y CONFIG_MCP9808=y -CONFIG_MCP9808_TRIGGER_GLOBAL_THREAD=y +#CONFIG_MCP9808_TRIGGER_NONE=y +CONFIG_MCP9808_TRIGGER_OWN_THREAD=y +#CONFIG_MCP9808_TRIGGER_GLOBAL_THREAD=y diff --git a/samples/sensor/mcp9808/src/main.c b/samples/sensor/mcp9808/src/main.c index 78c76bcaf8e..5809945a89d 100644 --- a/samples/sensor/mcp9808/src/main.c +++ b/samples/sensor/mcp9808/src/main.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2019 Peter Bigot Consulting, LLC * Copyright (c) 2016 Intel Corporation. * * SPDX-License-Identifier: Apache-2.0 @@ -9,54 +10,118 @@ #include #include +#define UCEL_PER_CEL 1000000 +#define UCEL_PER_MCEL 1000 +#define TEMP_INITIAL_CEL 25 +#define TEMP_WINDOW_HALF_UCEL 500000 + +static const char *now_str(void) +{ + static char buf[16]; /* ...HH:MM:SS.MMM */ + u32_t now = k_uptime_get_32(); + unsigned int ms = now % MSEC_PER_SEC; + unsigned int s; + unsigned int min; + unsigned int h; + + now /= MSEC_PER_SEC; + s = now % 60U; + now /= 60U; + min = now % 60U; + now /= 60U; + h = now; + + snprintf(buf, sizeof(buf), "%u:%02u:%02u.%03u", + h, min, s, ms); + return buf; +} + #ifdef CONFIG_MCP9808_TRIGGER + +static struct sensor_trigger trig; + +static int set_window(struct device *dev, + const struct sensor_value *temp) +{ + const int temp_ucel = temp->val1 * UCEL_PER_CEL + temp->val2; + const int low_ucel = temp_ucel - TEMP_WINDOW_HALF_UCEL; + const int high_ucel = temp_ucel + TEMP_WINDOW_HALF_UCEL; + struct sensor_value val = { + .val1 = low_ucel / UCEL_PER_CEL, + .val2 = low_ucel % UCEL_PER_CEL, + }; + int rc = sensor_attr_set(dev, SENSOR_CHAN_AMBIENT_TEMP, + SENSOR_ATTR_LOWER_THRESH, &val); + if (rc == 0) { + val.val1 = high_ucel / UCEL_PER_CEL, + val.val2 = high_ucel % UCEL_PER_CEL, + rc = sensor_attr_set(dev, SENSOR_CHAN_AMBIENT_TEMP, + SENSOR_ATTR_UPPER_THRESH, &val); + } + + if (rc == 0) { + printf("Alert on temp outside [%d, %d] milli-Celsius\n", + low_ucel / UCEL_PER_MCEL, + high_ucel / UCEL_PER_MCEL); + } + + return rc; +} + +static inline int set_window_ucel(struct device *dev, + int temp_ucel) +{ + struct sensor_value val = { + .val1 = temp_ucel / UCEL_PER_CEL, + .val2 = temp_ucel % UCEL_PER_CEL, + }; + + return set_window(dev, &val); +} + static void trigger_handler(struct device *dev, struct sensor_trigger *trig) { struct sensor_value temp; + static size_t cnt; + ++cnt; sensor_sample_fetch(dev); sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp); - printf("trigger fired, temp %d.%06d\n", temp.val1, temp.val2); + printf("trigger fired %u, temp %g deg C\n", cnt, + sensor_value_to_double(&temp)); + set_window(dev, &temp); } #endif void main(void) { - struct device *dev = device_get_binding("MCP9808"); + const char *const devname = DT_INST_0_MICROCHIP_MCP9808_LABEL; + struct device *dev = device_get_binding(devname); + int rc; if (dev == NULL) { - printf("device not found. aborting test.\n"); + printf("Device %s not found.\n", devname); return; } -#ifdef DEBUG - printf("dev %p\n", dev); - printf("dev %p name %s\n", dev, dev->config->name); -#endif - #ifdef CONFIG_MCP9808_TRIGGER - struct sensor_value val; - struct sensor_trigger trig; + rc = set_window_ucel(dev, TEMP_INITIAL_CEL * UCEL_PER_CEL); + if (rc == 0) { + trig.type = SENSOR_TRIG_THRESHOLD; + trig.chan = SENSOR_CHAN_AMBIENT_TEMP; + rc = sensor_trigger_set(dev, &trig, trigger_handler); + } - val.val1 = 26; - val.val2 = 0; - - sensor_attr_set(dev, SENSOR_CHAN_AMBIENT_TEMP, - SENSOR_ATTR_UPPER_THRESH, &val); - - trig.type = SENSOR_TRIG_THRESHOLD; - trig.chan = SENSOR_CHAN_AMBIENT_TEMP; - - if (sensor_trigger_set(dev, &trig, trigger_handler)) { - printf("Could not set trigger. aborting test.\n"); + if (rc != 0) { + printf("Trigger set failed: %d\n", rc); return; } + printk("Trigger set got %d\n", rc); #endif while (1) { struct sensor_value temp; - int rc; rc = sensor_sample_fetch(dev); if (rc != 0) { @@ -70,8 +135,9 @@ void main(void) break; } - printf("temp: %d.%06d\n", temp.val1, temp.val2); + printf("%s: %g C\n", now_str(), + sensor_value_to_double(&temp)); - k_sleep(K_MSEC(2000)); + k_sleep(K_SECONDS(2)); } }