Skip to content

Concepts First

  • I2C: a two-wire bus (SDA data, SCL clock) with many devices, distinguished by 7-bit addresses.
  • Master/slave: the master (development board) initiates transfers and generates the clock; the slave (EEPROM) responds. The example uses address 0x50.
  • Combined transfer: one transaction can chain several messages (e.g. "send sub-address, then read/write data"); the example combines two bflb_i2c_msg_s.

Example Overview

This page is based on the i2c_eeprom example in the official Bouffalo SDK (examples/peripherals/i2c/i2c_eeprom), which demonstrates I2C master read/write with an EEPROM:

  • I2C baud rate 400 kHz, slave address 0x50 (AT24Cxx module with A0/A1/A2 grounded);
  • bflb_i2c_transfer sends a combined message: first a 2-byte sub-address (page 0), then 32 bytes of data;
  • After a delay it reads back 32 bytes with the same sub-address and compares them byte by byte.
  • Sibling examples (examples/peripherals/i2c/): i2c_10_bit (10-bit addressing), i2c_eeprom_dma (DMA EEPROM), i2c_eeprom_interrupt (interrupt EEPROM), i2c_ds3231 (RTC chip), i2c_lsm6ds3 (IMU chip), i2c_pca8553 (IO expander).

Operation Steps

1
Prepare the Hardware

Get an AT24Cxx EEPROM module (the example uses address 0x50 by default). Wiring: module SDA to the I2C0 SDA pin, SCL to the I2C0 SCL pin (see board_i2c0_gpio_init()), VCC to 3.3V, GND to GND; keep A0/A1/A2 tied low for address 0x50.

2
Enter the Example Directory

Open a terminal and enter the I2C example directory (prerequisite: set up the environment as in Quick Start (Linux) or Windows):

cd examples/peripherals/i2c/i2c_eeprom
3
Build the Project

Run the build command. The Ai-M62 (BL616) and Ai-M61 (BL618) belong to the same series, so both use bl616:

make CHIP=bl616 BOARD=bl616dk
4
Flash the Firmware

Connect the board with a USB cable, hold the BOOT button (IO2 on the Ai-M61-32S-Kit), briefly press EN/RST to enter download mode, then flash (replace the serial port with the one on your computer):

make flash CHIP=bl616 COMX=/dev/ttyUSB0
5
Run and Verify

Open a serial tool (baud rate 2000000). You should see write over (write 32 bytes) → read over (read back) → check over (byte-by-byte verification) → end. If verification fails, the exact error position is printed.

Code Execution Flow

The complete execution flow from startup to running is shown below (loop arrows mean repeated execution):

APIs Used by the Example

bflb_i2c_init(i2c, 400000)

Initializes the I2C master; the second argument is the baud rate (400 kHz).

Parameters:

  • i2c: I2C device handle (bflb_device_get_by_name("i2c0"))
  • baudrate: clock frequency, 400000 in the example

Return: 0 on success; negative error code on failure

bflb_i2c_transfer(i2c, msgs, count)

Executes a group of I2C transfers from a message array (combining "write sub-address then read/write data" into one transaction).

Parameters:

  • i2c: I2C device handle
  • msgs: struct bflb_i2c_msg_s array, each entry contains:
    • addr: slave address, e.g. 0x50
    • flags: flags, I2C_M_NOSTOP (no stop condition, to chain the next segment) or I2C_M_READ (read direction)
    • buffer: data buffer
    • length: data length
  • count: number of messages, 2 in the example

Return: 0 on success; negative error code on failure

Complete Code

The complete source below matches the effect described on this page. It is based on the official example (examples/peripherals/i2c/i2c_eeprom); the LED pins are adapted to the Ai-M61/62-32S-Kit onboard RGB LED. Collapsed by default, click to expand:

📜 Click to expand i2c_eeprom/main.c full code
c
#include "bflb_mtimer.h"
#include "bflb_i2c.h"
#include "board.h"

#define EEPROM_TRANSFER_LENGTH 32
#define EEPROM_SELECT_PAGE0    (0 << 5)

static struct bflb_device_s *i2c0;

int main(void)
{
    struct bflb_i2c_msg_s msgs[2];
    uint8_t subaddr[2] = { 0x00, EEPROM_SELECT_PAGE0};
    uint8_t write_data[256];
    uint8_t read_data[256];

    board_init();
    board_i2c0_gpio_init();

    i2c0 = bflb_device_get_by_name("i2c0");

    bflb_i2c_init(i2c0, 400000);

    /* Write and read buffer init */
    for (size_t i = 0; i < 256; i++) {
        write_data[i] = i;
        read_data[i] = 0;
    }

    /* Write page 0 */
    msgs[0].addr = 0x50;
    msgs[0].flags = I2C_M_NOSTOP;
    msgs[0].buffer = subaddr;
    msgs[0].length = 2;

    msgs[1].addr = 0x50;
    msgs[1].flags = 0;
    msgs[1].buffer = write_data;
    msgs[1].length = EEPROM_TRANSFER_LENGTH;

    bflb_i2c_transfer(i2c0, msgs, 2);
    printf("write over\r\n");
    bflb_mtimer_delay_ms(100);

    /* Read page 0 */
    msgs[1].addr = 0x50;
    msgs[1].flags = I2C_M_READ;
    msgs[1].buffer = read_data;
    msgs[1].length = EEPROM_TRANSFER_LENGTH;
    bflb_i2c_transfer(i2c0, msgs, 2);
    printf("read over\r\n");
    bflb_mtimer_delay_ms(100);

    /* Check read data */
    for (uint8_t i = 0; i < EEPROM_TRANSFER_LENGTH; i++) {
        if (write_data[i] != read_data[i]) {
            printf("check fail, %d write: %02x, read: %02x\r\n", i, write_data[i], read_data[i]);
        }
    }
    printf("check over\r\n");
    printf("end\r\n");

    while(1){
    }
}

FAQ

write over is printed but not read over

Usually a wrong EEPROM address or wiring: make sure A0/A1/A2 are low (address 0x50), SDA/SCL are connected correctly, power is 3.3V, and grounds are shared.

check fail — data read back does not match

EEPROM needs a write cycle after programming (the example already delays 100 ms). If you use another EEPROM model, check the page size and write cycle time; also make sure SCL/SDA pull-up resistors are present (built in on most modules).

No output at all

Set the baud rate to 2000000; check that the I2C0 pins are not occupied by other peripherals; if the module has address jumpers, confirm the actual address matches msgs[0].addr.

Have questions?

For any other questions, visit the unified Q&A and discussion board: Ai-Thinker Discussions

Released under the MIT License. Build Time 2026-09-11 14:52:23