Skip to content

I2C

Introduction

The MikroSDK.Driver.I2C.Master library provides an API for controlling I2C master devices.

It includes functions for configuring the I2C master, setting speeds and timeouts, reading from and writing to the I2C bus, and managing the connection with I2C slave devices.

The I2C (Inter-Integrated Circuit) protocol is a widely used communication protocol for connecting peripheral devices to microcontrollers. This library allows you to configure and use the I2C master functionality of your hardware.

API Name

  • MikroSDK.Driver.I2C.Master

API Files

Prerequisites

  • Library Manager:

    • Select Driver.I2C.Master to add the API to your project using the Library Manager in NECTO Studio.
  • Headers:

    • Include the Driver.I2C.Master header in your source files to access the I2C functions.
    • This header pops up in the lower right part of NECTO Studio once you perform the previous task (while selecting Driver.I2C.Master in Library Manager)
    • Alternatively, include the drv_i2c_master.h header in your source files to access the I2C functions.
  • CMakeLists:

    • You do not have to perform anything, configuration (CMake) file is already taken care of automatically while you performed the first task in this Prerequisites!
    • You can ensure that your CMakeLists.txt includes the necessary configurations to link against the MikroSDK.Driver.I2C.Master library.

Code Examples

  • How to properly test I2C?
/* Project name:
 *   I2C demo
 * Copyright:
 *   (c) MIKROE, 2024.
 * Description:
 *   Example is meant for demonstrating I2C functionality using mikroSDK 2.0.
 *   Make sure to place [EEPROM Click](https://www.mikroe.com/eeprom-click)
 *   in mikroBUS1 and [TESTER Click](https://www.mikroe.com/tester-click) in mikroBUS2.
 *   Pin MIKROBUS_2_INT is set to high if transfer was successful. Written and read data
 *   is also printed out on the Standard output (determined by the chosen setup).
 *   Use a logic analyzer for more detailed insight into the transfer details.
 * Library dependencies?
 *   - Make sure `Driver.I2C.Master`, `Driver.GPIO.Out`, `Driver.GPIO.In`,
 *     `Log` and `Board` libraries are enabled in NECTO's Library Manager to
 *     ensure a successful build.
 */

/**
 * @brief For a detailed explanation of this demo, please visit:
 * <https://libstock.mikroe.com/projects/view/5398/i2c-demo>
 */

// ------------------------------------------------------------------ INCLUDES

/**
 * Any initialization code needed for MCU to function properly.
 * Do not remove this line or clock might not be set correctly.
 */
#ifdef PREINIT_SUPPORTED
#include "preinit.h"
#endif

#include "MikroSDK.Driver.I2C.Master"
#include "MikroSDK.Driver.GPIO.In"
#include "MikroSDK.Driver.GPIO.Out"
#include "MikroSDK.Board"
#include "MikroSDK.Log"

#ifdef MikroCCoreVersion
    #if MikroCCoreVersion >= 1
        #include "delays.h"
    #endif
#endif

// -------------------------------------------------------------------- MACROS
// Return value in case of error.
#define RET_FAIL (-1)

// If hardware without mikroBUS socket is used, make sure to define adequate pin.
#ifndef MIKROBUS_1_SCL
#define MIKROBUS_1_SCL NC
#endif
// If hardware without mikroBUS socket is used, make sure to define adequate pin.
#ifndef MIKROBUS_1_SDA
#define MIKROBUS_1_SDA NC
#endif
// If hardware without mikroBUS socket is used, make sure to define adequate pin.
#ifndef MIKROBUS_2_INT
#define MIKROBUS_2_INT NC
#endif

// I2C pins
#define TEST_PIN_I2C_SCL MIKROBUS_1_SCL
#define TEST_PIN_I2C_SDA MIKROBUS_1_SDA

// Number of bytes which shall be sent/read.
// Take into consideration that the max size is 1 byte( 255 )
#define ARRAY_LENGTH 20

// Slave address for [EEPROM Click](https://www.mikroe.com/eeprom-click).
#define I2C_MASTER_SLAVE_ADDRESS 0x50

#define signal_success(port,pin) digital_out_init( &port, pin ); \
                                 digital_out_write( &port, 1 )

// ----------------------------------------------------------------- VARIABLES
static digital_out_t scl_pin;
static digital_in_t sda_pin;

static i2c_master_t i2c_master;
static i2c_master_config_t i2c_master_cfg;

static digital_out_t output_pin;

static uint8_t write_buffer[ARRAY_LENGTH];
static uint8_t read_buffer[ARRAY_LENGTH];

static log_t logger;
static log_cfg_t logger_cfg;

static uint8_t i;
static int8_t read_data;
// ----------------------------------------------------------------- USER CODE
err_t i2c_demo_write( uint8_t wAddr, uint8_t wData ) {
    uint8_t wr_dat[2];

    wr_dat[0] = wAddr;
    wr_dat[1] = wData;

    if( I2C_MASTER_ERROR == i2c_master_write( &i2c_master, wr_dat, 2 )) {
        log_printf( &logger, "I2C master write failed.\n" );
        return RET_FAIL;
    }

    return 0;
}

err_t i2c_demo_read( uint8_t rAddr ) {
    uint8_t rd_dat;

    if( I2C_MASTER_ERROR == i2c_master_write( &i2c_master, &rAddr, 1 )) {
        log_printf( &logger, "I2C master write failed.\n" );
        return RET_FAIL;
    }

    if( I2C_MASTER_ERROR == i2c_master_read( &i2c_master, &rd_dat, 1 )) {
        log_printf( &logger, "I2C master read failed.\n" );
        return RET_FAIL;
    }

    return rd_dat;
}

int main(void) {
    /* Do not remove this line or clock might not be set correctly. */
    #ifdef PREINIT_SUPPORTED
    preinit();
    #endif

    // Initialize logger.
    LOG_MAP_USB_UART( logger_cfg );
    log_init( &logger, &logger_cfg );

    // Initializes I2C master configuration structure to default values.
    i2c_master_configure_default( &i2c_master_cfg );

    i2c_master_cfg.scl = TEST_PIN_I2C_SCL;
    i2c_master_cfg.sda = TEST_PIN_I2C_SDA;

    /*
     * The following piece of code is waiting for the slave device
     * to release the clock line (SCL) and acknowledge the I2C bus
     * is ready for communication. This is crucial because the master
     * must wait for the acknowledgment before starting any
     * communication on the I2C bus.
     */
    digital_out_init( &scl_pin, TEST_PIN_I2C_SCL );
    digital_in_init( &sda_pin, TEST_PIN_I2C_SDA );
    digital_out_high( &scl_pin );
    while ( digital_in_read( &sda_pin ) == 0 )
    {
        digital_out_low( &scl_pin );
        Delay_1ms();
        digital_out_high( &scl_pin );
        Delay_1ms();
    }

    // I2C master open.
    if( ACQUIRE_FAIL == i2c_master_open( &i2c_master, &i2c_master_cfg )) {
        log_printf( &logger, "I2C master open failed.\n" );
        return RET_FAIL;
    }

    // Set i2c timeout.
    if( I2C_MASTER_ERROR == i2c_master_set_timeout( &i2c_master, 0 )) {
        log_printf( &logger, "I2C master set timeout failed.\n" );
        return RET_FAIL;
    }

    // I2C master set speed.
    if( I2C_MASTER_ERROR == i2c_master_set_speed( &i2c_master, I2C_MASTER_SPEED_STANDARD )) {
        log_printf( &logger, "I2C master set speed failed.\n" );
        return RET_FAIL;
    }

    // I2C master set slave address.
    if( I2C_MASTER_ERROR == i2c_master_set_slave_address( &i2c_master, I2C_MASTER_SLAVE_ADDRESS )) {
        log_printf( &logger, "I2C master set slave address failed.\n" );
        return RET_FAIL;
    }

    log_printf( &logger, "Written data:\n" );
    for( i = 0; i < ARRAY_LENGTH; i++ ) {
        if( I2C_MASTER_ERROR == i2c_demo_write( i, i )) {
            return RET_FAIL;
        }
        write_buffer[i] = i;
        if( ARRAY_LENGTH - 1 != i ) {
            log_printf( &logger, "%d, ", (uint16_t)write_buffer[i] );
        } else {
            log_printf( &logger, "%d\n", (uint16_t)write_buffer[i] );
        }
        Delay_1ms();
        if( RET_FAIL != (read_data = i2c_demo_read(i)) ) {
            read_buffer[i] = read_data;
        } else return RET_FAIL;
    }

    log_printf( &logger, "Read data:\n" );
    for( i = 0; i < ARRAY_LENGTH; i++ ) {
        if( ARRAY_LENGTH - 1 != i ) {
            log_printf( &logger, "%d, ", (uint16_t)read_buffer[i] );
        } else {
            log_printf( &logger, "%d\n", (uint16_t)read_buffer[i] );
        }
    }

    /*
     *  memcmp compares buffers and returns 0 if they are the same.
     *  So, here, if it does return 0, it means that the transfer
     *  was successful and signal_success should set output_pin to high.
     */
    if ( !memcmp( write_buffer, read_buffer, sizeof( write_buffer ))){
        signal_success( output_pin, MIKROBUS_2_INT );
    }

    // Close I2C module.
    if( I2C_MASTER_ERROR == i2c_master_close( &i2c_master )) {
        log_printf( &logger, "I2C master close failed.\n" );
        return RET_FAIL;
    }

    log_printf( &logger, "End of I2C demo.\n" );

    return 0;
}

// ----------------------------------------------------------------------- END
  • How do I initialize the I2C Master with default settings?
/* Project name:
 *   How do I initialize the I2C Master with default settings?
 * Copyright:
 *   (c) MIKROE, 2024.
 * Description:
 *   Example is meant for demonstrating I2C functionality using mikroSDK 2.0.
 *   I2C master protocol shall be initialized with common day-to-day settings.
 * Library dependencies?
 *   - Make sure `Driver.I2C.Master`, `Driver.GPIO.Out`, `Driver.GPIO.In`,
 *     `Log` and `Board` libraries are enabled in NECTO's Library Manager to
 *     ensure a successful build.
 */

// ------------------------------------------------------------------ INCLUDES

/**
 * Any initialization code needed for MCU to function properly.
 * Do not remove this line or clock might not be set correctly.
 */
#ifdef PREINIT_SUPPORTED
#include "preinit.h"
#endif

#include "MikroSDK.Driver.I2C.Master"
#include "MikroSDK.Driver.GPIO.In"
#include "MikroSDK.Driver.GPIO.Out"
#include "MikroSDK.Board"
#include "MikroSDK.Log"

#ifdef MikroCCoreVersion
    #if MikroCCoreVersion >= 1
        #include "delays.h"
    #endif
#endif

// -------------------------------------------------------------------- MACROS
// Return value in case of error.
#define RET_FAIL (-1)

// If hardware without mikroBUS socket is used, make sure to define adequate pin.
#ifndef MIKROBUS_1_SCL
#define MIKROBUS_1_SCL NC // example: replace `NC` with `PA0`
#endif
// If hardware without mikroBUS socket is used, make sure to define adequate pin.
#ifndef MIKROBUS_1_SDA
#define MIKROBUS_1_SDA NC // example: replace `NC` with `PA0`
#endif
// If hardware without mikroBUS socket is used, make sure to define adequate pin.
#ifndef MIKROBUS_2_INT
#define MIKROBUS_2_INT NC // example: replace `NC` with `PA0`
#endif

// I2C pins
#define TEST_PIN_I2C_SCL MIKROBUS_1_SCL
#define TEST_PIN_I2C_SDA MIKROBUS_1_SDA

// Number of bytes which shall be sent/read.
// Take into consideration that the max size is 1 byte( 255 )
#define ARRAY_LENGTH 20

// Slave address for [EEPROM Click](https://www.mikroe.com/eeprom-click).
#define I2C_MASTER_SLAVE_ADDRESS 0x50

// ----------------------------------------------------------------- VARIABLES
static digital_out_t scl_pin;
static digital_in_t sda_pin;

static i2c_master_t i2c_master;
static i2c_master_config_t i2c_master_cfg;

static log_t logger;
static log_cfg_t logger_cfg;

// ----------------------------------------------------------------- USER CODE
int main(void) {
    /* Do not remove this line or clock might not be set correctly. */
    #ifdef PREINIT_SUPPORTED
    preinit();
    #endif

    // Initialize logger.
    LOG_MAP_USB_UART( logger_cfg );
    log_init( &logger, &logger_cfg );

    // Initializes I2C master configuration structure to default values.
    i2c_master_configure_default( &i2c_master_cfg );

    i2c_master_cfg.scl = TEST_PIN_I2C_SCL;
    i2c_master_cfg.sda = TEST_PIN_I2C_SDA;

    /*
     * The following piece of code is waiting for the slave device
     * to release the clock line (SCL) and acknowledge the I2C bus
     * is ready for communication. This is crucial because the master
     * must wait for the acknowledgment before starting any
     * communication on the I2C bus.
     */
    digital_out_init( &scl_pin, TEST_PIN_I2C_SCL );
    digital_in_init( &sda_pin, TEST_PIN_I2C_SDA );
    digital_out_high( &scl_pin );
    while ( digital_in_read( &sda_pin ) == 0 )
    {
        digital_out_low( &scl_pin );
        Delay_1ms();
        digital_out_high( &scl_pin );
        Delay_1ms();
    }

    // I2C master open
    if( ACQUIRE_FAIL == i2c_master_open( &i2c_master, &i2c_master_cfg )) {
        log_printf( &logger, "I2C master open failed.\n" );
        return RET_FAIL;
    }
    log_printf( &logger, "I2C master open successful.\n" );

    // Set i2c timeout
    if( I2C_MASTER_ERROR == i2c_master_set_timeout( &i2c_master, 0 )) {
        log_printf( &logger, "I2C master set timeout failed.\n" );
        return RET_FAIL;
    }
    log_printf( &logger, "I2C master set timeout successful.\n" );

    // I2C master set speed
    if( I2C_MASTER_ERROR == i2c_master_set_speed( &i2c_master, I2C_MASTER_SPEED_STANDARD )) {
        log_printf( &logger, "I2C master set speed failed.\n" );
        return RET_FAIL;
    }
    log_printf( &logger, "I2C master set speed successful.\n" );

    // I2C master set slave address
    if( I2C_MASTER_ERROR == i2c_master_set_slave_address( &i2c_master, I2C_MASTER_SLAVE_ADDRESS )) {
        log_printf( &logger, "I2C master set slave address failed.\n" );
        return RET_FAIL;
    }
    log_printf( &logger, "I2C master set slave address successful.\n" );

    // Initialization of the I2C Master with default settings done.
    log_printf( &logger, "I2C master init successful.\n" );

    // TODO Insert your application logic here

    return 0;
}

// ----------------------------------------------------------------------- END
  • How do I set the I2C Master speed to 400 kHz (Full Speed)?
/* Project name:
 *   How do I set the I2C Master speed to 400 kHz (Full Speed)?
 * Copyright:
 *   (c) MIKROE, 2024.
 * Description:
 *   Example is meant for demonstrating I2C functionality using mikroSDK 2.0.
 *   Baud rate of I2C master protocol shall be configured.
 * Library dependencies?
 *   - Make sure `Driver.I2C.Master`, `Driver.GPIO.Out`, `Driver.GPIO.In`,
 *     `Log` and `Board` libraries are enabled in NECTO's Library Manager to
 *     ensure a successful build.
 */

// ------------------------------------------------------------------ INCLUDES

/**
 * Any initialization code needed for MCU to function properly.
 * Do not remove this line or clock might not be set correctly.
 */
#ifdef PREINIT_SUPPORTED
#include "preinit.h"
#endif

#include "MikroSDK.Driver.I2C.Master"
#include "MikroSDK.Driver.GPIO.In"
#include "MikroSDK.Driver.GPIO.Out"
#include "MikroSDK.Board"
#include "MikroSDK.Log"

#ifdef MikroCCoreVersion
    #if MikroCCoreVersion >= 1
        #include "delays.h"
    #endif
#endif

// -------------------------------------------------------------------- MACROS
// Return value in case of error.
#define RET_FAIL (-1)

// If hardware without mikroBUS socket is used, make sure to define adequate pin.
#ifndef MIKROBUS_1_SCL
#define MIKROBUS_1_SCL NC // example: replace `NC` with `PA0`
#endif
// If hardware without mikroBUS socket is used, make sure to define adequate pin.
#ifndef MIKROBUS_1_SDA
#define MIKROBUS_1_SDA NC // example: replace `NC` with `PA0`
#endif

// I2C pins
#define TEST_PIN_I2C_SCL MIKROBUS_1_SCL
#define TEST_PIN_I2C_SDA MIKROBUS_1_SDA

// ----------------------------------------------------------------- VARIABLES
static digital_out_t scl_pin;
static digital_in_t sda_pin;

static i2c_master_t i2c_master;
static i2c_master_config_t i2c_master_cfg;

static log_t logger;
static log_cfg_t logger_cfg;

// ----------------------------------------------------------------- USER CODE
int main(void) {
    /* Do not remove this line or clock might not be set correctly. */
    #ifdef PREINIT_SUPPORTED
    preinit();
    #endif

    // Initialize logger.
    LOG_MAP_USB_UART( logger_cfg );
    log_init( &logger, &logger_cfg );

    // Initializes I2C master configuration structure to default values.
    i2c_master_configure_default( &i2c_master_cfg );

    i2c_master_cfg.scl = TEST_PIN_I2C_SCL;
    i2c_master_cfg.sda = TEST_PIN_I2C_SDA;

    /*
     * The following piece of code is waiting for the slave device
     * to release the clock line (SCL) and acknowledge the I2C bus
     * is ready for communication. This is crucial because the master
     * must wait for the acknowledgment before starting any
     * communication on the I2C bus.
     */
    digital_out_init( &scl_pin, TEST_PIN_I2C_SCL );
    digital_in_init( &sda_pin, TEST_PIN_I2C_SDA );
    digital_out_high( &scl_pin );
    while ( digital_in_read( &sda_pin ) == 0 )
    {
        digital_out_low( &scl_pin );
        Delay_1ms();
        digital_out_high( &scl_pin );
        Delay_1ms();
    }

    // I2C master open
    if( ACQUIRE_FAIL == i2c_master_open( &i2c_master, &i2c_master_cfg )) {
        log_printf( &logger, "I2C master open failed.\n" );
        return RET_FAIL;
    }
    log_printf( &logger, "I2C master open successful.\n" );

    // I2C master set speed
    if( I2C_MASTER_ERROR == i2c_master_set_speed( &i2c_master, I2C_MASTER_SPEED_FULL )) {
        log_printf( &logger, "I2C master set speed failed.\n" );
        return RET_FAIL;
    }
    log_printf( &logger, "I2C master set FULL SPEED (400kHz) successful.\n" );

    return 0;
}

// ----------------------------------------------------------------------- END
  • How do I open the I2C Master driver on specific pins?
/* Project name:
 *   How do I open the I2C Master driver on specific pins?
 * Copyright:
 *   (c) MIKROE, 2024.
 * Description:
 *   Example is meant for demonstrating I2C functionality using mikroSDK 2.0.
 *   I2C master protocol shall be opened with specific I2C pins.
 * Library dependencies?
 *   - Make sure `Driver.I2C.Master`, `Driver.GPIO.Out`, `Driver.GPIO.In`,
 *     `Log` and `Board` libraries are enabled in NECTO's Library Manager to
 *     ensure a successful build.
 */

// ------------------------------------------------------------------ INCLUDES

/**
 * Any initialization code needed for MCU to function properly.
 * Do not remove this line or clock might not be set correctly.
 */
#ifdef PREINIT_SUPPORTED
#include "preinit.h"
#endif

#include "MikroSDK.Driver.I2C.Master"
#include "MikroSDK.Driver.GPIO.In"
#include "MikroSDK.Driver.GPIO.Out"
#include "MikroSDK.Board"
#include "MikroSDK.Log"

#ifdef MikroCCoreVersion
    #if MikroCCoreVersion >= 1
        #include "delays.h"
    #endif
#endif

// -------------------------------------------------------------------- MACROS
// Return value in case of error.
#define RET_FAIL (-1)

// If hardware without mikroBUS socket is used, make sure to define adequate pin.
#ifndef MIKROBUS_1_SCL
#define MIKROBUS_1_SCL NC // example: replace `NC` with `PA0`
#endif
// If hardware without mikroBUS socket is used, make sure to define adequate pin.
#ifndef MIKROBUS_1_SDA
#define MIKROBUS_1_SDA NC // example: replace `NC` with `PA1`
#endif

// ----------------------------------------------------------------- VARIABLES
static digital_out_t scl_pin;
static digital_in_t sda_pin;

static i2c_master_t i2c_master;
static i2c_master_config_t i2c_master_cfg;

static log_t logger;
static log_cfg_t logger_cfg;

// ----------------------------------------------------------------- USER CODE
int main(void) {
    /* Do not remove this line or clock might not be set correctly. */
    #ifdef PREINIT_SUPPORTED
    preinit();
    #endif

    // Initialize logger.
    LOG_MAP_USB_UART( logger_cfg );
    log_init( &logger, &logger_cfg );

    // Initializes I2C master configuration structure to default values.
    i2c_master_configure_default( &i2c_master_cfg );

    i2c_master_cfg.scl = MIKROBUS_1_SCL;
    i2c_master_cfg.sda = MIKROBUS_1_SDA;

    /*
     * The following piece of code is waiting for the slave device
     * to release the clock line (SCL) and acknowledge the I2C bus
     * is ready for communication. This is crucial because the master
     * must wait for the acknowledgment before starting any
     * communication on the I2C bus.
     */
    digital_out_init( &scl_pin, i2c_master_cfg.scl );
    digital_in_init( &sda_pin, i2c_master_cfg.sda );
    digital_out_high( &scl_pin );
    while ( digital_in_read( &sda_pin ) == 0 )
    {
        digital_out_low( &scl_pin );
        Delay_1ms();
        digital_out_high( &scl_pin );
        Delay_1ms();
    }

    // I2C master open
    if( ACQUIRE_FAIL == i2c_master_open( &i2c_master, &i2c_master_cfg )) {
        log_printf( &logger, "I2C master open failed.\n" );
        return RET_FAIL;
    }
    log_printf( &logger, "I2C master open successful.\n" );

    // I2C Master open done
    log_printf( &logger, "I2C master open with specific pins successful.\n" );

    // TODO Insert other I2C functions necessary for proper I2C config

    // TODO Finally, insert your application logic here

    return 0;
}
  • How do I set the I2C slave address to 0x50?
/* Project name:
 *   How do I set the I2C slave address to 0x50?
 * Copyright:
 *   (c) MIKROE, 2024.
 * Description:
 *   Example is meant for demonstrating I2C functionality using mikroSDK 2.0.
 *   I2C master protocol shall be opened with specific I2C slave address.
 * Library dependencies?
 *   - Make sure `Driver.I2C.Master`, `Driver.GPIO.Out`, `Driver.GPIO.In`,
 *     `Log` and `Board` libraries are enabled in NECTO's Library Manager to
 *     ensure a successful build.
 */

// ------------------------------------------------------------------ INCLUDES

/**
 * Any initialization code needed for MCU to function properly.
 * Do not remove this line or clock might not be set correctly.
 */
#ifdef PREINIT_SUPPORTED
#include "preinit.h"
#endif

#include "MikroSDK.Driver.I2C.Master" // NOTE: this header is the same as `drv_i2c_master.h`
#include "MikroSDK.Driver.GPIO.In" // NOTE: this header is the same as `drv_digital_in.h`
#include "MikroSDK.Driver.GPIO.Out" // NOTE: this header is the same as `drv_digital_out.h`
#include "MikroSDK.Board" // NOTE: this header is the same as `board.h`
#include "MikroSDK.Log" // NOTE: this header is the same as `log.h`

#ifdef MikroCCoreVersion
    #if MikroCCoreVersion >= 1
        #include "delays.h"
    #endif
#endif

// -------------------------------------------------------------------- MACROS
// Return value in case of error.
#define RET_FAIL (-1)

// If hardware without mikroBUS socket is used, make sure to define adequate pin.
#ifndef MIKROBUS_1_SCL
#define MIKROBUS_1_SCL NC // example: replace `NC` with `PA0`
#endif
// If hardware without mikroBUS socket is used, make sure to define adequate pin.
#ifndef MIKROBUS_1_SDA
#define MIKROBUS_1_SDA NC // example: replace `NC` with `PA0`
#endif
// If hardware without mikroBUS socket is used, make sure to define adequate pin.
#ifndef MIKROBUS_2_INT
#define MIKROBUS_2_INT NC // example: replace `NC` with `PA0`
#endif

// I2C pins
#define TEST_PIN_I2C_SCL MIKROBUS_1_SCL
#define TEST_PIN_I2C_SDA MIKROBUS_1_SDA

// Number of bytes which shall be sent/read.
// Take into consideration that the max size is 1 byte( 255 )
#define ARRAY_LENGTH 20

// Slave address for [EEPROM Click](https://www.mikroe.com/eeprom-click).
#define I2C_MASTER_SLAVE_ADDRESS 0x50

// ----------------------------------------------------------------- VARIABLES
static digital_out_t scl_pin;
static digital_in_t sda_pin;

static i2c_master_t i2c_master;
static i2c_master_config_t i2c_master_cfg;

static log_t logger;
static log_cfg_t logger_cfg;

// ----------------------------------------------------------------- USER CODE
int main(void) {
    /* Do not remove this line or clock might not be set correctly. */
    #ifdef PREINIT_SUPPORTED
    preinit();
    #endif

    // Initialize logger.
    LOG_MAP_USB_UART( logger_cfg );
    log_init( &logger, &logger_cfg );

    // Initializes I2C master configuration structure to default values.
    i2c_master_configure_default( &i2c_master_cfg );

    i2c_master_cfg.scl = TEST_PIN_I2C_SCL;
    i2c_master_cfg.sda = TEST_PIN_I2C_SDA;

    /*
     * The following piece of code is waiting for the slave device
     * to release the clock line (SCL) and acknowledge the I2C bus
     * is ready for communication. This is crucial because the master
     * must wait for the acknowledgment before starting any
     * communication on the I2C bus.
     */
    digital_out_init( &scl_pin, TEST_PIN_I2C_SCL );
    digital_in_init( &sda_pin, TEST_PIN_I2C_SDA );
    digital_out_high( &scl_pin );
    while ( digital_in_read( &sda_pin ) == 0 )
    {
        digital_out_low( &scl_pin );
        Delay_1ms();
        digital_out_high( &scl_pin );
        Delay_1ms();
    }

    // I2C master open
    if( ACQUIRE_FAIL == i2c_master_open( &i2c_master, &i2c_master_cfg )) {
        log_printf( &logger, "I2C master open failed.\n" );
        return RET_FAIL;
    }
    log_printf( &logger, "I2C master open successful.\n" );

    // I2C master set slave address
    if( I2C_MASTER_ERROR == i2c_master_set_slave_address( &i2c_master,
                                            I2C_MASTER_SLAVE_ADDRESS )) {
        log_printf( &logger, "I2C master set slave address failed.\n" );
        return RET_FAIL;
    }
    log_printf( &logger, "I2C master set slave address successful.\n" );

    // TODO Insert other I2C functions from "drv_i2c_master.h"
    // necessary for proper I2C config

    // TODO Finally, insert your application logic here

    return 0;
}
  • How do I set the I2C timeout value?
/* Project name:
 *   How do I set the I2C timeout value?
 * Copyright:
 *   (c) MIKROE, 2024.
 * Description:
 *   Example is meant for demonstrating I2C functionality using mikroSDK 2.0.
 *   I2C master protocol shall be opened with specific I2C timeout value.
 * Library dependencies?
 *   - Make sure `Driver.I2C.Master`, `Driver.GPIO.Out`, `Driver.GPIO.In`,
 *     `Log` and `Board` libraries are enabled in NECTO's Library Manager to
 *     ensure a successful build.
 */

// ------------------------------------------------------------------ INCLUDES

/**
 * Any initialization code needed for MCU to function properly.
 * Do not remove this line or clock might not be set correctly.
 */
#ifdef PREINIT_SUPPORTED
#include "preinit.h"
#endif

#include "MikroSDK.Driver.I2C.Master" // NOTE: this header is the same as `drv_i2c_master.h`
#include "MikroSDK.Driver.GPIO.In" // NOTE: this header is the same as `drv_digital_in.h`
#include "MikroSDK.Driver.GPIO.Out" // NOTE: this header is the same as `drv_digital_out.h`
#include "MikroSDK.Board" // NOTE: this header is the same as `board.h`
#include "MikroSDK.Log" // NOTE: this header is the same as `log.h`

#ifdef MikroCCoreVersion
    #if MikroCCoreVersion >= 1
        #include "delays.h"
    #endif
#endif

// -------------------------------------------------------------------- MACROS
// Return value in case of error
#define RET_FAIL (-1)

// If hardware without mikroBUS socket is used, make sure to define adequate pin
#ifndef MIKROBUS_1_SCL
#define MIKROBUS_1_SCL NC // example: replace `NC` with `PA0`
#endif
// If hardware without mikroBUS socket is used, make sure to define adequate pin
#ifndef MIKROBUS_1_SDA
#define MIKROBUS_1_SDA NC // example: replace `NC` with `PA1`
#endif

// I2C specific timeout value
#define I2C_TIMEOUT 1000

// ----------------------------------------------------------------- VARIABLES
static digital_out_t scl_pin;
static digital_in_t sda_pin;

static i2c_master_t i2c_master;
static i2c_master_config_t i2c_master_cfg;

static log_t logger;
static log_cfg_t logger_cfg;

// ----------------------------------------------------------------- USER CODE
int main(void) {
    /* Do not remove this line or clock might not be set correctly. */
    #ifdef PREINIT_SUPPORTED
    preinit();
    #endif

    // Initialize logger
    LOG_MAP_USB_UART( logger_cfg );
    log_init( &logger, &logger_cfg );

    // Initializes I2C master configuration structure to default values
    i2c_master_configure_default( &i2c_master_cfg );

    i2c_master_cfg.scl = MIKROBUS_1_SCL;
    i2c_master_cfg.sda = MIKROBUS_1_SDA;

    /*
     * The following piece of code is waiting for the slave device
     * to release the clock line (SCL) and acknowledge the I2C bus
     * is ready for communication. This is crucial because the master
     * must wait for the acknowledgment before starting any
     * communication on the I2C bus
     */
    digital_out_init( &scl_pin, i2c_master_cfg.scl );
    digital_in_init( &sda_pin, i2c_master_cfg.sda );
    digital_out_high( &scl_pin );
    while ( digital_in_read( &sda_pin ) == 0 )
    {
        digital_out_low( &scl_pin );
        Delay_1ms();
        digital_out_high( &scl_pin );
        Delay_1ms();
    }

    // I2C master open
    if( ACQUIRE_FAIL == i2c_master_open( &i2c_master, &i2c_master_cfg )) {
        log_printf( &logger, "I2C master open failed.\n" );
        return RET_FAIL;
    }
    log_printf( &logger, "I2C master open successful.\n" );

    // Set I2C timeout to 1000 retries
    if( I2C_MASTER_ERROR == i2c_master_set_timeout( &i2c_master, I2C_TIMEOUT )) {
        log_printf( &logger, "I2C master set timeout failed.\n" );
        return RET_FAIL;
    }
    log_printf( &logger, "I2C master set timeout successful.\n" );

    // TODO Insert other I2C functions from "drv_i2c_master.h"
    // necessary for proper I2C config

    // TODO Finally, insert your application logic here

    return 0;
}
  • How do I write and read data to/from the I2C bus?
/* Project name:
 *   How do I write and read data to/from the I2C bus?
 * Copyright:
 *   (c) MIKROE, 2024.
 * Description:
 *   - Example is meant for demonstrating I2C functionality using mikroSDK 2.0.
 *   - Written and read data is also printed out on the Standard
 *   output (determined by the chosen setup).
 *   - Use a logic analyzer for more detailed insight into the transfer details.
 * Library dependencies?
 *   - Make sure `Driver.I2C.Master`, `Driver.GPIO.Out`, `Driver.GPIO.In`,
 *     `Log` and `Board` libraries are enabled in NECTO's Library Manager to
 *     ensure a successful build.
 * How to test this code example?
 *   - If you have [mikroBUS](https://www.mikroe.com/mikrobus)-based
 *     dev board: make sure to place
 *     [EEPROM Click](https://www.mikroe.com/eeprom-click) in mikroBUS1
 *     of your dev board.
 *   - Try this example remotely by utilizing
 *     [Planet Debug](https://www.mikroe.com/planet-debug)! Just open
 *     Planet Debug feature within NECTO Studio and search for this specific
 *     [EEPROM Click](https://www.mikroe.com/eeprom-click) in the search box.
 */

// ------------------------------------------------------------------ INCLUDES

/**
 * Any initialization code needed for MCU to function properly.
 * Do not remove this line or clock might not be set correctly.
 */
#ifdef PREINIT_SUPPORTED
#include "preinit.h"
#endif

#include "MikroSDK.Driver.I2C.Master" // NOTE: this header is the same as `drv_i2c_master.h`
#include "MikroSDK.Driver.GPIO.In" // NOTE: this header is the same as `drv_digital_in.h`
#include "MikroSDK.Driver.GPIO.Out" // NOTE: this header is the same as `drv_digital_out.h`
#include "MikroSDK.Board" // NOTE: this header is the same as `board.h`
#include "MikroSDK.Log" // NOTE: this header is the same as `log.h`

#ifdef MikroCCoreVersion
    #if MikroCCoreVersion >= 1
        #include "delays.h"
    #endif
#endif

// -------------------------------------------------------------------- MACROS
// Return value in case of error.
#define RET_FAIL (-1)

// If hardware without mikroBUS socket is used, make sure to define adequate pin.
#ifndef MIKROBUS_1_SCL
#define MIKROBUS_1_SCL NC // example: replace `NC` with `PA0`
#endif
// If hardware without mikroBUS socket is used, make sure to define adequate pin.
#ifndef MIKROBUS_1_SDA
#define MIKROBUS_1_SDA NC // example: replace `NC` with `PA1`
#endif

// Number of bytes which shall be sent/read.
// Take into consideration that the max size is 1 byte( 255 )
#define ARRAY_LENGTH 20

// Slave address for [EEPROM Click](https://www.mikroe.com/eeprom-click).
#define I2C_MASTER_SLAVE_ADDRESS 0x50

// ----------------------------------------------------------------- VARIABLES
static digital_out_t scl_pin;
static digital_in_t sda_pin;

static i2c_master_t i2c_master;
static i2c_master_config_t i2c_master_cfg;

static digital_out_t output_pin;

static uint8_t write_buffer[ARRAY_LENGTH];
static uint8_t read_buffer[ARRAY_LENGTH];

static log_t logger;
static log_cfg_t logger_cfg;

static uint8_t i;
static int8_t read_data;
// ----------------------------------------------------------------- USER CODE
err_t i2c_demo_write( uint8_t wAddr, uint8_t wData ) {
    uint8_t wr_dat[2];

    wr_dat[0] = wAddr;
    wr_dat[1] = wData;

    if( I2C_MASTER_ERROR == i2c_master_write( &i2c_master, wr_dat, 2 )) {
        log_printf( &logger, "I2C master write failed.\n" );
        return RET_FAIL;
    }

    return 0;
}

err_t i2c_demo_read( uint8_t rAddr ) {
    uint8_t rd_dat;

    if( I2C_MASTER_ERROR == i2c_master_write( &i2c_master, &rAddr, 1 )) {
        log_printf( &logger, "I2C master write failed.\n" );
        return RET_FAIL;
    }

    if( I2C_MASTER_ERROR == i2c_master_read( &i2c_master, &rd_dat, 1 )) {
        log_printf( &logger, "I2C master read failed.\n" );
        return RET_FAIL;
    }

    return rd_dat;
}

int main(void) {
    /* Do not remove this line or clock might not be set correctly. */
    #ifdef PREINIT_SUPPORTED
    preinit();
    #endif

    // Initialize logger.
    LOG_MAP_USB_UART( logger_cfg );
    log_init( &logger, &logger_cfg );

    // Initializes I2C master configuration structure to default values.
    i2c_master_configure_default( &i2c_master_cfg );

    i2c_master_cfg.scl = MIKROBUS_1_SCL;
    i2c_master_cfg.sda = MIKROBUS_1_SDA;

    /*
     * The following piece of code is waiting for the slave device
     * to release the clock line (SCL) and acknowledge the I2C bus
     * is ready for communication. This is crucial because the master
     * must wait for the acknowledgment before starting any
     * communication on the I2C bus.
     */
    digital_out_init( &scl_pin, i2c_master_cfg.scl );
    digital_in_init( &sda_pin, i2c_master_cfg.sda );
    digital_out_high( &scl_pin );
    while ( digital_in_read( &sda_pin ) == 0 )
    {
        digital_out_low( &scl_pin );
        Delay_1ms();
        digital_out_high( &scl_pin );
        Delay_1ms();
    }

    // I2C master open.
    if( ACQUIRE_FAIL == i2c_master_open( &i2c_master, &i2c_master_cfg )) {
        log_printf( &logger, "I2C master open failed.\n" );
        return RET_FAIL;
    }

    // Set i2c timeout.
    if( I2C_MASTER_ERROR == i2c_master_set_timeout( &i2c_master, 0 )) {
        log_printf( &logger, "I2C master set timeout failed.\n" );
        return RET_FAIL;
    }

    // I2C master set speed.
    if( I2C_MASTER_ERROR == i2c_master_set_speed( &i2c_master, I2C_MASTER_SPEED_STANDARD )) {
        log_printf( &logger, "I2C master set speed failed.\n" );
        return RET_FAIL;
    }

    // I2C master set slave address.
    if( I2C_MASTER_ERROR == i2c_master_set_slave_address( &i2c_master, I2C_MASTER_SLAVE_ADDRESS )) {
        log_printf( &logger, "I2C master set slave address failed.\n" );
        return RET_FAIL;
    }

    log_printf( &logger, "Written data:\n" );
    for( i = 0; i < ARRAY_LENGTH; i++ ) {
        if( I2C_MASTER_ERROR == i2c_demo_write( i, i )) {
            return RET_FAIL;
        }
        write_buffer[i] = i;
        if( ARRAY_LENGTH - 1 != i ) {
            log_printf( &logger, "%d, ", (uint16_t)write_buffer[i] );
        } else {
            log_printf( &logger, "%d\n", (uint16_t)write_buffer[i] );
        }
        Delay_1ms();
        if( RET_FAIL != (read_data = i2c_demo_read(i)) ) {
            read_buffer[i] = read_data;
        } else return RET_FAIL;
    }

    log_printf( &logger, "Read data:\n" );
    for( i = 0; i < ARRAY_LENGTH; i++ ) {
        if( ARRAY_LENGTH - 1 != i ) {
            log_printf( &logger, "%d, ", (uint16_t)read_buffer[i] );
        } else {
            log_printf( &logger, "%d\n", (uint16_t)read_buffer[i] );
        }
    }

    log_printf( &logger, "End of I2C Write and Read procedures.\n" );

    return 0;
}

// ----------------------------------------------------------------------- END