/**************************************************************************//**
  @file     hal_acc_trxeb.c

  @brief    Accelerometer HAL for VTI CMA3000-D01 on SmartRF TrxEB.

******************************************************************************/

/******************************************************************************
* INCLUDES
*/
#include <hal_msp430.h>
#include <hal_defs.h>
#include <hal_acc_trxeb.h>
#include <hal_mcu.h>


/******************************************************************************
* DEFINES
*/


/******************************************************************************
* LOCAL FUNCTIONS
*/
static void accSpiInit(uint16 divider);
static void accSpiUninit(void);

/******************************************************************************
* FUNCTIONS
*/

/**************************************************************************//**
* @fn       halAccInit(void)
*
* @brief    Initialize accelerometer with 2g/400Hz measurement mode and SPI
*           interfacing. Max bitrate for accelerometer is 500kHz. Bit rate is
*           set to 200 kHz, assuming SMCLK at 18MHz.
*
* @param    none
*
* @return   none
******************************************************************************/
void halAccInit(void)
{
    accSpiInit(80);         // Assuming SMCLK@8 MHz. 8MHz/80 = 100kHz SPI bit rate.

    ACC_PWR_ENABLE();       // Powering up accelerometer
    halMcuWaitMs(1);        // Wait for power to stabilize

    // Read REVID
    halAccReadReg(ACC_REVID);
    halMcuWaitUs(120);      // Wait (Min 11 SPI clock periods between
                            // transition "CSn high to CSn low".
                            // 11/100kHz = 110us.

    // Configure Accelerometer (2g range, 400Hz measurement mode, I2C disabled, interrupt disabled)
    halAccWriteReg(ACC_CTRL, (ACC_G_RANGE_2 | ACC_I2C_DIS | ACC_MODE_400 | ACC_INT_DIS) );

    halMcuWaitMs(15);        // Wait >10ms for accelerometer to settle

} // halAccInit


/**************************************************************************//**
* @fn       halAccUninit(void)
*
* @brief    Unitialize the accelerometer SPI interface and turn off the
*           accelerometer's power supply.
*
* @param    none
*
* @return   none
******************************************************************************/
void halAccUninit(void)
{
    accSpiUninit();         // Uninit SPI interface to accelerometer.

    ACC_PWR_DISABLE();      // Cut accelerometer power

} // halAccUninit


/**************************************************************************//**
* @fn       halAccRead(int8 *pXVal, int8 *pYVal, int8 *pZVal)
*
* @brief    Read x, y and z acceleration data in one operation.
*
* @param    *pXVal  Pointer to variable to put read out X acceleration
* @param    *pYVal  Pointer to variable to put read out Y acceleration
* @param    *pZVal  Pointer to variable to put read out Z acceleration
*
* @return   none
******************************************************************************/
void halAccRead(int8 *pXVal, int8 *pYVal, int8 *pZVal)
{
    // X
    *pXVal = halAccReadReg(ACC_DOUTX);
    halMcuWaitUs(120);    // Wait (11 SPI clock periods at 100kHz = 110us)

    // Y
    *pYVal = halAccReadReg(ACC_DOUTY);
    halMcuWaitUs(120);    // Wait (11 SPI clock periods at 100kHz = 110us)

    // Z
    *pZVal = halAccReadReg(ACC_DOUTZ);
    halMcuWaitUs(120);    // Wait (11 SPI clock periods at 100kHz = 110us)

} // halAccRead



/* BELOW: Functions specific for the accelerometer on TrxEB */


/**************************************************************************//**
* @fn       halAccGetRev(void)
*
* @brief    Reads accelerometer revision (should be 0x10);
*
* @param    none
*
* @return   Returns last accelerometer revision.
******************************************************************************/
uint8 halAccGetRev(void)
{
    return halAccReadReg(ACC_REVID);
} // halAccGetRev


/**************************************************************************//**
* @fn       halAccWriteReg(uint8 address, uint8 data)
*
* @brief    Write a single data byte to accelerometer given by address.
*           Function assumes halAccInit() to already have been executed.
*
* @param    address     Accelerometer internal register address.
* @param    data        Data to be written
*
* @return   Returns last received result.
******************************************************************************/
uint8 halAccWriteReg(uint8 address, uint8 data)
{
    uint8 result;
    address |= 0x02;                // RW bit (bit7 in MSB format) set for write command

    ACC_SPI_BEGIN();                // CSn low
    halMcuWaitUs(3);                // Wait 3 us
    result= ACC_SPI_RX();           // Dummy read to clear RX interrupt flag
    ACC_SPI_WAIT_TX();              // Waiting until TX buffer is ready
    ACC_SPI_TX( address );          // Write address to TX buffer
    ACC_SPI_WAIT_RX();              // Waiting until RX data is received
    result= ACC_SPI_RX();           // Dummy read to clear RX interrupt flag
    ACC_SPI_WAIT_TX();              // Waiting until TX buffer is ready
    ACC_SPI_TX( data );             // Write data to TX buffer
    ACC_SPI_WAIT_RX();              // Waiting until RX data is received
    result= UCA2RXBUF;              // Read RX buffer
    ACC_SPI_END();                  // CNs high

    return result;

} // halAccWriteReg


/**************************************************************************//**
* @fn       halAccReadReg(uint8 address)
*
* @brief    Read accelerometer register given by address.
*           Function assumes halAccInit() to already have been executed.
*
* @param    address     Accelerometer internal register address.
*
* @return   Returns register value.
******************************************************************************/
uint8 halAccReadReg(uint8 address)
{
    uint8 readVal;
    ACC_SPI_BEGIN();                // CSn low
    halMcuWaitUs(3);                // Wait 3 us
    readVal= ACC_SPI_RX();          // Dummy read to clear RX interrupt flag
    ACC_SPI_WAIT_TX();              // Waiting until TX buffer is ready
    ACC_SPI_TX( address );          // Write address to TX buffer
    ACC_SPI_WAIT_RX();              // Waiting until RX data is received
    readVal= ACC_SPI_RX();          // Dummy read to clear RX interrupt flag
    ACC_SPI_TX(0);                  // Dummy write to TX buffer
    ACC_SPI_WAIT_RX();              // Waiting until RX data is received
    readVal= ACC_SPI_RX();          // Read returned value
    ACC_SPI_END();                  // CNs high

    return readVal;

} // halAccReadReg


/**************************************************************************//**
* @fn       accSpiInit(uint16 divider)
*
* @brief    Local function for initializing the accelerometer SPI interface.
*           The divider parameter must result in an SPI frequency <400kHz.
*
* @param    divider     SMCLK divider
*
* @return   none
******************************************************************************/
static void accSpiInit(uint16 divider)
{
    // De-assert accelerometer CSn pin (set as output high)
    ACC_PORT_CS_SEL &= ~(ACC_CS_PIN);
    ACC_PORT_CS_OUT |=  (ACC_CS_PIN);
    ACC_PORT_CS_DIR |=  (ACC_CS_PIN);

    // Configure USCI_A2:
    UCA2CTL1 |= UCSWRST;            // Keep USCI_A2 state machine in reset
    UCA2CTL1 |= UCSSEL1;            // Set clock source SMCLK
    UCA2CTL1 &= ~UCSSEL0;

    // Bit rate given = (SMCLK / divider). Accelerometer SPI/I2C max: 500/400 kHz.
    UCA2BR0 = LO_UINT16(divider);
    UCA2BR1 = HI_UINT16(divider);

    UCA2CTL0 = UCMST + UCSYNC + UCMSB + UCCKPH; // 3pin SPI master, MSB first, data captured
                                                // on first edge (, 8bit data, inactive state low)

    // Configure to peripheral function
    ACC_PORT_SPI_SEL |= ( ACC_MOSI_PIN | ACC_MISO_PIN | ACC_CLK_PIN );

    UCA2CTL1 &= ~(UCSWRST); // Initialize USCI_A2 state machine

} // accSpiInit


/**************************************************************************//**
* @fn       accSpiInit(uint16 divider)
*
* @brief    Local function for releasing the accelerometer SPI interface.
*           SPI CSn is set to output high while MISO,MOSI and SCLK are set
*           as GPIO input.
*
* @param    none
*
* @return   none
******************************************************************************/
static void accSpiUninit(void)
{
    ACC_SPI_END();          // Set CSn high

    UCA2CTL1 |= UCSWRST;    // Disable USCI controller

    // Set MOSI, MISO and SCLK pins back to GPIO (input)
    ACC_PORT_SPI_SEL &= ~( ACC_MOSI_PIN | ACC_MISO_PIN | ACC_CLK_PIN ); // GPIO

} // accSpiUninit


/******************************************************************************
  Copyright 2011 Texas Instruments Incorporated. All rights reserved.

  IMPORTANT: Your use of this Software is limited to those specific rights
  granted under the terms of a software license agreement between the user
  who downloaded the software, his/her employer (which must be your employer)
  and Texas Instruments Incorporated (the "License").  You may not use this
  Software unless you agree to abide by the terms of the License. The License
  limits your use, and you acknowledge, that the Software may not be modified,
  copied or distributed unless embedded on a Texas Instruments microcontroller
  or used solely and exclusively in conjunction with a Texas Instruments radio
  frequency transceiver, which is integrated into your product.  Other than for
  the foregoing purpose, you may not use, reproduce, copy, prepare derivative
  works of, modify, distribute, perform, display or sell this Software and/or
  its documentation for any purpose.

  YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
  PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
  INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
  NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
  TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
  NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
  LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
  INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
  OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
  OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
  (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.

  Should you have any questions regarding your right to use this Software,
  contact Texas Instruments Incorporated at www.TI.com.
******************************************************************************/

