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_transfersends 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
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.
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_eepromRun the build command. The Ai-M62 (BL616) and Ai-M61 (BL618) belong to the same series, so both use bl616:
make CHIP=bl616 BOARD=bl616dkConnect 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/ttyUSB0Open 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,400000in 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 handlemsgs:struct bflb_i2c_msg_sarray, each entry contains:addr: slave address, e.g.0x50flags: flags,I2C_M_NOSTOP(no stop condition, to chain the next segment) orI2C_M_READ(read direction)buffer: data bufferlength: data length
count: number of messages,2in 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
#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.
Related Best Practices
Have questions?
For any other questions, visit the unified Q&A and discussion board: Ai-Thinker Discussions

