|
|
View previous topic :: View next topic |
Author |
Message |
simonspt
Joined: 12 Feb 2012 Posts: 10
|
Driver for ITG3200 digital gyroscope |
Posted: Sun Mar 04, 2012 6:21 pm |
|
|
Hi there!
I was planning to build a board with an ITG3200 gyroscope and some other sensors. I noticed that there isn't a complete driver for this gyroscope, so I decided to write my own driver based on datasheet informations.
I'm planning to test it as soon as my ITG3200 breakboard arrives, so i hope soon.
If somebody already have this gyroscope and wants to test this driver, it's very appreciated.
This is the first version. Any suggestion to make it better is very much appreciated.
If you find any error in the code please tell me!
Code: |
//DRIVER BASED ON PS-ITG-3200-00-01.4.pdf DATASHEET FILE
//PLEASE REFER TO THIS LINK http://invensense.com/mems/gyro/documents/PS-ITG-3200-00-01.4.pdf
//Driver by Simons © 2012
//Driver version: 1.0
//Please include this header if you want to use this driver
/*
FUNCTION DESCRIPTION:
Whenever an address is required as a function param, all register constants below can be used
NOTE: not all registers can be written, below there's a list of all R/W register and R/O registers.
int8 itg3200_read_who_am_i() returns the device address
void itg3200_write_who_am_i(int8 addr) writes 'addr' address to the WHO_AM_I register
the power-on reset value of WHO_AM_I <6:1> is 110100
void itg3200_write_reg(int8 ADDR, int8 VAL) writes VAL value to ADDR register
int8 itg3200_read_reg(int8 ADDR) reads the current value of ADDR register
void itg3200_init_setup() is used to set all init parameter of the device. Call to itg3200_init() is required after this function (read below)
void itg3200_init() must be called after itg3200_init_setup() to ensure a proper device initialization
void itg3200_get_data() reads all gyro's data from temperature to axis rates and stores it
in itg3200_output structure.
Please refer to the structure declaration below to access each individual parameters
signed int16 itg3200_get_rate_x()
signed int16 itg3200_get_rate_y()
signed int16 itg3200_get_rate_z() each function returns respectively X,Y and Z raw angular rates
signed int16 itg3200_get_temp() returns current device raw temperature
float itg3200_get_angular_rate(signed int16 VAL) returns the angular rate in °/s from VAL raw rate
float itg3200_get_temp_degrees(signed int16 VAL) returns the current device temperature in °C from VAL raw temperature value
void itg3200_reset() use this function to reset all parameters and registers to default power-on value
void itg3200_standby() puts all gyros in standby
void itg3200_sleep() puts the device in sleep mode leaving active only serial link and internal registers
void itg3200_wakeup() wakes up the device from the sleep mode, also put all gyros in normal mode
EXAMPLE USAGE:
//OUTPUTS ALL GYRO'S RATES AND DEVICE TEMP OVER SERIAL LINK EVERY 100ms
//WITHOUT CHECKING THE INTERRUPT PIN
//itg3200_config configured as below:
itg3200_config.smplrt_div=0; //sample rate divider set to zero (SAMPLING RATE 8khz, READ DATASHEET)
itg3200_config.dlpf_cfg=0; //low pass filter set to 256hz
itg3200_config.fs_sel=3; //FIXED. set the full scale to +/- 2000°/s
itg3200_config.raw_rdy_en=0; //interrupt on data ready disabled
itg3200_config.itg_rdy_en=0; //interrupt on device ready disabled
itg3200_config.int_anyrd_2clear=1; //each interrupt is cleared by reading any register
itg3200_config.latch_int_en=1; //enable interrupt latch
itg3200_config.open=1; //open drain interrupt pin
itg3200_config.actl=0; //interrupt level active high
itg3200_config.clk_sel=1; //clock source to X gyro reference (READ DATASHEET page 27)
itg3200_config.stby_zg=0; //all gyro's in normal mode
itg3200_config.stby_yg=0;
itg3200_config.stby_xg=0;
itg3200_config.sleep=0; //device not in sleep mode
itg3200_config.h_reset=0; //device not reset
void main()
{
itg3200_init_setup();
itg3200_init();
float rates[3];
float temp;
while(1)
{
rates[0]=itg3200_get_angular_rate(itg3200_get_rate_x());
rates[1]=itg3200_get_angular_rate(itg3200_get_rate_y());
rates[2]=itg3200_get_angular_rate(itg3200_get_rate_z());
temp=itg3200_get_temp_degrees(itg3200_get_temp());
printf("Current angular rates:\r\n");
printf("X=%1.2f\r\n",rates[0]);
printf("Y=%1.2f\r\n",rates[1]);
printf("Z=%1.2f\r\n",rates[2]);
printf("Current device temperature:\r\n");
printf("T=%1.2f\r\n",temp);
delay_ms(100);
}
}
//OUTPUTS ALL GYRO'S RATES AND DEVICE TEMP OVER SERIAL LINK EVERYTIME THERE'S NEW DATA IN INTERNAL REGISTERS
//CHECKING THE INTERRUPT PIN
//IN THIS EXAMPLE PIN_B0 IS HARD WIRED TO THE INT PIN OF ITG3200
//itg3200_config configured as below:
itg3200_config.smplrt_div=0; //sample rate divider set to zero (SAMPLING RATE 8khz, READ DATASHEET)
itg3200_config.dlpf_cfg=0; //low pass filter set to 256hz
itg3200_config.fs_sel=3; //FIXED. set the full scale to +/- 2000°/s
itg3200_config.raw_rdy_en=1; //interrupt on data ready ENABLED
itg3200_config.itg_rdy_en=0; //interrupt on device ready disabled
itg3200_config.int_anyrd_2clear=1; //each interrupt is cleared by reading any register
itg3200_config.latch_int_en=1; //enable interrupt latch
itg3200_config.open=0; //push pull interrupt pin
itg3200_config.actl=0; //interrupt level active high
itg3200_config.clk_sel=1; //clock source to X gyro reference (READ DATASHEET page 27)
itg3200_config.stby_zg=0; //all gyro's in normal mode
itg3200_config.stby_yg=0;
itg3200_config.stby_xg=0;
itg3200_config.sleep=0; //device not in sleep mode
itg3200_config.h_reset=0; //device not reset
void main()
{
itg3200_init_setup();
itg3200_init();
float rates[3];
float temp;
while(1)
{
if(input(PIN_B0))
{
rates[0]=itg3200_get_angular_rate(itg3200_get_rate_x());
rates[1]=itg3200_get_angular_rate(itg3200_get_rate_y());
rates[2]=itg3200_get_angular_rate(itg3200_get_rate_z());
temp=itg3200_get_temp_degrees(itg3200_get_temp());
printf("Current angular rates:\r\n");
printf("X=%1.2f\r\n",rates[0]);
printf("Y=%1.2f\r\n",rates[1]);
printf("Z=%1.2f\r\n",rates[2]);
printf("Current device temperature:\r\n");
printf("T=%1.2f\r\n",temp);
}
}
}
*/
#DEFINE ITG3200_DRIVER_VERSION_V1
#CASE //makes compiler case sensitive. Required to use this driver
//#DEFINE I2C_DEFINED //uncomment this line to use your own i2c configuration
#ifndef ITG3200_SDA
#DEFINE ITG3200_SDA PIN_B0
#DEFINE ITG3200_SCL PIN_B1
#endif
#ifndef I2C_DEFINED
#use I2C(master, sda=ITG3200_SDA, scl=ITG3200_SCL, FAST) //uses 400khz fast i2c mode
#endif
#ifndef I2C_WRITE
#define I2C_WRITE 0x00
#define I2C_READ 0x01
#endif
//uncomment the desired address to use
#DEFINE GYRO_ADDR_1 0b01101000 //7 bit addressing with pin AD0 tied to ground
//#DEFINE GYRO_ADDR_2 0b01101001 //7 bit addressing with pin AD0 tied to VDD (max 3.6V)
#ifndef GYRO_ADDR_1
#DEFINE GYRO_ADDR GYRO_ADDR_2
#else
#DEFINE GYRO_ADDR GYRO_ADDR_1
#endif
///// INTERNAL REGISTER MAP - ALL REGISTER ARE 8bits LONG
//EVERY REGISTER IS NAMED AFTER THE DATASHEET
//READ/WRITE REGISTERS
#DEFINE WHO_AM_I 0x00
#DEFINE SMPLRT_DIV 0x15
#DEFINE DLPF_FS 0x16
#DEFINE INT_CFG 0x17
#DEFINE PWR_MGM 0x3E
//READ-ONLY REGISTERS
#DEFINE INT_STATUS 0x1A
#DEFINE TEMP_OUT_H 0x1B
#DEFINE TEMP_OUT_L 0x1C
#DEFINE GYRO_XOUT_H 0x1D
#DEFINE GYRO_XOUT_L 0x1E
#DEFINE GYRO_YOUT_H 0x1F
#DEFINE GYRO_YOUT_L 0x20
#DEFINE GYRO_ZOUT_H 0x21
#DEFINE GYRO_ZOUT_L 0x22
/////GYRO SENSOR PARAMETERS
#DEFINE GYRO_SENSITIVITY 14.375f // LSB per °/s
#DEFINE TEMP_SENSITIVITY 280 //LSB per °C
#DEFINE TEMP_OFFSET -13200 //LSB temp offset
/////CONFIGURATION STRUCTURE USED IN itg3200_init_setup() FUNCTION
//EVERY PARAMETER IS NAMED AFTER THE DATASHEET SO IT'S EASIER TO FIND IF YOU DON'T REMEMBER ITS FUNCTION
struct
{
int8 smplrt_div;
int8 dlpf_cfg;
int8 fs_sel;
short raw_rdy_en;
short itg_rdy_en;
short int_anyrd_2clear;
short latch_int_en;
short open;
short actl;
int8 clk_sel;
short stby_zg;
short stby_yg;
short stby_xg;
short sleep;
short h_reset;
} itg3200_config;
/////OUTPUT STRUCTURE FOR GYRO ANGULAR RATES AND TEMPERATURE USED IN itg3200_get_data()
//YOU CAN ACCESS THIS STRUCTURE WHEREVER YOU WANT, AS SOON AS YOU CALL itg3200_get_data() BEFORE ACCESSING IT
//HOWEVER IS BETTER TO CHECK THE INTERRUPT PIN TO ENSURE NEW DATA AVAILABLE IS STORED CORRECTLY IN THE INTERNAL REGISTER
struct
{
signed int16 XRATE;
signed int16 YRATE;
signed int16 ZRATE;
signed int16 TEMP;
} itg3200_output;
/////FUNCTIONS
//THIS FUNCTION MUST BE CALLED BEFORE itg3200_init() TO ENSURE PROPER DEVICE INITIALIZATION
void itg3200_init_setup()
{
//EXAMPLE SETUP. PLEASE REFER TO THE DATASHEET TO SET EACH PARAMETER
itg3200_config.smplrt_div=0; //sample rate divider set to zero (SAMPLING RATE 8khz, READ DATASHEET)
itg3200_config.dlpf_cfg=0; //low pass filter set to 256hz
itg3200_config.fs_sel=3; //FIXED. set the full scale to +/- 2000°/s
itg3200_config.raw_rdy_en=0; //interrupt on data ready disabled
itg3200_config.itg_rdy_en=0; //interrupt on device ready disabled
itg3200_config.int_anyrd_2clear=1; //each interrupt is cleared by reading any register (set to 0 to clear only by reading status register)
itg3200_config.latch_int_en=1; //enable interrupt latch (set to 0 to 50us pulse interrupt)
itg3200_config.open=1; //open drain interrupt pin
itg3200_config.actl=0; //interrupt level active high
itg3200_config.clk_sel=1; //clock source to X gyro reference (READ DATASHEET page 27)
itg3200_config.stby_zg=0; //all gyro's in normal mode
itg3200_config.stby_yg=0;
itg3200_config.stby_xg=0;
itg3200_config.sleep=0; //device not in sleep mode
itg3200_config.h_reset=0; //device not reset (this bit is used to reset all values to power-on default value)
}
int8 itg3200_read_who_am_i()
{
int8 addr;
i2c_start();
i2c_write((GYRO_ADDR<<1)|I2C_WRITE);
i2c_write(WHO_AM_I);
i2c_start();
i2c_write((GYRO_ADDR<<1)|I2C_READ);
addr=i2c_read(0);
i2c_stop();
return addr;
}
void itg3200_write_who_am_i(int8 addr)
{
i2c_start();
i2c_write((GYRO_ADDR<<1)|I2C_WRITE);
i2c_write(WHO_AM_I);
i2c_write(addr);
i2c_stop();
}
//single register write
void itg3200_write_reg(int8 ADDR, int8 VAL)
{
i2c_start();
i2c_write((GYRO_ADDR<<1)|I2C_WRITE);
i2c_write(ADDR);
i2c_write(VAL);
i2c_stop();
}
//single register read
int8 itg3200_read_reg(int8 ADDR)
{
int8 val;
i2c_start();
i2c_write((GYRO_ADDR<<1)|I2C_WRITE);
i2c_write(ADDR);
i2c_start();
i2c_write((GYRO_ADDR<<1)|I2C_READ);
val=i2c_read(0);
i2c_stop();
return val;
}
void itg3200_init()
{
int8 samp_div, low_pass, int_cfg, fs_sel,dlpf_fs;
int8 pwr_mgm;
int_cfg|=itg3200_config.raw_rdy_en;
int_cfg|=(itg3200_config.itg_rdy_en<<2);
int_cfg|=(itg3200_config.int_anyrd_2clear<<4);
int_cfg|=(itg3200_config.latch_int_en<<5);
int_cfg|=(itg3200_config.open<<6);
int_cfg|=(itg3200_config.actl<<7);
samp_div=itg3200_config.smplrt_div;
low_pass=itg3200_config.dlpf_cfg;
fs_sel=itg3200_config.fs_sel;
pwr_mgm|=itg3200_config.clk_sel;
pwr_mgm|=(itg3200_config.stby_zg<<3);
pwr_mgm|=(itg3200_config.stby_yg<<4);
pwr_mgm|=(itg3200_config.stby_xg<<5);
pwr_mgm|=(itg3200_config.sleep<<6);
pwr_mgm|=(itg3200_config.h_reset<<7);
dlpf_fs=((low_pass & 0x07) | ((fs_sel & 0x03) << 3));
i2c_start();
i2c_write((GYRO_ADDR<<1)|I2C_WRITE);
i2c_write(SMPLRT_DIV);
i2c_write(samp_div);
i2c_write(dlpf_fs);
i2c_write(int_cfg);
i2c_stop();
i2c_start();
i2c_write((GYRO_ADDR<<1)|I2C_WRITE);
i2c_write(PWR_MGM);
i2c_write(pwr_mgm);
i2c_stop();
}
signed int16 itg3200_get_rate_x()
{
int16 xrate;
xrate=(itg3200_read_reg(GYRO_XOUT_H)<<8);
xrate|=itg3200_read_reg(GYRO_XOUT_L);
return xrate;
}
signed int16 itg3200_get_rate_y()
{
int16 yrate;
yrate=(itg3200_read_reg(GYRO_YOUT_H)<<8);
yrate|=itg3200_read_reg(GYRO_YOUT_L);
return yrate;
}
signed int16 itg3200_get_rate_z()
{
int16 zrate;
zrate=(itg3200_read_reg(GYRO_ZOUT_H)<<8);
zrate|=itg3200_read_reg(GYRO_ZOUT_L);
return zrate;
}
signed int16 itg3200_get_temp()
{
int16 temp;
temp=(itg3200_read_reg(TEMP_OUT_H)<<8);
temp|=itg3200_read_reg(TEMP_OUT_L);
return temp;
}
void itg3200_get_data()
{
int16 xrate, yrate, zrate, temp;
i2c_start();
i2c_write((GYRO_ADDR<<1)|I2C_WRITE);
i2c_write(TEMP_OUT_H); //start address
i2c_start();
i2c_write((GYRO_ADDR<<1)|I2C_READ); //set mode to read
temp=(i2c_read(1)<<8); //acknowledge each byte
temp|=i2c_read();
xrate=(i2c_read()<<8);
xrate|=i2c_read();
yrate=(i2c_read()<<8);
yrate|=i2c_read();
zrate=(i2c_read()<<8);
zrate|=i2c_read(0); //n-ack last byte to end transmission
i2c_stop();
itg3200_output.XRATE=xrate;
itg3200_output.YRATE=yrate;
itg3200_output.ZRATE=zrate;
itg3200_output.TEMP=temp;
}
float itg3200_get_angular_rate(signed int16 VAL)
{
float tmpf;
tmpf = VAL/GYRO_SENSITIVITY; //convert raw value to °/s
return tmpf;
}
float itg3200_get_temp_degrees(signed int16 VAL)
{
float tmpf;
tmpf = VAL - TEMP_OFFSET;
tmpf = tmpf/TEMP_SENSITIVITY;
return tmpf;
}
void itg3200_reset()
{
itg3200_write_reg(PWR_MGM,0x40);
delay_ms(50);
}
void itg3200_standby()
{
itg3200_write_reg(PWR_MGM,0x38);
}
void itg3200_sleep()
{
itg3200_write_reg(PWR_MGM,0x20);
}
void itg3200_wakeup()
{
itg3200_write_reg(PWR_MGM,0x01); //wakes up device and sets X gyro as clock source
} |
Regards
Last edited by simonspt on Thu Jan 02, 2014 9:29 am; edited 2 times in total |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Mar 04, 2012 6:36 pm |
|
|
You are doing the usual mistake of not doing a NACK on the last i2c read
operation. You're not doing it in this routine:
itg3200_read_reg(int8 ADDR)
and also this one:
itg3200_read_who_am_i()
The requirement for a final NACK is shown in these diagrams on page 20
of the ITG3200 data sheet:
Single-Byte Read Sequence
Burst Read Sequence
http://invensense.com/mems/gyro/documents/PS-ITG-3200-00-01.4.pdf
This post shows how to do a NACK on the last i2c_read() in a multi-byte
read operation:
http://www.ccsinfo.com/forum/viewtopic.php?t=26969&start=1
If you only read one byte in a transaction, then that i2c_read() must do
a NACK. (Because it's the "last" one). |
|
|
simonspt
Joined: 12 Feb 2012 Posts: 10
|
|
Posted: Sun Mar 04, 2012 6:45 pm |
|
|
thanks! i read the datasheet and noticed the NACK but i forgot to put it in those functions!
only in itg3200_get_data() it's present
sorry for that! i'll correct them immediately |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|