Embedded system Fun Blog
























































Find out all the best information, libraries and circuit about the latest Embedded systems.

Saturday 7 January 2012

MBED Example: How to use MS3DMGX2 3DM-GX2 Sensor libraries

.from: http://mbed.org/users/Blaze513/programs/3DM-GX2/lmj4el

XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx MS3DMGX2.cpp XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx

#include "MS3DMGX2.h"

MS3DMGX2::MS3DMGX2(PinName tx, PinName rx) : DataLines(tx, rx),
    CommandByte(0xCF), ResponseLength(6), PacketSize(31), Continuous(0)//,
   
    ///////////////////
    //PC(USBTX,USBRX)
    //////////////////
   
{
    DataLines.baud(115200);
    DataLines.format(8, Serial::None, 1);
    DataLines.attach(this, &MS3DMGX2::FillSerialBuffer, Serial::RxIrq);
       
        ////////////////////
    //PC.baud(9600);
    ////////////////////////
}

MS3DMGX2::~MS3DMGX2()
{
    delete this;
}

bool MS3DMGX2::Mode(unsigned char Selection)
{
    bool Result;
    switch (Selection & 0x03)
    {
        case 0x00:
            CommandByte = 0xCF;
            ResponseLength = 6;
            PacketSize = 31;
            break;
                //euler angles and angular rates
        case 0x01:
            CommandByte = 0xD2;
            ResponseLength = 9;
            PacketSize = 43;
            break;
                //gyro-stabilized acceleration, angular rate and magnetometer vector
        case 0x02:
            CommandByte = 0xC8;
            ResponseLength = 15;
            PacketSize = 67;
            break;
                //acceleration, angular rate and orientation matrix
        case 0x03:
            CommandByte = 0xCC;
            ResponseLength = 18;
            PacketSize = 79;
            break;
                //acceleration, angular rate, magnetometer vector, and orientation matrix
    }
        //record desired packet command and packet length as number of 16 bit fields
    if (Selection & 0x04)
    {
        unsigned char lbuff = PacketSize;
        PacketSize = 87;
       
        DataLines.putc(0xC4);
        DataLines.putc(0xC1);
        DataLines.putc(0x29);
        DataLines.putc(CommandByte);
            //send the desired continuous mode command
        Continuous = 1;
            //set synchronous mode to true
        while ((Buffer[BufferStart] != 0xC4) || (Buffer[BufferStart + 1] != CommandByte))
        {
            if (((BufferStart + 2) % PacketSize) != BufferEnd)
            {
                BufferStart++;
                BufferStart%=PacketSize;
            }
        }
            //find the response header
        while (((BufferStart + 8) % PacketSize) != BufferEnd);
        BufferEnd = 0;
        Result = Checksum(BufferStart, 8);
        BufferStart = 0;
        PacketSize = lbuff;////////////////NOTE: if there wasn't a packet waiting while the async cmd was made, there will be no "extra data" here
    }
    else
    {
        if (Continuous)
        {
            DataLines.putc(0xFA);
                //send stop continuous mode command
            Continuous = 0;
                //set synchronous mode to true
        }
        Result = 1;
    }
        //put the IMU into continuous mode if the correct flag is set
        //Computer.printf("stop command success %d \n", Workspace[0]);
        //Computer.printf("sync mode %d \n", SyncMode);
    /*if (Selection & 0x08)
    {
        DataLines.attach(this, &MS3DMGX2::Interrupt, Serial::RxIrq);
            //attach automatic buffer-writing function to serial interrupt
    }
    else
    {
        DataLines.attach(NULL, Serial::RxIrq);
            //attach a null to detach any previous interrupt
    }*/
        //attaches or detaches interrupt function depending on interrupt flag
    return Result;
        //return success or failure
}

bool MS3DMGX2::Readable()
{
    return BufferStart == BufferEnd;
}

/*void MS3DMGX2::AttachInterruptBuffer(float* Buffer)
{
    InterruptBuffer = Buffer;
}
    //store user's data pointer for use in interrupt modes

void MS3DMGX2::AttachInterruptFunction()
{
    DataLines.attach(this, &MS3DMGX2::Interrupt, Serial::RxIrq);
}
void MS3DMGX2::AttachInterruptFunction(void (*Function)())
{
    DataLines.attach(Function);
}
template<class Class> void AttachInterruptFunction(Class* Object, void (Class::*Function)())
{
    DataLines.attach(Object, Function, Serial::RxIrq);
}*/
    //overloads start interrupt modes, allowing user all possible options

void MS3DMGX2::RequestSyncRead()
{
    if (Continuous)
    {
        DataLines.putc(0xFA);
        Continuous = 0;
    }
    DataLines.putc(CommandByte);
}
    //lazy switches to synchronous mode and sends polled mode command byte

bool MS3DMGX2::Read(float* Data)
{
    bool Result;
    unsigned char t = 0;
   
    while ((Buffer[BufferStart] != CommandByte) && (t < PacketSize))
    {
        BufferStart++;
        BufferStart %= PacketSize;
        t++;
    }
        //find the header byte
    Result = Checksum(BufferStart, PacketSize);
        //compute checksum
    BufferStart++;
    BufferStart %= PacketSize;
        //move past header byte
    if (t < PacketSize)
    {
        for (unsigned int i = 0; i < ResponseLength; i++)
        {
            for(unsigned int j = 3; j < 4; j--)
            {
                ((unsigned char*)&Data[i])[j] = Buffer[BufferStart];
                BufferStart++;
                BufferStart %= PacketSize;
            }
        }
            //convert big endian bytes to little endian floats
        BufferStart += 6;
            //move index past timer and checksum bytes
        BufferStart %= PacketSize;
    }
        //if the header search did not timeout
   
    return Result;
}

/*MS3DMGX2::operator float*()
{
    Read((float*)&Workspace[8]);
    return (float*)&Workspace[8];
}
    //conversion function acts as shorthand for Read()

void MS3DMGX2::Interrupt()
{
    Read(InterruptBuffer);
}*/
    //this will be called when in an interrupt mode and a serial interrupt is generated

bool MS3DMGX2::Checksum(unsigned char Index, unsigned char Length)
{
    unsigned short Sum = 0;
    for (unsigned char i = 0; i < Length - 2; i++)
    {
        Sum += Buffer[Index];
        Index++;
        Index %= PacketSize;
    }
    return (((unsigned char*)&Sum)[0] == Buffer[Index+1])
        && (((unsigned char*)&Sum)[1] == Buffer[Index]);
}

void MS3DMGX2::FillSerialBuffer()//if the interrupt recurs faster than the time to complete its code, the rest of the system will be suspended indefinitely
{
    while (DataLines.readable())
    {
        Buffer[BufferEnd] = DataLines.getc();
        BufferEnd++;
      
        BufferEnd %= PacketSize;
    }
}
    //this automatically reads in new serial data as it is received to
    //make a software buffer that is big enough to handle an entire
    //packet; the processor is about 1000 times faster than the data lines

XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx MS3DMGX2.h XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx

#ifndef MS3DMGX2Library
#define MS3DMGX2Library

#include "stdint.h"
#include "mbed.h"

class MS3DMGX2
{
    private:
    /////////////////////
//Serial PC;
//////////////////////////

        Serial DataLines;
        volatile unsigned char Buffer[87];//volatile is for interrupted access
        volatile unsigned char BufferEnd;
        volatile unsigned char PacketSize;
        bool Checksum(unsigned char Index, unsigned char Length);
        void FillSerialBuffer();

    public:
        MS3DMGX2(PinName tx, PinName rx);
            //serial output, serial input
        ~MS3DMGX2();
            //release resources
        unsigned char BufferStart;
       
        unsigned char CommandByte;
        unsigned char ResponseLength;
        unsigned char Continuous; 
       
       
        bool Readable();
       
        bool Mode(unsigned char Selection);
            //argument sets operating mode;
            //set flag 0x08 to 0 for polled modes, or 1 for interrupt modes;
            //set flag 0x04 to 0 for synchronous modes, or 1 for asynchronous modes;
            //set flags 0x03 to 0 for pwm, 1 for analog, or 2 for serial;
            //asynchronous modes read user input command, measures and calculates
            //output, and writes the data packet to the serial buffer every 10 ms;
            //interrupt modes automatically read the packet into the buffer provided
            //by AttachInterruptBuffer with the selected input method every 10 ms
            //if in an asynchronous mode, or 10 ms after RequestSyncRead is called;
            //interrupt mode interrupts are generated if there are bytes on the
            //serial buffer and are only cleared if the serial buffer is emptied;
            //default is 0
        //void AttachInterruptBuffer(float* Buffer);
            //if interrupts are used, user must provide address to write result to
        //void AttachInterruptFunction();
            //this overload reattaches the native interrupt function
        //void AttachInterruptFunction(void (*Function)());
            //this overload attaches a function to the serial interrupt
        //template<class Class> void AttachInterruptFunction
        //    (Class* Object, void (Class::*Function)());
            //this overload attaches a member function to the serial interrupt;
            //to change the interrupt function, call one of the
            //"AttachInterruptFunction" overloads with pointers to the desired function;
            //changes polled mode to interrupt equivalent;
            //the interrupt will not be cleared until the serial buffer is emptied
        void RequestSyncRead();
            //this tells the device to prepare a synchronous reading;
            //must be called at least 10 ms before the reading is needed;
            //changes asynchronous mode to synchronous equivalent
        void DiscardSerialBuffer();
            //the serial port has a buffer and only the oldest data is read from it;
            //the buffer has limited space and, when full, the newest data is discarded;
            //this method allows the user to empty the buffer of old data so new data is used
        bool Read(float* Data);
            //get a reading from the device in the set mode;
            //RequestSyncRead() must be called at least 10 ms
            //before this method can be called in a synchronous mode;
            //may be called at any time during asynchronous mode;
            //it is assumed that the input buffer has enough
            //room to accomodate the desired data packet
        //operator float*();
            //shorthand for taking a reading;
            //ex: "float reading[packetlength]; reading = MB1210Object;"
};

#endif

XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx main.cpp XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx

#include "mbed.h"
#include "MS3DMGX2.h"

MS3DMGX2 IMU(p9, p10);
DigitalOut led(LED1);
DigitalOut led4(LED4);
Serial PC(USBTX,USBRX);
int main()
{
led=0;
led4=0;
PC.baud(9600);
    float data[9];
    bool isvalid;
    wait(1);
    isvalid = IMU.Mode(0x05);
    PC.printf("Data Valid: %d\r\n\r\n", isvalid);
    //IMU.RequestSyncRead();
    wait(1);
   
    while (1)
    {
        while(!IMU.Readable());
        isvalid = IMU.Read(data);
       
        PC.printf("IMU Accel x Reads %f\r\n",data[0]);//NOTE: the compiler will not even calculate unused variables
        PC.printf("IMU accel y Reads %f\r\n",data[1]);//If the data retrieved above was not used, it wouldn't even be retrieved and the validity check would not pass
        PC.printf("IMU accel z Reads %f\r\n",data[2]);//this is called "compiler optimization"
       
        PC.printf("IMU ang rate x Reads %f\r\n",data[3]);
        PC.printf("IMU ang rate y Reads %f\r\n",data[4]);
        PC.printf("IMU ang rate z Reads %f\r\n",data[5]);
       
        PC.printf("IMU mag x Reads %f\r\n",data[6]);
        PC.printf("IMU mag y Reads %f\r\n",data[7]);
        PC.printf("IMU mag z Reads %f\r\n",data[8]);
        PC.printf("Validity: %d\r\n\r\n", isvalid);
       
        wait_ms(1000);
    }
}

XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx EOF XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx

No comments:

Post a Comment