Driver for the NXP PCT2075 digital temperature sensor and thermal watchdog

NXP PCT2075 temperature sensor driver for mbed

This library is a driver for the [NXP PCT2075](http://www.nxp.com/products/sensors/i2c-temperature-voltage-monitors/ic-bus-fm-plus-1-degree-c-accuracy-digital-temperature-sensor-and-thermal-watchdog:PCT2075). It only handles the I2C communication with the sensor, it does not handle the OS interrupt line. The [mbed InterruptIn](https://developer.mbed.org/handbook/InterruptIn) library can be used for this.

example usage

#include <mbed.h>
#include <PCT2075.h>
 
Serial s(USBTX, USBRX); // tx, rx
 
InterruptIn TempPinInt(PC4);
LowPowerTicker ticker;
 
static volatile bool temp_int = false;
static volatile bool tick_int = false;
 
int main( void )
{
    TempPinInt.mode(PullUp);
 
    PCT2075::Configuration config = {
        PCT2075::OS_FAULT_QUE_1,
        PCT2075::OS_ACTIVE_LOW,
        PCT2075::OS_MODE_INTERRUPT,
        PCT2075::DEVICE_MODE_SHUTDOWN
    };
    temp_sensor.set_configuration(config);
    temp_sensor.set_idle_time(PCT2075::TIDLE_MAX);
    
    temp_sensor.set_hyst_temperature(2000);
    temp_sensor.set_os_temperature(2500);
    
    TempPinInt.fall(&on_fall);
    ticker.attach(&tick, 2.0);
 
    while(true) {
        sleep(); // wait to be woken up by ticker or temp sensor
 
        if (tick_int) {
            s.printf("Tick\r\n");
            config.device_mode = PCT2075::DEVICE_MODE_NORMAL;
            temp_sensor.set_configuration(config);
            tick_int = false;
        }
 
        if (temp_int) {
            config.device_mode = PCT2075::DEVICE_MODE_SHUTDOWN;
            temp_sensor.set_configuration(config);
            uint16_t t = temp_sensor.read_temperature();
            s.printf("Temperature: %d\r\n", t);
            temp_int = false;
        }
    }
}
 
Revision:
1:a2b7889eb4e9
diff -r 396665cc3ea0 -r a2b7889eb4e9 PCT2075.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PCT2075.cpp	Fri Sep 23 15:38:34 2016 +0200
@@ -0,0 +1,214 @@
+#include "PCT2075.h"
+
+// R/W - Configuration register: contains a single 8-bit data byte to set the
+// device operating condition; default = 0
+static const char configuration_register    = 0x01;
+// Read only - Temperature register: contains two 8-bit data bytes to store the
+// measured Temp data
+static const char temperature_register      = 0x00;
+// R/W - Overtemperature shutdown threshold register: contains two 8-bit data
+// bytes to store the overtemperature shutdown T ots limit; default = 80 °C
+static const char os_temperature_register   = 0x03;
+// R/W - Hysteresis register: contains two 8-bit data bytes to store the
+// hysteresis T hys limit; default = 75 °C
+static const char hyst_temperature_register = 0x02;
+// R/W - Temperature conversion cycle; default = 100 ms
+static const char idle_time_register        = 0x04;
+
+PCT2075::PCT2075 (I2C &i2c_obj, uint8_t address) : i2c( i2c_obj ) {
+    // I2C uses 7 bit addresses, so the address is left shifted by 1 and added
+    // with the R/W bit before using it
+    address_write = (address << 1)|0;
+    address_read  = (address << 1)|1;
+}
+
+PCT2075::~PCT2075 () {
+    ;
+}
+
+static PCT2075::OSFaultQue parse_os_fault_que(char config_byte) {
+    switch ((config_byte >> 3) & 0x03) {
+    case 0:
+        return PCT2075::OS_FAULT_QUE_1;
+    case 1:
+        return PCT2075::OS_FAULT_QUE_2;
+    case 2:
+        return PCT2075::OS_FAULT_QUE_4;
+    case 3:
+        return PCT2075::OS_FAULT_QUE_6;
+    }
+
+    return PCT2075::OS_FAULT_QUE_1;
+}
+
+PCT2075::Configuration PCT2075::get_configuration() {
+    char data;
+
+    i2c.write( address_write, &configuration_register, 1, true);
+    i2c.read( address_read, &data, 1 );
+
+    PCT2075::Configuration config = {
+        parse_os_fault_que(data),
+        ((data >> 2) & 0x01) == 0x00 ? OS_ACTIVE_LOW : OS_ACTIVE_HIGH,
+        ((data >> 1) & 0x01) == 0x00 ? OS_MODE_COMP : OS_MODE_INTERRUPT,
+        (data & 0x01) == 0x00 ? DEVICE_MODE_NORMAL : DEVICE_MODE_SHUTDOWN
+    };
+
+    return config;
+}
+
+void PCT2075::set_configuration(Configuration& config) {
+    char command[2] = {configuration_register, 2};
+
+    switch (config.os_fault_que) {
+    case OS_FAULT_QUE_1:
+        break;
+    case OS_FAULT_QUE_2:
+        command[1] |= 1 << 3;
+        break;
+    case OS_FAULT_QUE_4:
+        command[1] |= 2 << 3;
+        break;
+    case OS_FAULT_QUE_6:
+        command[1] |= 3 << 3;
+        break;
+    }
+
+    if (config.os_polarity == OS_ACTIVE_HIGH)
+        command[1] |= 1 << 2;
+    if (config.os_mode == OS_MODE_INTERRUPT)
+        command[1] |= 1 << 1;
+    if (config.device_mode == DEVICE_MODE_SHUTDOWN)
+        command[1] |= 1;
+
+    i2c.write(address_write, command, 2);
+}
+
+void PCT2075::set_os_fault_queue(PCT2075::OSFaultQue fault_que) {
+    Configuration conf = get_configuration();
+    conf.os_fault_que = fault_que;
+    set_configuration(conf);
+}
+
+void PCT2075::set_os_polarity(PCT2075::OSPolarity polarity) {
+    Configuration conf = get_configuration();
+    conf.os_polarity = polarity;
+    set_configuration(conf);
+}
+
+void PCT2075::set_os_mode(PCT2075::OSMode os_mode) {
+    Configuration conf = get_configuration();
+    conf.os_mode = os_mode;
+    set_configuration(conf);
+}
+
+void PCT2075::set_device_mode(PCT2075::DeviceMode device_mode) {
+    Configuration conf = get_configuration();
+    conf.device_mode = device_mode;
+    set_configuration(conf);
+}
+
+void PCT2075::shutdown_mode() {
+    set_device_mode(DEVICE_MODE_SHUTDOWN);
+}
+
+void PCT2075::normal_mode() {
+    set_device_mode(DEVICE_MODE_NORMAL);
+}
+
+int16_t PCT2075::read_temperature() {
+    char data[2];
+
+    i2c.write(address_write, &temperature_register, 1, true);
+    i2c.read(address_read, data, 2);
+
+    int16_t temperature = (data[0] << 8) | data[1];
+    temperature = temperature >> 5;
+
+    // temperature should not overflow since 0x3FF * 25 < MaxInt16
+    // and 0x4FF * 25 < MaxUint16
+    return (temperature*25) / 2; // = temperature / 8 * 100
+}
+
+int16_t PCT2075::get_os_temperature() {
+    char data[2];
+
+    i2c.write(address_write, &os_temperature_register, 1, true);
+    i2c.read(address_read, data, 2);
+
+    int16_t temperature = (data[0] << 8) | data[1];
+    temperature = temperature >> 7;
+
+    return temperature * 50; // = temperature / 2 * 100
+}
+
+void PCT2075::set_os_temperature(int16_t temperature) {
+    char command[3];
+
+    if( temperature > TEMP_MAX ) {
+        temperature = TEMP_MAX;
+    } else if (temperature < TEMP_MIN) {
+        temperature = TEMP_MIN;
+    }
+
+    temperature = temperature / 50; // = temperature / 100 * 2
+    command[0] = os_temperature_register;
+    command[1] = (char)(temperature >> 1); // = << 7 and >> 8
+    command[2] = (char)((temperature << 7) & 0x80);
+
+    i2c.write(address_write, command, 3);
+}
+
+int16_t PCT2075::get_hyst_temperature() {
+    char data[2];
+
+    i2c.write(address_write, &hyst_temperature_register, 1, true);
+    i2c.read(address_read, data, 2);
+
+    int16_t temperature = (data[0] << 8) | data[1];
+    temperature = temperature >> 7;
+
+    return temperature * 50; // = temperature / 2 * 100
+}
+
+void PCT2075::set_hyst_temperature (int16_t temperature) {
+    char command[3];
+
+    if( temperature > TEMP_MAX ) {
+        temperature = TEMP_MAX;
+    } else if ( temperature < TEMP_MIN ) {
+        temperature = TEMP_MIN;
+    }
+
+    temperature = temperature / 50; // = temperature / 100 * 2
+    command[0] = hyst_temperature_register;
+    command[1] = (char)(temperature >> 1); // = << 7 and >> 8
+    command[2] = (char)((temperature << 7) & 0x80);
+
+    i2c.write(address_write, command, 2);
+}
+
+uint16_t PCT2075::get_idle_time() {
+    char data[2];
+
+    i2c.write(address_write, &idle_time_register, 1, true);
+    i2c.read(address_read, data, 1);
+
+    uint16_t time = (uint16_t)data[0];
+    return  time * 100;
+}
+
+void PCT2075::set_idle_time(uint16_t time) {
+    char command[2];
+
+    if( time > TIDLE_MAX) {
+        time = TIDLE_MAX;
+    } else if( time < TIDLE_MIN ) {
+        time = TIDLE_MIN;
+    }
+
+    command[0] = idle_time_register;
+    command[1] = (char)(time / 100);
+
+    i2c.write(address_write, command, 2);
+}