Post Go back to editing

ADIS16210 Sharp Jumps Between Readings

Hi there,

I've been playing around with the ADIS16210-CMLZ IMU and it was working quite well. However it has suddenly stopped showing any values that make sense. I used some old code that I knew worked and so I believe the issue lies with the IMU. I'm using an Arduino MEGA 2560 for the connection. Here's the code:

 

#include <SPI.h> 
#define SS 53

int16_t x16,y16,z16;
float xOut = 1,yOut = 1,zOut = 1;
int16_t ax16,ay16,az16;
float axOut = 1,ayOut = 1,azOut = 1;
int16_t test = 0;

void setup() {
  Serial.begin(57600);
  SPI.begin(); 
  SPI.beginTransaction(SPISettings(830000,MSBFIRST,SPI_MODE3));
  pinMode(SS, OUTPUT); //added on suggestion
  Serial.println();

 digitalWrite(SS,LOW);

  SPI.transfer(0xB8);  
  SPI.transfer(0x00);//Change this variable for Sample Rate (Table 23) //Changed to 0x00
  delay(1);

  SPI.transfer(0xBE);
  SPI.transfer(0x01);
  delay(1000);
  
  
  //Edit 1
  SPI.transfer(0x3E);
  SPI.transfer(0x10); //Clear DIAG_STAT register
  delay(300);

  SPI.transfer(0x3E);
  SPI.transfer(0x04);// Self Test
  delay(300);

  SPI.transfer16(0x3C20); // DIAG_STAT[5]
  delay(1);
  int16_t selfcheck = SPI.transfer16(0);
  delay(1);
  Serial.print(" "); Serial.print("Self Check: "); Serial.print(selfcheck,HEX);

  SPI.transfer16(0x5600);// Prod ID
  delay(1);
  int16_t prodID = SPI.transfer16(0);
  delay(1);
  Serial.print(" "); Serial.print("Prod ID: "); Serial.print(prodID,HEX);

  Serial.println();
  int16_t temp = 0;
  int16_t reg = 0;
  for(int i = 0; i < 12; i++){
    reg = 0x3C00 + (0x01 << i);
    SPI.transfer16(reg);
    delay(1);
    temp = SPI.transfer16(0);    
    delay(1);
    Serial.print(" "); Serial.print("DIAG_STAT["); Serial.print(i);Serial.print("] ");
    Serial.print((reg),HEX); Serial.print(" "); Serial.print(temp,BIN);
    Serial.println();
  }
  Serial.println();
  //End of Edit 1

  digitalWrite(SS,HIGH);
}

void loop() {
  digitalWrite(SS,LOW);
  delay(2);
    //--------------Accelerometer-----------------//
  SPI.transfer16(0x0400);
  delay(1);
  ax16 = SPI.transfer16(0);
  axOut = ((float)ax16)/16384;
  delay(1);
  Serial.print(" "); Serial.print("ax: "); Serial.print(ax16); Serial.print(" "); Serial.print(axOut); Serial.print(" ");
  
  SPI.transfer16(0x0600);
  delay(1);
  ay16 = SPI.transfer16(0);
  ayOut = ((float)ay16)/16384;
  delay(10);
  Serial.print(" "); Serial.print("ay: "); Serial.print(ay16); Serial.print(" "); Serial.print(ayOut); Serial.print(" ");

  SPI.transfer16(0x0800);
  delay(1);
  az16 = SPI.transfer16(0x0000);
  azOut = ((float)az16)/16384;
  delay(1);
  Serial.print(" "); Serial.print("az: "); Serial.print(az16); Serial.print(" "); Serial.print(azOut); Serial.print(" ");

  //--------------Incline-----------------//

  SPI.transfer16(0x0C00);
  delay(1);
  x16 = SPI.transfer16(0x0000);
  xOut = ((float)x16)*180/32768;
  delay(1);
  Serial.print(" "); Serial.print("x: "); Serial.print(x16); Serial.print(" "); Serial.print(xOut); Serial.print(" ");
  
  SPI.transfer16(0x0E00);
  delay(1);
  y16 = SPI.transfer16(0x0000);
  yOut = ((float)y16)*180/32768;
  delay(1);
  Serial.print(" "); Serial.print("y: "); Serial.print(y16); Serial.print(" "); Serial.print(yOut); Serial.print(" ");

  SPI.transfer16(0x1000);
  delay(1);
  z16 = SPI.transfer16(0x0000);
  zOut = ((float)z16)*180/32768;
  delay(1);
  Serial.print(" "); Serial.print("z: "); Serial.print(z16); Serial.print(" "); Serial.print(zOut); Serial.print(" ");
  
  Serial.println();
  digitalWrite(SS,HIGH);
  delay(10);
}

Some of the more consistent or interesting trends:

x acc will sharply drop from 0.56 to -1.14. x inc will go from 24 to -124 degrees. All of this happens at about a 60 degree incline

Doing a full rotation y acc will climb to 0.64, then go back down to -0.64

Doing a full rotation z acc will go from -1 to 0 to 0.06 then back to 0 then down to -0.75 then sharply jump to 1.22 then back to 0.76 then sharply jump to -1.24 then climb back to -1 at its original position

I'm at my wits end. Is the IMU simply broken?

Edit Notes

Changed sample rate, set SS to OUTPUT
[edited by: lotm at 1:44 AM (GMT -4) on 27 Jul 2021]
  • Hi there! Thanks for the question and apologies that you're having issues here. Sadly I don't have access to hardware to double check your code, but it's on order and should arrive early tomorrow morning and I can get back to you later in the day. Sorry for the delay here, but I'll get back to you once I get the HW. Thanks for your understanding!

  • Yes. I apologize for the delay here. I was pulled off on another project. I have hardware in the office to test out tomorrow and will get back to you ASAP thanks!

  • Hi there! Sorry for the delay. I just had a chance to get a board set up and try a few things:

    1. Can you provide a pinout of the HW to your Arduino? Related to this, while the part does seem to support 5V, it would be better if you could get everything down to 3.3V in the future since the datasheet and VDD are spec'd at 3.6V or less as the recommended operating conditions. Either using a level translator or possibly using a Teensy instead of an Arduino. For now it should be okay though. 
    2. Can you set the CS pin to a digital output in your set up routine? pinMode(SS, OUTPUT); should be what you want there. Seems to be working without, but good to be explicit

    3. In your set up routine, can we change the number of averages to 0? just change line 18 to 0x00 to do this. I'm hoping to see instantaneous changes with this rather than waiting for a huge number of samples (128). This we can check after the following steps.

    4. Can you try running the "self test" routine in the setup function? For this you need to write to register 0x3E with a value of 0x10. This resets all the flags in the DIAG_STAT register. Then write to register 0x3E again with value of 0x04 to enable the self test. The self test should take about 54ms (so give it a delay of like 300 to be safe). Then go and read the DIAG_STAT register (0x3C). Bit 5 of this register is whether or not the self test function passed or failed. (https://www.analog.com/media/en/technical-documentation/data-sheets/adis16210.pdf on page 16). What is the value of the whole DIAG_STAT register in hex? Does the self test pass?

    5. We can also check if the SPI is working by reading the PROD_ID registers (0x56 and 0x57). According to page 16 of the datasheet, the PROD_ID registers should produce the value 0x3F52 in hex (16,210 decimal). Do you get the proper ID?

    6. Also if you want a number to print in HEX in Arduino, you can change the Serial.print to something like Serial.print(az16, HEX); This might make it easier to read the hex values of registers rather than the decimal values!

    Give those things a shot and let's take it from there Slight smile

    Thanks,

    Chas

  • Thank you for the extensive reply

    1. I'm using the 3.3V pin to avoid that issue. Pin layout is labelled J1 -> Arduino:

    12->3.3V

    9->GND

    2->52

    3->53

    4->50

    6->51

    2/3. Done and done

    4/5. Here's the Output. 0x57 returns 0 so I just used 0x56.

    09:38:28.004 -> Self Check: 88 Prod ID: 3F52
    09:38:28.004 -> DIAG_STAT[0] 3C01 10001000
    09:38:28.004 -> DIAG_STAT[1] 3C02 1000
    09:38:28.004 -> DIAG_STAT[2] 3C04 10001000
    09:38:28.004 -> DIAG_STAT[3] 3C08 10001000
    09:38:28.004 -> DIAG_STAT[4] 3C10 10001000
    09:38:28.004 -> DIAG_STAT[5] 3C20 10001000
    09:38:28.004 -> DIAG_STAT[6] 3C40 1000
    09:38:28.004 -> DIAG_STAT[7] 3C80 10001000
    09:38:28.067 -> DIAG_STAT[8] 3D00 10001000
    09:38:28.067 -> DIAG_STAT[9] 3E00 0
    09:38:28.067 -> DIAG_STAT[10] 4000 0
    09:38:28.067 -> DIAG_STAT[11] 4400 0

    Edit: Just ran the code again and got this output instead. Didn't change any code
    09:51:55.924 -> Self Check: 80 Prod ID: 3F52
    09:51:55.924 -> DIAG_STAT[0] 3C01 0
    09:51:55.924 -> DIAG_STAT[1] 3C02 10000000
    09:51:55.924 -> DIAG_STAT[2] 3C04 10000000
    09:51:55.924 -> DIAG_STAT[3] 3C08 10000000
    09:51:55.924 -> DIAG_STAT[4] 3C10 10000000
    09:51:55.971 -> DIAG_STAT[5] 3C20 10000000
    09:51:55.971 -> DIAG_STAT[6] 3C40 10000000
    09:51:55.971 -> DIAG_STAT[7] 3C80 10000000
    09:51:55.971 -> DIAG_STAT[8] 3D00 10000000
    09:51:55.971 -> DIAG_STAT[9] 3E00 0
    09:51:55.971 -> DIAG_STAT[10] 4000 0
    09:51:55.971 -> DIAG_STAT[11] 4400 0

    Edit2: After a few more repeats it seems that my first output and the following output are the most common. Those second results I haven't received again. Could the issue be my voltage pin?
    10:28:37.283 -> Self Check: 88 Prod ID: 3F52
    10:28:37.283 -> DIAG_STAT[0] 3C01 10001000
    10:28:37.283 -> DIAG_STAT[1] 3C02 10001000
    10:28:37.283 -> DIAG_STAT[2] 3C04 10001000
    10:28:37.283 -> DIAG_STAT[3] 3C08 10001000
    10:28:37.283 -> DIAG_STAT[4] 3C10 10001000
    10:28:37.345 -> DIAG_STAT[5] 3C20 10001000
    10:28:37.345 -> DIAG_STAT[6] 3C40 10001000
    10:28:37.345 -> DIAG_STAT[7] 3C80 10001000
    10:28:37.345 -> DIAG_STAT[8] 3D00 10001000
    10:28:37.345 -> DIAG_STAT[9] 3E00 0
    10:28:37.345 -> DIAG_STAT[10] 4000 0
    10:28:37.345 -> DIAG_STAT[11] 4400 0

  • Hmm. Connections look good. It's strange to me that the accel works with voltages as you have. Seems to be roughly working for now.

    The print outs don't see, to be working as expected. All of those DIAG_STAT bits should be a single digit. Can you show the code for printing these numbers please?

  • Can you also make the VDD 5V? It should be okay as per the datasheet max specs. Also I don't quite understand the output format above. The register address and data are not easy to follow. Can you format the output to be register = value or something similar? 

    Also did you do the self test? I can't tell in the code above. Thanks!

  • Everything here is done with 5V. Still some variance like before, but most of the time it returns this:

    09:04:49.685 -> Self Check: 82 Prod ID: 3F52
    09:04:50.201 -> DIAG_STAT[0] 3C01 = 10000010
    09:04:50.341 -> DIAG_STAT[1] 3C02 = 10000010
    09:04:50.435 -> DIAG_STAT[2] 3C04 = 10000010
    09:04:50.529 -> DIAG_STAT[3] 3C08 = 10000010
    09:04:50.623 -> DIAG_STAT[4] 3C10 = 10000010
    09:04:50.716 -> DIAG_STAT[5] 3C20 = 10000010
    09:04:50.810 -> DIAG_STAT[6] 3C40 = 10000010
    09:04:50.919 -> DIAG_STAT[7] 3C80 = 10000010
    09:04:51.028 -> DIAG_STAT[8] 3D00 = 10000010
    09:04:51.123 -> DIAG_STAT[9] 3E00 = 0
    09:04:51.232 -> DIAG_STAT[10] 4000 = 0
    09:04:51.352 -> DIAG_STAT[11] 4400 = 0

    Self test is on line 34

    Here are some results as their raw int16_t values. Each time I make two rotations clockwise on their axis and then made two rotations anticlockwise.

  • Hi there! I'm sorry this has been such a long delay, but I finally had a chance to test this out again!

    In rereading the datasheet, the reading of the sensors did not seem to be as smooth as it should be (there were extra read cycles in there). It's easier to pipeline the data as mentioned in Figure 6 on page 7 of the datasheet (https://www.analog.com/media/en/technical-documentation/data-sheets/adis16210.pdf). 

    So in the code below I did just that and then printed information. I gave this a quick try on a sensor I had here and it didn't seem to have any major jumps in the data output. Can you give this code a shot? I noticed that if I had the write to enable the user alignment (writing to 0xBE01) that I had issues with the sensor data, but when I removed that write it seemed to be ok.

    #include <SPI.h> 
    #define SS 53
    
    int16_t x16,y16,z16;
    float xOut = 1,yOut = 1,zOut = 1;
    int16_t ax16,ay16,az16;
    float axOut = 1,ayOut = 1,azOut = 1;
    int16_t test = 0;
    
    void setup() {
      Serial.begin(57600);
      SPI.begin(); 
      SPI.beginTransaction(SPISettings(750000, MSBFIRST, SPI_MODE3));
      pinMode(SS, OUTPUT); //added on suggestion
      Serial.println();
    
      digitalWrite(SS,LOW);
      SPI.transfer16(0xB800); // Lower 8 bits are 0x00 for Sample Rate (Table 23 addr 0x38), changed to 0x00  
      digitalWrite(SS,HIGH);
    
    //  Skip user alignment 
    //  digitalWrite(SS,LOW);
    //  SPI.transfer(0xBE);
    //  SPI.transfer(0x01);
    //  digitalWrite(SS,HIGH);
     
      delay(1000);
     
      digitalWrite(SS,LOW);
      SPI.transfer16(0xBE10); // Clear DIAG_STAT register (Table 42)
      digitalWrite(SS,HIGH);
      delay(300);
      
      digitalWrite(SS,LOW);
      SPI.transfer16(0xBE04); // Start self test
      digitalWrite(SS,HIGH);
      delay(300);
    
      digitalWrite(SS,LOW);
      SPI.transfer16(0x3C00); 
      delay(1);
      int16_t selfcheck = SPI.transfer16(0);
      delay(1);
      Serial.print(" "); Serial.print("Self Check: "); Serial.print(selfcheck,HEX);
      digitalWrite(SS,HIGH);
    
      digitalWrite(SS,LOW);
      SPI.transfer16(0x5600);// Prod ID
      delay(1);
      int16_t prodID = SPI.transfer16(0);
      delay(1);
      Serial.print(" "); Serial.print("Prod ID: "); Serial.print(prodID,HEX);
      digitalWrite(SS,HIGH);
    }
    
    void loop() {
      digitalWrite(SS,LOW);
      delay(2);
      //-------------- Accelerometer & Inclinometer Reads-----------------//
      //
      SPI.transfer16(0x0400); // Start read of X axis
      delay(1);
      ax16 = SPI.transfer16(0x0600); // Read X axis accel data and Enable next read of Y axis accel 
      delay(1);
      ay16 = SPI.transfer16(0x0800); // Read Y axis accel & prep for Z axis accel 
      delay(1);
      az16 = SPI.transfer16(0x0C00); // Read Z axis accel & prep for Inclinometer X axis
      delay(1);
      x16 = SPI.transfer16(0x0E00); // Read X axis inclin & prep for Inclinometer Y axis
      delay(1);
      y16 = SPI.transfer16(0x1000); // Read Y axis inclin & prep for Inclinometer Z axis
      delay(1);
      z16 = SPI.transfer16(0x0000); // Read Z axis inclin
      digitalWrite(SS,HIGH);
    
      //-------------- Conversions & printing -----------------//
      // Note that Arduino doesn't have a floating point unit on it so these will be slow & emulated in software
      axOut = ((float)ax16)/16384;
      ayOut = ((float)ay16)/16384;
      azOut = ((float)az16)/16384;
      xOut = ((float)x16)*180/32768;
      yOut = ((float)y16)*180/32768;
      zOut = ((float)z16)*180/32768;
      Serial.print(" "); Serial.print("ax: "); Serial.print(ax16); Serial.print(" "); Serial.print(axOut); Serial.print(" ");
      Serial.print(" "); Serial.print("ay: "); Serial.print(ay16); Serial.print(" "); Serial.print(ayOut); Serial.print(" ");
      Serial.print(" "); Serial.print("az: "); Serial.print(az16); Serial.print(" "); Serial.print(azOut); Serial.print(" ");
      Serial.print(" "); Serial.print("x: "); Serial.print(x16); Serial.print(" "); Serial.print(xOut); Serial.print(" ");
      Serial.print(" "); Serial.print("y: "); Serial.print(y16); Serial.print(" "); Serial.print(yOut); Serial.print(" ");
      Serial.print(" "); Serial.print("z: "); Serial.print(z16); Serial.print(" "); Serial.print(zOut); Serial.print(" ");
      Serial.println();
      delay(10);
    }

     I tested this on a Teensy (and changed the SS). Does this change anything?

  • Hi there,

    Just tried your code and it produces the same results.

    Any further advice? Who do I need to contact to request a replacement?