Newer
Older
avrrfm / mcp9808.c
/* 
 * File:   mcp9808.h
 * Author: torsten.roemer@luniks.net
 *
 * Created on 9. Februar 2025, 20:41
 */

#include <util/delay.h>

#include "mcp9808.h"
#include "usart.h"

/**
 * Writes the given value to the given register,
 * MSB first.
 * 
 * @param address
 * @param value
 */
static void regWrite(uint8_t address, uint16_t value) {
    i2cStart();
    i2cSend(MCP9808_WRITE);
    i2cSend(address);
    i2cSend(value >> 8);
    i2cSend(value & 0x00ff);
    i2cStop();
}

/**
 * Reads and returns the value from the given register,
 * MSB first.
 * 
 * @param address
 * @return register value
 */
static uint16_t regRead(uint8_t address) {
    i2cStart();
    i2cSend(MCP9808_WRITE);
    i2cSend(address);
    i2cStart();
    i2cSend(MCP9808_READ);
    uint8_t upper = i2cReadAck();
    uint8_t lower = i2cReadNack();
    i2cStop();

    uint16_t value = 0;
    value |= upper << 8;
    value |= lower;

    return value;
}

void sleepTSens(void) {
    uint16_t conf = regRead(MCP9808_CONF);
    conf |= (1 << 8);
    regWrite(MCP9808_CONF, conf);
}

void wakeTSens(void) {
    uint16_t conf = regRead(MCP9808_CONF);
    conf &= ~(1 << 8);
    regWrite(MCP9808_CONF, conf);

    // TODO need to wait for first conversion result after wake up
    // can use an alert irq to wake up sleeping MCU instead?
    _delay_ms(300);
}

uint16_t readTSens(void) {
    uint16_t raw = regRead(MCP9808_TEMP);

    return raw;
}

int16_t convertTSens(uint16_t raw) {
    uint8_t upper = raw >> 8;
    uint8_t lower = raw & 0x00ff;

    // check flags
    if ((upper & 0x80) == 0x80) {
        // T >= TA CRIT
    }
    if ((upper & 0x40) == 0x40) {
        // T > TA UPPER
    }
    if ((upper & 0x20) == 0x20) {
        // T < TA LOWER
    }

    // clear flag bits
    upper &= 0x1F;
    int16_t temp;
    if ((upper & 0x10) == 0x10) {
        // TA < 0°C
        // clear sign
        upper &= 0x0f;
        temp = -(2560 - (upper * 160 + lower * 10 / 16));
    } else {
        // TA >= 0°C
        temp = (upper * 160 + lower * 10 / 16);
    }
    
    return temp;
}