Library files for ADT74xx, ADT73xx famile of products.
Diff: adt7420.c
- Revision:
- 1:a86efb0ef0ad
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/adt7420.c Wed Aug 28 15:37:55 2019 +0000 @@ -0,0 +1,564 @@ +/***************************************************************************//** + * @file adt7420.c + * @brief Implementation of ADT7420 Driver. + * @author DBogdan (dragos.bogdan@analog.com) +******************************************************************************** + * Copyright 2012, 2019(c) Analog Devices, Inc. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * - The use of this software may or may not infringe the patent rights + * of one or more patent holders. This license does not release you + * from the requirement that you obtain separate licenses from these + * patent holders to use this software. + * - Use of the software either in source or binary form, must be run + * on or directly connected to an Analog Devices Inc. component. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +/******************************************************************************/ +/***************************** Include Files **********************************/ +/******************************************************************************/ +#include <stdint.h> +#include <stdlib.h> +#include "platform_drivers.h" +#include "adt7420.h" + +static const struct adt7420_chip_info chip_info[] = { + [ID_ADT7410] = { + .resolution = 16, + .communication = I2C, + }, + [ID_ADT7420] = { + .resolution = 16, + .communication = I2C, + }, + [ID_ADT7422] = { + .resolution = 16, + .communication = I2C, + }, + [ID_ADT7310] = { + .resolution = 16, + .communication = SPI, + }, + [ID_ADT7320] = { + .resolution = 16, + .communication = SPI, + } +}; + +/***************************************************************************//** + * @brief Reads the value of a register SPI/I2C. + * + * @param dev - The device structure. + * @param register_address - Address of the register. + * + * @return register_value - Value of the register. +*******************************************************************************/ +uint16_t get_register_value(struct adt7420_dev *dev, + uint8_t register_address) +{ + uint16_t register_value = 0; + + //remap register map + if (chip_info[dev->act_device].communication == SPI) { + switch (register_address) { + case REG_TEMP: register_address = ADT7320_REG_TEMP;break; // Temperature value + case REG_STATUS:register_address = ADT7320_REG_STATUS;break; // status info + case REG_CONFIG:register_address = ADT7320_REG_CONFIG;break; // Configuration + case REG_T_CRIT:register_address = ADT7320_REG_T_CRIT;break; // Temperature CRIT setpoint (147'C) + case REG_HIST: register_address = ADT7320_REG_HIST;break; // Temperature HYST setpoint (5'C) + case REG_T_HIGH:register_address = ADT7320_REG_T_HIGH;break; // Temperature HIGH setpoint (64'C) + case REG_T_LOW: register_address = ADT7320_REG_T_LOW;break; // Temperature LOW setpoint (10'C) + case REG_ID: register_address = ADT7320_REG_ID;break; // ID value + } + register_value = adt7420_get_register_value(dev, register_address); + } else { + switch(register_address) { + case REG_TEMP: { + register_value = adt7420_get_register_value(dev,ADT7420_REG_TEMP_MSB) << 8; + register_value |= adt7420_get_register_value(dev,ADT7420_REG_TEMP_LSB); + break; + } + case REG_STATUS: register_value = adt7420_get_register_value(dev, ADT7420_REG_STATUS); break; + case REG_CONFIG: register_value = adt7420_get_register_value(dev, ADT7420_REG_CONFIG);break; + case REG_T_HIGH: { + register_value = adt7420_get_register_value(dev,ADT7420_REG_T_HIGH_MSB) << 8; + register_value |= adt7420_get_register_value(dev,ADT7420_REG_T_HIGH_LSB); + break; + } + case REG_T_LOW: { + register_value = adt7420_get_register_value(dev,ADT7420_REG_T_LOW_MSB) << 8; + register_value |= adt7420_get_register_value(dev,ADT7420_REG_T_LOW_LSB); + break; + } + case REG_T_CRIT: { + register_value = adt7420_get_register_value(dev,ADT7420_REG_T_CRIT_MSB) << 8; + register_value |= adt7420_get_register_value(dev,ADT7420_REG_T_CRIT_LSB); + break; + } + case REG_HIST: register_value = adt7420_get_register_value(dev, ADT7420_REG_HIST);break; + case REG_ID: register_value = adt7420_get_register_value(dev, ADT7420_REG_ID);break; + } + } + return register_value; +} + +/***************************************************************************//** + * @brief Reads the value of a register SPI/I2C interface. + * + * @param dev - The device structure. + * @param register_address - Address of the register. + * + * @return register_value - Value of the register. +*******************************************************************************/ +uint16_t adt7420_get_register_value(struct adt7420_dev *dev, + uint8_t register_address) +{ + uint8_t register_value = 0; + uint8_t data[2] = {0,0xFF}; + + if (chip_info[dev->act_device].communication == SPI) { + /* Set the SPI command byte. datasheet page 17 */ + data[0] = ADT7320_READ_CMD | (register_address << 3); + + return set_shift_reg(dev, register_address,data); + } else { + data[0] = register_address; + + i2c_write(dev->i2c_desc, + ®ister_address, + 1, + NO_STOP_BIT); //add a repeat start + i2c_read(dev->i2c_desc, + ®ister_value, + 1, + STOP_BIT); + + return register_value; + } +} + +/**************************************************************************//** + * @brief Write to input shift register SPI interface. + * + * @param dev - The device structure. + * @param register_address - Command control bits. + * @param data - Data to be written in input register. + * + * @return read_back_data - value read from register. +******************************************************************************/ +uint16_t set_shift_reg(struct adt7420_dev *dev, + uint8_t register_address, + uint8_t *data) +{ + uint8_t data_buffer[PKT_LENGTH] = { 0, 0, 0 }; + uint16_t read_back_data = 0; + uint8_t numBytes; + + switch (register_address) { + case ADT7320_REG_STATUS: + case ADT7320_REG_CONFIG: + case ADT7320_REG_ID: + case ADT7320_REG_HIST: numBytes = ONE_BYTE; break; + default: + numBytes = TWO_BYTE; + break; + } + + if (numBytes == ONE_BYTE) { + data_buffer[0] = data[0]; + data_buffer[1] = data[1] & ADT7420_LSB_MASK; + spi_write_and_read(dev->spi_desc, data_buffer, ONE_BYTE); + read_back_data = (data_buffer[0] & ADT7420_MSB_MASK) | data_buffer[1]; + } + else { + data_buffer[0] = data[0]; + data_buffer[1] = data[1] & ADT7420_LSB_MASK; + data_buffer[2] = (data[2] & ADT7420_LSB_MASK) << 8; + spi_write_and_read(dev->spi_desc, data_buffer, TWO_BYTE); + read_back_data = data_buffer[1] << ADT7420_MSB_OFFSET | data_buffer[2]; + } + return read_back_data; +} + +/***************************************************************************//** + * @brief Sets the value of a register SPI/I2C. + * + * @param dev - The device structure. + * @param register_address - Address of the register. + * @param num_data_bytes - Number of bytes. + * @param data - Data to be written in input register. + * + * @return None. +*******************************************************************************/ +void set_register_value(struct adt7420_dev *dev, + uint8_t register_address, + uint8_t num_data_bytes, + uint8_t *data) +{ + + uint8_t data_buffer[PKT_LENGTH] = {0, 0, 0}; + + + data_buffer[1] = data[0]; + data_buffer[2] = data[1]; + + if (chip_info[dev->act_device].communication == SPI) { + //simple address re-map for SPI devices + switch (register_address) { + case REG_TEMP: register_address = ADT7320_REG_TEMP; break; // Temperature value + case REG_STATUS:register_address = ADT7320_REG_STATUS; break; // status info + case REG_CONFIG:register_address = ADT7320_REG_CONFIG; break; // Configuration + case REG_T_CRIT:register_address = ADT7320_REG_T_CRIT; break; // Temperature CRIT setpoint (147'C) + case REG_HIST: register_address = ADT7320_REG_HIST; break; // Temperature HYST setpoint (5'C) + case REG_T_HIGH:register_address = ADT7320_REG_T_HIGH; break; // Temperature HIGH setpoint (64'C) + case REG_T_LOW: register_address = ADT7320_REG_T_LOW; break; // Temperature LOW setpoint (10'C) + case REG_ID: register_address = ADT7320_REG_ID; break; // ID value + } + /* Set the SPI command byte. datasheet page 17 */ + data_buffer[0] = (register_address << 3) & ADT7320_WRITE_MASK_CMD; + spi_write_and_read(dev->spi_desc, data_buffer, num_data_bytes); + } else { + //simple address re-map for I2Cdevices + switch (register_address) { + case REG_TEMP: register_address = ADT7420_REG_T_HIGH_MSB; break; // Temperature value + case REG_STATUS: register_address = ADT7420_REG_STATUS; break; // status info + case REG_CONFIG: register_address = ADT7420_REG_CONFIG; break; // Configuration + case REG_T_CRIT: register_address = ADT7420_REG_T_CRIT_MSB; break; // Temperature CRIT setpoint (147'C) + case REG_HIST: register_address = ADT7420_REG_HIST; break; // Temperature HYST setpoint (5'C) + case REG_T_HIGH: register_address = ADT7420_REG_T_HIGH_MSB; break; // Temperature HIGH setpoint (64'C) + case REG_T_LOW: register_address = ADT7420_REG_T_LOW_MSB; break; // Temperature LOW setpoint (10'C) + case REG_ID: register_address = ADT7420_REG_ID; break; // ID value + } + + data_buffer[0] = register_address; + + i2c_write(dev->i2c_desc, + data_buffer, + num_data_bytes, + STOP_BIT); //no repeat start + } +} + +/***************************************************************************//** + * @brief Initializes the communication peripheral and checks if the device is + * present. + * + * @param device - The device structure. + * @param init_param - The structure that contains the device initial + * parameters. + * + * @return status - The result of the initialization procedure. + * Example: -1 - I2C peripheral was not initialized or the + * device is not present. + * 0 - I2C peripheral was initialized and the + * device is present. +*******************************************************************************/ +int32_t adt7420_init(struct adt7420_dev **device, + struct adt7420_init_param init_param) +{ + struct adt7420_dev *dev; + int32_t status; + uint8_t device_connected_check = 0; + + dev = (struct adt7420_dev *)malloc(sizeof(*dev)); + if (!dev) + return -1; + + dev->act_device = init_param.act_device; + + + if (chip_info[dev->act_device].communication == SPI) { + status = spi_init(&dev->spi_desc, &init_param.spi_init); + } else { + status = i2c_init(&dev->i2c_desc, &init_param.i2c_init); + } + + /* Device Settings */ + dev->resolution_setting = init_param.resolution_setting; + + /* Reset device to default values to ensure all internal circuitry is properly initialised*/ + adt7420_reset_interface(dev); + + /*Register read to ensure that next read will be valid - acts as 200us delay while + device resets*/ + get_register_value(dev, REG_STATUS); + + + device_connected_check = get_register_value(dev, REG_ID); + device_connected_check >>= GET_MANUFACTURER_ID; + + if (device_connected_check != ADT7XXX_ID_CHECK) + status = FAILURE; + else + status = SUCCESS; + + *device = dev; + + return status; +} + +/***************************************************************************//** + * @brief Free the resources allocated by adt7420_init(). + * + * @param dev - The device structure. + * + * @return ret - The result of the remove procedure. +*******************************************************************************/ +int32_t adt7420_remove(struct adt7420_dev *dev) +{ + int32_t ret; + + ret = i2c_remove(dev->i2c_desc); + free(dev); + + return ret; +} + +/***************************************************************************//** + * @brief Sets the operational mode for ADT7420/ADT7320. + * + * @param dev - The device structure. + * @param mode - Operation mode. + * Example: ADT7420_OP_MODE_CONT_CONV - continuous conversion; + * ADT7420_OP_MODE_ONE_SHOT - one shot; + * ADT7420_OP_MODE_1_SPS - 1 SPS mode; + * ADT7420_OP_MODE_SHUTDOWN - shutdown. + * + * @return None. +*******************************************************************************/ +void adt7420_set_operation_mode(struct adt7420_dev *dev, + uint8_t mode) +{ + uint8_t register_value [ONE_BYTE] = { 0, 0 }; + + register_value[0] = get_register_value(dev, REG_CONFIG); + + register_value[0] &= ~ADT7420_CONFIG_OP_MODE(ADT7420_OP_MODE_SHUTDOWN); + register_value[0] |= ADT7420_CONFIG_OP_MODE(mode); + + set_register_value(dev,REG_CONFIG, ONE_BYTE, register_value); +} + +/***************************************************************************//** + * @brief Sets the resolution for ADT7420/ADT7320. + * + * @param dev - The device structure. + * @param resolution - Resolution. + * Example: 0 - 13-bit resolution; + * 1 - 16-bit resolution. + * + * @return None. +*******************************************************************************/ +void adt7420_set_resolution(struct adt7420_dev *dev, + uint8_t resolution) +{ + uint8_t register_value[1] = { 0 }; + + register_value[0] = get_register_value(dev, REG_CONFIG); + + register_value[0] &= ~ADT7420_CONFIG_RESOLUTION; + register_value[0] |= (resolution * ADT7420_CONFIG_RESOLUTION); + + + set_register_value(dev,REG_CONFIG, ONE_BYTE, register_value); + dev->resolution_setting = resolution; +} + +/***************************************************************************//** + * @brief Resets the SPI or I2C inteface for the ADT7420/ADT7320 + * + * @param dev - The device structure. + * + * @return None. +*******************************************************************************/ +void adt7420_reset_interface(struct adt7420_dev *dev) +{ + uint8_t data_buffer[] = { 0xFF, 0xFF, 0xFF, 0xFF }; + + if (chip_info[dev->act_device].communication == SPI) + spi_write_and_read(dev->spi_desc, data_buffer, FOUR_BYTES); + else { + uint8_t register_address = ADT7420_REG_RESET; + i2c_write(dev->i2c_desc, + ®ister_address, + 1, + STOP_BIT);//no repeat start + dev->resolution_setting = 0; + } +} + +/***************************************************************************//** + * @brief Reads the temperature data and converts it to Celsius degrees. + * + * @param dev - The device structure. + * + * @return temperature - Temperature in degrees Celsius. +*******************************************************************************/ +float adt7420_get_temperature(struct adt7420_dev *dev) +{ + uint16_t temp = 0; + float temp_c = 0; + + temp = get_register_value(dev, REG_TEMP); + + if(dev->resolution_setting) { + if(temp & 0x8000) + /*! Negative temperature */ + temp_c = (float)((int32_t)temp - 65536) / 128; + else + /*! Positive temperature */ + temp_c = (float)temp / 128; + } else { + temp >>= 3; + if(temp & 0x1000) + /*! Negative temperature */ + temp_c = (float)((int32_t)temp - 8192) / 16; + else + /*! Positive temperature */ + temp_c = (float)temp / 16; + } + + return temp_c; +} + +/**************************************************************************//** + * @brief Write to a setpoint register. + * + * @param dev - The device structure. + * @param register_value - Command control bits. + * @param data - Data to be written in input register. + * + * @return read_back_data - value read from register. +******************************************************************************/ +uint8_t adt7420_wr_setpoint_reg(struct adt7420_dev *dev, + uint8_t register_value, + uint16_t data) +{ + uint16_t read_back_data = 0; + uint8_t address, num_bytes; + uint8_t data_buffer[PKT_LENGTH] = { 0, 0, 0 }; + + switch (register_value) { + case REG_T_CRIT: + case REG_T_HIGH: + case REG_T_LOW: { + num_bytes = TWO_BYTE; + data_buffer[0] = ((data & ADT7420_MSB_MASK) >> ADT7420_MSB_OFFSET); + data_buffer[1] = data & ADT7420_LSB_MASK; + break; + } + case REG_HIST: { + num_bytes = ONE_BYTE; + data_buffer[0] = data & ADT7420_LSB_MASK; + break; + } + } + + set_register_value(dev, register_value, num_bytes, data_buffer); + read_back_data = get_register_value(dev, register_value); + + if (register_value == REG_HIST) { + data &= 0x000F; //msbits are all low for HIST register + read_back_data &= 0x000F; //msbits are all low for HIST register + } + + return read_back_data == data ? SUCCESS : FAILURE; +} + +/***************************************************************************//** + * @brief Sets the Fault Queue option for ADT7420/ADT7320. + * + * @param dev - The device structure. + * @param mode - Fault Queue selection. + * Example: 1 - 1 fault (default). + * 2 - 2 faults. + * 3 - 3 faults. + * 4 - 4 faults. + * + * @return None. +*******************************************************************************/ +void adt7420_set_fault_queue(struct adt7420_dev *dev, + uint8_t mode) +{ + uint8_t register_value[1] = { 0 }; + + register_value[0] = get_register_value(dev, REG_CONFIG); + + register_value[0] &= ~ADT7420_CONFIG_FAULT_QUEUE(ADT7420_FAULT_QUEUE_4_FAULTS); + register_value[0] |= ADT7420_CONFIG_FAULT_QUEUE(mode); + + set_register_value(dev,REG_CONFIG, ONE_BYTE, register_value); +} + +/***************************************************************************//** + * @brief Sets comparator/interrupt (CT/INT) mode for ADT7420/ADT7320. + * + * @param dev - The device structure. + * @param setting - Mode selection. + * Example: 0 - Interrupt (default). + * 1 - Comparator. + * + * + * @return None. +*******************************************************************************/ +void adt7420_set_ct_int_mode(struct adt7420_dev *dev, + uint8_t setting) +{ + uint8_t register_value[1] = { 0 }; + + register_value[0] = get_register_value(dev, REG_CONFIG); + + register_value[0] &= ~ADT7420_CONFIG_INT_CT_MODE; + register_value[0] |= (setting * ADT7420_CONFIG_INT_CT_MODE); + + set_register_value(dev,REG_CONFIG, ONE_BYTE, register_value); + } + +/***************************************************************************//** + * @brief Sets output polarity for the pins CT/INT (Critical Temp - Over/Under Temp). + * + * @param dev - The device structure. + * @param polarity - Polarity selection. + * Example: 0 - Active Low (default). + * 1 - Active High. + * + * + * @return None. +*******************************************************************************/ +void adt7420_set_ct_int_polarity(struct adt7420_dev *dev, + uint8_t polarity) +{ + uint8_t register_value[1] = { 0 }; + + register_value[0] = get_register_value(dev, REG_CONFIG); + + register_value[0] &= ~ADT7420_CONFIG_CT_POL; + register_value[0] &= ~ADT7420_CONFIG_INT_POL; + register_value[0] |= (polarity * ADT7420_CONFIG_CT_POL); + register_value[0] |= (polarity * ADT7420_CONFIG_INT_POL); + + set_register_value(dev,REG_CONFIG, ONE_BYTE, register_value); +} \ No newline at end of file