4.26. I2C Module

4.26.1. Module Files

4.26.1.1. Driver

  • src/app/driver/i2c/i2c.c

  • src/app/driver/i2c/i2c.h

4.26.1.2. Unit Test

  • tests/unit/app/driver/can/test_i2c.c

4.26.2. Detailed Description

The driver consists of READ functions and WRITE functions. In all cases, slaveAddress are the seven bits of the I2C slave address.

4.26.2.1. Reading

There are two cases for READ:

  • I2C_WriteRead(): implements the usual way of reading. First a write operation is made after the START condition and nrBytesWrite are written directly. The data to be written is pointed by writeData. Then a REPEATED START condition issued on the bus and nrBytesRead are read. The result is stored in the data pointed by readData.

  • I2C_Read(): a START condition is issued on the bus and nrBytes are

    read directly. The result is stored in the data pointed by readData.

4.26.2.2. Writing

There is one function to WRITE:

  • I2C_Write(): a START condition is issued on the bus and nrBytes are written directly. The data to be written is pointed by writeData.

4.26.2.3. DMA

Three similar DMA functions are also implemented, with the suffix DMA at the end of the function name. dmaGroupANotification() is called after the bytes are written to or read from I2C to deactivate the corresponding DMA transfers. The DMA functions lack transaction control: in case the I2C transaction does not finish or take place, this is not signaled to the driver. This is detected because the OS function waiting for the tasks to be notified times out instead of receiving a notification.

Warning

When using the DMA functions, the read and write variables must be declared in a non-cacheable area.

4.26.2.4. Details on the implementation

The functions all use the I2C interface as a master.

To send bytes with a stop condition at the end, the repeat mode of the I2C interface is deactivated. The counter register is set with the number of bytes to send and the stop condition is generated. With this configuration, the counter is decremented each time a byte is sent. When the counter reaches zero, a stop bit is sent.

To read bytes, the repeat mode must be activated. When the start condition is set, a start bit is sent and the master starts receiving bytes. The byte counter is not used. When the stop condition is generated, the stop bit is send, but due to the double buffer on the receiver side, the stop condition must be issued after reading the (message size-1)th byte. Due to this, the DMA receive functions use the DMA last transfer started interrupt to issue the stop condition, but the stop bit is sent after the last byte is received by DMA. To avoid receiving one byte more than needed, when receiving N bytes, N-1 received bytes are transferred with DMA. The last byte is copied by the CPU in the DMA receive transfer finished interrupt. As a consequence, the following must be considered:

Warning

The DMA receive functions works only to receive two bytes and more. To receive one byte, the functions without DMA must be used.

4.26.2.5. Task running the functions with DMA

As the DMA functions are non blocking, the synchronization must be taken care of. A specific task has been implemented for the communication with I2C devices. It runs continuously like the AFE task. At the end of the DMA function, the task will be blocked, waiting for a notification. The notification is made in the DMA complete interrupt: the task then wakes up. If the notification does not come within I2C_NOTIFICATION_TIMEOUT_ms milliseconds, the task is unblocked and the I2C communication is declared to have failed. To leave CPU time for the other tasks, the I2C task should be blocked for at least 1 millisecond after each I2C transaction.