The SeeSaw operates as an I2C secondary device using standard I2C protocol. It uses the SDA and SCL pins to communicate with the host system.

The I2C bus on the SAMD09 is 3.3V logic level, but all boards other than the SAMD09 breakout have level shifting so you can use 3 or 5V logic. Boards with Attiny chips are 3 or 5V safe so you can use either for power and logic

Only 7-bit addressing is supported.

I2C pullup resistors are included in our SeeSaw boards but if you are DIY'ing, be sure to add your own! 2.2K - 10K is a good range.

Setting the Device Address

Standard 7-bit addressing is used. The seesaw's default I2C address is initially configured in the compiled firmware (e.g for theSeeSaw breakouts we use 0x49) but other boards will have a different base address. Check the board documentation for the default base I2C address, or you can plug it in and scan the I2C bus to find it.

This address can be modified using the address select pins, there can be multiple address pins. If address select pin 0 (A0) is tied to ground on boot, the I2C address is incremented by 1. If address select pin 1 (A1) is pulled low, the I2C address is incremented by 2. If both address select pins are pulled low, the I2C address is incremented by 3. Thus you can, with the same hardware, have up to 4 devices

On both the SAMD09 and Attiny817 breakouts, the default A0 pin is 16, default A1 pin is 17. On boards where the chips are embedded, there may be as many as 4 address pins, they'll be labeled with jumpers

The base I2C address can also be modified by writing a new address to EEPROM. See the EEPROM section for more information.

I2C Transactions

We recommend using 100KHz I2C, but speeds of up to 400KHz are supported. You may want to decrease the SDA/SCL pullups to 2.2K from 10K in that case.

Writing Data

A seesaw write command consists of the standard I2C write header (with the R/W bit set to 0), followed by 2 register bytes followed by zero or more data bytes.

The first register byte is the module base register address. Each module (GPIO, ADC, DAC, etc.) has it's own unique 8 bit base identifier.

The second register byte is the module function register address. This byte specifies the desired register within the module to be written.

Thus we have up to 254 modules available (0x00 is reserved) and 255 functions per module - plenty to allow all sorts of different capabilities!

In code, this may look like this (using the Arduino wire I2C object):

void Adafruit_seesaw::write(uint8_t moduleBase, uint8_t moduleFunction, uint8_t *buf, uint8_t num)
{ 
	Wire.beginTransmission((uint8_t)_i2caddr);
	Wire.write((uint8_t)moduleBase); //module base register address
	Wire.write((uint8_t)moduleFunction); //module function register address
	Wire.write((uint8_t *)buf, num); //data bytes
	Wire.endTransmission();
}
The Arduino UNO Wire library implementation has a limit of 32 bytes per transaction so be aware you may not be able to read/write more than that amount. We have designed the library to work within those constraints

Base Register Summary

The following table summarizes the module base registers addresses. Further details about the function registers associated for each base register are covered in later sections.

Not all seesaw products implement all of these features.

Base Register Address

Module

0x00

Status

0x01

GPIO

0x02 - 0x07

SERCOM

0x08

PWM

0x09

ADC

0x0A

DAC

0x0B

Interrupt

0x0C

DAP

0x0D

EEPROM

0x0E

NeoPixel

0x0F

Touch

0x10

Keypad

0x11

Encoder

Reading Data

A register read is accomplished by first sending the standard I2C write header, followed by the two register bytes corresponding to the data to be read. Allow a short delay, and then send a standard I2C read header (with the R/W bit set to 1) to read the data.

The length of the required delay depends on the data that is to be read. These delays are discussed in the sections specific to each module.

In code, this may look like this  (using the Arduino wire I2C object):

void Adafruit_seesaw::read(uint8_t moduleBase, uint8_t moduleFunction, uint8_t *buf, uint8_t num, uint16_t delay)
{
  Wire.beginTransmission((uint8_t)_i2caddr);
  Wire.write((uint8_t)moduleBase); //module base register address
  Wire.write((uint8_t)moduleFunction); //module function register address
  Wire.endTransmission();

  delayMicroseconds(delay);

  Wire.requestFrom((uint8_t)_i2caddr, num);

  for(int i=0; i<num; i++){
    buf[i] = Wire.read();
  }
}

This guide was first published on Oct 20, 2021. It was last updated on Dec 04, 2023.

This page (Reading and Writing Data) was last updated on Sep 19, 2023.

Text editor powered by tinymce.