This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Tiva launchpad I2C only receiving 255 from MLX90614

Other Parts Discussed in Thread: EK-TM4C123GXL

Hi. I am using the tiva launchpad to read the temperature from the MLX90614 using I2c. For some reason I am only getting 255 back no matter what register I read from. The slave address is 0x5A and the register I want to read from is 0x07. I am not sure why it does not work or how to fix it. 

This is the sensor datasheet and it says it needs a repeated start. 

http://www.datasheetlib.com/datasheet/1139830/mlx90614_melexis-microelectronic-systems.html?page=13#datasheet

This is my code. 

#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_gpio.h"
#include "inc/hw_ints.h"
#include "inc/hw_uart.h"
#include "inc/hw_sysctl.h"
#include "inc/hw_i2c.h"
#include "driverlib/fpu.h"
#include "driverlib/systick.h"
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom_map.h"
#include "driverlib/debug.h"
#include "driverlib/interrupt.h"
#include "driverlib/gpio.h"
#include "driverlib/uart.h"
#include "driverlib/rom.h"
#include "driverlib/i2c.h"

#ifdef DEBUG
void__error__(char *pcFilename, unsigned long ulLine) {}
#endif
void i2c_setup(void)
{
	SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
	// Open-Drain operation
	//
	GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_2, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_OD);
	GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_3, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_OD);
	//
	GPIODirModeSet(GPIO_PORTB_BASE, GPIO_PIN_3, GPIO_DIR_MODE_HW);
	GPIODirModeSet(GPIO_PORTB_BASE, GPIO_PIN_2, GPIO_DIR_MODE_HW);
	GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
	GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
	//GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_3);
	GPIOPinConfigure(GPIO_PB2_I2C0SCL);
	GPIOPinConfigure(GPIO_PB3_I2C0SDA);
	I2CMasterEnable(I2C0_MASTER_BASE);
	I2CMasterInitExpClk(I2C0_MASTER_BASE, SysCtlClockGet(), false);
	SysCtlDelay(100);
}
void i2c_send_read(char addre, unsigned long data,unsigned long *receive)
{
	unsigned long err;
	unsigned long temp[2];
	// Write the address first with direction as transmit to write the address for read
	I2CMasterSlaveAddrSet(I2C0_MASTER_BASE,addre,false);
	I2CMasterDataPut(I2C0_MASTER_BASE,data);
	I2CMasterControl(I2C0_MASTER_BASE,I2C_MASTER_CMD_BURST_SEND_START);
	while(I2CMasterBusy(I2C0_MASTER_BASE));
	err = I2CMasterErr(I2C_MASTER_ERR_ADDR_ACK);

	// Repeated Start to receive can be used to get data
	I2CMasterSlaveAddrSet(I2C0_MASTER_BASE,addre,true);
	I2CMasterControl(I2C0_MASTER_BASE,I2C_MASTER_CMD_BURST_RECEIVE_START);
	while(I2CMasterBusy(I2C0_MASTER_BASE));
	err = I2CMasterErr(I2C_MASTER_ERR_ADDR_ACK);
	temp[0]=I2CMasterDataGet(I2C0_MASTER_BASE);
	I2CMasterControl(I2C0_MASTER_BASE,I2C_MASTER_CMD_BURST_RECEIVE_CONT);
	while(I2CMasterBusy(I2C0_MASTER_BASE));
	temp[1]=I2CMasterDataGet(I2C0_MASTER_BASE);
	I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
	while(I2CMasterBusy(I2C0_MASTER_BASE));
	// convert 10 place to ASCII
	receive[1] = (temp[0]-((temp[0] / 10)*10)) + 0x30;	// Convert 1's place to ASCII
}

int main(void)
{
	// set the control clock  to 8MHZ
	SysCtlClockSet(SYSCTL_SYSDIV_1|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_8MHZ);
	i2c_setup();
	unsigned long tempData=0;
	while(1)
	{
		i2c_send_read(0x5A,0x07,&tempData);
		SysCtlDelay(SysCtlClockGet() / 10 / 3);
	}

}

  • Hello Bethany,

    My best bet would be that the ADDR is getting NACK'ed. Please check the err status variable which is reading back the Status Byte and also check the scope for ADDR being NACK'ed.

    Regards
    Amit
  • Hi Amit,

    I have checked the err variable status and it returns a zero. however when I look on the scope I see the NACK. How do I fix this in order to get ACK?

    regards
    Bethany
  • Hello Bethany,

    I2CMasterErr requires the base address of the I2C Module and not the error type. Also since there is an address NAK, you would need to check if the address is correctly being put out on the bus.

    Regards
    Amit
  • Hi Amit 

    I have changed the I2CMasterErr to have the base address but I'm still getting zero. How do I check if the address is correctly being out on the bus? 

    regards, 

    Bethany

    void i2c_send_read(char addre, unsigned long data,unsigned long *receive)
    {
    	unsigned long err =0;
    	unsigned long temp[2];
    	unsigned long error;
    	// Write the address first with direction as transmit to write the address for read
    	I2CMasterSlaveAddrSet(I2C0_MASTER_BASE,addre,false);
    	I2CMasterDataPut(I2C0_MASTER_BASE,data);
    	I2CMasterControl(I2C0_MASTER_BASE,I2C_MASTER_CMD_BURST_SEND_START);
    	while(I2CMasterBusy(I2C0_MASTER_BASE));
    	err = I2CMasterErr(I2C0_MASTER_BASE);
    	if (err & I2C_MASTER_ERR_ADDR_ACK)
    	{
    		error = 1;
    	}
    	// Repeated Start now with direction as recieve can be used to get data
    	I2CMasterSlaveAddrSet(I2C0_MASTER_BASE,addre,true);
    	I2CMasterControl(I2C0_MASTER_BASE,I2C_MASTER_CMD_BURST_RECEIVE_START);
    	while(I2CMasterBusy(I2C0_MASTER_BASE));
    	err = I2CMasterErr(I2C0_MASTER_BASE);
    		if (err & I2C_MASTER_ERR_ADDR_ACK)
    		{
    			error = 1;
    		}
    	temp[0]=I2CMasterDataGet(I2C0_MASTER_BASE);
    	I2CMasterControl(I2C0_MASTER_BASE,I2C_MASTER_CMD_BURST_RECEIVE_CONT);
    	while(I2CMasterBusy(I2C0_MASTER_BASE));
    	temp[1]=I2CMasterDataGet(I2C0_MASTER_BASE);
    	I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
    	while(I2CMasterBusy(I2C0_MASTER_BASE));
    	// convert 10 place to ASCII
    	receive[1] = (temp[0]-((temp[0] / 10)*10)) + 0x30;	// Convert 1's place to ASCII
    }

  • Hello Bethany,

    The EK-TM4C123GXL has a 16MHz oscillator, However you are using the following line which is incorrect.

    SysCtlClockSet(SYSCTL_SYSDIV_1|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_8MHZ);

    Can you please confirm what is the system clock you intend to use?

    Regards
    Amit
  • I had originally had it as
    SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
    I was looking at other posts that seemed to have the same problem I was having and they said that changing the clock fixed it so I was just trying different clocks to see if it would work.
    regards,
    Bethany
  • Hello Bethany,

    Please keep the clocking as the original for 40MHz system clock to reduce the variables.

    As for the issue here of address NAK do you see 0x5A on the I2C Bus during address phase as expected by the Slave device?

    Also if you replace the following line in your code

    while(I2CMasterBusy(I2C0_MASTER_BASE));
    err = I2CMasterErr(I2C0_MASTER_BASE);
    if (err & I2C_MASTER_ERR_ADDR_ACK)
    {
    error = 1;
    }

    with

    error = 0;
    uint32_t ui32Status = 0;
    while((ui32Status = HWREG(ui32Base + I2C_O_MCS)) & I2C_MCS_BUSY)
    {
    if((ui32Status & I2C_MCS_ADRACK) == I2C_MCS_ADRACK)
    {
    error = 1;
    }
    }

    then does the error flag become 1?

    Regards
    Amit
  • hi
    I changed the clock back to 40Mhz and tried changing the code but the error flag is still 0.

    regards
    Bethany
  • Hello Bethany,

    The current code and Scope snapshot please?

    Regards
    Amit
  • hi
    this is my current code. I do not have access to a scope right now so I can't get a snapshot.
    regards
    Bethany

    /* * main.c */ #include <stdint.h> #include <stdbool.h> #include "inc/hw_types.h" #include "inc/hw_memmap.h" #include "inc/hw_gpio.h" #include "inc/hw_ints.h" #include "inc/hw_uart.h" #include "inc/hw_sysctl.h" #include "inc/hw_i2c.h" #include "driverlib/fpu.h" #include "driverlib/systick.h" #include "driverlib/sysctl.h" #include "driverlib/pin_map.h" #include "driverlib/rom_map.h" #include "driverlib/debug.h" #include "driverlib/interrupt.h" #include "driverlib/gpio.h" #include "driverlib/uart.h" #include "driverlib/rom.h" #include "driverlib/i2c.h" unsigned long tempData=0; #ifdef DEBUG void__error__(char *pcFilename, unsigned long ulLine) {} #endif void i2c_setup(void) { SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); // Set GPIO Pins for Open-Drain operation // GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_2, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_OD); GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_3, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_OD); // Give control to the I2C Module // GPIODirModeSet(GPIO_PORTB_BASE, GPIO_PIN_3, GPIO_DIR_MODE_HW); GPIODirModeSet(GPIO_PORTB_BASE, GPIO_PIN_2, GPIO_DIR_MODE_HW); GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2); // special I2CSCL treatment for M4F devices GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3); GPIOPinConfigure(GPIO_PB2_I2C0SCL); GPIOPinConfigure(GPIO_PB3_I2C0SDA); I2CMasterEnable(I2C0_MASTER_BASE); I2CMasterInitExpClk(I2C0_MASTER_BASE, SysCtlClockGet(), false); SysCtlDelay(100); } void i2c_send_read(char addre, unsigned long data,unsigned long *receive) { unsigned long err =0; unsigned long temp[2]; unsigned long error; // Write the address first with direction as transmit to write the address for read I2CMasterSlaveAddrSet(I2C0_MASTER_BASE,addre,false); I2CMasterDataPut(I2C0_MASTER_BASE,data); I2CMasterControl(I2C0_MASTER_BASE,I2C_MASTER_CMD_BURST_SEND_START); error = 0; uint32_t ui32Status = 0; while((ui32Status = HWREG(I2C0_MASTER_BASE + I2C_O_MCS))&I2C_MCS_BUSY) { if((ui32Status & I2C_MCS_ADRACK) == I2C_MCS_ADRACK) { error = 1; } } // Repeated Start now with direction as recieve can be used to get data I2CMasterSlaveAddrSet(I2C0_MASTER_BASE,addre,true); I2CMasterControl(I2C0_MASTER_BASE,I2C_MASTER_CMD_BURST_RECEIVE_START); while(I2CMasterBusy(I2C0_MASTER_BASE)); temp[0]=I2CMasterDataGet(I2C0_MASTER_BASE); I2CMasterControl(I2C0_MASTER_BASE,I2C_MASTER_CMD_BURST_RECEIVE_CONT); while(I2CMasterBusy(I2C0_MASTER_BASE)); temp[1]=I2CMasterDataGet(I2C0_MASTER_BASE); I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH); while(I2CMasterBusy(I2C0_MASTER_BASE)); // convert 10 place to ASCII receive[1] = (temp[0]-((temp[0] / 10)*10)) + 0x30; // Convert 1's place to ASCII } int main(void) { // set the control clock to 16MHZ SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ); i2c_setup(); i2c_send_read(0x5A,0x07,&tempData); SysCtlDelay(SysCtlClockGet() / 10 / 3); }

  • Hello Bethany

    Where is the value of I2C0_MASTER_BASE coming from? I do not see the same in TivaWare 2.1.171

    Also the scope snapshot would be useful.

    Regards
    Amit
  • Hi Amit,
    thank you for your help, I got it working now
    best regards,
    Bethany
  • Hello Bethany,

    What was the issue?

    Regards
    Amit
  • Hi! I'm having the same problem.. How do you fix it?
    Thanks!
  • Hello Leonardo,

    Please use the following application note to see how TM4C129x is accessing the Slave.

    www.ti.com/.../spma073.pdf
  • Bethany Le said:
    I got it working now

    Simply delightful - multiple back/forth - great assistance from Amit - and then Silence!   Simply Dreadful!

    Even the (slightest of care/consideration) would see "such well-aided posters" PAY BACK to the forum by, "Identifying their corrective action!"

    As always - this stands as YET MORE PROOF that posters DO REQUIRE GUIDANCE - as it stands now - this post is essentially of (very) little value...

  • Oddly the early returns in the while loops don't extend down to process the directives lines. In my opinion early return renders only a pause when (I2c_Master_Base) remains true and does not process the directive for the condition.