Low Cost PCB's Low Cost Components

Author Topic: MLX90161 IR Thermometer I2C problems  (Read 506 times)

0 Members and 1 Guest are viewing this topic.

Offline OliverK

  • Contributor
  • Posts: 19
  • Country: nl
  • student electrical engineering
MLX90161 IR Thermometer I2C problems
« on: June 10, 2017, 05:41:30 AM »
Code: [Select]
With a samd 21 i want to read the object temperture of an mlx90616 thermometer. In the datasheet i found that the slave adress is 0x00 but if i google about the mlx90161 i find that the slave adress is 0x5A (even in the arudino IDE), doest anybody know why they are diffent? The RAM adress (where the object temp is begin written to) of the MLX90616 is 0x07. In the datasheet i found how i needed to read the memory : Start bit : slave adress + W : A (from slave): Write byte (RAM memory) : A (from slave) : Start repeat slave adress + R: Upper byte : A (from Master) : Lowerbite (ack master) : PEC : A/N : stop bit

I need to keep doing this sequeal to read out the object temp (i want to do it every sencond for as long as uc is powerd), and it would be awsome if i could print the value in the seriel monitor with uart

I how do i set the clock frequentie to 100kHz (MLX90616 works betweens 10 and 100kHz)

I want to know if its also possible to stop the I2C read after the lower byte is send instead of after the PEC?

I tryied using ASF but i dont really understand it? Cant figure out how i need to rewrite the code to make it fit for my project.
This was the example code for asf i2c : [http://www.atmel.com/Images/Atmel-42631-SAM-D21-SERCOM-I2C-Configuration_ApplicationNote_AT11628.pdf][/url]

Could anybody help me writing this code (would like to do it without asf)?
« Last Edit: June 10, 2017, 06:04:14 AM by OliverK »
 

Offline OliverK

  • Contributor
  • Posts: 19
  • Country: nl
  • student electrical engineering
Re: MLX90161 IR Thermometer I2C problems
« Reply #1 on: June 10, 2017, 05:47:28 AM »
sorry forgot but ive already withen this code, is this any good?

Code: [Select]
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "samd21.h"
#include "hal_gpio.h"
#include "component/sercom.h"

#define I2C_ADDRESS           0x00
#define RAM_ADDRESS   0x07

#define I2C_SERCOM            SERCOM2
#define I2C_SERCOM_PMUX       PORT_PMUX_PMUXE_D_Val
#define I2C_SERCOM_GCLK_ID    SERCOM2_GCLK_ID_CORE
#define I2C_SERCOM_CLK_GEN    0
#define I2C_SERCOM_APBCMASK   PM_APBCMASK_SERCOM2


#define T_RISE                215e-9 // Depends on the board, actually

enum
{
I2C_TRANSFER_WRITE = 0,
I2C_TRANSFER_READ  = 1,
};

enum
{
I2C_PINS_SDA = (1 << 0),
I2C_PINS_SCL = (1 << 1),
};

//-----------------------------------------------------------------------------
static void sys_init(void)  // enable 8Mhz OSC, no prescaler
{
  SYSCTRL->OSC8M.bit.PRESC = 0;
}

//-----------------------------------------------------------------------------

int i2c_init(int freq)
{
int baud = ((float)F_CPU / freq - (float)F_CPU * T_RISE - 10.0) / 2.0;

if (baud < 0)
baud = 0;
else if (baud > 255)
baud = 255;

freq = (float)F_CPU / (2.0 * (5.0 + baud) + (float)F_CPU * T_RISE);

PM->APBCMASK.reg |= I2C_SERCOM_APBCMASK;

GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(I2C_SERCOM_GCLK_ID) |
GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(I2C_SERCOM_CLK_GEN);

I2C_SERCOM->I2CM.CTRLA.reg = SERCOM_I2CM_CTRLA_SWRST;
while (I2C_SERCOM->I2CM.CTRLA.reg & SERCOM_I2CM_CTRLA_SWRST);

I2C_SERCOM->I2CM.CTRLB.reg = SERCOM_I2CM_CTRLB_SMEN;
while (I2C_SERCOM->I2CM.SYNCBUSY.reg);

I2C_SERCOM->I2CM.BAUD.reg = SERCOM_I2CM_BAUD_BAUD(baud);
while (I2C_SERCOM->I2CM.SYNCBUSY.reg);

I2C_SERCOM->I2CM.CTRLA.reg = SERCOM_I2CM_CTRLA_ENABLE |
SERCOM_I2CM_CTRLA_MODE_I2C_MASTER |
SERCOM_I2CM_CTRLA_SDAHOLD(3);
while (I2C_SERCOM->I2CM.SYNCBUSY.reg);

I2C_SERCOM->I2CM.STATUS.reg |= SERCOM_I2CM_STATUS_BUSSTATE(1);

return freq;
}

//-----------------------------------------------------------------------------
bool i2c_read(uint8_t *data, int size)
{
// Start + Slave_adress + write (ten ack from slave)
// master send RAM adress to read from ( ten ack from slave)
// repeted start +read bit (ack slave)
// read slave lowebit from slave (ack master)
// read save upperbit  slave (ack master)
// read pec form slave (ack master)
// stop

I2C_SERCOM->I2CM.ADDR.reg = I2C_ADDRESS | I2C_TRANSFER_WRITE; // I2C adress = 0x00 eni2c wirte = 0x07

while (0 == (I2C_SERCOM->I2CM.INTFLAG.reg & SERCOM_I2CM_INTFLAG_MB));

if (I2C_SERCOM->I2CM.STATUS.reg & SERCOM_I2CM_STATUS_RXNACK)
{
I2C_SERCOM->I2CM.CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);
//dbg_log("I2C: RXNACK during write (address)\r\n");
return false;
}

I2C_SERCOM->I2CM.DATA.reg = RAM_ADDRESS;  // send ram adrees byte

while (0 == (I2C_SERCOM->I2CM.INTFLAG.reg & SERCOM_I2CM_INTFLAG_MB));

if (I2C_SERCOM->I2CM.STATUS.reg & SERCOM_I2CM_STATUS_RXNACK)
{
I2C_SERCOM->I2CM.CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);
//dbg_log("I2C: RXNACK during write (data)\r\n");
return false;
}

I2C_SERCOM->I2CM.ADDR.reg = I2C_ADDRESS | I2C_TRANSFER_READ;

while (0 == (I2C_SERCOM->I2CM.INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB));

if (I2C_SERCOM->I2CM.STATUS.reg & SERCOM_I2CM_STATUS_RXNACK)
{
I2C_SERCOM->I2CM.CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);
return false;
}

I2C_SERCOM->I2CM.CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT;

for (int i = 0; i < size-1; i++)  // read lower bite, upper bite and pec
{
data[i] = I2C_SERCOM->I2CM.DATA.reg;
while (0 == (I2C_SERCOM->I2CM.INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB));
}

if (size)
{
I2C_SERCOM->I2CM.CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT;
I2C_SERCOM->I2CM.CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);
data[size-1] = I2C_SERCOM->I2CM.DATA.reg;
}

if ((I2C_SERCOM->I2CM.INTFLAG.reg & SERCOM_I2CM_INTFLAG_MB) ||
(I2C_SERCOM->I2CM.INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB))
{
I2C_SERCOM->I2CM.CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);   // stop bit
}

return true;
}

/*Assigning pin to the alternate peripheral function*/
static inline void pin_set_peripheral_function(uint32_t pinmux)
{
uint8_t port = (uint8_t)((pinmux >> 16)/32);
PORT->Group[port].PINCFG[((pinmux >> 16) - (port*32))].bit.PMUXEN = 1;
PORT->Group[port].PMUX[((pinmux >> 16) - (port*32))/2].reg &= ~(0xF << (4 * ((pinmux >> 16) & 0x01u)));
PORT->Group[port].PMUX[((pinmux >> 16) - (port*32))/2].reg |= (uint8_t)((pinmux & 0x0000FFFF) << (4 * ((pinmux >> 16) & 0x01u)));
}

/* I2C pin initialization */
void i2c_pin_init()
{
/* PA08 and PA09 set into peripheral function D*/
pin_set_peripheral_function(PINMUX_PA08D_SERCOM2_PAD0); // SDA
pin_set_peripheral_function(PINMUX_PA09D_SERCOM2_PAD1); // SCL
}

int main(void)
{

uint16_t value;
uint8_t buf[3];
float temp;

sys_init();

i2c_init(8000000);

i2c_read(buf, 4);

value = ((uint16_t)buf[0] << 8) | buf[1];  // combining the upper and lower byte value into a 16bit value

// convert to temp hex to decimal, devide bij 50 and subsitute 273 (Kelvin to C)

temp = ( (float)value/ (float)50) - (float)273;

while (1)
{
}

return 0;
}
 

Offline kenny

  • Contributor
  • Posts: 5
  • Country: us
Re: MLX90161 IR Thermometer I2C problems
« Reply #2 on: June 13, 2017, 11:05:31 PM »
Do you know how to decode the output stream on the serial port for this device?  i've been looking online and this is the first info i've found related to it.  thanks
 

Offline OliverK

  • Contributor
  • Posts: 19
  • Country: nl
  • student electrical engineering
Re: MLX90161 IR Thermometer I2C problems
« Reply #3 on: June 16, 2017, 12:29:40 AM »
What do u mean with seriele stream from usart? I2C or what?
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf