I2C communication issue

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

I2C communication issue

Jump to solution
1,718 Views
MikeCalm
Contributor II

Hi All,

 

I have the issue with I2C communication between QN9090 and temperature sensor TM116.

This is my first attempt using SDK for I2C, and I am not sure if everything is right.

There is no example reading from slave device, and not even one topic here.

Following existing examples, here is what I have:

 

I2C_MasterGetDefaultConfig(&masterConfig);

/* Change the default baudrate configuration */
masterConfig.baudRate_Bps = I2C_BAUDRATE;

/* Initialize the I2C master peripheral */
I2C_MasterInit(EXAMPLE_I2C_MASTER, &masterConfig, I2C_MASTER_CLOCK_FREQUENCY);

/* prepare for reading
 * 1. write register 2. read 2 bytes
 */
I2C_MasterStart(EXAMPLE_I2C_MASTER, I2C_SLAVE_ADDR_7BIT, kI2C_Write);
g_master_buff[0] = 0x00U;

reVal = I2C_MasterWriteBlocking(EXAMPLE_I2C_MASTER, g_master_buff, 1, kI2C_TransferDefaultFlag);
if (reVal != kStatus_Success)
{
	PRINTF(printf("Write Error! %d\n", reVal));
}
else
{
	PRINTF("Write Success\n");
}
I2C_MasterStop(EXAMPLE_I2C_MASTER);

Above works fine. Writing returns no error.

Reading part never worked:

I2C_MasterStart(EXAMPLE_I2C_MASTER, I2C_SLAVE_ADDR_7BIT, kI2C_Read);
int32_t i2c_status = I2C_MasterReadBlocking(I2C_SLAVE_ADDR_7BIT, g_slave_buff, 2, kI2C_TransferDefaultFlag);
if (i2c_status != kStatus_Success)
{
	PRINTF(printf("Read Error! %d\n", i2c_status));
}
else
{
	PRINTF("Read Success\n");
}

I have i2c_status error 2605 - kStatus_I2C_ArbitrationLost error.

I am sure there might be something missing. Not sure if writing works fine, despite no error.

I will have it checked with oscilloscope in few day.

 

Can anyone point possible solution?

Thanks,

Mike

Labels (1)
  • QN

0 Kudos
1 Solution
1,703 Views
MikeCalm
Contributor II

Hi All,

This not correct way how to read back data from slave.

That is a bit disappointing there is no simple example in SDK for something like:

Read 2 bytes from register 0x01 from Slave 0x78.

However, it took me a while figuring out what to do and everything works fine.

Cheers

View solution in original post

0 Kudos
4 Replies
1,704 Views
MikeCalm
Contributor II

Hi All,

This not correct way how to read back data from slave.

That is a bit disappointing there is no simple example in SDK for something like:

Read 2 bytes from register 0x01 from Slave 0x78.

However, it took me a while figuring out what to do and everything works fine.

Cheers

0 Kudos
824 Views
jrevans
Contributor III

I know it's been a while, but any chance that you could share your code, since I also noticed that there isn't a simple example that uses the API (fsl_i2c) to do something like:

    Read 2 bytes from register 0x01 from Slave 0x78.

I'm trying to read the LM75 sensor on the OM40001  LPCXpresso804 board, and although I have the sample "I2C_temperature" project working, that project doesn't use the fsl_i2c SDK API calls.

When I try to implement it using the I2C_MasterWriteBlocking() and I2C_MasterReadBlocking() calls, the I2C_MasterReadBlocking() call is failing.  

Instead of getting the master_state value of I2C_STAT_MSTCODE_RXREADY (value = 1) so it would read out the data, it is instead seeing a value of 2, which makes the code fall to the default: case and sets err = kStatus_I2C_UnexpectedState;

Does anyone have a simple I2C code example that just reads two bytes from a slave SPI device using the I2C_MasterWriteBlocking() and I2C_MasterReadBlocking() calls from the fsl_i2c SDK API?

The lpcxpresso804_lpc_i2c_polling sample project is too generic.  Why wouldn't NXP create the sample project to talk to the I2C device (the LM75) that is on the actual board that the project is named for and supposedly a project for?

 

0 Kudos
807 Views
jrevans
Contributor III

Of course, ten minutes after posting this, I figured out how to use the code from the lpcxpresso804_lpc_i2c_polling sample project and modify it to correctly read the temperature from the on-board LM75 sensor....   

 

I'll clean up my code and post it here in a little while, to hopefully help anyone else who is looking to do this.

0 Kudos
734 Views
jrevans
Contributor III

Okay, here is the code that I used to be able to use the SDK's I2C library to communicate with the LM75 on the OM40001 LPCXpresso804 development board.

Create a project and use the ConfigTools to enable the Peripheral Signals to include I2C0.  Then setup PIO0_7 with pin identifier I2C_SDA, and PIO0_14 with pin identifier I2C_SCL.

First make sure you include the i2c header file.  When you make you project and select the pins for I2C, it may add this already:

#include "fsl_i2c.h"  // For I2C calls

 

After the includes, add this glob:

#define I2C_MASTER_BASE    			(I2C0_BASE)
#define I2C_MASTER_CLOCK_FREQUENCY	(12000000)
#define I2C_MASTER 					((I2C_Type *)I2C_MASTER_BASE)
#define I2C_BAUDRATE               	100000U
#define I2C_DATA_LENGTH				16U  // Used to set the size of the buffers

i2c_master_config_t masterConfig;
uint8_t g_master_txBuff[I2C_DATA_LENGTH];
uint8_t g_master_rxBuff[I2C_DATA_LENGTH];

// The OM40001 documentation says: NXP LM75BDP temperature sensor
// JP4 and JP23 need to be installed, which they are by default
// Temperature sensor (LM75, circuit ref U7)
// The I2C address is 0x1001100.
// From I2C_temperature_main.c
//#define LM75_ADDR			(0x90 >> 1) // = 0x48 72d ('H')
#define LM75_ADDR			0x48  // Should be the same as (0x90 >> 1)
#define LM75_CONFIG			0x01
#define LM75_TEMPERATURE	0x00

int32_t init_LM75(void);
uint32_t read_LM75(void);

 

In main() after BOARD_InitBootPeripherals() you want to add this glob:

    BOARD_InitI2CPins();  // Enable the I2C pins
    CLOCK_Select(kI2C0_Clk_From_MainClk);  // Select the main clock as the source clock for I2C0
    I2C_MasterGetDefaultConfig(&masterConfig);  // Load the default values into masterConfig
    masterConfig.baudRate_Bps = I2C_BAUDRATE;  // Change the default baudrate in the configuration to our value
    I2C_MasterInit(I2C_MASTER, &masterConfig, I2C_MASTER_CLOCK_FREQUENCY);  // Initialize the I2C master peripheral using our masterConfig
    init_LM75();  // Initialize the sensor

 

I created two functions related to the LM75.  init_LM75() and read_LM75().  Here they are:

int32_t init_LM75(void)
{
    status_t retVal = kStatus_Fail;

    // The write only process is done by:
    //  I2C_MasterStart()
    //  I2C_MasterWriteBlocking() with kI2C_TransferDefaultFlag flag
    //  I2C_MasterStop()
	if (kStatus_Success == I2C_MasterStart(I2C_MASTER, LM75_ADDR, kI2C_Write))
    {
    	g_master_txBuff[0] = LM75_CONFIG;
    	g_master_txBuff[1] = 0x00;  // Set the default operating mode

        retVal = I2C_MasterWriteBlocking(I2C_MASTER, g_master_txBuff, 2, kI2C_TransferDefaultFlag);

        if (retVal != kStatus_Success)
        {
            return -1;
        }

        retVal = I2C_MasterStop(I2C_MASTER);

        if (retVal != kStatus_Success)
        {
            return -1;
        }

        retVal = kStatus_Success;
    }

	return(retVal);
}


uint32_t read_LM75(void)
{
    status_t retVal = kStatus_Fail;
    uint8_t deviceAddress = LM75_TEMPERATURE;

    memset(g_master_rxBuff, 0, I2C_DATA_LENGTH);

    // The combination write/read is done by:
    //  I2C_MasterStart()
    //  I2C_MasterWriteBlocking() with kI2C_TransferNoStopFlag flag
    //  I2C_MasterRepeatedStart()
    //  I2C_MasterReadBlocking() with kI2C_TransferDefaultFlag flag
    //  I2C_MasterStop()
	if (kStatus_Success == I2C_MasterStart(I2C_MASTER, LM75_ADDR, kI2C_Write))
	{
		// We're writing one byte, the register value of 0x00 to immediately read temperature data from.
		// We set the flag to kI2C_TransferNoStopFlag since we're doing a read right after this.
		retVal = I2C_MasterWriteBlocking(I2C_MASTER, &deviceAddress, 1, kI2C_TransferNoStopFlag);

		if (retVal != kStatus_Success)
		{
			return -1;
		}

		retVal = I2C_MasterRepeatedStart(I2C_MASTER, LM75_ADDR, kI2C_Read);

		if (retVal != kStatus_Success)
		{
			return -1;
		}

		// Now we're reading two bytes of the temperature data from the slave device, into g_master_rxBuff
		retVal = I2C_MasterReadBlocking(I2C_MASTER, g_master_rxBuff, 2, kI2C_TransferDefaultFlag);

		if (retVal != kStatus_Success)
		{
			return -1;
		}

		retVal = I2C_MasterStop(I2C_MASTER);

		if (retVal != kStatus_Success)
		{
			return -1;
		}
	}

	uint32_t temperatureValue = 0;

	// NXP's LM75B data sheet shows the format of the data https://www.nxp.com/docs/en/data-sheet/LM75B.pdf
	if ((g_master_rxBuff[0] & 0x80) > 0) {  // This is the sign bit
		temperatureValue = 0xffffff00;
	}

	temperatureValue |= (g_master_rxBuff[0] & 0x7f) << 1;
	temperatureValue |= ((g_master_rxBuff[1] >> 7) & 1);

	// Since we're not using the half degrees, just shift right by one and lose that piece of data
	temperatureValue = temperatureValue >> 1;

	return(temperatureValue);
}

 

The code we added in main() already called init_LM75() and you just need to call read_LM75() when you want to read the temperature.  (You may not need to call init_LM75() as the sensor seems to startup in the correct mode to begin with.)  My demo program just calls read_LM75() from a one second interval SysTick_Handler() and uses this code to display the value:

	int32_t temperatureReading = read_LM75();
	char console_string[128];

	// Bit 16 is the sign (1 is negative, 0 is positive) after the temperature conversion
	if (temperatureReading & 0x10000) {
		snprintf(console_string, 128, "Current temperature is -%d degrees C.\r\n", (temperatureReading & 0xFFFF));
	}
	else {
		uint16_t temperature_farenheit = (temperatureReading * 9 / 5) + 32;  // Create the farenheit temperature value for positive temperatures
		snprintf(console_string, 128, "Current temperature is %d degrees C and %d degrees F.\r\n", temperatureReading, temperature_farenheit);
	}

	PutTerminalString(USART0, (unsigned char *)console_string);

 

I'm not doing much in the way of checking return values, but you should get the idea.  The PutTerminalString() function above is just a function that I'm using to send the string out on the USART0 port that I'm using.  Replace it with whatever diagnostic print that you're using.

Enjoy!

0 Kudos