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