Go to content Go to menu

RX2635H using the ITG-3205 mems gyro

Sunday, April 12, 2015

ITG3205_axis.png One of the important parts of a quadcopter controller is a gyro. The RX2635H uses an ITG-3205 from INVENSENSE. Accessing it is very simple as it uses the I2C interface (Two Wire Interface - TWI on the XMEGA) to read the X, Y and Z values of the gyro.
 
 
 
 
 
 
 
 
 

This post is part of a series

  1. Flashing new Firmware to Walkera RX/TX without UP02
  2. Decrypting receiver firmware
  3. Walkera receiver components
  4. Hello World firmware for the RX2635H board
  5. Serial port and external 16MHz oscillator
  6. Using the ITG-3205 mems gyro (this post)
  7. Walkera UP02 software clone: UP42
  8. Walkera RX2635H as generic development board?
  9. Walkera USB port
  10. Walkera + Arduino = Walkino

The ITG-3205 is connected to the XMEGA I2C (TWI) pins on PORTE. The following sample application reads the chip ID and the X, Y and Z values via I2C and prints it on the serial console. The ITG3-205 can have the 7bit I2C addresses 0×68 or 0×69 depending on pin 9. On the RX2635H board this pin is low (0) so it uses the I2C address 0×68.


RX2635H-D-ITG3205.jpg    ITG3205_out.png

The RX2635H board image shows the location of the ITG-3205 and also its X, Y and Z sensitivity directions as well as the I2C data (SDA) and clock (SCL) lines.

Be sure to include a printf library (e.g. printf_min) in your project as it uses the printf C library function for output of the sensor values. You can download the complete AVR Studio solution here.

#include <avr/io.h>
#include <string.h>
#include <stdio.h>

// 16MHz CPU speed using external oscillator
#define F_CPU 16000000UL

char b = 1;

// Some defines and macros for calculating the I2C bus speed
// We use 100kHz for the I2C bus on XMEGA port E
#define I2C_E_BAUDRATE			100000
#define I2C_BAUD(F_SYS, F_TWI)	((F_SYS / (2 * F_TWI)) - 5)
#define I2C_E_BAUD				I2C_BAUD(F_CPU, I2C_E_BAUDRATE)

// ITG-3205 can have the 7bit I2C addresses 0x68 or 0x69 depending on 
// ITG-3205 pin 9. On the RX2635H board this pin is low (0) so it has 
// the I2C address 0x68. The address 0x68 is shifted 1 bit to the 
// left because of the I2C read/write bit which gives 0xD0.
#define ITG3205_ADDR			0xD0

// buffer for reading and writing data on the I2C bus
uint8_t buffer[8];

// --------------------------------------------------------------------
// 16MHz external resonator setup

void setupOsc(void)
{
	//16MHz external crystal
	OSC_XOSCCTRL = OSC_FRQRANGE_12TO16_gc | OSC_XOSCSEL_XTAL_16KCLK_gc;

	//Enable external oscillator
	OSC_CTRL |= OSC_XOSCEN_bm;

	//Wait for clock stabilization
	while(!(OSC_STATUS & OSC_XOSCRDY_bm));

	// Selects clock system as external clock
	// through change protection mechanism
	CCP = CCP_IOREG_gc;
	CLK_CTRL = CLK_SCLKSEL_XOSC_gc;
}

// --------------------------------------------------------------------
// red LED on PD4

void setupLED(void)
{
	// PD4 = LED output
	PORTD_OUTSET = PIN4_bm;
	PORTD_DIRSET = PIN4_bm;
}

void LEDon(void)
{
	PORTD.OUTCLR = PIN4_bm;
}

void LEDoff(void)
{
	PORTD.OUTSET = PIN4_bm;
}

// --------------------------------------------------------------------
// 2nd serial port on PD6, PD7

void setupSerial(void)
{
	// PD7 = RS232 TX output
	PORTD_OUTSET = PIN7_bm;
	PORTD_DIRSET = PIN7_bm;

	// PD6 = RS232 RX input
	PORTD_OUTCLR = PIN6_bm;
	PORTD_DIRCLR = PIN6_bm;

	// calculate 9600 baud
	// BSEL = (16000000 / (2^0 * 16 * 9600) - 1 = 103,1666
	// BSCALE = 0
	// FBAUD = (16000000 / (2^0 * 16 * (103 + 1)) = 9615.384
	USARTD1_BAUDCTRLB = 0;
	USARTD1_BAUDCTRLA = 0x67; // 103

	// Disable interrupts, just for safety
	USARTD1_CTRLA = 0;

	// 8 data bits, no parity and 1 stop bit
	USARTD1_CTRLC = USART_CHSIZE_8BIT_gc;

	// enable receive and transmit
	USARTD1_CTRLB = USART_TXEN_bm | USART_RXEN_bm;
}

void sendChar(char c)
{
	while( !(USARTD1_STATUS & USART_DREIF_bm) );

	USARTD1_DATA = c;
}

static int sendCharStream(char c, FILE *stream)
{
	if(c == 'n')
		sendCharStream('r', stream);

	sendChar(c);

	return 0;
}

void sendString(const char *text)
{
	while(*text)
	sendChar(*text++);
}

char receiveChar(void)
{
	while( !(USARTD1_STATUS & USART_RXCIF_bm) );

	return USARTD1_DATA;
}

int receiveCharStream(FILE *stream)
{
	char c = receiveChar();	

	if(c == 'r')
		c = 'n';

	// Send to console what has been received, so we can 
	// see when typing
	sendCharStream(c, stream);

	return c;
}

// --------------------------------------------------------------------
// I2C interface on  PORTE - connected to ITG-3205 gyro

void setupI2C_E()
{
	TWIE.MASTER.CTRLB = TWI_MASTER_SMEN_bm;
	TWIE.MASTER.BAUD = I2C_E_BAUD;
	TWIE.MASTER.CTRLA = TWI_MASTER_ENABLE_bm;
	TWIE.MASTER.STATUS = TWI_MASTER_BUSSTATE_IDLE_gc;
}

void writeI2C_E(uint8_t slaveAddr, 
		uint8_t addr, uint8_t *buffer, uint8_t len)
{
	TWIE.MASTER.ADDR = slaveAddr;
	while( !(TWIE.MASTER.STATUS & TWI_MASTER_WIF_bm) );

	TWIE.MASTER.DATA = addr;
	while( !(TWIE.MASTER.STATUS & TWI_MASTER_WIF_bm) );

	for(uint8_t i = 0; i < len; i++)
	{
		TWIE.MASTER.DATA = buffer[i];
		while( !(TWIE.MASTER.STATUS & TWI_MASTER_WIF_bm) );
	}

	TWIE.MASTER.CTRLC = TWI_MASTER_CMD_STOP_gc;
}

void readI2C_E(uint8_t slaveAddr, 
		uint8_t addr, uint8_t *buffer, uint8_t len)
{
	uint8_t slaveReadAddr = slaveAddr | 0x01;

	TWIE.MASTER.ADDR = slaveAddr;
	while( !(TWIE.MASTER.STATUS & TWI_MASTER_WIF_bm) );

	TWIE.MASTER.DATA = addr;
	while( !(TWIE.MASTER.STATUS & TWI_MASTER_WIF_bm) );

	TWIE.MASTER.ADDR = slaveReadAddr;

	for(uint8_t i = 0; i < len; i++)
	{
		while( !(TWIE.MASTER.STATUS & TWI_MASTER_RIF_bm) );

		if((i + 1) == len)
			TWIE.MASTER.CTRLC |= TWI_MASTER_ACKACT_bm;
		else
			TWIE.MASTER.CTRLC &= ~TWI_MASTER_ACKACT_bm;

		buffer[i] = TWIE.MASTER.DATA;
	}
}

// --------------------------------------------------------------------
// main part
// use printf to print X,Y and Z values from the gyro to the 
// serial port

FILE serialStream = FDEV_SETUP_STREAM(sendCharStream, 
							receiveCharStream, _FDEV_SETUP_RW);

int main(void)
{
	int16_t T;
	int16_t X;
	int16_t Y;
	int16_t Z;

	setupOsc();
	setupLED();
	setupSerial();
	stdout = stdin = &serialStream;
	setupI2C_E();

	printf("\r\nITG-3205 Gyro Test\r\n");

	// read ID from gyro
	// see page 23 of ITG-3205 manual
	readI2C_E(ITG3205_ADDR, 0x00, buffer, 1);
	printf("ID=(0x%02x)\r\n", buffer[0]);

	while(1)
	{
		memset(&buffer, 0, sizeof(buffer));

		// read Temperature, X, Y and Z values from gyro
		// see page 27 of ITG-3205 manual
		readI2C_E(ITG3205_ADDR, 0x1B, buffer, 8);
		T = (buffer[0] << 8) + buffer[1];
		X = (buffer[2] << 8) + buffer[3];
		Y = (buffer[4] << 8) + buffer[5];
		Z = (buffer[6] << 8) + buffer[7];
		printf("TEMP=(%6d), X=(%6d), Y=(%6d), Z=(%6d)     \r", 
			T, X, Y, Z);

		if(b) LEDon(); else LEDoff();
		b = !b;
	}
}