I2C
Last updated
Was this helpful?
Last updated
Was this helpful?
is serial communication bus. It is very popular in embedded development and mostly used to communicate to various low speed peripherals, such as eeproms and various sensors.
The control and use of I2C fits nicely into the model described in this book. It is a serial interface and the controlling Device object will have to read/write characters one by one, just like it was with . It would be nice if we coud reuse the Character Driver we implemented before. However, the I2C is multi-master / multi-slave bus and there is a need to specify the slave ID (or address) when initiating read and/or write operation.
It is quite clear that some kind of ID Device Adaptor is needed. It will be constructed with additional ID parameter and will be responsible to forward all the API calls from the Character Driver to I2C Device while adding one extra parameter of ID.
The implementation of such adaptor is very simple and straightforward:
The I2C protocol allows existence of multiple independent slaves on the same bus. It means there may be several independent Components that communicate to different I2C devices (for example EEPROM and temperature sensor), but must share the same Device control object and may issue read/write requests to it in parallel. To resolve this problem, there must be some kind of operation queuing facility that is responsible to queue all the read/write requests to the Device and issue them one by one.
The objects' usage map looks like this:
When the TSize
template parameter is set to 1
, there is no need for all the queuing facility and the DeviceOpQueue class may become a simple pass-through inline class using template specialisation:
Based on the information above, the platform specific I2C control Device object must provide the following public interface:
The same adaptor class is implemented in file of library.
Such queue is a platform/product independent piece of code and it should be implemented without using dynamic memory allocation and/or exceptions. It means that it should receive number of various Driver objects, that may issue independent read/write requests to it (i.e. size of the internal queue), as a template parameter and probably use to queue all the requests that are coming in. It should also receive callback storage types to report when a new character can be read/written, as well as when read/write operation is complete.
Such queue is also implemented in library. It resides in the file.
Please note that and are both Device layer classes. The serve as wrappers to actual peripheral control Device in order to expose the right interface to the upper layer Driver.
The only thing that remains is to properly implement I2C control device, which can be used by the DeviceOpQueue
, which in turn is used by the IdAdaptor
. The IdAdaptor
object can be used with the existing Character
Driver implemented to be used with the peripheral.
Such device to control I2C0 interface on RaspberryPi platform is implemented in file of project.
The project contains an application called . It implements a parallel access to 2 EEPROMs connected to the same I2C0 bus, but having different addresses. The EEPROMs are accessed independently at the same time with read/write operations. These operations are queued and managed by the DeviceOpQueue
object that wraps actual I2C control Device and forwards the requests one by one.