Library files for ADT74xx, ADT73xx famile of products.

Dependents:  

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,
+		      &register_address,
+			  1,
+			  NO_STOP_BIT); //add a repeat start
+		i2c_read(dev->i2c_desc,
+			 &register_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,
+	    	  &register_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