cancel
Showing results for 
Search instead for 
Did you mean: 

I2c cannot read from sensor

Mant Sandy
Associate III
Posted on August 03, 2017 at 06:49

I am using mlx90614 sensor attached to my nucleo F091RC.

I have a working code with mbed :

double mlx90614::read_temp(uint8_t reg)

{

char cmd[2];

cmd[0] = 0x01;

cmd[1] = 0x00;

// Send start bit

__i2c->write(__addr, cmd, 2);

cmd[0] = reg;

// Write the RAM slave address (register) to read from..

//true argument means a repeated start..

__i2c->write(__addr, cmd, 1, true);

// Now read the response..

__i2c->read( __addr, cmd, 2);

// Reading pec bit.. we just ignore it.. not useful..

int pec = __i2c->read(true);

float temp = (cmd[0] | (cmd[1] << 8));

temp *= 0.02;

temp -= 15;

return temp;

}

But due to some issues with mbed-os, I would like to shift to STM cube HAL API's

Following exactly what I did in mbed, I wrote following function

------------------------

static int read_temp()

{

unsigned char cmd[2];

cmd[0] = 0;

cmd[1] = 1;

HAL_I2C_Master_Transmit(&hi2c2, 0x5A << 1, cmd, 2, 100);

cmd[0] = 0x07;

HAL_I2C_Master_Transmit(&hi2c2, 0x5A << 1, cmd, 1, 100);

HAL_I2C_Master_Receive(&hi2c2, 0x5A << 1, cmd, 2, 100);

float temp = (cmd[0] | (cmd[1] << 8));

temp *= 0.02;

temp -= 15;

return temp;

}

------------------------

I am getting a constant value 0xfff for cmd[0] and cmd[1];

I realized it is due to fact that HAL_I2C_Master_Transmit/Receive API's do not support repeat start.

From the data sheet, follow is the algorithm

https://cloud.githubusercontent.com/assets/5645667/26305867/06c1de46-3f2c-11e7-9dad-d3fda7dce60a.png

Therefore in order to support repeat start, I see that I can use HAL_I2C_Master_Transmit/Receive_IT() API's

I wrote the following code..

------------------------

static int read_temp_IT()

{

unsigned char cmd[2];

cmd[0] = 0;

cmd[1] = 1;

HAL_I2C_Master_Transmit(&hi2c2, 0x5A << 1, cmd, 2, 100);

cmd[0] = 0x07;

HAL_I2C_Master_Transmit_IT(&hi2c2, 0x5A << 1, cmd, 1);

while (HAL_I2C_GetState(&hi2c2) != HAL_I2C_STATE_READY); HAL_I2C_Master_Receive_IT(&hi2c2, 0x5A << 1, cmd, 2);

float temp = (cmd[0] | (cmd[1] << 8));

temp *= 0.02;

temp -= 15;

return temp;

}

------------------------

The while() loop for status check - while (HAL_I2C_GetState(&hi2c2) != HAL_I2C_STATE_READY); - hangs indefinitely.

I took reference of following sample project : STM32Cube_FW_F0_V1.8.0/Projects/STM32F091RC-Nucleo/Examples/I2C/I2C_TwoBoards_AdvComIT/Src/main.c

Could some one point out how to get proper I2c values from mlx90614

https://community.st.com/people/FORTOUNAS.EVANGELOS

‌ I saw your post other day. Please share your thoughts. It will greatly help me.

Note: this post was migrated and contained many threaded conversations, some content may be missing.
15 REPLIES 15
Posted on August 03, 2017 at 12:48

Hello!!

According to the ''From the data sheet, follow is the algorithm'' above figure,

The code is like this.

char cmd=0x07; // RAM access address 07 TOBJ 
char readbuf[3]={0,0,0};// send start bit, send slave address, send write bit, send command
 
HAL_I2C_Master_Sequential_Transmit_IT(&hi2c2, 0x5A << 1, &cmd, 1, I2C_FIRST_FRAME); 
while (HAL_I2C_GetState(&hi2c2) != HAL_I2C_STATE_READY); 
//send rep start bit,send slave address, read three bytes with acks(dont care for now, about pec), and stop bit 
HAL_I2C_Master_Sequential_Receive_IT(&hi2c2, 0x5A << 1, readbuf, 3, I2C_LAST_FRAME); 
while (HAL_I2C_GetState(&hi2c2) != HAL_I2C_STATE_READY);�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

This is from datasheet found

http://cpre.kmutnb.ac.th/esl/learning/mlx90614_infrared_thermometer/MLX90614_Datasheet.pdf

. 0690X00000603RNQAY.jpg 0690X00000607fVQAQ.png

________________________________________________________________________________________

The first mbed code , especialy

// Send start bit ...??

__i2c->write(__addr, cmd, 2);

I don't understand why to send 0x00, 0x01 bytes to device

and after, do a repeated start to write the command by

cmd[0] = reg;

// Write the RAM slave address (register) to read from.. //true argument means a repeated start.. __i2c->write(__addr, cmd, 1, true);

So I couldn't made any code for this.

Posted on August 04, 2017 at 10:37

Thank you for your quick reply.

Before posting this question, I tried using

HAL_I2C_Master_Sequential_Transmit_IT

() api.. but 1. The following line blocks indefinitely

while (HAL_I2C_GetState(&hi2c2) != HAL_I2C_STATE_READY);

2. The examples provided by ST for nucleo F091RC are not using

HAL_I2C_Master_Sequential_Transmit_IT

() API. But for other F0* mcu's they are using this API. Therefore, I was thinking these API's are not supported and tried out HAL_I2C_Master_Transmit_IT() API. The result is same. The while loop to check the I2c state hangs indefinitely. Any idea why is this happenning?

I am assuming internally, this API sends the data to I2c in the following form (start bit - slave address - writebit - command)

HAL_I2C_Master_Sequential_Transmit_IT(&hi2c2, 0x5A << 1, &cmd, 1, I2C_FIRST_FRAME);

Is my understanding correct?

Posted on August 04, 2017 at 11:36

Hello.

'I am assuming internally, this API sends the data to I2c in the following form (start bit - slave address - writebit - command)' Yes it is true but it not sends a stop bit.

HAL_I2C_Master_Transmit_IT(), sends a stop bit after transaction. this is the difference.

Read the the coments the file stm32f0xx_hal_i2c.c You will find all the info about theese fuctions Check the pullup resistors check the voltage of sensor, is 3.3v? Is your device's address the default 0x5A ? Is your code correct initialised with I2C interrupts enabled? When this function stucks:

while(HAL_I2C_GetState(&hi2c2) != HAL_I2C_STATE_READY);
try to put a breakpoint at I2Cx_IRQHandler, to find the cause of error.

Posted on August 04, 2017 at 11:48

> Check the pullup resistors check the voltage of sensor, is 3.3v?

The pull up resistors and voltage should be fine as I am able to read using mbed code.

> Is your device's address the default 0x5A?

Yes. I used the same code in mbed code. > Is your code correct initialised with I2C interrupts enabled? I generated the code using cubeMX software. I selected I2c2. So, may be it has enabled the interrupts. I am trying to check if the interrupts are enabled or not. I dont see any code to enable I2c interrupts in main.c I am checking at other places.


> try to put a breakpoint at I2Cx_IRQHandler, to find the cause of error.

Sure. I will put a breakpoint..

Posted on August 04, 2017 at 12:31

I see that the HAL_I2C_Master_Sequential_Transmit_IT() enables the interrupt at the end of the function.

I2C_Enable_IRQ(hi2c, I2C_XFER_TX_IT);

So, the interrupt should be enabled.

Posted on August 04, 2017 at 12:47

I placed a breakpoint at I2c2_IRQHandler(). The breakpoint at I2C_IRQHandler is never hit.

:(

Posted on August 04, 2017 at 13:05

Yes it enables it but there must be implemented the IRQ handler for this interrupt  at your stm32f0xx_it.c.

0690X00000607t2QAA.png

But , let's start from the beginning.

I tried In my previous post to translate the scripts to I2c HAL functions, supposed that this solution worked at least  in the past. (i2c and SMBUS have some incompatibilities but at many real cases  some smbus parts work well with IC2 Masters.)

I don?t have this four pins device in my hands .

Generally  is not the correct approximation  to connect an SMBUS device on an I2C port.

The I2C1 port supports smbus in master  mode (provides also hardware support)

With cubeMX you can produce the appropriate code.

Then the function will  have this  form

HAL_SMBUS_Master_Transmit_IT(SMBUS_HandleTypeDef *hsmbus, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions)

Read the functionality of XferOptions to send or to read from device..

Posted on August 07, 2017 at 12:58

In the setup I have, the I2c devices are soldered.

:(

So, I cannot use I2C1 for the sensor..

I checked that I2c1 by default supports SMBUS.. but since the mbed code is working, we should be having a way to make it work with ST code as well with I2c2 interface.

I enabled the interrupts from nvic settings.. Still the IRQ handler is never hit..

Breakpoint 1, read_temp_IT () at Src/main.c:68

68    {

(gdb) n

70      cmd[0] = 0;

(gdb)

71      cmd[1] = 1;

(gdb)

72      HAL_I2C_Master_Transmit(&hi2c2, 0x5A << 1, cmd, 2, 100);

(gdb)

73      while (HAL_I2C_GetState(&hi2c2) != HAL_I2C_STATE_READY);

(gdb) b I2C2_IRQ

I2C2_IRQHandler  I2C2_IRQn        

(gdb) b I2C2_IRQHandler

Breakpoint 2 at 0x800300e: file Src/stm32f0xx_it.c, line 79.

(gdb) n

74      cmd[0] = 0x07;

(gdb)

75      HAL_I2C_Master_Sequential_Transmit_IT(&hi2c2, 0x5A << 1, cmd, 1, I2C_FIRST_FRAME);

(gdb)

76      while (HAL_I2C_GetState(&hi2c2) != HAL_I2C_STATE_READY);

(gdb)

The output of the  GDB is here..

I am now referring to mbed-os source code to see what steps they are following.

Posted on August 07, 2017 at 14:05

Hi again!

you wrote 'In the setup I have, the I2c devices are soldered'

Are theese two devices the same?

Every device has a default slave address 0x5a

In case you have two same devices connected, it is obvious(is it for maker?)  that theese devices have different slave addresses reprogrammed in their eeprom.

It is very posible no one have its default address.

For the interrupt issue , it's very strange if you have done the proper initialization.

It would be very helpful to post your .IOC file produced from STM32CubeMX and/or some schematic.