vectornav, mega, and SPI

Hi all,
I need some guidance here. I'm new to SPI and am not having much luck getting the data I want. The set-up is a vectornav sensor connected to the 4 SPI pins on the arduino mega. And here's my not-so-polished code:

/*
code to read vectornav data via an arduino mega SPI pins 

SPI mode uses a lightweight binary message format over the SPI data bus. The start of a command is signaled
by pulling the VN-100 module's chip select pin (pin 23) low. Both the chip select line and clock are active low. 
The first byte transmitted to the module should be the command ID and then a variable number of bytes will 
follow dependent on the type of command specified. A communication transaction can be cancelled at any time 
by releasing the chip select pin. Pulling the pin low again will start a new communication transaction. All binary 
data is sent to and from the chip with most significant bit (MSB) first in little-endian byte order with all 
numbers either represented as 32-bit floating point or 32-bit unsigned integers. For example the serial baud 
rate register with a value of 9600 (0x2580) would be sent across the SPI as a 0x80, 0x25, 0x00, 0x00. Data is 
requested from and written to the device using multiple SPI transactions.
 */

#define DATAOUT 51      //MOSI
#define DATAIN  50      //MISO 
#define SPICLOCK  52    //sck
#define SLAVESELECT 53  //ss

byte serialIn; // container to hold incoming serial data

byte clr;

byte attitude[16]; // yaw, pitch, & roll

unsigned long start_sample;
unsigned long end_sample;
unsigned long elapsed_time;


void setup() 
{
  Serial.begin(115200); // main UART pins
  delay(500);
  
  for (int i = 0; i < 16; i++) {
    attitude[i] = i;
  }

  // SPI configs
  pinMode(DATAOUT, OUTPUT);
  pinMode(DATAIN, INPUT);
  pinMode(SPICLOCK,OUTPUT);
  pinMode(SLAVESELECT,OUTPUT);
  digitalWrite(SLAVESELECT,HIGH); //disable device

  // SPCR = 01010000
  //interrupt disabled,spi enabled,msb 1st,master,clk low when idle,
  //sample on leading edge of clk,system clock/4 rate (fastest)

  SPCR = B01010000; //MPIE=0, SPE=1 (on), DORD=0 (MSB first), MSTR=1 (master), CPOL=0 (clock idle when low), CPHA=0 (samples MOSI on rising edge), SPR1=0 & SPR0=0 (4MHzHz)
  clr = SPSR;
  clr = SPDR;
  delay(500); // everyone else is doing it; i am a lemming

} // end setup

void loop() {
  // check UART pin for any incoming data
  if (Serial.available() > 0) { // mail call
    serialIn = Serial.read();

    // let's take a some sample
    if (serialIn == 33) { // = ! = time to start sampling
      // 01 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00

      digitalWrite(SLAVESELECT,LOW);
      
      attitude[0] = spi_transfer(0x01);
      delayMicroseconds(100);
      attitude[1] = spi_transfer(0x08);
      delayMicroseconds(100);
      attitude[2] = spi_transfer(0x00);
      delayMicroseconds(100);
      attitude[3] = spi_transfer(0x00);
      delayMicroseconds(100);
      attitude[4] = spi_transfer(0x00);
      delayMicroseconds(100);
      attitude[5] = spi_transfer(0x00);
      delayMicroseconds(100);
      attitude[6] = spi_transfer(0x00);
      delayMicroseconds(100);
      attitude[7] = spi_transfer(0x00);
      delayMicroseconds(100);
      attitude[8] = spi_transfer(0x00);
      delayMicroseconds(100);
      attitude[9] = spi_transfer(0x00);
      delayMicroseconds(100);
      attitude[10] = spi_transfer(0x00);
      delayMicroseconds(100);
      attitude[11] = spi_transfer(0x00);
      delayMicroseconds(100);
      attitude[12] = spi_transfer(0x00);
      delayMicroseconds(100);
      attitude[13] = spi_transfer(0x00);
      delayMicroseconds(100);
      attitude[14] = spi_transfer(0x00);
      delayMicroseconds(100);
      attitude[15] = spi_transfer(0x00);
      delayMicroseconds(100);

      digitalWrite(SLAVESELECT,HIGH); //release chip, signal end transfer

      for (int i = 0; i < 16; i++) {
        Serial.print(attitude[i], BYTE);
      }
      Serial.print(10, BYTE);
      
    } // end sample if/then

  } // end UART while loop

}


byte spi_transfer(volatile byte data)
{
  SPDR = data;                    // Start the transmission
  while (!(SPSR & (1<<SPIF)))     // Wait the end of the transmission
  {
  };
  return SPDR;                    // return the received byte
}

So with the above code I'm just trying to get attitude vales (heading, pitch, roll). The message I'm sending (in hex) is:

01 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00

what I should get back should be something like:
00 01 08 00 39 8A 02 43 FD 43 97 C1 CD 9D 67 42

(the last 12 bytes = -130.54, -18.91, +57.90)

What I'm getting is:
1 128 0 0 0 0 0 0 0 0 0 0 0 0 0 0
or
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

I feel like I'm close since it's at least writing over my init values for the array, but after a couple days of reading up on SPI I'm a bit at a loss at what to try next, or if there is an error in my code or ??

Any advice? Also FYI I can communicate just fine via the UART pins (one of the reasons why getting the mega), but was looking for a faster method for getting data out of the sensor.

TIA,
David

Hi David, I'm also interested in getting the SPI to work, kinda new this kind of comms and in the same situation as you. Let me know how it turns out.

Cheers,

Luke

So I talked to vectornav developers and they believe it might be a voltage level mis-match. Although the vectornav is powered off a 5V supply, the SPI interface uses 3V. Anybody know what the voltage levels are coming out the SPI pins on the mega running at 5V?

Thanks,
David

You will need to do voltage level conversion. Arduino uses 5V. There are search the forum for voltage level conversion. You may be able to cheat with a resistor divider.

Spark fun has a board with two converters, they're not to pricey. I think you'd need two of them.

For the voltage level conversion - rather stay away from resistor-dividers, although they work in theory, you can easily be snookered by the degradation of signal quality - in terms of voltage rise-time, and hnce bit-rate. Use a solid-state converter - there are many to choose from.

Charlie

Hi David, just a quick note, the VN-100(t) can be powered on the Vcc line from 3.3-5.5V (http://www.vectornav.com/Downloads/Support/UM002.pdf, pg.7), have you tried operating it via the 3.3V output on the mega?

@Hallicarnassus:
I have, but that's not really the problem. The problem is the mis-match in voltages on the communication lines. The arduino is still sending out voltages up to 5V, while the vectornav expects things around 3V.

@mrmeval:
I saw your post last night just about the time I found the level shifter on sparkfun (my home away from from):

I'm going to grab a bunch anyway since I'm using a bunch of wireless radios @3.3V connected to arduinos @5V via the UART pins (always seem to forget that I need to convert the levels).

The biggest note I saw wrt the shifter above was that it might not be quick enough for the higher frequency shifting of the SPI pins (which I think is what CharlieD is referring to above). This article was very helpful:
http://delphys.net/d.holmes/hardware/levelshift.html
in particular using the "Fairchild Semiconductor BSS138 N-channel enhancement mode MOSFET". I have orders ready to go at both sparkfun and digikey, so we'll see if this helps.

Also, I know it's been cited a couple times in the forum, but just in case sparkfun has a helpful tutorial on level shifting:
http://www.sparkfun.com/commerce/tutorial_info.php?tutorials_id=65

Thanks,
David

wait...just looked at the schematic and sparkfun's level shifter uses the BSS138 mosfet. Even better!
David

Could you use a TTL voltage shifting IC for the same effect?