ADIS16448 with MSP430FR5739

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



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;}

//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] = 
  /* The output of burst mode will be in the following order:
  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
  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)  
    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
    while(! (UCA0IFG & UCTXIFG)){}  


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!