Thomas Stegeman

Bidirectional SPI

Discussion created by Thomas Stegeman on Aug 17, 2010
Latest reply on Aug 19, 2010 by Thomas Stegeman

I am using the SLKS12 with option "C128", MC9S12 C128 MCU, 80 LQFP.  The accelerometer module that I am trying to communicate with is the HitachiH48C3 from Parallax.  It only has one data pin so I have no choice but to use bidirectional mode.  The datasheet is not very specific about the communication protocol but I found the data sheet for the ATD chip on the accelerometer module.  I have read a lot of threads concerning this mode but to no avail.  Hopefully Peg or BigMac can help with these short comings.  Here is the code I have been working with:


void main(void)
   float gforce[] = {0.0,0.0,0.0};                 //Calculated G-forces
                                                //0 is X axis
                                                //1 is Y axis
                                                //2 is Z axis
  //Forever loop
       if( gforce[0]!=0.0 || gforce[1]!=0.0 || gforce[2]!=0.0)     //Test to see if motion
      PTT_PTT1 = 1;
      PTT_PTT1 = 0;
       for (i=0 ; i<3 ; i++)
      gforce[i] = axis_acceleration(i);   //Interrogate accelerometer and calc G's
  }/* loop forever */
  /* please make sure that you never leave main */
}//end of main


 void SPIinit(void)
  SPICR1 = 0x70;                            //Load pattern for SPI control register 1
                                                //Interrupt disabled
                                                //System enabled
                                                //Trans interrupt enabled
                                                //Master mode
                                                //Clock polarity (idle low)
                                                //Clock phase (rising)
                                                //Slave select output disabled
                                                //MSB first
  SPICR2 = 0x03;                            //Load pattern for SPI control register 2
                                                //Mode fault disabled
                                                //Bidirectional mode(recieve)
                                                //Stop in wait mode
                                                //Serial pin control(bidirectional)
  SPIBR = 0x01;                             //Load pattern for SPI baud rate
                                                //Bus clock divide by 4
                                                //500ns minimum clokc for accelerometer
                                                //2MHz clock maximum
}//SPI initialize subroutine


float axis_acceleration(int i)
  //Developed from example code "HitachiH48C3AxisAccelerometer.pdf"
  //Also referenced MCP3204/3208 datasheet from Microchip for SPI
  //Routine for reading accelerometer
  //To interogate accelerometer send 000110"axis"
    //000 are just fill bits for the 8bit SPIDR register
    //1 for start bit
    //1 for single ended operation of the ATD chip
    //0 is actually a don't care b/c there are only 4 ATD channels
    //"axis" is where the analog inputs are connected to the ATD
      //X axis is channel 00
      //Y axis is channel 01
      //Z axis is channel 10
      //Ref    is channel 11
  //Next series of words will contain 12bit channel conversion
    //First High-Z then "null" bit and then as MSB then LSB

    //then repeating nulls until interrogated again

 const int clkStall = 3;                    //Used to stall clock in communication with accelerometer                                                        
  const float G_convert =0.055000055;       //Constant used to convert ADC data to G-forces
                                       //4095 for max voltage on 12bit ADC
                                       //3.3V operational voltage
                                       //0.3663V = 1g output
                                       //G = (axis-vref)/4095*(3.3/0.3663)
                                       //G = (axis - vref)*0.0022000022
                                       //G/4 for shifting the data to align "0" bit
                                       //G*100 to make output unit 0.01g
  int j = 0;                        //Variable used for looping
  float gforce = 0.0;                 //Calculated G-forces
  word refCount = 0;                //Refernce data from accelerometer
  word axisCount = 0;               //Axis data from accelerometer
                                        //0 is X axis
                                        //1 is Y axis
                                        //2 is Z axis
  //Get reference conversion
  SPICR2_BIDIROE = 1;               //Set pin for ouput
  PTT_PTT0 = 0;                            //Turn accelerometer on
  PORTA = SPI_trans(3 + 24);        //Request reference
                                                                  //Reads erroneous data
  SPICR2_BIDIROE = 0;               //Set pin for input
  PORTA = SPI_trans(0xFF);          //Save MSB data
  PORTB = SPI_trans(0xFF);          //Save LSB data
  PTT_PTT0 = 1;                     //Turn accelerometer off
  refCount = PORTAB;                //Save reference count
  for( j=0 ; j<clkStall ; j++ ){}   //Delay loop for next accelerometer data
                                        //500ns minimum
                                        //3 * 250 = 750ns
  //Get Axis conversion
  SPICR2_BIDIROE = 1;               //Set pin for output
  PTT_PTT0 = 0;                             //Turn accelerometer on
  PORTA = SPI_trans(i + 24);        //Request axis
                                                                   //Reads erroneous data
  SPICR2_BIDIROE = 0;               //Set pin for input
  PORTA = SPI_trans(0xFF);          //Save MSB data
  PORTB = SPI_trans(0xFF);          //Save LSB data
  PTT_PTT0 = 1;                              //Turn accelerometer off
  axisCount = PORTAB;               //Save axis count


 //calculate g-forces
  gforce = (axisCount - refCount) * G_convert;
  return gforce;
}//axis acceleration subroutine


byte SPI_trans(byte val)
//SPI tranmit subroutine developed from
  volatile byte garbage = 0;              //Variable used to collect "garbage"
  while (!SPISR_SPTEF);                   //Loops unitl Transmit Empty Flag is set
  garbage = SPISR;                        //First step to clear flags
  SPIDR = val;                            //Loads data and clears Flags
  while (!SPISR_SPIF);                    //Loops until data is transfered(8 clocks)
  garbage = SPISR;                        //First step to clear flags
  return SPIDR;                           //Returns data in SPI data register to caller and clears flags
}//SPI transmit subroutine