vmzaccar

ADIS16448 with MSP430FR5739

Discussion created by vmzaccar on Oct 21, 2015
Latest reply on Oct 21, 2015 by NevadaMark

All,

 

I worked with Mark Looney to establish communication between a ADIS61448 and a TI MSP430FR5739 launchpad. I've posted the code below in case anyone else would find this useful:

 

//My main loop consists of calling a function to get new readings from the ADIS16448 every 100ms:

  if(five_msec_timer >= main_next_time){
      main_next_time = five_msec_timer + 10;   //10*5msec = 100msec
      if(main_next_time >= FIVE_MSEC_UL){main_next_time = main_next_time - FIVE_MSEC_UL;}
     
      read_IMU();
  }


//The function read_IMU contains the following:

void read_IMU(void){
  
  int i = 0;
  
  //The transmit sequence below contains the command for burst mode, followed
  //by 12, 16 bit words to allow the device to transmit the requested 
  //information back. The MSP430 I'm using has a 8 bit SPI buffer, so for every
  //16 bit word, I used 2, 8 bit hex zeros.
  char transmit_sequence[NUM_BYTES_TX] = 
  {BURST_MODE,HEX_ZERO,HEX_ZERO,HEX_ZERO,HEX_ZERO,HEX_ZERO,
  HEX_ZERO  ,HEX_ZERO,HEX_ZERO,HEX_ZERO,HEX_ZERO,HEX_ZERO,
  HEX_ZERO  ,HEX_ZERO,HEX_ZERO,HEX_ZERO,HEX_ZERO,HEX_ZERO,
  HEX_ZERO  ,HEX_ZERO,HEX_ZERO,HEX_ZERO,HEX_ZERO,HEX_ZERO,
  HEX_ZERO  ,HEX_ZERO};  
  
  
  /* The output of burst mode will be in the following order:
  DIAG_STAT 
  XGYRO_OUT, YGYRO_OUT, ZGYRO_OUT, 
  XACCL_OUT, YACCL_OUT, ZACCL_OUT,
  XMAGN_OUT, YMAGN_OUT, ZMAGN_OUT, 
  BARO_OUT,  TEMP_OUT.
  See the datasheet for conversion from hex to real values*/
  
  
  //Clear out old data from the results arrays
  for(i = 0; i < NUM_BYTES_TX; i++){raw_data[i] = 0;}
  i = 0;
  
  for(i = 0; i < NUM_READINGS; i++){complete_data[i] = 0;}
  i = 0;
  
  
  //- In this loop, the UCB0RXBUF is always 1 behind because we don't wait for 
  //  the recieve flag to happen before we read the RX buf. Therefore, the RX 
  //  buf is always one behind the current loop
  
  //This loop works like this:   
  //- Transmit the i-th element of transmit_sequence
  //- Wait for it to finish transmitting. Note that this does not necessarily 
  //  mean that we've recieved the i-th bit - in fact, since we don't wait, the
  //  RX buffer will always read one loop behind the current iteration. Take
  //  this into account by putting this value into the i-1'th position in the
  //  raw data array.
  //- Now we save the recieved byte to the raw data array. As I mentioned before
  //  this will be 1 behind the current loop, but additionally since the ADIS16448
  //  waits 2 bytes to return sensor data, total delay in data is 1 + 2 = 3 bytes
  //  If we're on i = 0..2, just trash the data we recieved (to clear the rx flag)
  
  
  int trash = UCB0RXBUF;                   //Clear the RX buffer, just in case
  P1OUT &= ~CS_IMU;                        //Pull CS for the IMU low  
  
  while(i != NUM_BYTES_TX){
    
    if(UCB0IFG & UCTXIFG){                // If the previous character has been trasmitted
      UCB0TXBUF = transmit_sequence[i];   // Write the corrisponding letter to the TX buffer  
      while(! (UCB0IFG & UCTXIFG)){}      // Wait for the transmit to finish
      if(i >= BYTE_OFFSET){raw_data[i-BYTE_OFFSET] = UCB0RXBUF;} //The recieve buffer still has the previous character in it, so grab that
      else{int trash = UCB0RXBUF;} // Otherwise we're reeciving stuff we don't care about, so trash it
      i++;
    }
  }
  
  if(! (UCB0IFG & UCRXIFG)){         // If we're not done recieving yet
    while(! (UCB0IFG & UCRXIFG)){}   // Wait to finish recieving
  }
  raw_data[i-BYTE_OFFSET] = UCB0RXBUF; //Write the last char we were waiting on to the results array
  
  P1OUT |= CS_IMU;                   //Once everything is transmitted, pull CS high again
  
  
  //This chunk of code just concatonates all the 8 bit readings into a 16 bit
  //values, since that's what the sensor outputs. 
  i = 0;
  int lower_byte = 0;
  int upper_byte = 0;
  for(i = 0; i < NUM_READINGS; i++){
    lower_byte = 2*i;
    upper_byte = lower_byte + 1;
    
    complete_data[i] = (raw_data[lower_byte]<<8 | raw_data[upper_byte]);
  }
  
  //This function converts the decimal binary to a string of hex, then transmits
  //it out the serial port in reverse order (so it reads correctly on the screen)  
  if(IMU_TRANSMIT){
    
    i = 0;
    int j = 0;
    int temp = 0;
    for(i = 0; i < NUM_READINGS; i++){ //Run through all the complete readings
      while(! (UCA0IFG & UCTXIFG)){}   //Wait until the serial TX buffer is ready
      UCA0TXBUF = APOSTROPHE;          //Transmit an apostrophe to begin the value,
      //Makes reading it in matlab easier
      for(j = 3; j >= 0 ; j--){        //Every value has 4 nibbles, convert them to hex 
        
        temp = complete_data[i];       //Grab the value we're going to convert
        temp  = temp >> (4*j);         //Bit shift by 4*(current loop #)
        temp &= 0x000F;                //Bit mask to only get the last nibble
        
        if(temp <= 9){                  //If the nibble is a number
          temp |= 0x30;                 //OR with 0x30 to get an ASCII character
        }
        else{                           //Otherwise it's a hex letter
          temp = ((temp-9) | 0x40);     //Subtract 9 and OR with 0x40 to get a
        }                               //A through F
        



        while(! (UCA0IFG & UCTXIFG)){}   //Wait until the serial TX buffer is ready
        UCA0TXBUF = temp;                //Transmit the hex value
      }     
      while(! (UCA0IFG & UCTXIFG)){}   //Wait until the serial TX buffer is ready
      UCA0TXBUF = APOSTROPHE;          //Transmit an apostrophe to make reading into matlab easier
      while(! (UCA0IFG & UCTXIFG)){}   //Wait until the serial TX buffer is ready
      if(i != NUM_READINGS - 1){UCA0TXBUF = COMMA;} //If it's a normal value, delimit it with a comma
      else{UCA0TXBUF = SEMICOLON;}     //If it's the end, delimit with a semicolon
    }
    
    while(! (UCA0IFG & UCTXIFG)){}   //At the end of the line, transmit a CR LF
    UCA0TXBUF = CARRIAGE_RETURN;  
    while(! (UCA0IFG & UCTXIFG)){}  
    UCA0TXBUF = LINE_FEED;    
  }
}

 

Configuring the SPI bus on UCB0 below. Note that the MSP430 DOES NOT MATCH THE ADIS16448 DATASHEET PHASE. Phase should be left at 0, polarity should be 1.


void Init_SPI_UCB0(void){   
 //Configure UCB0 for SPI mode 3
  
  UCB0CTLW0 |= UCSWRST;                  //Set Software reset - used to configure module
  
  UCB0CTLW0 = CLEAR_REGISTER;            //Start with UCB0CLW0 by clearing it
  UCB0CTLW0 |= UCCKPL;                   //CPOL = 1 (Polarity)
  UCB0CTLW0 |= UCMSB;                    //MSB first
  UCB0CTLW0 |= UCMST;                    //Set the MSP430 as the master
  UCB0CTLW0 |= UCMODE_1;                 //4 pin SPI with UCxSTE active high: Slave enabled when UCxSTe = 1
  UCB0CTLW0 |= UCSYNC;                   //Synchronous mode (SPI)
  UCB0CTLW0 |= UCSSEL_1;                 //Select ACLK as clock source - must be <= 2MHz for IMU
  UCB0CTLW0 &= ~UCSTEM;                  //Configure STE (CS) pin to prevent conflicts. If =1, would use STE pin for CS,
                                         //but since we've got multiple slaves we need to do it with software
  
  UCB0TXBUF = CLEAR_REGISTER;            //Clear the TX register
  UCB0STATW = CLEAR_REGISTER;            //Clear just in case - disables loopback mode


  UCB0CTLW0 &= ~UCSWRST;                 //Disable software reset
}

 

Finally, my relevant #defines:

 

#define NUM_READINGS           (12) // Number of readings to take 
#define NUM_BYTES_TX           (26) // Number of bytes to transmit - 2*NUM_BYTES_TX + 2
                                    // (blank bytes to get the last reading out)


#define BYTE_OFFSET             (3) // Number of bytes to offset the recieve - since the results being transmitted are 16 bit,
                                    // wait 2 bytes to read the response we asked before, plus 1 because we read the recieve 
                                    // buffer one cycle later


#define XGYRO_OUT            (0x04) // Address for X gyro output 
#define YGYRO_OUT            (0x06) // Address for Y gyro output 
#define ZGYRO_OUT            (0x08) // Address for Z gyro output
#define XACCL_OUT            (0x0A) // Address for X accelerometer output
#define YACCL_OUT            (0x0C) // Address for Y accelerometer output
#define ZACCL_OUT            (0x0E) // Address for Z accelerometer output
#define XMAGN_OUT            (0x10) // Address for X magnetometer output
#define YMAGN_OUT            (0x12) // Address for Y magnetometer output
#define ZMAGN_OUT            (0x14) // Address for Z magnetometer output
#define BARO_OUT             (0x16) // Address for Barometer output
#define TEMP_OUT             (0x18) // Address for Temperature output
#define DIAG_STAT            (0x3C) // Diagnostic/Status register
#define PROD_ID              (0x56) // Should return 0x4040
#define HEX_ZERO             (0x00) // Hex zero, for padding
#define BURST_MODE           (0x3E) // Command to send burst mode

 

Hope this is helpful!

Outcomes