interface class for an inertial measurement unit that uses a serial protocol.

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
Blaze513
Date:
Sun Feb 13 10:49:06 2011 +0000
Parent:
0:fd1fce2347d9
Commit message:
interrupt still under construction

Changed in this revision

3DM-GX2.cpp Show diff for this revision Revisions of this file
3DM-GX2.h Show diff for this revision Revisions of this file
MS3DMGX2.cpp Show annotated file Show diff for this revision Revisions of this file
MS3DMGX2.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/3DM-GX2.cpp	Tue Aug 31 04:38:14 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,169 +0,0 @@
-#include "3DM-GX2.h"
-
-MS3DMGX2::MS3DMGX2(PinName tx, PinName rx) : DataLines(tx, rx),
-    ModeCommand(0xCF), ModeLength(6), ModeSync(0), InterruptBuffer((float*)Workspace)
-{
-    DataLines.baud(115200);
-    DataLines.format(8, Serial::None, 1);
-    DataLines.attach(NULL, Serial::RxIrq);
-}
-
-unsigned char MS3DMGX2::Mode(unsigned char Selection)
-{
-    switch (Selection & 0x03)
-    {
-        case 0x00:
-            ModeCommand = 0xCF;
-            ModeLength = 6;
-            break;
-        case 0x01:
-            ModeCommand = 0xD2;
-            ModeLength = 9;
-            break;
-        case 0x02:
-            ModeCommand = 0xC8;
-            ModeLength = 15;
-            break;
-        case 0x03:
-            ModeCommand = 0xCC;
-            ModeLength = 18;
-            break;
-    }
-    if (Selection & 0x04)
-    {
-        DiscardSerialBuffer();
-        DataLines.putc(0xC4);
-        DataLines.putc(0xC1);
-        DataLines.putc(0x29);
-        DataLines.putc(ModeCommand);
-        ModeSync = 1;
-        wait_ms(10);
-        Workspace[0] = DataLines.getc();
-        Workspace[1] = DataLines.getc();
-        while (DataLines.readable() && ((Workspace[0] != 0xC4) || (Workspace[1] != ModeCommand)))
-        {
-            Workspace[0] = Workspace[1];
-            Workspace[1] = DataLines.getc();
-        }
-        unsigned char i = 7;
-        while (DataLines.readable() && (i > 1))
-        {
-            Workspace[i] = DataLines.getc();
-            i--;
-        }
-        CheckSum(0xC4, 1, &ModeCommand, &Workspace[4], Workspace);
-        Workspace[0] = (Workspace[0] != Workspace[2]) || (Workspace[1] != Workspace[3]);
-    }
-    else
-    {
-        DataLines.putc(0xFA);
-        ModeSync = 0;
-    }
-    if (Selection & 0x08)
-    {
-        DataLines.attach(this, &MS3DMGX2::Interrupt, Serial::RxIrq);
-    }
-    else
-    {
-        DataLines.attach(NULL, Serial::RxIrq);
-    }
-    if (Workspace[0])
-    {
-        return 0x01;
-    }
-    else
-    {
-        return 0x00;
-    }
-}
-
-void MS3DMGX2::AttachInterruptBuffer(float* Buffer)
-{
-    InterruptBuffer = Buffer;
-}
-    //store user's data pointer for use in interrupt modes
-
-void MS3DMGX2::RequestSyncRead()
-{
-    if (ModeSync)
-    {
-        DataLines.putc(0xFA);
-        ModeSync = 0x00;
-    }
-        //if operating in an asynchronous mode, switch to the synchronous equivalent
-    DataLines.putc(ModeCommand);
-        //send polled mode command byte
-}
-    //lazy switches to synchronous mode and sends polled mode command byte
-
-void MS3DMGX2::DiscardSerialBuffer()
-{
-    while (DataLines.readable())
-    {
-        DataLines.getc();
-    }
-}
-    //empty buffer of all data
-
-unsigned char MS3DMGX2::Read(float* Data)
-{
-    unsigned char j = 0;
-    do
-    {
-        j++;
-    } while (DataLines.readable() && (DataLines.getc() != ModeCommand) && (j < (ModeLength << 2)));
-        //find the header byte for synchronization
-    for (unsigned char i = 0; i < ModeLength; i++)
-    {
-        j = 3;
-        while (DataLines.readable() && (j < 4))
-        {
-            ((unsigned char*)&Data[i])[j] = DataLines.getc();
-            j--;
-        }
-    }
-        //change endianness and fill user buffer
-    j = 7;
-    while (DataLines.readable() && (j > 1))
-    {
-        Workspace[j] = DataLines.getc();
-        j--;
-    }
-        //change endianness and gather timer and checksum (bytes 2 and 3)
-    CheckSum(ModeCommand, ModeLength << 2, (unsigned char*)Data, &Workspace[4], Workspace);
-        //compute checksum and store in bytes 0 and 1
-    if ((Workspace[0] != Workspace[2]) || (Workspace[1] != Workspace[3]))
-    {
-        return 0x01;
-    }
-    else
-    {
-        return 0x00;
-    }
-        //verify checksum and return result
-}
-    //this method reads a measurement from the serial port, assuming one is waiting there
-
-void MS3DMGX2::Interrupt()
-{
-    Read(InterruptBuffer);
-    DiscardSerialBuffer();
-}
-    //this will be called when in an interrupt mode and a serial interrupt is generated
-
-void MS3DMGX2::CheckSum(unsigned char Header, unsigned char Length,
-    unsigned char* Data, unsigned char* Timer, unsigned char* Result)
-{
-    unsigned short Sum = Header;
-    for (unsigned char i = 0; i < Length; i++)
-    {
-        Sum += Data[i];
-    }
-    for (unsigned char i = 0; i < 4; i++)
-    {
-        Sum += Timer[i];
-    }
-    Result[0] = ((char*)&Sum)[0];
-    Result[1] = ((char*)&Sum)[1];
-}
-    //compute the checksum of a data packet and store the result in the first two bytes of "Result"
\ No newline at end of file
--- a/3DM-GX2.h	Tue Aug 31 04:38:14 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-#ifndef MS3DMGX2Library
-#define MS3DMGX2Library
-
-#include "stdint.h"
-#include "mbed.h"
-
-class MS3DMGX2
-{
-    private:
-        Serial DataLines;
-
-        unsigned char ModeCommand;
-        unsigned char ModeLength;
-        unsigned char ModeSync;
-        unsigned char Workspace[72];
-        float* InterruptBuffer;
-
-        void Interrupt();
-        void CheckSum(unsigned char Header, unsigned char Length,
-            unsigned char* Data, unsigned char* Timer, unsigned char* Result);
-
-    public:
-        MS3DMGX2(PinName tx, PinName rx);
-        unsigned char Mode(unsigned char Selection);
-        void AttachInterruptBuffer(float* Buffer);
-        void RequestSyncRead();
-        void DiscardSerialBuffer();
-        unsigned char Read(float* Data);
-};
-
-#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MS3DMGX2.cpp	Sun Feb 13 10:49:06 2011 +0000
@@ -0,0 +1,224 @@
+#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
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MS3DMGX2.h	Sun Feb 13 10:49:06 2011 +0000
@@ -0,0 +1,81 @@
+#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
\ No newline at end of file
--- a/main.cpp	Tue Aug 31 04:38:14 2010 +0000
+++ b/main.cpp	Sun Feb 13 10:49:06 2011 +0000
@@ -1,12 +1,41 @@
-#include "mbed.h"
-
-DigitalOut myled(LED1);
-
-int main() {
-    while(1) {
-        myled = 1;
-        wait(0.2);
-        myled = 0;
-        wait(0.2);
-    }
-}
+#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);
+    }
+}
\ No newline at end of file