Special I2C Interface

Many devices that work with the Lego NXT communicate using the I2C interface. Although the Lego EV3 uses in mainly the RS232 serial communication, it can still detect when an I2C devices is plugged in the brick and set the communication protocol accordingly. The following program shows how to set-up the I2C communication for a third party device, the Microinfinity XG1300L gyroscope/accelerometer, which I use in many of my projects. This example demonstrates a method in which the device is configured once and the kernel module uses the same configuration to request data thereafter. Two variations of the program are presented, one where the program requests full data packet and another that uses a reduced data packet.


XG1300L Gyroscope/Accelerometer, Full Data Packet

/*
 * Robot Navigation Program
 * www.robotnav.com
 *
 * (C) Copyright 2013 - 2014 Navigation Solutions, LLC
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <fcntl.h>
#include <stdio.h>
#include  <string.h>
#include  <sys/mman.h>
#include  <sys/ioctl.h>
#include "lms2012.h"

//Runtime constants
const int MAX_SAMPLES  = 100;
const char XGL_PORT = 0x0; //EV3 label minus 1
const int XGL_PACKET_SIZE = 10; //2(gyyro angle) + 2(gyro rate) + 2(acc x) + 2(acc y) + 2(acc z) 

int main()
{
	//DEFINE VARIABLES
	int xgl_device_file;
	IIC     *pXgl;
	IICDAT IicDat;
	int i;
	float angle;
	float rate;
	float acc_x;
	float acc_y;
	float acc_z;

	//INITIALIZE DEVICE
	//Open the device xgl_device_file
	if((xgl_device_file = open(IIC_DEVICE_NAME, O_RDWR | O_SYNC)) == -1)
	{
		printf("Failed to open device\n");
		return -1; 
	}
	pXgl  =  (IIC*)mmap(0, sizeof(IIC), PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, xgl_device_file, 0);
	if (pXgl == MAP_FAILED)
	{
		printf("Map failed\n");
		return -1;
	}

	//SPECIAL CONFIGURATION
	//Setup IIC to read 2 packets
	IicDat.Port = XGL_PORT;
	IicDat.Time = 0;
	IicDat.Repeat = 0;
	IicDat.RdLng = XGL_PACKET_SIZE;
	IicDat.WrLng = 2;
	// Set the device I2C address
	IicDat.WrData[0] = 0x01;
	// Specify the register that will be read (0x42 = angle)
	IicDat.WrData[1] = 0x42;
	// Setup I2C comunication
	ioctl(xgl_device_file,IIC_SETUP,&IicDat);
	printf("Device is ready\n");
	
	//PROCESS SENSOR DATA
	for(i = 0;i<MAX_SAMPLES;i++)
	{
		//Compute angle, angular rate and accelerations
		acc_z = (pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][0]*256+pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][1])/100.0;
		acc_y = (pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][2]*256+pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][3])/100.0;
		acc_x = (pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][4]*256+pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][5])/100.0;
		rate =  (pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][6]*256+pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][7])/100.0;
		angle = (pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][8]*256+pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][9])/100.0;

		printf("Angle = %0.2f [deg], Rate = %0.2f [deg/s]\n", angle,rate);
		printf("AccX = %0.2f, AccY = %0.2f,AccZ = %0.2f [m/s^2g]\n\n", acc_x, acc_y, acc_z);
		sleep(1);
	}

	//CLOSE DEVICE
	printf("Clossing device\n");
	close(xgl_device_file);
	return 0;
}


XG1300L Gyroscope/Accelerometer, Limited Data Packet

#include <fcntl.h>
#include <stdio.h>
#include  <string.h>
#include  <sys/mman.h>
#include  <sys/ioctl.h>
#include "lms2012.h"

//Runtime constants
const int MAX_SAMPLES  = 100;
const char XGL_PORT = 0x0; //EV3 label minus 1
const int XGL_PACKET_SIZE = 2; //2(gyyro angle) 

int main()
{
	//DEFINE VARIABLES
	int xgl_device_file;
	IIC     *pXgl;
	IICDAT IicDat;
	int i;

	//INITIALIZE DEVICE
	//Open the device xgl_device_file
	if((xgl_device_file = open(IIC_DEVICE_NAME, O_RDWR | O_SYNC)) == -1)
	{
		printf("Failed to open device\n");
		return -1; 
	}
	pXgl  =  (IIC*)mmap(0, sizeof(IIC), PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, xgl_device_file, 0);
	if (pXgl == MAP_FAILED)
	{
		printf("Mapping device failed\n");
		return -1;
	}

	//SPECIAL CONFIGURATION
	//Setup IIC to read 2 packets
	//This part is only needed for devices that use more than one byte
	//or special configuration
	IicDat.Port = XGL_PORT;
	IicDat.Time = 0;
	IicDat.Repeat = 0;
	IicDat.RdLng = XGL_PACKET_SIZE;
	IicDat.WrLng = 2;
	// Set the device I2C address
	IicDat.WrData[0] = 0x01;
	// Specify the register that will be read (0x42 = angle)
	IicDat.WrData[1] = 0x42;
	// Setup I2C comunication
	ioctl(xgl_device_file,IIC_SETUP,&IicDat);
	printf("Device is ready\n");

	//PROCESS SENSOR DATA
	for(i = 0;i<MAX_SAMPLES;i++)
	{
		//COmpute and show angle, the units are hundreds of degress
		printf("Angle [deg]x100 =  %d\n", pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][0]*256+pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][1]);
		sleep(1);
	}

	//CLOSE DEVICE
	printf("Clossing device\n");
	close(xgl_device_file);
	return 0;
}