AnsweredAssumed Answered

MCF52259 "interrupt" I2C driver enhancements

Question asked by gilles buloz on Dec 17, 2011
Latest reply on Jul 2, 2014 by gilles buloz

After using the "interrupt driven" I2C driver (ii2c) intensively on a MCF52259, in master-only mode, I had the following problems :
- the task doing I2C accesses heavily was consuming nearly all CPU time
- the bus sometimes hanged but as no timeout was supported by the driver, this was fatal

After some investigation I discovered that :

 

- the driver was not fully interrupt driven : even if data is received or sent in interrupt mode using internal buffer, this is not the

case when you call IO_IOCTL_FLUSH_OUTPUT ioctl (or fflush()) where polling at full speed is performed; as also does IO_IOCTL_I2C_STOP ioctl. As a result :
    - when you want to receive some data, you have to call read() multiple times until some data is available, which is actually a polling if you do that in a loop as in MQX I2C examples (you do nothing else except calling read())
    - when you send some data and wait for the end of transfer before going further you have to call IO_IOCTL_FLUSH_OUTPUT but this call also does full speed polling.

 

- there"s no timeout for polling in IO_IOCTL_FLUSH_OUTPUT nor IO_IOCTL_I2C_STOP so this can be deathlock. I had the problem when probing some temperature sensors on which power supply was removed at any time (including during a transfer), while MCF52259 remained powered.

To solve that, I made the following changes to the I2C driver :
- added support for sleeping in read() / write() / IO_IOCTL_FLUSH_OUTPUT calls, and removed polling in IO_IOCTL_I2C_STOP
    - when read() is called the task sleeps in this call until all requested data has been received or RX buffer full
    - write() call only sleeps if the amount of data to be writtent is bigger than the buffer.
    - IO_IOCTL_FLUSH_OUTPUT ioctl (or fflush()) sleeps until data has been transfered
    - in any case check the return value to know the amount of data processed or if a timeout occured.
- added support for a settable timeout (default 20mS) for these calls, using two new ioctls : IO_IOCTL_I2C_SET_TIMEOUT_MS and IO_IOCTL_I2C_GET_TIMEOUT_MS. In cas of timeout :
    - read() and write() return -IO_ERROR_TIMEOUT (negative value; easier than returing IO_ERROR and setting errno to IO_ERROR_TIMEOUT)
    - IO_IOCTL_FLUSH_OUTPUT returns IO_ERROR_TIMEOUT (positive value)

Below is a zip file containing modified files for MQX 3.7 under mqx/source/io/i2c

WARNING : this breaks support for slave mode I2C : the interrupt handler has to be modified for its slave part to support these changes and I did not have the opprtunity to do that (however this should be very simple). So only use this zip if you use I2C as master-only.

NOTE : in case of timeout, if you retry and also get another timeout, the bus is probably hang. You may unlock the bus as described in this post :
https://community.freescale.com/thread/99204

TODO :
- add the required code to support slave-only mode
- fix the code to support both master and slave mode at the same time : this may require to use separate buffers for master and slave, separate semaphore. TBD : use same file descriptor for master and slave or open ii2c device twice ?

Outcomes