Lab Assignment: I2C

I2C Code Assignment

Assignment Outline

This is a group of two assignment; submit one copy of code per team and put down the names of your group members as part of the source code you turn in. Only turn in the new code you added, not the entire file.

  • The I2C#2 driver is already implemented and used for on-board sensors.
  • Study the existing I2C code: i2c_base.cpp. Please ask any questions if you have any, but the driver was implemented using the state machine diagrams given at the below wikipedia page.
  • On your master board, you can just use i2c terminal command to write a register to the other board which is acting as a slave. Hence, you only need to write code on one board (I2C slave board).


Design an I2C slave interface, and use one person's board as MASTER and communicate with the second person's SLAVE board. Here are the guidelines: Extend the I2C base class to also support slave operation. Test your I2C driver by using one board as a master, and another board as a slave.

  1. Study i2c_base.cpp, particularly the following methods:
    • init()
    • i2cStateMachine()
      Note that this function is called by the hardware interrupt asynchronously whenever I2C state changes.
      The other I2C master will simply "kick off" the START state, and this function carries the hardware through its states to carry out the transaction.
    • The functions you add to this base class are accessible by the I2C2 instance.
  2. Add initSlave() method to the I2C to initialize the slave operation.
    • Allow the user to supply a memory to be read or written by another master.
  3. Extend the state machine for I2C slave operation.
    • Study the CPU user manual first, and create a state machine diagram on paper.
    • The first register supplied after the slave address should be used as an "offset" of the memory to read or write.
  4. Demonstrate the following :
    • Demonstrate that you are able to read and write the slave memory.
    • For extra credit and bragging rights, create state machine diagrams, and if you can make better ones, I will use your diagrams at this wikipedia page :)

Sample Code

#include "i2c2.hpp"
#include <stdint.h>
#include <stdio.h>

int main(void)
    I2C2& i2c = I2C2::getInstance(); // Get I2C driver instance
    const uint8_t slaveAddr = 0xC0;  // Pick any address other than the used used at i2c2.hpp
    uint8_t buffer[256] = { 0 };     // Our slave read/write buffer

    // high_level_init() will init() I2C, let's init slave
    i2c.initSlave(slaveAddr, &buffer, sizeof(buffer));

    // I2C interrupt will (should) modify our buffer.
    // So just monitor our buffer, and print and/or light up LEDs
    // ie: If buffer[0] == 0, then LED ON, else LED OFF
    uint8_t prev = buffer[0];
        if (prev != buffer[0]) {
            prev = buffer[0];
            printf("buffer[0] changed to %#x\n", buffer[0]);

    return 0;


Since the I2C state machine function is called from inside an interrupt, you may not be able to to use printf(), especially if you are running FreeRTOS. As an alternative, use the debug printf methods from the printf_lib.h file.


  • Start by hooking up master microcontroller running the default, unmodified sample FreeRTOS project
  • Familiarize yourself with the master microcontroller I2C commands: "help i2c"
  • Initialize the slave microcontroller's slave address such that you will get an interrupt when your address is sent by the master microcontroller
  • Add printfs to the I2C state machine code to identify what states you enter when the other master microcontroller is trying to do an I2C transaction
  • Follow your diagram and figure out how to make the I2C slave state machine walk through to read and write registers
Back to top