[SOLUCIONADO] Problemas comunicando MAX11616 ADC con Atmega2560

Buenas tardes,

Estoy intentando hacer lecturas a través de un ADC MAX11616 y Atmega2560 pero no he tenido éxito. Me podrían guiar en que podría estar haciendo mal.

  1. Estoy utilizando la librería Wire.h
  2. La dirección del MAX11616EEE+ es 0110101 (53 DEC, 0x35 HEX)
  3. Las entradas son Single-Ended (estoy probando alimentando la entrada directamente de la salida 3.3V de arduino y GND)
  4. De acuerdo a lo que interpreto del datasheet, he configurado el MAX11616 de la siguiente manera:

Setup Byte: 11011010
1: Selecciono escribir en Setup byte
1 0 1: Vref interna, A11/REF analog input, ref interna siempre encendida
1: reloj externo
0: unipolar
1: sin reset

Configuration Byte: 00010101
0: Selecciono escribir en Configuration byte
00 1010: escanear entradas desde A0 hasta A10 (son las entradas que estoy utilizando)
1: Selecciono modo Single-ended

Este es el código de prueba que estoy utilizando:

#include <Wire.h>        //libreria para activar I2C comunicación con RTC
char c;

void setup() {

Serial1.begin(9600);// Comunicacion RS485
Wire.begin();       // join i2c bus 
delay(100);
pinMode(38,OUTPUT);
digitalWrite(38,HIGH);

Wire.beginTransmission(53);        //Slave addres DEC (0110101)
Wire.write(byte(218));             //Setup byte (11011010) (setup, internal reference, AREF analog input,Int. Ref always on, external clock, unipolar, sin reset, last bit dont care)
Wire.write(byte(21));              //Configuration byte (00010101) (config byte, Scan from A0 to A10, single ended)
Wire.endTransmission();      
delay(50);
}

void loop() {
c = ' ';
Wire.requestFrom(53, 22);         // realizo lectura
 if (Wire.available()>0){
 while (Wire.available()) {   
   c = Wire.read();               // recibo cada caracter
   Serial1.print(c);              // imprimo cada caracter
}}
delay(3000);

}

Nota: La salida la obtengo a través de comunicación RS485 ya que todo esta integrado en una sola tarjeta (uC ATMEGA2560, chip MAX11616EEE+, MAS485). El Max485 esta conectado a RX1 y TX1 del Atmega con su pin de control D38 para DE RE.

El diagrama de conexión es como esta en las imagenes adjuntas, las seccioné para que se puedan detallar mejor.

1.- Conexiones del Atmega256:
-Los capacitores de desacople son de 0.1uF
-Xtal 16Mhz + 2 Cap de 22pF + 1Res 1M
-2 Res Pull Up de 4,7K en el Bus I2C

2- Conexión Max11616:
-Capacitor de desacople 0.1uF

3- Entradas Max11616:
-De A0 a A10 con res Pull Down de 10k (Excepto A7)

  • A7: kty81
    (Vcc 5+)-------+------>3.3k------+------->kty81-110-->(GND)
[ltr][color=#4f4e4e] | |
 +------>100nF----+-----> A7 max11616


Nota 2: La salida que obtengo es la que sigue: F000 F000 F000 F000 F000 F000 F000 F000 F000 F000 F000 

Para esta respuesta tengo conectado 3.3V en el pin A0 del Max11616.


Gracias por cualquier ayuda!




[/color][/ltr]

atmega2560_sch.png

atmega2560_sch.png

¿Error de tipeo o error de conexión?
¿No se supone que estarías leyendo el A7 del Max que es el que no le pusiste R pulldown?
Pero dices que los 3V3 los mandas a A0...

O yo te estoy interpretando mal... ::slight_smile:

Busqueda rápida arroja esta librería en C standard pero puedes adaptarla con suma facilidad o reforzar lo que estas haciendo.

Este es el ejemplo de uso
max11615.ino sería así mas o menos

#include "max11615.h"          // include the library
/* USER CODE BEGIN 0 */
#define ADDRESS_MAX11615  0x66
MAX11615 adcDriver_1;
/* USER CODE END 0 */

void setup() {
    // initialize the adcDriver_1 with the I2C handle, the I2C address \
       and the settings for analog reference according to the datasheet
    // analog ref: (internal) + (reference not connected) \
                    + (internal reference always on)
    MAX11615_Init(&adcDriver_1, &hi2c1, ADDRESS_MAX11615, 4+2+1);

    Serial.begin(115200);
}

void loop(){
    char buffer[40];

    /* USER CODE BEGIN 2 */


    uint8_t adc_value = 0;
    MAX11615_ADC_Read(&adcDriver_1, 0, adc_value); 
    // read adc value from channel 0 and print to console
    sprintf(buffer, "ADC Value CH0: %d\n", adc_value);  // modificar linea si no tienes STM32 o ESP
    Serial.println(buffer);

}

Que lo vuelves Arduino facilmente.

La librería quedaría asi

#include "max11615.h"

/**
 * @brief      writes a single value into a MAX11615 register
 * @param      *chip, pointer to the MAX11615 typedef struct
 * @param      reg, the destination register's address
 * @param      val, the value for the destination register
 */
uint8_t MAX11615_Write8(MAX11615 *chip, uint8_t reg, uint8_t val){
 	if(HAL_I2C_Mem_Write(chip->wireIface, chip->devAddress, reg, 1, &val, 1, 10) != HAL_OK) 
		return 1;
	return 0;
}

/**
 * @brief       reads a single value from a MAX11615 register
 * @param       *chip, pointer to the MAX11615 typedef struct
 * @param       reg, the destination register's address
 * @param       val, pointer to the location where the value shall be stored
 * @return      0 on success, 1 on transmission error
 */
uint8_t MAX11615_Read8(MAX11615 *chip, uint8_t reg, uint8_t *val){
	if(HAL_I2C_Mem_Read(chip->wireIface, chip->devAddress, reg, 1, val, 1, 10) != HAL_OK) 
		return 1;
	return 0;
}

/**
 * @brief        sets up the MAX11615 chip with the provided Vref setting
 * @param        *chip, pointer to the MAX11615 typedef struct
 * @param        *wireIface a pointer to a HAL I2C_HandleTypeDef
 * @param 		 address of the chip on the I2C bus
 */
uint8_t MAX11615_Init(MAX11615* chip, I2C_HandleTypeDef* wireIface, uint16_t address, uint8_t vRef){
	chip->wireIface = wireIface;
	chip->devAddress = address; 
	uint8_t ret = 0;
	// 0 - don't care
	// 1 - reset configuration register to default
	// 2 - unipolar
	// 3 - internal clock
	// 4 - SEL0 (vRef)
	// 5 - SEL1 (vRef)
	// 6 - SEL2 (vRef)
	vRef = (vRef<<4) & 0xf0;
	vRef |= 2; // do not reset the setup register
	ret += MAX11615_Setup(chip, vRef);
	// 0 - Single Ended
	// 1 to 4 - Channel Select:  7
	// 5 to 6 - Scan Mode: read channels up to selected channel
	uint8_t config_byte = 0x00;
	config_byte |= 1; // single ended mode
	config_byte |= ((1<<5) & (1<<6)); // SCAN bits: convert only the channel selected by CS bits
	ret += MAX11615_Configuration(chip, config_byte);
	return ret;
}

uint8_t MAX11615_Setup(MAX11615* chip, uint8_t data){
	data = data | 0x80; // make REG bit 7 = 1 (setup byte)
	if(HAL_I2C_Master_Transmit(chip->wireIface, chip->devAddress, &data, 1, 10) != HAL_OK) 
		return 1;
	return 0;
}

uint8_t MAX11615_Configuration(MAX11615* chip, uint8_t data){
	data = data & (~0x80); // make REG bit 7 = 0 (configuration byte)
	if(HAL_I2C_Master_Transmit(chip->wireIface, chip->devAddress, &data, 1, 10) != HAL_OK) 
		return 1;
	return 0;
}

/**
 * Reads one channel.
 * @author Miguel  (5/24/2015)
 * @param channel  The channel to convert or read. Alternatively 
 *                 if a channel was set already leave null.
 * @param val      Pointer to where the return value should be stored.
 * @return uint8_t 
 */
uint8_t MAX11615_ADC_Read(MAX11615* chip, uint8_t channel, uint16_t* val){
	uint8_t result[2] = {0,0};

	uint8_t configurationByte = ( (channel<<1) & 0x0e) | 0x61;
	MAX11615_Configuration(chip, configurationByte);
	// the conversion consists of two bytes per channel
	if(HAL_I2C_Master_Receive(chip->wireIface, chip->devAddress, &result[0], 2, 10) != HAL_OK){
		return 1;
	}
	uint16_t value = 0;
	// cast to uint16_t is necessary to not loose the values by the left shift
	value =  (((uint16_t)result[0] & 0x000f) << 8); // MSB is returned first
	value += ((uint16_t)result[1] & 0x00ff); // read LSB
	*val = value;
	return 0;
}

/**
 * Reads all channels conversion into a buffer/array.
 * 
 * @author Miguel (5/24/2015)
 * 
 * @param buffer an array where the channel read values are put.
 */
uint8_t MAX11615_Scan(MAX11615* chip, uint16_t* buffer){
	uint8_t ret = 0;
	uint8_t configurationByte = 0xf0;
	ret += MAX11615_Configuration(chip, configurationByte);
	// 2 bytes per channel. There are 8 channels
	for(uint8_t i = 0;i<8;i++){
		ret += MAX11615_ADC_Read(chip, i, buffer+i);
	}
	return ret;
}

solo borrar la linea main, muy facil.
El

#include <MAX11615.h>

podría quedar asi

#ifndef MAX11615_H_
#define MAX11615_H_

/**
  * @note 		tested using STM32F373
  */


/** @see Datasheet p.19 Table 6
  */
#define MAX11615_REF_VDD      0x00
#define MAX11615_REF_EXTERNAL 0x02
#define MAX11615_REF_INTERNAL 0x04
#define MAX11615_ANANLOG_IN   0x00
#define MAX11615_REF_OUT      0x02
#define MAX11615_INT_REF_ON   0x01

typedef struct {
	uint16_t devAddress;
	I2C_HandleTypeDef *wireIface;
} MAX11615;

MAX11615 new_MAX11615              (void);

uint8_t MAX11615_Write8            (MAX11615*, uint8_t, uint8_t);
uint8_t MAX11615_Read8             (MAX11615*, uint8_t, uint8_t*);
uint8_t MAX11615_Init              (MAX11615*, I2C_HandleTypeDef*, uint16_t, uint8_t);
uint8_t MAX11615_Setup             (MAX11615*, uint8_t);
uint8_t MAX11615_Configuration 	   (MAX11615*, uint8_t);
uint8_t MAX11615_ADC_Read          (MAX11615*, uint8_t, uint16_t*);
uint8_t MAX11615_Scan              (MAX11615*, uint16_t*);

#endif

Eso a grandes rasgos si no funciona le debe faltar muy poco.

¡Muy buena idea @surbyte!
Yo vi la librería pero todavía no me da para arriesgarme a modificarla, así que cerré el pico. :grin:

Gracias Gatul y Surbyte por sus respuestas.

Gatul, lo que intentaba hacer era un escaneo de todas las entradas y obtener valores solamente en A0 donde conecté los 3.3v y A7 que tiene el kty81.

Surbyte, muchas gracias. La verdad si la había visto pero aun me falta agarrar destreza por lo que no supe como trabajarla. Tomaré tus códigos y los implementaré a ver que tal me va y vuelvo para comentar los resultados!

He descargado las librerías y pegado el código que modificaste en los respectivos archivos. Las instalé y traté de correr tu programa pero me saltan errores al compilar y tengo una duda con eso.

En esta parte del código:

MAX11615_Init(&adcDriver_1, &hi2c1, ADDRESS_MAX11615, 4+2+1);

El &hi2c1 me dice que no está declarado, leyendo la librería veo que esto hace referencia a I2C_HandleTypeDef* wireIface. Creo que es algo específico del SMT32. No sé que debería ir en su lugar para el Atmega2560.

Tampoco entiendo la suma de los números al final, entiendo que habla del Aref pero la tabla es como sigue:

Que implica el 4+2+1 en este caso?

Por otro lado, lo que había hecho con la librería Wire como lo ven? Estaba bien encaminado?

Errores seguramente ocurran porque solo le di un enfoque superficial y hay que trabajarlo mas.

Luego lo miro con mas detalle y pongo mi modificación acá, mas allá que no puedo probarlo.
Te envío privado.

Ok surbyte, estaré atento a tu ayuda. He intentado varias cosas y aún sin éxito.

Ya logré obtener lecturas del Max11616 con la librería Wire. Aparentemente era el chip defectuoso. Probé con uno nuevo y funcionó.

#include <Wire.h>        //libreria para activar I2C comunicación con RTC
char c;

void setup() {

Serial1.begin(115200);// Comunicacion RS485
Wire.begin();        // join i2c bus (address optional for master)
delay(100);
pinMode(38,OUTPUT);
digitalWrite(38,HIGH);

Wire.beginTransmission(53);        //Slave addres DEC (0110101)
Wire.write(0xDA);             //Setup byte
Wire.write(0X21);             //Configuration byte 
Wire.endTransmission();      
delay(50);
}

void loop() {
c = ' ';
Wire.requestFrom(53, 2);         // request 6 bytes from slave device #53
 while (Wire.available()) {   
   c = Wire.read();          // receive a byte as character
   Serial1.print(c);              // print the character
}
Wire.endTransmission(); 
delay(3000);
}

Lo hago individualmente, debo seguir trabajando un poco para el modo SCAN pero al menos ya obtengo algo.

La respuesta que obtengo al conectar 3.3v a A0 es 0000 FD00. De acuerdo al datasheet, La respuesta son 2 bytes (en esta caso FD00) donde los 4 MSB son 1 (F) y luego viene el dato. Al pasar D00 a decimal obtengo 3328. Una regla de 3 con el VRef interno (4,096) y la resolucion (4096) obtengo el valor de 3.32V.

Ahora bien, yo debería tener una resolución de 4,096/4096 = 0.001V pero al bajar 2v comienzo a perder exactitud, en aproximadamente (10mv) y al bajar aun más el rango de error se hace mayor. Mi idea era poder medir sensores que entregan valores en los rangos de 10mV hasta 2v aprox. Debería poder, podría ser problema de ruido?

Adjunto algunas imágenes de como esta hecha la tarjeta. Es de 2 capas, planos de tierra en top y bottom layer. Capacitor de desacople.

En la imagen he desactivado los planos a tierra para poder detallar de mejor manera las conexiones.