Thomas Hamilton
/
3DM-GX2
interface class for an inertial measurement unit that uses a serial protocol.
Revision 1:555c2c2bf9d3, committed 2011-02-13
- Comitter:
- Blaze513
- Date:
- Sun Feb 13 10:49:06 2011 +0000
- Parent:
- 0:fd1fce2347d9
- Commit message:
- interrupt still under construction
Changed in this revision
diff -r fd1fce2347d9 -r 555c2c2bf9d3 3DM-GX2.cpp --- 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
diff -r fd1fce2347d9 -r 555c2c2bf9d3 3DM-GX2.h --- 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
diff -r fd1fce2347d9 -r 555c2c2bf9d3 MS3DMGX2.cpp --- /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
diff -r fd1fce2347d9 -r 555c2c2bf9d3 MS3DMGX2.h --- /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
diff -r fd1fce2347d9 -r 555c2c2bf9d3 main.cpp --- 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