Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Pinguino Micro + ADXL345, L3G4200D, HMC5883L, BMP085 drivers
24-06-2013, 04:24 PM, (This post was last modified: 29-06-2013, 01:50 PM by nikolajpp.)
#1
Pinguino Micro + ADXL345, L3G4200D, HMC5883L, BMP085 drivers
Hello everybody!
In the following week i have a goal: To make my Pinguino Micro able to talk to the GY-80 sensor module.
The sensor module contains the following sensors:
L3G4200D - 3 axis Gyroscope
29.06.13 - Done done..

Code:
// L3G4200D BareBone I2C driver
// By Nikolaj Kjaer Nielsen

//http://bildr.org/2011/06/l3g4200d-arduino/
#include <pinguinoi2c1.c>
#include <i2c.c>


#define DEVICE 0xD2 // Original address: 0x69, has to be left-shifted 1 bit
#define CTRL_REG1 0x20
#define CTRL_REG2 0x21
#define CTRL_REG3 0x22
#define CTRL_REG4 0x23
#define CTRL_REG5 0x24
#define readd 0x28

int16_t x1,x2,y1,y2,z1,z2 = 0;
int temperature = 0;
void setup()
{
   delay(2000); //give time for manually hooking up to the virtual com port
   CDC.printf("Hello! \n");
  
   //initalize I2C port on the UEXT port (I2C1)
   I2C_init(I2C1, I2C_MASTER_MODE, I2C_100KHZ);

    writeTo(CTRL_REG1, 0b00001111);  // Enable x, y, z and turn off power down:
    writeTo(CTRL_REG2, 0b00000000);  // If you'd like to adjust/use the HPF, you can edit the line below to configure CTRL_REG2:
    // Configure CTRL_REG3 to generate data ready interrupt on INT2
    // No interrupts used on INT1, if you'd like to configure INT1
    // or INT2 otherwise, consult the datasheet:
    writeTo(CTRL_REG3, 0b00001000);
    writeTo(CTRL_REG4, 0b00010000);
    // CTRL_REG5 controls high-pass filtering of outputs, use it
    // if you'd like:
    writeTo(CTRL_REG5, 0b00000000);
    delay(1500); //wait for the sensor to be ready
}

void loop()
{
readGyro(); // read the x/y/z rotation
  delay(10); // only read every 1 second
}


void writeTo(byte address, byte val)
{
    I2C1_start();
    I2C1_sendID(DEVICE,I2C_WRITE); //set the device as write(0)
    I2C1_writechar(address);
    I2C1_writechar(val);
    I2C1_stop();
}


void readGyro() {
  readFrom(readd); //read the acceleration data from the ADXL345

  // each axis reading comes in 16 bit resolution, ie 2 bytes.  LEAST Significat Byte first!!
  // thus we are converting both bytes in to one int
  
    int16_t x = ((x2 << 8) | x1); //int16 because http://forum.arduino.cc/index.php?topic=133031.0
    int16_t y = ((y2 << 8) | y1);
    int16_t z = ((z2 << 8) | z1);

  // print to screen
    CDC.printf("%d,", -x);
    CDC.printf("%d,", -y);
    CDC.printf("%d,", -z);

    //CDC.printf(" temp = %d\r\n", temperature); //http://forums.parallax.com/showthread.php/137598-Gyroscope-L3G4200D-and-problems-with-thermometer
}


// Reads 6 bytes starting from address register on device
void readFrom(byte address) {

    //structure of multibyte read is specified in the HMC5883L datasheet
    // all registers must be adressed individually, and the read must end with a NAK
    I2C1_start();
    I2C1_sendID(DEVICE,I2C_WRITE); //set the device as write(0)
    I2C1_writechar(0x28);
    I2C1_stop();
    I2C1_start();
    I2C1_sendID(DEVICE,I2C_READ); //set the device as write(0)
    x1 = I2C1_readchar();
    I2C1_stop();

    I2C1_start();
    I2C1_sendID(DEVICE,I2C_WRITE); //set the device as write(0)
    I2C1_writechar(0x29);
    I2C1_stop();
    I2C1_start();
    I2C1_sendID(DEVICE,I2C_READ); //set the device as write(0)
    x2 = I2C1_readchar();
    I2C1_stop();

    I2C1_start();
    I2C1_sendID(DEVICE,I2C_WRITE); //set the device as write(0)
    I2C1_writechar(0x2A);
    I2C1_stop();
    I2C1_start();
    I2C1_sendID(DEVICE,I2C_READ); //set the device as write(0)
    z1 = I2C1_readchar();
    I2C1_stop();

    I2C1_start();
    I2C1_sendID(DEVICE,I2C_WRITE); //set the device as write(0)
    I2C1_writechar(0x2B);
    I2C1_stop();
    I2C1_start();
    I2C1_sendID(DEVICE,I2C_READ); //set the device as write(0)
    z2 = I2C1_readchar();
    I2C1_stop();

    I2C1_start();
    I2C1_sendID(DEVICE,I2C_WRITE); //set the device as write(0)
    I2C1_writechar(0x2C);
    I2C1_stop();
    I2C1_start();
    I2C1_sendID(DEVICE,I2C_READ); //set the device as write(0)
    y1 = I2C1_readchar();
    I2C1_stop();

    I2C1_start();
    I2C1_sendID(DEVICE,I2C_WRITE); //set the device as write(0)
    I2C1_writechar(0x2D);
    I2C1_stop();
    I2C1_start();
    I2C1_sendID(DEVICE,I2C_READ); //set the device as write(0)
    y2 = I2C1_readchar();
    I2C1_stop();
/*
    I2C1_start();
    I2C1_sendID(DEVICE,I2C_WRITE); //set the device as write(0)
    I2C1_writechar(0x26);
    I2C1_stop();
    I2C1_start();
    I2C1_sendID(DEVICE,I2C_READ); //set the device as write(0)
    temperature = I2C1_readchar();
  */
    
}

ADXL345 - 3 axis Accelerometer
27.06.13 - Finally after 3 days of cursing, shouting and crying i got the accelerometer working. The I2C library has some wired bugs..
This is the most barebone driver, however the com link is established.


Code:
// ADXL345 BareBone I2C driver
// By Nikolaj Kjaer Nielsen

#include <pinguinoi2c1.c>
#include <i2c.c>

// left shift 1 step device address! - the I2C library is fucked!
#define DEVICE 0xA6 // Device address as specified in data sheet , Original address: 0x53
#define POWER_CTL       0x2D    //Power Control Register , 0x2D
#define DATA_FORMAT     0x31 // 0x31
#define DATAX0          0x32    //X-Axis Data 0 , 0x32
//addresses below are only for reference
#define DATAX1          0x33    //X-Axis Data 1 , 0x33
#define DATAY0          0x34    //Y-Axis Data 0 , 0x34
#define DATAY1          0x35    //Y-Axis Data 1 , 0x35
#define DATAZ0          0x36    //Z-Axis Data 0 , 0x36
#define DATAZ1          0x37    //Z-Axis Data 1 , 0x37

int16_t x1,x2,y1,y2,z1,z2 = 0;

void setup()
{
   delay(2000); //give time for manually hooking up to the virtual com port
   //CDC.printf("Hello! \n");
  
   //initalize I2C port on the UEXT port (I2C1)
   I2C_init(I2C1, I2C_MASTER_MODE, I2C_100KHZ);

   writeTo(DATA_FORMAT, 0x01); //Put the ADXL345 into +/- 4G range by writing the value 0x01 to the DATA_FORMAT register
   writeTo(POWER_CTL, 0x08); //Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
    }

void loop()
{
readAccel(); // read the x/y/z tilt
  delay(1000); // only read every 1 second
}


void writeTo(byte address, byte val)
{
    I2C1_start();
    I2C1_sendID(DEVICE,I2C_WRITE); //set the device as write(0)
    I2C1_writechar(address);
    I2C1_writechar(val);
    I2C1_stop();
}


void readAccel() {
  readFrom(DATAX0); //read the acceleration data from the ADXL345

  // each axis reading comes in 10 bit resolution, ie 2 bytes.  Least Significat Byte first!!
  // thus we are converting both bytes in to one int
  
    int16_t x = ((x2 << 8) | x1); //int16 because http://forum.arduino.cc/index.php?topic=133031.0
    int16_t y = ((y2 << 8) | y1);
    int16_t z = ((z2 << 8) | z1);

  // print to screen
    CDC.printf("x = %d\r\n", -x);
    CDC.printf("y = %d\r\n", -y);
    CDC.printf("z = %d\r\n", -z);
}

// Reads 6 bytes starting from address register on device
void readFrom(byte address) {

    //structure of multibyte read is specified in the ADXL datasheet
    I2C1_start();
    I2C1_sendID(DEVICE,I2C_WRITE); //set the device as write(0)
    I2C1_writechar(address);
    I2C1_stop();
    I2C1_start();
    I2C1_sendID(DEVICE,I2C_READ); //set the device as read(1)
    
     //read 6 bytes of data(each axis comes in two byte packages)
    x1 = I2C1_readcharAck();
    x2 = I2C1_readcharAck();
    y1 = I2C1_readcharAck();
    y2 = I2C1_readcharAck();
    z1 = I2C1_readcharAck();
    z2 = I2C1_readchar();

    I2C1_stop();
}
Note: in the i2c.c library you have to outcomment I2C_start(module) in the I2C_sendID function. Otherwise the pic will send the startbit wise, because the compiler requires a I2C_start statement in the main.c file(if not it will not compile, and not state any reason(GRRRR!!)).

HMC5883L - 3 axis Magnetometer
27.06.13 - ITS ALIVE!!!

Code:
// HMC5883L  BareBone I2C driver
// By Nikolaj Kjaer Nielsen

#include <pinguinoi2c1.c>
#include <i2c.c>

// left shift 1 step device address! - the I2C library is fucked!
#define DEVICE          0x3C  // Device address as specified in data sheet , Original address: 0x3C 78
#define CRA             0x00    // Confifuration register A  (R/W)
#define CRB             0x01  // Confifuration register B  (R/W)
#define MR              0x02    // Mode register             (R/W)
#define DATAX0          0x03    // Data Output X MSB Register (R)
#define DATAX1          0x04    // Data Output X LSB Register (R)
#define DATAZ0          0x05    // Data Output Z MSB Register (R)
#define DATAZ1          0x06    // Data Output Z LSB Register (R)
#define DATAY0          0x07    // Data Output Y MSB Register (R)
#define DATAY1          0x08    // Data Output Y LSB Register (R)
#define SR              0x09    // Status Register            (R)
#define IRA             0x10    // Idenfication Register A    (R)
#define IRB             0x11    // Idenfication Register B    (R)
#define IRC             0x12    // Idenfication Register C    (R)

int16_t x1,x2,y1,y2,z1,z2 = 0;

void setup()
{
    pinMode(USERLED,OUTPUT);
    digitalWrite(USERLED, HIGH);
    delay(3000); //give time for manually hooking up to the virtual com port
    digitalWrite(USERLED, LOW);
  
   //initalize I2C port on the UEXT port (I2C1)
   I2C_init(I2C1, I2C_MASTER_MODE, I2C_100KHZ);

   writeTo(CRA, 0x70); //(8-average, 15 Hz default, normal measurement
   writeTo(CRB, 0xA0); //Gain=5, or any other desired gain
   writeTo(MR, 0x00); //Continuous-measurement mode
    delay(6); // datasheet requirement
    }

void loop()
{
  readMag(); // read the x/y/z tilt
  delay(200); // only read every 1 second
}


void writeTo(byte address, byte val)
{
    I2C1_start();
    I2C1_sendID(DEVICE,I2C_WRITE); //set the device as write(0)
    I2C1_writechar(address);
    I2C1_writechar(val);
    I2C1_stop();
}


void readMag() {
  readFrom(DATAX0); //read the acceleration data from the ADXL345

  // each axis reading comes in 10 bit resolution, ie 2 bytes.  Most Significat Byte first!!
  // thus we are converting both bytes in to one int
  
    int16_t x = ((x1 << 8) | x2); //int16 because http://forum.arduino.cc/index.php?topic=133031.0
    int16_t y = ((y1 << 8) | y2);
    int16_t z = ((z1 << 8) | z2);

  // print to screen
    CDC.printf("x = %d  ", -x);
    CDC.printf("y = %d  ", -y);
    CDC.printf("z = %d\r\n", -z);
}


// Reads 6 bytes starting from address register on device
void readFrom(byte address) {
    //structure of multibyte read is specified in the HMC5883L datasheet
    I2C1_start();
    I2C1_sendID(DEVICE,I2C_WRITE); //set the device as write(0)
    I2C1_writechar(0x03);
    I2C1_stop();
    I2C1_start();
    I2C1_sendID(DEVICE,I2C_READ); //set the device as write(0)
    x1 = I2C1_readcharAck();
    x2 = I2C1_readcharAck();
    z1 = I2C1_readcharAck();
    z2 = I2C1_readcharAck();
    y1 = I2C1_readcharAck();
    y2 = I2C1_readchar();

    I2C1_stop();
}
BMP085 - Barometric pressure sensor

The link for the module is below:
http://dx.com/p/gy-80-bmp085-9-axis-magn...ino-145912

I will be updating this post as I progress, however my knowledge about PIC and its utilization of the I2C protocol is non-exsistant. Therefore I hope some folks here at the forum are able to participate with advice and expertiseSmile

Status:
- Researching the ADXL345 I2C interface - done
- Trying to understand the I2C handling in Pinguino enviroment - done
- Make accelerometer driver - done
- Make magnetometer driver - done
- Make gyro driver - done

- Make pressure sensor driver - in progress

Questions:
- SOLVED How can i choose between the two I2C ports on the Pinguino micro with the I2C.c library?
Solution: pinguinoi2c1.c, and pinguinoi2c2.c are wrappers of the i2c.c library that represent each channel of the Pinguino.

- Are there any good way to port arduino libraries to Pinguino? - As I understand the two biggest problems are that:
The arduino libraries use the arduino.h file as reference to pins, and functionalities of the atmel chips, what does pinguino use?.
Reply
24-06-2013, 07:21 PM,
#2
RE: Pinguino Micro + GY80 module
Hi

Is very easy port library from Arduino to Pinguino, in these days I ported library for DS1306 RTC.
I will port, in the next months, even library for ADXL345 because I want use it in my projects.

The board you want use is very nice and cheap.


Bye Bye, Moreno
Reply
27-06-2013, 08:32 PM,
#3
RE: Pinguino Micro + GY80 module
(24-06-2013, 07:21 PM)moreno Wrote: Is very easy port library from Arduino to Pinguino, in these days I ported library for DS1306 RTC.
I will port, in the next months, even library for ADXL345 because I want use it in my projects.

Thank you for your response.. though im not the most hardcore coder, I honestly got a pretty bad impression of the I2C library implementation of the pinguino. I understand this is a open source project, and the prospects are great. However the environment is still at its infancy state.. there are many bugs, and many of the libraries has not been updated for years, with obvious bugs. That is the primary reason why I made this post, to expand the platform so other can help develop it.
Reply
28-06-2013, 07:47 AM,
#4
RE: Pinguino Micro + GY80 module
Hi

At the moment I do not have the ADXL345

can you try this code:

Code:
void ADXL345_readFromI2C(byte address, int num, byte _buff[])
{
  int i = 0;
  I2C_start(ADXL345_channel);        // All I2C commands must begin with a Start condition
  I2C_writechar(ADXL345_channel,DEVICE);              // start transmission to device
  I2C_writechar(ADXL345_channel,address);             // sends address to read from

  I2C_start(ADXL345_channel);        // All I2C commands must begin with a Start condition
  I2C_writechar(ADXL345_channel,DEVICE);              // start transmission to device

  for (i=0; i<num; i++)                         // Sequential read (auto. inc.)
    {
     if (i>=num-1)                           // Last byte is sent ?
      _buff[i] = I2C_readchar(ADXL345_channel,ADXL345_ACK);                // read a byte from the slave
     else
      _buff[i] = I2C_readchar(ADXL345_channel,ADXL345_NACK);                // read a byte from the slave
    }

  I2C_stop(ADXL345_channel);                                 // Terminate the read sequence
}

for the read routine??

I do not understand the problem about DEVICE, Why you use 0xA6 instead of 0x53?? A6=53*2


Bye Bye, Moreno
Reply
28-06-2013, 08:50 AM,
#5
RE: Pinguino Micro + GY80 module
Afaik i2c uses the least significant bit of the address byte as direction flag (read/write), with the effect that some people "think of" 7-bit addresses, whilst others refer to the (shiftet) 8-bit values.
Reply
28-06-2013, 06:01 PM,
#6
RE: Pinguino Micro + GY80 module
(28-06-2013, 08:50 AM)trollpatsch Wrote: Afaik i2c uses the least significant bit of the address byte as direction flag (read/write), with the effect that some people "think of" 7-bit addresses, whilst others refer to the (shiftet) 8-bit values.

its a funny problem, because the gyro did not suffer from the bitshift problem(dunno why..). The sendID function requires a second argument that will define its 8th bit R/W bit, so it does not make sense to parse a shifted address..
Reply
23-04-2016, 07:05 PM,
#7
RE: Pinguino Micro + ADXL345, L3G4200D, HMC5883L, BMP085 drivers
Hello,

Did someone tryed to port this code to a 8 bit pinguino, or any at all?

I'm trying and still no luck...

Using every example, and trying to understand the mechanics beind, but i thing it's a little too much for my knowledge.

Thanks
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)