Thursday, June 18, 2015

Sharing I2C bus in interrupt-driven IO

For quite some time we have been discussing various libraries supporting I2C communication with multiple devices using interrupt-driven IO. Today we will look at some timing diagrams to confirm that everything works as expected. We will be looking at I2C buss hosting two sensors – MPL3115A2 barometric altimeter and MPU-6050 gyroscope and accelerometer. MPLab-X project 18-I2C-All-Async contains the code that drives the board during this experiment.

The main routine of the project, defined in the code file main.c, initializes all the HW components and supporting libraries, and then in the loop reads all sensors. MPL3115A2 initialized with the OSR=3 resulting in update rate of about 37.7 Hz so a new sample is produced about every 26.5 msec. MPU-6050 initialized with the 0 value for the frequency divider, resulting in update rate of 1 KHz. Both sensors operate in asynchronous mode implementing interrupt-driven IO. To facilitate contention on the I2C bus, the bus is configured to run at 200 KHz (half of the normal “high” speed) so every read/write operation takes twice the normal time.

Using SaleaeLogic (mine is the older version than the ones showcased on the site) logic analyzer I capture interrupt signals from each of the sensors as well as the SCL and SDA lines of the I2C bus so that we may see I2C communication in relationship to the Data Ready interrupt signals from the sensors. Conveniently Saleae Logic has a parser for the I2C bus so we may see the actual commands on the bus (if we zoom into the capture with enough resolution). The following picture provides an overview of about 30 msec.
  


The top line (input line 0) captures Data Ready interrupt line from MPL3115A2 barometric sensor – you see strobes about every 26.5 msec. The next line captures Data Ready strobes from the MPU-6050 – these strobes are 50 usec in width and come, as expected, every millisecond. Line number 2 (third from the top) presents I2C clock line, which has strobes at 200 KHz (bus speed) while there is a communication on the bus. At this resolution we cannot see individual clock strobes – they come as the white area on the chart. Finally, the last line (fourth from the top, line 3) captures I2C data line.

The next figure provides a blow-up of the data exchange session with MPU-6050.


A few microseconds after receiving a Data Ready interrupt from the MPU-6050, a communication session with the sensor is started. The session starts with the I2C Start command (indicated by the green circle on the chart) immediately followed by the address of the sensor and then the address of the register to work with. This is followed by I2C Repeated-Start command (also indicated by the green circle), which is required to change the direction of communication, and the read command with the address of the sensor. Then there is a stream of data bytes from the sensor. Each byte is acknowledged by the I2C ACK command. When the master (our program) reads the last byte from the sensor, it informs sensor that no more bytes is needed by issuing I2C NACK (negative acknowledgement). The session ends with the master issuing I2C Stop command indicated on the chart by the red square. The whole communication session, demarcated by the green marker 1 and 2, takes just under 0.9 milliseconds leaving about 100 microseconds free bus time until the next sample is available from the MPU-6050 sensor.

Now let’s see what will happen when MPL3115A2 signals that the new sample is ready. This situation is captured on the following chart:


At a time point around 14 msec MPU-6050 signals that a new sample is ready (please zoom in into the image). As expected, a few microseconds later a communication session is started with MPU-6050 to read this sample. At around 14.4 millisecond point MPL3115A2 signals that it has a new sample ready. Respective interrupt routine captures this signal and requests I2C library to start communication session with MPL315A2; however the bus is busy, so I2C Library puts this request into the queue.

Around 14.9 millisecond point (highlighted by the green marker 2) the session with MPU-6050 ends and I2C Library practically immediately starts communication session with MPL3115A2, which was earlier put into the queue. Around the 15 millisecond point MPU-6050 reports that the next sample is ready – respective interrupt routine requests communication session now with MPU-6050. However as the bus is busy, this request also goes into the queue – by the way, the queue was empty at this point as the previously queued request for MPL3115A2 was de-queued and is active now.


At around 15.7 millisecond point the communication with MPL3115A2 concludes and previously queued request for MPU-6050 is promoted to active and respective session is started. However at around 16 millisecond point MPU-6050 generates a new sample as indicated by the strobe on the respective interrupt line. The interrupt routine again requests I2C library to start communication session with MPU-6050. However this request is rejected by the I2C library as there is no reason to queue request for the same device with which I2C bus is communicating currently – this sample is being lost!
  
The current communication session with MPU-6050 ends at a point around 16.6 milliseconds; at this time as there is no queued request I2C bus goes quiescent. Then the new sample arrives from the MPU-6050 (around 17 millisecond point) and everything starts again.

In real life the I2C bus would run at 400 KHz, so communication session with MPU-6050 would take half the time, about 450 microseconds; similarly, communication session with MPL3115A2 will also take half the time – about 380 microseconds, so both of them would fit nicely in a 1 millisecond interval between the MPU-6050 data samples and now data samples will be lost due to the contention on the bus.


In the next post we will look at measuring battery voltage level, which is an important feature as we are dealing with the LiPo batteries and should be very careful not to over-discharge them.

No comments:

Post a Comment