![](/media/cache/profiles/53420bd6e6798761679772a7dd012674.50x50_q85.jpg)
This program acquires data from an ADIS16355 IMU via the SPI bus and sends the data to a host computer via UDP over Ethernet.
Dependencies: mbed StrippedDownNetServices
Revision 0:79f663186c05, committed 2012-05-31
- Comitter:
- yahugh
- Date:
- Thu May 31 18:37:12 2012 +0000
- Commit message:
Changed in this revision
diff -r 000000000000 -r 79f663186c05 StrippedDownNetServices.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/StrippedDownNetServices.lib Thu May 31 18:37:12 2012 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/idinor/code/StrippedDownNetServices/#dcf3c92487ca
diff -r 000000000000 -r 79f663186c05 imu-spi.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imu-spi.cpp Thu May 31 18:37:12 2012 +0000 @@ -0,0 +1,164 @@ +// +// imu-spi.cpp +// +// copyright 2010 Hugh Shane +// +#include "mbed.h" +#include "imu-spi.h" + +ImuSpi::ImuSpi(void) : + spi(p11, p12, p13), // mosi, miso, sclk (Note: mbed uses SSPx for the SPI busses) + cs(p16), // IMU chip select, active low + reset(p15), // IMU reset, active low. Also resets the altimeter. + diag(p17), // diagnostic output + imuDataReady(p14), // IMU data-ready interrupt input, active falling edge + onePPS(p19) // GPS 1 PPS interrupt input, active rising edge +{ + cs = 1; // set to quiescent state + diag = 0; + imuDataReady.mode(PullUp); // just to be safe + sequenceNumber = 0; + imuReadIndex = 0; + + // Initialize the IMU command sequence. Note: register 0x00 is a dummy + // value that triggers the last read in a burst cycle. + int8_t regVals[] = {0x04,0x06,0x08,0x0A,0x0C,0x0E,0x3C,0x00}; + for (int i = 0; i < bufferSize; i++) imuRegs[i] = regVals[i]; + + // init the pingpong buffer + pingpong = 0; + + // init the buffer ready semaphore + bufferReady = false; + + // Setup the SPI bus for 16 bit data, high steady state clock, + // second edge capture, with a 1 MHz clock rate + spi.format(16,3); + spi.frequency(1000000); + + // init the IMU + InitImu(); + wait_us(100); // allow things to settle before starting interrupts + + // Connect the IMU data-ready signal to its interrupt handler + imuDataReady.fall(this, &ImuSpi::IMUDataReadyISR); + + // Connect the onePPS signal to its interrupt handler + imuDataReady.rise(this, &ImuSpi::OnePPSISR); + +} + + +// initialize the IMU +void ImuSpi::InitImu(void) { + // deselect the IMU + cs = 1; + reset = 1; + // perform a hard reset + reset = 0; wait(.1); reset = 1; wait(.1); + // send initialization commands + WriteSynch(0x34, 0x04); // enable active low data ready on DIO1 + WriteSynch(0x39, 0x01); // Set the gyro sensitivity to 75 deg/sec + WriteSynch(0x38, 0x00); // Set the FIR filter to its widest possible bandwidth + +} + +// When the IMU has data ready, trigger a burst read. +// Launch an interrupt-driven process to read the IMU +// accelerometer and gyro registers into the pingpong buffer. +void ImuSpi::IMUDataReadyISR(void) { + // initialize the IMU data buffer + wp = GetBufferWritePtr(); + imuCmdIndex = 0; + imuReadIndex = 0; + + // reject spurious interrupts + if (imuDataReady == 0) { + // set up the first register read operation + SendReadCmd(imuRegs[imuCmdIndex++]); + } + +} + +// Start an asynchronous (non-blocking) read of the IMU +// register designated by 'adr' +void ImuSpi::SendReadCmd(int8_t adr) { + int16_t cmd = 0x3f00 & (((int16_t)adr) << 8); + cs = 0; + LPC_SSP0->DR = cmd; + + // start the timer that triggers the next command write + writeTrigger.attach_us(this, &ImuSpi::WriteTriggerTimeoutISR, (16+9)); + +} + +// handle the write trigger timeout interrupt +void ImuSpi::WriteTriggerTimeoutISR(void) { +diag = 1; + // buffer the contents of the receive data register that was acquired + // during the prior command write + *wp++ = (int16_t)(LPC_SSP0->DR); + + // if we've acquired an entire buffer of data, signal the foreground task + if (imuReadIndex++ >= dataSize) { + int16_t* p = GetBufferWritePtr(); + p[0] = sequenceNumber++; // buffer[0] has garbage, replace with the sequence number + bufferReady = true; + cs = 1; // deassert the IMU chip select + } else { + // we haven't yet read all the IMU registers, trigger the next read + SendReadCmd(imuRegs[imuCmdIndex++]); + } +diag = 0; +} + +// The foreground process uses this method to determine if +// if a burst read of the IMU is complete. If read was +// completed, the ping-pong buffers are toggled so that the +// most recent data is made available to the foreground +// process. +bool ImuSpi::IsBufferReady(void) { + bool ret; + + if (bufferReady == true) { + __disable_irq(); // ---- critical + TogglePingpong(); + bufferReady = false; + __enable_irq(); // ---- \critical + ret = true; + } else { + ret = false; + } + + return ret; +} + +// perform a synchronous (blocking) read of the IMU +// register designated by 'adr' +int16_t ImuSpi::ReadSynch(char adr) { + int16_t cmd = 0x3f00 & (((int16_t)adr) << 8); + int16_t response; + cs = 0; + // (1) command a read of the desired register while reading back garbage + spi.write(cmd); + // (2) command a read of register 0x00 while reading back the desired register + response = spi.write(0x3f00); + cs = 1; + return response; +} + +// perform a synchronous (blocking) write of 'data' to the IMU +// register designated by 'adr' +void ImuSpi::WriteSynch(char adr, char data) { + int16_t cmd = 0x8000 | (((int16_t)adr) << 8) | data; + cs = 0; + spi.write(cmd); + cs = 1; + wait_us(9); +} + +// When the GPS 1 PPS signal is asserted, clear the sequence number. +// This is how IMU data is synched with GPS data. +void ImuSpi::OnePPSISR(void) { + sequenceNumber = 0; +} \ No newline at end of file
diff -r 000000000000 -r 79f663186c05 imu-spi.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imu-spi.h Thu May 31 18:37:12 2012 +0000 @@ -0,0 +1,42 @@ +// +// imu-spi.h +// +// copyright 2010 Hugh Shane +// + +class ImuSpi { +private: + const static int dataSize = 7; + const static int bufferSize = dataSize+1; // we need to leave room for one junk data + int8_t imuRegs[bufferSize]; + int16_t buffer[2][bufferSize]; // ping-pong IMU data buffer + int8_t pingpong; + bool bufferReady; + SPI spi; + DigitalOut cs; + DigitalOut reset; + DigitalOut diag; + InterruptIn imuDataReady; + void InitImu(void); + void IMUDataReadyISR(void); + int16_t ReadSynch(char); + void WriteSynch(char, char); + void SendReadCmd(int8_t); + void TogglePingpong() {pingpong = (~pingpong) & 0x01;}; + int16_t* GetBufferWritePtr() {return &buffer[pingpong][0];}; + volatile int imuCmdIndex; + volatile int imuReadIndex; + Timeout writeTrigger; + int16_t* wp; + void WriteTriggerTimeoutISR(void); + void SSP0ISR(void); + static void _ssp0isr(void); + int sequenceNumber; + InterruptIn onePPS; +public: + ImuSpi(void); + void StartBurstRead(void); + int16_t* GetBufferReadPtr() {return buffer[(~pingpong) & 0x01];}; + bool IsBufferReady(void); + int GetBufferSize(void) {return bufferSize*sizeof(int16_t);}; +}; \ No newline at end of file
diff -r 000000000000 -r 79f663186c05 main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Thu May 31 18:37:12 2012 +0000 @@ -0,0 +1,93 @@ +// +// main.cpp +// +// Container class for mbed-based ADIS16355 IMU data acquisition system +// +// copyright 2010 Hugh Shane +// +#include "mbed.h" +#include "imu-spi.h" + +// http://mbed.org/cookbook/Networking-Stack-Releases +#include "EthernetNetIf.h" +#include "UDPSocket.h" + +#define NLOOPS 100 +#define PORT_DONT_CARE 10000 + +AnalogOut signal(p18); + +// mask off the flag bits +// convert two's complement to offset binary +uint16_t fixImuData(int16_t imuData) { + uint16_t imu16 = (imuData & 0x3fff) ^ 0x2000; + return imu16; +} + +int main() { + + EthernetNetIf eth( + IpAddr(192,168,1,2), //IP Address + IpAddr(255,255,255,0), //Network Mask + IpAddr(192,168,1,1), //Gateway + IpAddr(192,168,1,1) //DNS + ); + + int ethErr = eth.setup(); + + if ( ethErr == ETH_OK ) { + IpAddr localIp = eth.getIp(); + printf("mbed IP Address is %d.%d.%d.%d\r\n", + localIp[0], localIp[1], localIp[2], localIp[3]); + } else printf ("ETHERNETSETUP FAILED\n"); + + Host destHost(IpAddr(192,168,1,8), 55555); + UDPSocket udpSocket; + UDPSocketErr udpErr = udpSocket.bind(Host(IpAddr(), PORT_DONT_CARE)); + + if (udpErr != UDPSOCKET_OK) { + printf("error %d\n", udpErr); + }; + + DigitalOut diag_led(LED1); + ImuSpi imu; + int16_t* imubuffer; + int bufLength = 16; + int bufDepth = 10; // buffer this many acq. cycles before UDP send + char outBuf[bufLength * bufDepth]; + int nSent; + + diag_led = 0; + + Net::poll(); // ensure that every component of the network stack keeps running + wait(1); // give things time to settle before commencing + + for (int i = 0; i < NLOOPS; i++) { + //while(1) { + + for (int n = 0; n < bufDepth; n++) { + while (!imu.IsBufferReady()) {} // wait for the IMU buffer-ready signal + imubuffer = imu.GetBufferReadPtr(); // get a pointer to the new IMU output data + memcpy(&outBuf[bufLength*n] , imubuffer, bufLength); + signal.write_u16(fixImuData(imubuffer[6])); // write to the D/A converter + } + + Net::poll(); // ensure that every component of the network stack keeps running + nSent = udpSocket.sendto((char*)outBuf,(bufLength*bufDepth),&destHost); + + if ( nSent <= 0 ) { + printf("error %d\n", (UDPSocketErr)nSent); + fflush(stdout); + diag_led = 0; + break; + } else { + diag_led = 1; + //printf("."); + //fflush(stdout); + } + + } + + +} +
diff -r 000000000000 -r 79f663186c05 mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Thu May 31 18:37:12 2012 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/737756e0b479