# How to use the I2C ports

<abstract>
This article illustrates how to use the I2C on Acme Systems Linux boards based on Microchip
SAMG25 (Aria, Arietta) and SAMA5D3x (Acqua) CPUs
</abstract>

For the RoadRunner SOM (SAMA5D27) please read [this article](/roadrunner_i2c).

## Pinout of I2C ports

This is the list of I2C ports implemented in hardware. Any other GPIO pin can be used as I2C 
in bitbanging mode.

| Signal     | Dir | Description                 | Acqua        | Aria G25   | Arietta      |
|------------|-----|-----------------------------|--------------|------------|--------------|
| TWD0       | I/O | Serial data                 | J3.42 (PA30) | W17 (PA30) | J4.14 (PA30) |
| TWCK0      | O   | Clock                       | J3.41 (PA31) | W18 (PA31) | J4.12 (PA31) |
| TWD1       | I/O | Serial data                 | J3.26 (PC26) | N2 (PC0)   | J4.39 (PC0)  |
| TWCK1      | O   | Clock                       | J3.28 (PA27) | N3 (PC1)   | J4.37 (PC1)  |
| TWD2       | I/O | Serial data                 | J3.36 (PA18) |            |              |
| TWCK2      | O   | Clock                       | J3.41 (PA31) |            |              |

## Linux Kernel modules to activate

Probably the Kernel used on your Acme Board is already configured to have 
the I2C bus enabled. To check it just type:

	ls /dev/i2c*
	/dev/i2c-0  /dev/i2c-1

in this case two busses are already configured on your board. To know on which pins are available the I2C signals, 
read the pinout section of this page.

However if no device is present you have to check the Kernel drivers setup and the device tree contents.

Follow this tutorial: @h1='compile_linux_kernel' to know how to cross compile the Linux Kernel
and how to configure the drivers to enable inside it.

Inside the <b>make menuconfig</b> enable the following items:

	Device drivers --->
			I2C support  --->
				<*> I2C support
					[*]   Enable compatibility bits for old user-space
					<*>   I2C device interface
					<*>   I2C bus multiplexing support
							Multiplexer I2C Chip support  --->
					[*]   Autoselect pertinent helper modules
							I2C Hardware Bus support  --->
								<*> Atmel AT91 I2C Two-Wire interface (TWI)
								<*> GPIO-based bitbanging I2C

then compile the Kernel image, save it on the microsd and reboot.

## Using I2C from user space

### i2c-tools

The faster way to do the first experiments with this board is by 
installing and using the [i2c-tools](http://packages.debian.org/squeeze/i2c-tools). 

i2c-tools is a package contains a heterogeneous set of I2C tools for Linux such as: 

*  a bus probing tool 
*  a chip dumper
*  a register-level access helpers
*  an EEPROM decoding scripts
*  ...and more 

To install i2c-tools on the FOX Board just type: 

	sudo apt update
	sudo apt install i2c-tools

## Using i2cdetect

i2cdetect is an userspace program to scan an I2C bus for devices. 
It outputs a table with the list of detected devices on the specified bus.

*  [i2cdetect man page](http://man.cx/i2cdetect)

Example of use:

	sudo i2cdetect -y 0
	
	     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f                             
	00:          -- -- -- -- -- -- -- -- -- -- -- -- --                             
	10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --                             
	20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --                             
	30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --                             
	40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --                             
	50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --                             
	60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --                             
	70: -- -- -- -- -- -- -- --                                                     

In this case a device has been detected on address 20 hex. 

### i2cset and i2cset

[i2cset](http://man.cx/i2cset) is a small helper program to set 
registers visible through the I2C bus.

The follow simple command writes the byte value 255 to the I2C 
device at address 20 hex on the i2c bus 0 (<b>/dev/i2c-0</b>). 

	sudo i2cset -y 0 0x20 255

If for example you are using a [DAISY-22](/DAISY-22) module with a 
PCF8574 I2C I/O expander this command will set all the GPIO lines to 1.

[i2cget](http://man.cx/i2cset) i2cget is a small helper program to 
read registers visible through the I2C bus.

The follow simple command read a byte from an I2C 
device at address 20 hex on the i2c bus 0 (<b>/dev/i2c-0</b>). 

	sudo i2cget -y 0 0x20 0x01

### Python code example

python-smbus is a Python module allows SMBus access through the I2C /dev interface on Linux hosts. 
The host kernel must have I2C support, I2C device interface support, and a bus adapter driver.

#### Write a register

The following example sends a sequence of values from 0 to 255 to the PCF8574 I2C I/O expander
at address 0x20.

	This example will be available as soon as possible

Run it by typing:

	python write.py

#### Read a register

The following read the GPIO status of a PCF8574 I2C I/O expander at address 0x20.
Note that we have to write <b>1</b> on the input line we want to read.

	import smbus
	 
	I2C_ADDRESS = 0x20 
	 
	bus = smbus.SMBus(0)
	 
	#Set all ports in input mode
	bus.write_byte(I2C_ADDRESS,0xFF)
	
	#Read all the unput lines
	value=bus.read_byte(I2C_ADDRESS)
	print "%02X" % value


Run it by typing:

	python read.py

### C code example

#### Write a register

The following example sends a sequence of values from 0 to 255 to the PCF8574 I2C I/O expander
at address 0x20 in C language.

	#include <stdio.h>
	#include <fcntl.h>
	#include <linux/i2c-dev.h>
	#include <errno.h>
	#include <string.h> 
	#include <sys/ioctl.h> 
	#include <unistd.h>
	
	#define I2C_ADDR 0x20
	 
	int main (void) {
		int value;
		int fd;
	
		fd = open("/dev/i2c-0", O_RDWR);
	
		if (fd < 0) {
			printf("Error opening file: %s\n", strerror(errno));
			return 1;
		}
	
		if (ioctl(fd, I2C_SLAVE, I2C_ADDR) < 0) {
			printf("ioctl error: %s\n", strerror(errno));
			return 1;
		}
	
		for (value=0; value<=255; value++) {
			if (write(fd, &value, 1) != 1) {
				printf("Error writing file: %s\n", strerror(errno));
			}
			usleep(100000);
		}
		return 0;
	}

Compile it by typing:

	gcc write.c -o write

Then launch it:

	./write

#### Read a register

The following example get the state of the GPIO line from a PCF8574 I2C I/O expander
at address 0x20.

	#include <stdio.h>
	#include <fcntl.h>
	#include <linux/i2c-dev.h>
	#include <errno.h>
	#include <string.h> 
	#include <sys/ioctl.h> 
	#include <unistd.h>
	
	#define I2C_ADDR 0x20
	 
	int main (void) {
		char buffer[1];
		int fd;
	
		fd = open("/dev/i2c-0", O_RDWR);
	
		if (fd < 0) {
			printf("Error opening file: %s\n", strerror(errno));
			return 1;
		}
	
		if (ioctl(fd, I2C_SLAVE, I2C_ADDR) < 0) {
			printf("ioctl error: %s\n", strerror(errno));
			return 1;
		}
	
		buffer[0]=0xFF;
		write(fd, buffer, 1);
		
		read(fd, buffer, 1);
		printf("0x%02X\n", buffer[0]);
		return 0;
	}
Compile it by typing:

	gcc read.c -o read

Then launch it:

	./read

## Examples

* @article='pca9685'

## Links

* [I2C device tree Kernel Doc](https://www.kernel.org/doc/Documentation/devicetree/bindings/i2c/i2c-gpio.txt)
* [Using the I2C on Roadrunner SOM](/roadrunner_i2c)
* [How to Use the SAMA5D2 I2C Under Linux](https://ww1.microchip.com/downloads/en/Appnotes/AN_3252-How-to-Use-SAMA5D2-I2C-underLinux-00003252a.pdf)


@include='bio_tanzilli'