Interfacing with IMU using SPI

I’m using an Arduino Uno to read in data from a DMU02. This is my first time using SPI, and I’m having difficulty figuring out how to read from the DMU02 and output the data in the Serial Monitor. The IMU has 3 slave ports, and by turning 1 out of the 3 from HIGH to LOW I can access the Gyroscope, Magnetometer, and Accelerometer. Just going off the help I’ve found online, I’ve written a bit of skeleton code and I was hoping I could get some insight on how to get the data out of the IMU.

//
#include <SPI.h>

#define DATAOUT 11 //MOSI
#define DATAIN 12 //MISO
#define SPICLOCK 13 //CLK
#define S1 7 //Slave 1
#define S2 6 //Slave 2
#define S3 5 //Slave 3
void setup() {

Serial.begin(9600);
//Initialize input and outputs
pinMode(DATAOUT, OUTPUT);
pinMode(DATAIN, INPUT);
pinMode(SPICLOCK,OUTPUT);
pinMode(S1,OUTPUT);
pinMode(S2, OUTPUT);
pinMode(S3, OUTPUT);
//raise all the slave selects high
digitalWrite(S1,HIGH);
digitalWrite(S2,HIGH);
digitalWrite(S3,HIGH);

SPI.begin(); // Initialize SPI parameters
SPI.setBitOrder(MSBFIRST); // MSB to be sent first
SPI.setDataMode(SPI_MODE3); // Set for clock rising edge
}

void loop()
{
int val=0; //test variable used when reading pins
int j=0; //variable used in data read operation
byte pot=B00000000; //zero out all the values in the byte, where data will be written to
for (int i=0; i<2;i++)
{
j=i+1;
val=digitalRead(j);
if(val==HIGH)
{
bitSet(pot,i);
i++;
}
}
digitalWrite(S1, LOW);
SPI.transfer(pot);
digitalWrite(S1, HIGH);
Serial.print(pot);
delay(1000);
}
//

Thanks!

srivathsa92:
I’m using an Arduino Uno to read in data from a DMU02. This is my first time using SPI, and I’m having difficulty figuring out how to read from the DMU02 and output the data in the Serial Monitor. The IMU has 3 slave ports, and by turning 1 out of the 3 from HIGH to LOW I can access the Gyroscope, Magnetometer, and Accelerometer. Just going off the help I’ve found online, I’ve written a bit of skeleton code and I was hoping I could get some insight on how to get the data out of the IMU.

please use the code tags </> around your code

I have inserted critiques to your code below:

//
#include <SPI.h>

/* unnecessary defines 
#define DATAOUT 11  //MOSI
#define DATAIN 12   //MISO
#define SPICLOCK 13 //CLK
*/

#define S1 7        //Slave 1
#define S2 6        //Slave 2
#define S3 5        //Slave 3
void setup() {
  
  Serial.begin(9600);
  //Initialize input and outputs
/* Unnecessary, the SPI.begin() will do this.
 
  pinMode(DATAOUT, OUTPUT);
  pinMode(DATAIN, INPUT);
  pinMode(SPICLOCK,OUTPUT);
*/

// but you should set SS (digital 10) to output,  When using the SPI hardware, if (digital pin 10),SS is 
// ever set as an INPUT, and it goes LOW, the next call to SPI.transfer() will hang forever.  The SPI
// hardware will switch to SPI Slave mode, and It will nolonger drive CLK,  It will accept CLK from the 
// 'other' SPI Master device one the bus.
  pinMode(SS,OUTPUT);
  digitalWrite(SS,HIGH); // this doesn't really matter, but SS should be OUTPUT whenever SPI is used.

// you could us SS, digital pin 10, as one of your 'Sx' pins.  

  pinMode(S1,OUTPUT);
  pinMode(S2, OUTPUT);
  pinMode(S3, OUTPUT);
  //raise all the slave selects high
  digitalWrite(S1,HIGH);  
  digitalWrite(S2,HIGH);  
  digitalWrite(S3,HIGH); 
  
  SPI.begin();                  //  Initialize SPI parameters
  SPI.setBitOrder(MSBFIRST);    //  MSB to be sent first
  SPI.setDataMode(SPI_MODE3);   //  Set for clock rising edge
}

void loop() 
{
  int val=0;  //test variable used when reading pins 
  int j=0;     //variable used in data read operation
  byte pot=B00000000;  //zero out all the values in the byte, where data will be written to
  for (int i=0; i<2;i++)
  {
    j=i+1;
    val=digitalRead(j);
    if(val==HIGH)
    {
      bitSet(pot,i);

      i++;
/*      
      why are you messing with the for loop value?
      here is what your code actually does:

      if val is HIGH 
         then bitSet(pot,i), 
         then increment i, 
         then the for loop incriments i again
         then the for loop test i <2, which always fails
   */
    }

// Here is my rewrite of this for loop
// also you should have set digital pins 1..2 as input (pinMode(1,INPUT); pinMode(2,INPUT);

  byte pot=B00000000;  //zero out all the values in the byte, where data will be written to
  for (int i=0; i<2;i++)  {
    if(digitalRead(i+1)) pot = pot | (1 << i);   
/*
     explaination:
      (1 << i)  means create a value by shifting 1, i binary places to the left 
      pot | (1 << i) means take the value of pot and 'OR' it with the value of (1 << i),
         so if pot =0, and i =0  then pot become 1;
             if pot =0 and i =1 then pot  = B00000000 | B00000010 = B00000010 = 2
             if pot = 2 and i= 0 then pot = B00000010 | B00000001 = B00000011 = 3
*/
    }

  digitalWrite(S1, LOW);
  SPI.transfer(pot);            // this command just sent 
// the Device will do nothing, because it is expecting a 6 byte command sequence with cksum.
  digitalWrite(S1, HIGH);
  Serial.print(pot);
  delay(1000);
}
//

Here is my code to read an axis;

#include <SPI.h>

#define axisX 2 // connect digital pin 2 GND to read X axis
#define axisY 3 // connect digital pin 3 GND to read Y axis
#define axisZ 4 // connect digital pin 4 GND to read Z axis

#define S1 7        //Slave 1
#define S2 6        //Slave 2
#define S3 5        //Slave 3


void getAxisData( uint8_t axisPin){
uint8_t cmd[6],data[6]; // buffers for SPI data

cmd[0] = 1; // get rate and Acceleration data
cmd[1] = 0; //reserved
cmd[2] = 0; //
cmd[3] = 0; //
cmd[4] = 0; //
cmd[5] = ~(cmd[0]+cmd[1]+cmd[2]+cmd[3]+cmd[4]); // one's complement of Sum (0..4)


switch(axisPin){
   case axisX : digitalWrite(S1,LOW);
      break;
   case axisY : digitalWrite(S2,LOW);
      break;
   case axisZ : digitalWrite(S3,LOW);
      break;
   default : 
      Serial.print("unknow Axis =");
      Serial.println(axisPin,DEC);
      return;
   }

for(int i=0;i<6;i++){
  data[i] = SPI.transfer(cmd[i]);
  }

switch(axisPin){
   case axisX : digitalWrite(S1,HIGH);
      break;
   case axisY : digitalWrite(S2,HIGH);
      break;
   case axisZ : digitalWrite(S3,HIGH);
      break;
   default : // can never get here, the first switch statement would have exited
      Serial.print("unknow Axis =");
      Serial.println(axisPin,DEC);
      return;
   }

Serial.print(" Rate and Accel for Axis pin=");

Serial.println(axisPin,DEC);
for(int i =0;i<6;i++){
   Serial.print("data[");Serial.print(i,DEC); Serial.print("]= B");Serial.println(data[i],BIN);
   }
Serial.println();
}
  

void setup() {
  
  Serial.begin(9600);
  //Initialize input and outputs

  pinMode(SS,OUTPUT);
  digitalWrite(SS,HIGH); // this doesn't really matter, but SS should be OUTPUT whenever SPI is used.

  pinMode(axisX,INPUT_PULLUP); // connect weak pullup on input pin, 'switch' is active 'LOW'

  pinMode(axisY,INPUT_PULLUP); // connect weak pullup on input pin, 'switch' is active 'LOW'

  pinMode(axisZ,INPUT_PULLUP); // connect weak pullup on input pin, 'switch' is active 'LOW'


  pinMode(S1,OUTPUT);
  pinMode(S2, OUTPUT);
  pinMode(S3, OUTPUT);
  //raise all the slave selects high
  digitalWrite(S1,HIGH);  
  digitalWrite(S2,HIGH);  
  digitalWrite(S3,HIGH); 
  
  SPI.begin();                  //  Initialize SPI parameters
  SPI.setBitOrder(MSBFIRST);    //  MSB to be sent first
  SPI.setDataMode(SPI_MODE3);   //  Set for clock rising edge
}

unsigned long timeout=0;

loop(){
  if (millis()>timeout){ // limit the rate of message to Serial monitor
    timeout = millis() + 1000; // once per second;
   
    for(int i = axisX;i<=axisZ;i++){
   
      if(!digitalRead(i) ) getAxisData(i); // if input is low then read axis data
   
      }

    }

}

try this code, I haven’t complied it, there may be some syntax errors

Chuck.


Check out my Kickstarter Project Memory Panes an expansion RAM Shield for Mega2560’s. It adds 1MB of RAM for those projects where 8KB is not enough.

Thank you! I'm sorry if this is obvious, but can you tell me why in the #define axisX (and Y and Z) lines, you say I'm supposed to connected digital pins 2, 3, and 4 to GND?

srivathsa92:
Thank you! I’m sorry if this is obvious, but can you tell me why in the #define axisX (and Y and Z) lines, you say I’m supposed to connected digital pins 2, 3, and 4 to GND?

In your loop code

int j=0;     //variable used in data read operation
  for (int i=0; i<2;i++)
  {
    j=i+1;
    val=digitalRead(j);

you are effectively executing the following statements

val = digitalRead(1) // which reads the TX line which is talking to the Serial Monitor(PC)
// I have no Idea why you did this but it would probably generate confusing values.

val = digitalRead(2) // which is ok.

What was your plan for using these two pins? were you connecting them to ground or Vcc?

I am using Pin 2, to tell my program when to read and display the S1 axis (I assume it is the X axis)

I am using Pin 3, to tell my program when to read and display the S2 axis (I assume it is the Y axis)

I am using Pin 4, to tell my program when to read and display the S3 axis (I assume it is the Z axis)

If you use a removable jumper (effectively a switch) then you can control which channel the Arduino displays without rewriting your sketch.

The pinMode(axisX,INPUT_PULLUP); command places pin {axisX or 2} in input mode, and it connects a 50k ohm resistor from pin 2 to VCC. This means that a digitalRead(2) will return HIGH if nothing is connected to pin 2. If you ‘ground’ or connect a jumper wire from ‘GND’ to pin 2, a digitalRead(2) will return LOW. So this is a really simple input method. The only hardware required is a piece of wire.

The way the program works is:

if (one second has elapsed since last I read sensor) then begin
set new timeout to be NOW plus one second.
if ( pin 2 is low) then begin
read and display S1 axis of sensor.
end
if ( pin 3 is low) then begin
read and display S2 axis of sensor.
end
if ( pin 4 is low) then begin
read and display S3 axis of sensor.
end
end
else begin
one second has not yet elapsed so
don’t do anything.
end

If none of my ‘switches’ are grounded, then the program just runs around the loop without appearing to do anything.

you can ground none, Pin2,Pin3, or Pin4, or any combination.

Chuck.