I2C Master RTOS Driver

The driver is intended to use I2C master functions in a Real-Time operating system, i.e. is thread safe.

The stop condition is automatically controlled by the driver if the I/O write and read functions are used, but can be manually controlled by using the i2c_m_os_transfer function.

The transfer functions of the I2C Master RTOS driver are optimized for RTOS support. When data transfer is in progress, the transfer functions use semaphore to block the current task or thread until the transfer end. So the transfer functions do not work without RTOS, the transfer functions must be called in an RTOS task or thread.

During data transfer, the I2C transfer process is not protected, so that a more flexible way can be chosen in the application.

I2C Modes (standard mode/fastmode+/highspeed mode) can only be selected in START. If the SCL frequency (baudrate) has changed run-time, make sure to stick within the SCL clock frequency range supported by the selected mode. The requested SCL clock frequency is not validated by the i2c_m_os_set_baudrate function against the selected I2C mode.

Summary of the API's Functional Features

The API provides functions to:
  • Initialize and deinitialize the driver and associated hardware

  • Register I/O descriptor

  • Enable or disable I2C master

  • Hookup callback handlers on TX complete, RX complete, and error events

  • Set the address of the slave device

  • Read/Write message to/from the slave

Summary of Configuration Options

Below is a list of the main I2C master parameters that can be configured in START. Many of these parameters are used by the i2c_m_os_init function when initializing the driver and underlying hardware. Most of the initial values can be overridden and changed runtime by calling the appropriate API functions, such as i2c_m_os_set_baudrate.
  • Set I2C bus clock speed

  • Which clock source is used

Driver Implementation Description

After I2C hardware initialization, the i2c_m_os_get_io function is needed to register an I/O descriptor. Then the application needs to set the slave address by the i2c_m_os_set_slaveaddr function. At the end, start the read/write operation.

Limitations

  • System Management Bus (SMBus) is not supported

  • Power Management Bus (PMBus) is not supported

  • The register value for the requested I2C speed is calculated and placed in the correct register, but not validated if it works correctly with the clock/prescaler settings used for the module. To validate the I2C speed setting use the formula found in the configuration file for the module. Selectable speed is automatically limited within the speed range defined by the I2C mode selected

Example of Usage

The following shows a simple example of using the I2C master. The I2C master must have been initialized by i2c_m_os_init. This initialization will configure the operation of the I2C master.

The example registers an I/O descriptor and sets the slave address, and finally starts a writing operation.

The example creates an I2C master example task. In the task, it registers an I/O descriptor for an I2C instance, then sets the slave address. Here we assume that the I2C device is a 0AT30TSE temperature sensor on an I/O1 Xplained Pro connected to an Xplained board. Write the data to the slave device, and the RTOS task scheduler starts to read the data from the slave device.

          /**
           * Example task of using I2C_0 to echo using the I/O abstraction.
           * Assume the I2C device is AT30TSE temp sensor on IO1 Xplained Pro connected to
           * XPlained board.
           */
          void I2C_example_task(void *p)
          {
              struct io_descriptor *io;
              uint16_t              data;
              uint8_t               buf[2];
              (void)p;
              i2c_m_os_get_io(&I2C_0, &io);
              /* Address of the temp sensor. */
              i2c_m_os_set_slaveaddr(&I2C_0, 0x4f, 0);
              /* Set configuration to use 12-bit temperature */
              buf[0] = 1;
              buf[1] = 3 << 5;
              io_write(&I2C_0.io, buf, 2);
              /* Set to temperature register. */
              buf[0] = 0;
              io_write(&I2C_0.io, buf, 1);
              for (;;) {
                  if (io->read(io, (uint8_t *)&data, 2) == 2) {
                      /* read OK, handle data. */;
                  } else {
                      /* error. */;
                  }
              }
          }
          #define TASK_TRANSFER_STACK_SIZE            ( 256/sizeof( portSTACK_TYPE ))
          #define TASK_TRANSFER_STACK_PRIORITY        ( tskIDLE_PRIORITY + 0 )
          static TaskHandle_t xCreatedTransferTask;
          static void task_transfer_create(void)
          {
              /* Create the task that handles the CLI. */
              if (xTaskCreate(I2C_example_task, "transfer", TASK_TRANSFER_STACK_SIZE, NULL,
              TASK_TRANSFER_STACK_PRIORITY, &xCreatedTransferTask) != pdPASS) {
                  while(1) {;
                  }
              }
          }
          static void tasks_run(void)
          {
              vTaskStartScheduler();
          }
          int main(void)
          {
              /* Initializes MCU, drivers and middleware */
              atmel_start_init();
              task_transfer_create();
              tasks_run();
              /* Replace with your application code */
              while (1) {
              }
          }
        

Dependencies

  • The I2C master peripheral and its related I/O lines and clocks

  • The NVIC must be configured so that I2C interrupt requests are periodically serviced

  • RTOS