This is the multi-page printable view of this section. Click here to print...

Return to the regular view of this page

As of 2025-07-24

Wire

Read/write as 2-wire serial (I2C) master (controller) (mwx::periph_wire)
Performs read/write operations as a 2-wire serial (I2C) master (controller).

Definition

Alias Definition

using TwoWire = mwx::periph_twowire<MWX_TWOWIRE_RCVBUFF>;

mwx::periph_wire<MWX_TWOWIRE_RCVBUFF> can be referenced as TwoWire.

Type Definitions

The following typedefs are used for argument and return types:

typedef uint8_t size_type;
typedef uint8_t value_type;

Notes

Initialization and Termination

Creating a Wire instance

The instance and necessary initialization are handled within the library. In user code, call Wire.begin() to start using it.

When using the requestFrom() method, you can specify the size of a FIFO queue for temporary data storage. At compile time, set the number of bytes via the macro MWX_TWOWIRE_BUFF. The default is 32 bytes.

Example: -DMWX_TWOWIRE_BUFF=16

begin()

void begin(
    const size_type u8mode = WIRE_100KHZ,
    bool b_portalt = false)

Initializes the hardware.

ParameterDescription
u8modeSpecifies the bus frequency. Default is 100KHz (WIRE_CONF::WIRE_100KHZ).
You can specify WIRE_CONF::WIRE_??KHZ where ?? can be 50, 66, 80, 100, 133, 160, 200, 266, 320, 400.
b_portaltChanges the hardware pin assignment.

Example

void setup() {
    ...
    Wire.begin();
    ...
}

void wakeup() {
    ...
    Wire.begin();
    ...
}

Reading and Writing

There are two procedures for reading and writing. Use either as needed.

Others

Probe (Device Presence Check)

bool probe(uint8_t address)

Checks if the device specified by address responds. Returns true if the device exists.

setClock()

void setClock(uint32_t speed)

This is intended to change the bus frequency, but it performs no action.

1 - Wire (Member Function Version)

Wire (using member functions)

This method using member functions has relatively low abstraction and follows a general API structure similar to that provided by C language libraries. It offers a more intuitive procedure for operating a two-wire serial bus.

However, you need to explicitly manage the start and end of bus usage.

Reading

requestFrom()

size_type requestFrom(
    uint8_t u8address,
    size_type length,
    bool b_send_stop = true)

Reads a specified number of bytes in one operation. The result is stored in a queue, so you should call the .read() method repeatedly until the queue is empty immediately afterward.

ParameterDescription
u8addressI2C address to read from
lengthNumber of bytes to read
b_send_stop=trueIf true, a STOP bit is issued at the end of reading
Return type size_typeNumber of bytes read. 0 indicates failure

Code Example

int len = Wire.requestFrom(0x70, 6);
for (int i = 0; i < 6; i++) {
  if (Wire.available()) {
    au8data[i] = Wire.read();
    Serial.print(buff[i], HEX);
  }
}
// skip the rest (just in case)
// while (Wire.available()) Wire.read(); // normally, not necessary.

Writing

The writing process starts with beginTransmission(), then proceeds with the write() method. After the entire write operation is complete, call endTransmission().

#define DEV_ADDR (0x70)
const uint8_t msg[2] =
  {SHTC3_SOFT_RST_H, SHTC3_SOFT_RST_L};

Wire.beginTransmission(DEV_ADDR);
Wire.write(msg, sizeof(msg));
Wire.endTransmission();

beginTransmission()

void beginTransmission(uint8_t address)

Initializes a write transfer. After the write process, call endTransmission() promptly.

ParameterDescription
u8addressI2C address to write to

write(value)

size_type write(const value_type value)

Writes a single byte.

ParameterDescription
valueByte to write
Return size_typeNumber of bytes written. 0 indicates an error.

write(*value, quantity)

size_type write(
  const value_type* value,
  size_type quantity)

Writes a sequence of bytes.

ParameterDescription
*valueByte sequence to write
size_typeNumber of bytes
Return size_typeNumber of bytes written. 0 indicates an error.

endTransmission()

uint8_t endTransmission(bool sendStop = true)

Finalizes the write operation.

ParameterDescription
sendStop = trueIssues a STOP bit
Return uint8_t0: success, 4: failure

2 - Wire (Helper Class Version)

Wire (How to use with helper classes)
The helper class version is a more abstract implementation. Generating objects reader, writer that correspond to reading and writing marks the start of bus usage, and destroying the object performs the bus usage termination procedure.

By creating objects inside the condition expression of an if statement, the object’s lifetime is limited to the scope of the if block. When exiting the if block, the object is destroyed, and at that time, the bus usage termination procedure is performed.

if (auto&& wrt = Wire.get_writer(...)) { // Object creation and device communication check
   // The scope (curly braces) is the lifetime of wrt.
   wrt << 0x00; // Write 0x00 using the mwx::stream interface
}
// wrt is destroyed when exiting the if block, and bus termination is performed

Also, since the read/write objects implement the mwx::stream interface, operators like << can be used.

  • Matching the start and end of bus usage with the object’s lifetime improves code readability and prevents omission of termination procedures.
  • Unified reading and writing procedures via the mwx::stream interface.

Reading

This is a reading method using helper classes to perform reading and its termination procedure within a scope if() { ... }.

const uint8_t DEV_ADDR = 0x70;
uint8_t au8data[6];
if (auto&& rdr = Wire.get_reader(DEV_ADDR, 6)) {
		for (auto&& c: au8data) {
			c = rdr();
		}
}

// same above
uint16_t u16temp, u16humd;
uint8_t u8temp_csum, u8humd_csum;
if (auto&& rdr = Wire.get_reader(SHTC3_ADDRESS, 6)) {
		rdr >> u16temp;
		rdr >> u8temp_csum;
		rdr >> u16humd;
		rdr >> u8humd_csum;
}

Above, the rdr object generated by the get_reader() method is used to read one byte at a time. The method parameter specifies the two-wire serial ID to read.

  1. The rdr object is created inside if(...). (The type is resolved as a universal reference auto&& by type inference.)
  2. The created rdr object defines operator bool () and is used for evaluation in the condition. If communication is possible with the specified ID, it returns true.
  3. The rdr object defines int operator () (void), which reads one byte from the two-wire serial bus when called. Returns -1 on failure, or the read byte value on success.
  4. The destructor of rdr is called at the end of the if() { ... } scope, issuing a STOP on the two-wire serial bus.

get_reader(addr, read_count=0)

periphe_wire::reader
get_reader(uint8_t addr, uint8_t read_count = 0)

Obtains a worker object used for I2C reading.

ParameterDescription
addrI2C address for reading
read_countNumber of bytes to read (if specified, a STOP bit is issued at the end of the transfer). If 0 is specified, no STOP bit is issued (some devices may work without it).

Writing (writer)

This is a writing method using helper classes to perform writing and its termination procedure within a scope if() { ... }.

const uint8_t DEV_ADDR = 0x70;
if (auto&& wrt = Wire.get_writer(DEV_ADDR)) {
	wrt(SHTC3_TRIG_H);
	wrt(SHTC3_TRIG_L);
}

// same above
if (auto&& wrt = Wire.get_writer(DEV_ADDR)) {
	wrt << SHTC3_TRIG_H; // int type is handled as uint8_t
	wrt << SHTC3_TRIG_L;
}

Above, the wrt object generated by the get_writer() method is used to write one byte at a time. The method parameter specifies the two-wire serial ID to write.

  1. The wrt object is created inside if(...). (The type is resolved as auto to avoid long type names.)
  2. The created wrt object defines operator bool () and is used for evaluation in the condition. If communication is possible with the specified ID, it returns true.
  3. The wrt object defines int operator () (void), which writes one byte to the two-wire serial bus when called. Returns -1 on failure, or the written byte value on success.
  4. The destructor of wrt is called at the end of the if() { ... } scope, issuing a STOP on the two-wire serial bus.

get_writer()

periph_wire::writer
get_writer(uint8_t addr)

Obtains a worker object used for I2C writing.

ParameterDescription
addrI2C address for writing

Worker Object (writer)

<< operator

operator << (int c)
operator << (uint8_t c)
operator << (uint16_t c)
operator << (uint32_t c)

int and uint8_t types transfer 8 bits. Data order is big-endian (higher byte transferred first).

() operator

operator() (uint8_t val)
operator() (int val)

Writes one byte.

Worker Object (reader)

>> operator

operator >> (uint8_t& c)
operator >> (uint16_t& c)
operator >> (uint32_t& c)
operator >> (uint8_t(&c)[N]) // fixed array of N bytes

Reads the size of each data type. Data order is big-endian (first transferred byte is stored in the higher byte).

() operator

int operator() (bool b_stop = false)

// example
uint8_t dat[6];
if (auto&& rdr = Wire.get_reader(0x70)) {
  for(uint8_t& x : dat) {
    x = rdr();
  }
}

Reads one byte. Returns -1 on error, or the read byte on success.

If b_stop is set to true, a STOP bit is issued on that read.

Example

The following example is a measurement example for the environmental sensor pal’s temperature and humidity sensor SHTC3.

Wire.begin();
// reset (may not necessary...)
if (auto&& wrt = Wire.get_writer(0x70)) {
	wrt << 0x80; // SHTC3_SOFT_RST_H
	wrt << 0x05; // SHTC3_SOFT_RST_L
}

delay(5); // wait some

// start read
if (auto&& wrt = Wire.get_writer(0x70)) {
	wrt << 0x60; // SHTC3_TRIG_H
	wrt << 0x9C; // SHTC3_TRIG_L
}

delay(10); // wait some

// read result
uint16_t u16temp, u16humd;
uint8_t u8temp_csum, u8humd_csum;
if (auto&& rdr = Wire.get_reader(0x70, 6)) {
	rdr >> u16temp;
	rdr >> u8temp_csum;
	rdr >> u16humd;
	rdr >> u8humd_csum;
}

// checksum 0x31, init=0xFF
if (CRC8_u8CalcU16(u16temp, 0xff) != u8temp_csum) {
	Serial << format("{SHTC3 T CKSUM %x}", u8temp_csum); }
if (CRC8_u8CalcU16(u16humd, 0xff) != u8humd_csum) {
	Serial << format("{SHTC3 H CKSUM %x}", u8humd_csum); }

// calc temp/humid (degC x 100, % x 100)
int16_t i16Temp = (int16_t)(-4500 + ((17500 * int32_t(u16temp)) >> 16));
int16_t i16Humd = (int16_t)((int32_t(u16humd) * 10000) >> 16);

Serial << "temp=" << int(i16Temp)
	   << ",humid=" << int(i16Humd) << mwx::crlf;