HLP: I2C communication in MCF52259 with MQX 3.5 - Fails when context switch happens

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

HLP: I2C communication in MCF52259 with MQX 3.5 - Fails when context switch happens

3,075 Views
tkvenki
Contributor III

I2C communication in MCF52259 with MQX3.5
------------------------------------------

I2C Master - MCF52259
I2C Slave  - Hitachi H83687
Baudrate  - 178571

Initially the communication between I2c Master and Slave has been established. During communication, if the master encounters continuous task switching,the synchronization between the I2C master and Slave is lost.
For instance, say, if the actual number of bytes to be read is 32 and if the communication is lost while transfering the 16th byte, slave is made to free the bus after some timeout. In I2C master also, after some timeout the MCF52259 controller comes out of I2C communication.

But while doing the Flush operation (Using IO_IOCTL_FLUSH_OUTPUT) in the successive I2C communication attempt, the Master  is getting into the foll. while loop in the file i2c_pol_mcf52xx.c and is not coming out.

The exact line in this file is (while ((0 == (tmp & MCF52XX_I2C_I2SR_ICF)) || (io_info_ptr->ONTHEWAY) || ((i2c_ptr->I2CR & MCF52XX_I2C_I2CR_MTX) && (io_info_ptr->TX_IN != io_info_ptr->TX_OUT))); )


Please clarify what the pointers and macros in the above while statement denotes and why the while condition is not getting satisfied.

Tags (1)
0 Kudos
Reply
11 Replies

1,663 Views
PetrM
Senior Contributor I

Hello,

 

I'm not sure about this I2C transfer corruption caused by task switching. I guess it will be something else.

Do you use IO_IOCTL_I2C_SET_RX_REQUEST command before master starts to read data? It is important for driver to know the length of the transfer to issue NACK correctly at the end.

Regarding that flush while, it basically says wait until all bytes are transferred and current byte transfer is finished. It's complicated because it has to work in both polled and interrupt modes.

If you are able to detect that communication is lost at the master, you should issue STOP command immediately.

Can you provide more information about what mode you use, what are the values in the flush while and maybe piece of code of the master?

 

PetrM

 

0 Kudos
Reply

1,663 Views
vijay111111
Contributor I

Hi PetrM,
   Thanks for your reply.

Find the algorithm below.....

1. Set the destination address using IO_IOCTL_I2C_SET_DESTINATION_ADDRESS command
2. Initiate start and send I2C bus address using fwrite(&mem,1,0,fd)
3. Check for the acknowledgement using (I2C_OK == ioctl (fd, IO_IOCTL_FLUSH_OUTPUT, &param)).
4. If ACK is High set the Dev_Flag and Give IO_IOCTL_FLUSH_OUTPUT and issue the STOP condition using IO_IOCTL_I2C_STOP.
5. Else ACK is LOW clear the Dev_flag and issue the STOP condition.

If the Dev_Flag is high proceed I2C read operation
else again check for the devive existance.

 

I2C Read
-------------

1. Set the Destination address
2. Get the destination address
3. Set the master to Master Receive mode using IO_IOCTL_I2C_SET_RX_REQUEST command, param is number of bytes to be read
4. Read operation

    do
    {
      result = fread (ReceiveBuffer + result , 1, tempNoOfBytesToBeRead , fd);
      Count++;
      if(Count == 10)
      {
       Count = 0;
       if(result == 0) /*If there is no valid reply from the slave device */
       {
           Dev_flag = 0;
           printf("\n %d %d \n",Count,result);
           break;
       }
      }
      printf("\n result %d \n",result);
      tempNoOfBytesToBeRead = tempNoOfBytesToBeRead - result;
     } while (tempNoOfBytesToBeRead != 0);

5. Check whether all the byte transfer are completed by IO_IOCTL_FLUSH_OUTPUT command
6. Send a STOP condition.

Note: Our system is working properly untill we get the proper response from the slave device.Once if the communication is lost between the master and slave,in slave the I2C bus is getting released (HIGH),but in MCF if we send IO_IOCTL_FLUSH_OUTPUT command it is getting hanged in the previous byte transfer while loop or if we send directly STOP command,it is getting hanged in the I2C busy while loop (We checked the bus status using DPO,it is Free)

 

Thanks

Vijay

0 Kudos
Reply

1,663 Views
PetrM
Senior Contributor I

I can see one problem in your partial reads - the result is overwritten in the beginning of each loop, so the data are read into the wrong position in the ReceiveBuffer... It should look like this:

 

 

 tempNoOfBytesToBeRead = 16;

 ioctl (fd, IO_IOCTL_I2C_SET_RX_REQUEST, &tempNoOfBytesToBeRead);

 result = 0;

 do
    {
      result += fread (ReceiveBuffer + result , 1, tempNoOfBytesToBeRead - result , fd);
      Count++;
      if(Count == 10)
      {
       Count = 0;
       if(result == 0) /*If there is no valid reply from the slave device */
       {
           Dev_flag = 0;
           printf("\n %d %d \n",Count,result);
           break;
       }
      }
      printf("\n result %d \n",result);
     } while (tempNoOfBytesToBeRead != result);

 

 

Maybe this helps,

PetrM

0 Kudos
Reply

1,663 Views
vijay111111
Contributor I

Thanks PetrM. The piece of code which i have posted is just a pseudo code. But in the actual code the corrections whatever u have mentioned is there. Still we are facing the same problem which we mentioned in our previous posts.  

0 Kudos
Reply

1,663 Views
PetrM
Senior Contributor I

So, are you using polled or interrupt mode? Can you debug and tell me which one of the conditions in the while loop above is not satisfied? I still seems to me that the bus is being held down by someone and that causes the infinite waiting.

 

PetrM

 

0 Kudos
Reply

1,663 Views
vijay111111
Contributor I

We are using polled mode (As in interrupt mode I2C communication is not working for High Baud rates and High priority (Priority less than 4)).

In the while loops all the conditions are not getting satisfied. We have tried some timeouts in the while loop.But still it is not working.

0 Kudos
Reply

1,663 Views
PetrM
Senior Contributor I

Well, this could happen during second transmission when the first one is not finished properly. The driver is not in default state.

I suggest you to start with some simple, basic scenario, read or write 1 byte and watch the process on oscilloscope if everything runs correctly till the bus release at the end. Then add more bytes...

Anyway, does the MQX I2C example work well? Because it's like a test of everything the driver offers.

 

PetrM

 

0 Kudos
Reply

1,663 Views
vijay111111
Contributor I

When we are running the I2C driver alone,it is happening properly and we are not facing any problems. But I2C with other tasks (mainly when the task switch happens frequently) only we are facing this issue. The problem here is the synchronization between the Hitachi and the MCF processor is missing and after that we are not able to restart the I2C device even if the bus is freed by the Slave (Hitachi)

0 Kudos
Reply

1,663 Views
vijay111111
Contributor I

One more problem what we have observed is, in Interrupt mode I2C communication is not happening for Higher Baudrates (>400K) and Higher Priorities (<4). So now we are working in Polled Mode

0 Kudos
Reply

1,663 Views
JKadin
Contributor II

Did you ever solve this?

I am working on a similar problem using the I2c Example and a 24AA02 EEPROM.

I found that after the desired number of reads occur, the bus becomes free but the MCF52259 I2C port reports busy always, so flush and stop go into endless loops.

I found that if you disable/enable the port at the end of reading the correct number of bytes that keeps the flush from hanging up the system.

I do not feel that disable/enable is the best way to handle this, but if it works...

 

   result = fread (buffer, 1, n, fd);
   if (result == n)
   {
      printf ("OK\n");
   } else {
      printf ("ERROR\n");
   }

   if (result == n)  //added by jkadin
   {
       /* Stop I2C transfer - initiate EEPROM write cycle */
       /* Stop did not work used port disable */
       printf ("  Disable/Enable port ... ");
       if (I2C_OK == ioctl (fd, IO_IOCTL_I2C_DISABLE_DEVICE, NULL))
       {
           printf ("OK\n");
       } else {
           printf ("ERROR\n");
       }
       if (I2C_OK == ioctl (fd, IO_IOCTL_I2C_ENABLE_DEVICE, NULL))
       {
           printf ("OK\n");
       } else {
           printf ("ERROR\n");
       }
   }

0 Kudos
Reply

1,663 Views
Tonkabot
Contributor III

I have exactly the same problem on my MCF52254 hardware when trying to talk to a MMA7455 Accelerometer using the I2C MQX drivers.      I used your 'fix' of disableing and re-enabling the I2C port, and it 'fixes' the problem.

However, on my bus monitor I can see that there never is a 'STOP' after my read of one byte.

 

What it looks like is happening is that the Coldfire hardware uses the MSTA bit transistion to 0 to generate the 'STOP' condition.

 

But once that has happened, the hardware is now in SLAVE mode.   and trying to send the FLUSH or STOP at that point hangs in deep in the driver (in _mcf52xx_i2c_polled_ioctl, to be precise) because of some check it wants to see (the STOP wants to see the IBB busy bit, the flush wants to see a combination of things, including that same bit)

 

So somewhere along the way the MSTA bit got cleared (maybe when the repeated START got sent).   and it seems the only way to

generate the STOP is to clear it (but it is clear already!).

 

There is also a not on the data sheet that when the I2DR register is read, it releases the busy bit so the STOP can be sent.

 

Not sure where the problem is or the fix.

0 Kudos
Reply