MQX i2C driver on Kinetis K70. Blocked if device not connected

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

MQX i2C driver on Kinetis K70. Blocked if device not connected

Jump to solution
1,339 Views
arnogir
Senior Contributor II

Hello every body.

I'm using an I2C bus to communicate with a peripheral.

All work corerclty, but I tested when the peripheral is not connected. For my Application I should detect it and signal a problem on this device.

But after test, the write funtion never return:

Bellow is my code, I'm calling DV_Touch_i2cWrite:



uint8_t DV_Touch_iI2cAck(void) {   uint8_t   ReturnValue;   uint32_t  Param;     ReturnValue = ioctl(DV_Touch_I2cComponent, IO_IOCTL_FLUSH_OUTPUT, &Param);   if (Param)   {     /* NACk received, send STOP */     ReturnValue = ioctl(DV_Touch_I2cComponent, IO_IOCTL_I2C_STOP, NULL);   }     return(ReturnValue); }   /****************************************************************************** ** Function name: DV_Touch_iI2cWrite ** Description: Send a sequuence to Writing to the device ** Parameter: Addr of the starting write register ** Parameter: Buffer: data to write ** Parameter: BufferSize: Number of byte to write ** Return value: Number of written Byte; ******************************************************************************/ uint16_t DV_Touch_iI2cWrite(uint8_t Addr, uint8_t * Buffer, uint16_t BufferSize) {   uint16_t  ReturnValue = 0;   uint8_t   Error;   uint32_t  Param;         /* I2C bus address */   Param = DV_Touch_EASY_I2C_ADDR;   Error = ioctl(DV_Touch_I2cComponent, IO_IOCTL_I2C_SET_DESTINATION_ADDRESS, &Param);   if (I2C_OK != Error)   {     return(0);   }   /* Send a START and send I2C bus address */   fwrite(DV_Touch_Buffer, 1, 0, DV_Touch_I2cComponent);     /* Check ack (device exists) */   Error = DV_Touch_iI2cAck();   if (I2C_OK != Error)   {     /* Bad Ack or NACK, then stop stransmission */     return(0);   }   /* Send memory address */   DV_Touch_Buffer[0] = Addr;   do   {     ReturnValue = fwrite(DV_Touch_Buffer, 1, 1, DV_Touch_I2cComponent);   } while (ReturnValue < 1);           i2c   /* Send Data */   ReturnValue = 0;   do   {     ReturnValue += fwrite(&Buffer[ReturnValue], 1, BufferSize - ReturnValue, DV_Touch_I2cComponent);   } while (ReturnValue < BufferSize);     ReturnValue = ioctl(DV_Touch_I2cComponent, IO_IOCTL_FLUSH_OUTPUT, &Param);   if (Param)   {     /* NACk received, send STOP */     ReturnValue = ioctl(DV_Touch_I2cComponent, IO_IOCTL_I2C_STOP, NULL);   }     /* Wait for completion */   Error = fflush(DV_Touch_I2cComponent);   if (I2C_OK != Error)   {     ReturnValue = 0;   }   /* Stop I2C transfer  */   Error = ioctl(DV_Touch_I2cComponent, IO_IOCTL_I2C_STOP, NULL);   if (I2C_OK != Error)   {     ReturnValue = 0;   }

    return(ReturnValue); }

So when device not connected, the write on line 113 return one time with return value set to 0. But the second time, fwrite nev er return, teh task is in pause.

It is strange the Ack check not detect the problem because in my case, Ack is not done by device.

Is any body have an Idea of where come from my problem?

Thank

Note: MQX 4.1

0 Kudos
1 Solution
1,015 Views
isaacavila
NXP Employee
NXP Employee

Hello Arnaud,

I made a quick review on your code, when you use IO_IOCTL_FLUSH_OUTPUT command to validate if ACK is received, if not, you stop I2C driver and return NO_ERROR, so, in function  DV_Touch_iI2cAck, it does not matter if ACK was or not received, you always return NO_ERROR, and, in DV_Touch_iI2cWrite, you considerar that slave is not connected when you return an ERROR code (line 93), so i think you should modify this function.

uint8_t DV_Touch_iI2cAck(void)  

{

  uint8_t   ReturnValue; 

  uint32_t  Param; 

  ReturnValue = ioctl(DV_Touch_I2cComponent, IO_IOCTL_FLUSH_OUTPUT, &Param); 

  if (Param) {

      /* NACk received, send STOP */ 

      ReturnValue = ioctl(DV_Touch_I2cComponent, IO_IOCTL_I2C_STOP, NULL);

      if (ReturnValue == I2C_OK) {

          RreturnValue = ERROR_CODE_I2C_IS_STOPPED;

      }

  }

  return(ReturnValue);

}

This way, when NACK is received and you stop I2C driver, upper layer can know about it and shouldn't try to write/read.

Remember that write/read function could be blocking functions so if you try to write/read when I2C driver is stopped, you will wait to finish an event that never started.

Could you please validate this?

Best Regards,

Isaac

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

Note: If this post answers your question, please click the Correct Answer button. Thank you!

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

View solution in original post

0 Kudos
10 Replies
1,016 Views
isaacavila
NXP Employee
NXP Employee

Hello Arnaud,

I made a quick review on your code, when you use IO_IOCTL_FLUSH_OUTPUT command to validate if ACK is received, if not, you stop I2C driver and return NO_ERROR, so, in function  DV_Touch_iI2cAck, it does not matter if ACK was or not received, you always return NO_ERROR, and, in DV_Touch_iI2cWrite, you considerar that slave is not connected when you return an ERROR code (line 93), so i think you should modify this function.

uint8_t DV_Touch_iI2cAck(void)  

{

  uint8_t   ReturnValue; 

  uint32_t  Param; 

  ReturnValue = ioctl(DV_Touch_I2cComponent, IO_IOCTL_FLUSH_OUTPUT, &Param); 

  if (Param) {

      /* NACk received, send STOP */ 

      ReturnValue = ioctl(DV_Touch_I2cComponent, IO_IOCTL_I2C_STOP, NULL);

      if (ReturnValue == I2C_OK) {

          RreturnValue = ERROR_CODE_I2C_IS_STOPPED;

      }

  }

  return(ReturnValue);

}

This way, when NACK is received and you stop I2C driver, upper layer can know about it and shouldn't try to write/read.

Remember that write/read function could be blocking functions so if you try to write/read when I2C driver is stopped, you will wait to finish an event that never started.

Could you please validate this?

Best Regards,

Isaac

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

Note: If this post answers your question, please click the Correct Answer button. Thank you!

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

0 Kudos
1,015 Views
arnogir
Senior Contributor II

Hi,

after test, this is Ok for the write.

But I have same problem for the read with code bellow.

I not use ACK, may be I must add it but where?

 

uint8_t  Error;   uint32_t  Param;   /* Set Bus Address, Composed by Device Address and sometime device page Select in case of a memory (MSB memory address) */   Param = (uint32_t) BusAddress;   Error = ioctl(DV_I2c_Component[ChannelID], IO_IOCTL_I2C_SET_DESTINATION_ADDRESS, &Param);   if (I2C_OK != Error)   {     return(0);   }   /* Set read request */   Param = (uint32_t) BufferSize;   Error = ioctl(DV_I2c_Component[ChannelID], IO_IOCTL_I2C_SET_RX_REQUEST, &Param);   if (I2C_OK != Error)   {     return(0);   }   /* Read all data */   ReturnValue = 0;   do   {     ReturnValue += fread(&Buffer[ReturnValue], 1, 4 - ReturnValue, DV_I2c_Component[ChannelID]);   } while (ReturnValue < BufferSize);   /* Stop I2C transfer  */   Error = ioctl(DV_I2c_Component[ChannelID], IO_IOCTL_I2C_STOP, NULL);   if (I2C_OK != Error)   {     ReturnValue = 0;   }   return(ReturnValue);

0 Kudos
1,015 Views
isaacavila
NXP Employee
NXP Employee

Hi Arnaud,

As well as you did it with Transmission, you can validate ACK before reading from I2C bus, this way if no ACK is received you do not need to read data from I2C.

It should be done before do-while loop.

I hope this can help.

Regards,

Isaac

0 Kudos
1,015 Views
arnogir
Senior Contributor II

Ok, I tested the follwoing code by insert it on lin "20"

This working correctly if I2C device is never connected.

But if I start with the device, and I Unplug the I2C device (Touch panel), the DV_I2C_iIc2Ack not return error..:smileyconfused:

Then the next  fread will never return.

/* Check ack (device exists) */

  Error = DV_I2C_iI2cAck(ChannelID);

  if (I2C_OK != Error)

  {

    /* Bad Ack or NACK, then stop transmission */

    return(0);

  }

0 Kudos
1,015 Views
isaacavila
NXP Employee
NXP Employee

Hi Arnaud,

When did you unplug the I2C device?

Best Regards,

Isaac

0 Kudos
1,015 Views
arnogir
Senior Contributor II

In fact I have a touch pannel.

To use It, The touch pannel is link to a provided mini board. THis mini-board allow me to get touch data via I2C format with an easy interface to configure and use the touch pannel.

So this mini board is link to my board with a connector.

So by unpluging the device, I simulate a problem on the Device or on the link cable during the life, in runtime.

0 Kudos
1,015 Views
isaacavila
NXP Employee
NXP Employee

Hi Arnaud,

I got the point, but remember that I2C interface allows user to connect/disconnect devices in the bus at any time and the only way to notice when device is not connected is through ACK reception. This is solved in write operation by calling the ioctl function and request for FLUSH_OUTPUT, which allows user to validate if ACK was received.

For read operation, it is quite different. When you call fread function, this function waits until "N" bytes have been received, if they are not received due disconnection for example, function will not return, in this case, you should try to implement different logc. Could you please tell me which I2C mode you are using? You can use either polling or interrupt mode, by default, both drivers are enabled but user choses which one will be used when calls the fopen function:

I2C mode.jpgI haven't analized I2C driver deeper, but i think that when I2C poll driver is used, you should be able to use fread function and when data is not received returning value should be zero. Using this mode, you can identify when slave is not responding and notify upper layers.

I hope this can help,

Best Regards,

Isaac

0 Kudos
1,014 Views
arnogir
Senior Contributor II

I'm working in Interrupt mode.

If I well understand, I have two way to solve my problem:

1- Use Polling  Mode (fread value will always be Ok If device connected, else return 0)

2- Use a Write function before read

Are they other simple way?

0 Kudos
1,014 Views
isaacavila
NXP Employee
NXP Employee

Hi Arnaud,

I think these are the simplest way to solve your issue.

I hope this can help you.

Best Regards,

Isaac

0 Kudos
1,015 Views
arnogir
Senior Contributor II

Hello,

I understand  what you said and my mistake.

i will test it on next monday and reply here.

Thank you:smileyhappy:

0 Kudos