FXLS8471Q - Bare metal example project

Document created by Tomas Vaverka Employee on Feb 27, 2014Last modified by Tomas Vaverka Employee on Sep 5, 2015
Version 4Show Document
  • View in full screen mode

Hi Everyone,

 

In this article I would like to describe a simple bare-metal example code for the new Xtrinsic FXLS8471Q digital accelerometer. I have used recently released FRDM-FXS-MULTI(-B) sensor expansion board, that features many of the Xtrinsic sensors introduced in 2013 including the FXLS8471Q, in conjunction with the  Freescale FRDM-KL25Z development platform. The FreeMASTER tool is used to visualize the acceleration data that are read from the FXLS8471Q using an interrupt technique through the SPI interface.

 

This example illustrates:

 

1. Initialization of the MKL25Z128 MCU (mainly SPI and PORT modules).

2. SPI data write and read operations.

3. Initialization of the accelerometer to achieve the highest resolution.

4. Simple offset calibration based on the AN4069.

5. Output data reading using an interrupt technique.

6. Conversion of the output values from registers 0x01 – 0x06 to real acceleration values in g’s.

7. Visualization of the output values in the FreeMASTER tool.

 

1. As you can see in the FRDM-FXS-MULTI(-B)/FRDM-KL25Z schematics and the image below, SPI signals are routed to the SPI0 module of the KL25Z MCU and the INT1 output is connected to the PTA5 pin (make sure that pins 2-3 of J6 on the sensor board are connected together using a jumper). The PTD0 pin (Chip select) is not controlled automatically by SPI0 module, hence it is configured as a general-purpose output. The INT1 output of the FXLS8471Q is configured as a push-pull active-low output, so the corresponding PTA5 pin configuration is GPIO with an interrupt on falling edge.The core/system clock frequency is 20.97 MHz and SPI clock is 524.25 kHz.

 

Boards.jpg

 

The MCU is, therefore, configured as follows.

 

void MCU_Init(void)

{

     //SPI0 module initialization

     SIM_SCGC4 |= SIM_SCGC4_SPI0_MASK;        // Turn on clock to SPI0 module

     SIM_SCGC5 |= SIM_SCGC5_PORTD_MASK;       // Turn on clock to Port D module

     PORTD_PCR1 = PORT_PCR_MUX(0x02);         // PTD1 pin is SPI0 CLK line

     PORTD_PCR2 = PORT_PCR_MUX(0x02);         // PTD2 pin is SPI0 MOSI line

     PORTD_PCR3 = PORT_PCR_MUX(0x02);         // PTD3 pin is SPI0 MISO line

     PORTD_PCR0 = PORT_PCR_MUX(0x01);         // PTD0 pin is configured as GPIO (CS line driven manually)

     GPIOD_PSOR |= GPIO_PSOR_PTSO(0x01);      // PTD0 = 1 (CS inactive)

     GPIOD_PDDR |= GPIO_PDDR_PDD(0x01);       // PTD0 pin is GPIO output

   

     SPI0_C1 = SPI_C1_SPE_MASK | SPI_C1_MSTR_MASK;     // Enable SPI0 module, master mode

     SPI0_BR = SPI_BR_SPPR(0x04) | SPI_BR_SPR(0x02);     // BaudRate = BusClock / ((SPPR+1) * 2^(SPR+1)) = 20970000 / ((4+1) * 2^(2+1)) = 524.25 kHz

                 

     //Configure the PTA5 pin (connected to the INT1 of the FXLS8471Q) for falling edge interrupts

     SIM_SCGC5 |= SIM_SCGC5_PORTA_MASK;       // Turn on clock to Port A module

     PORTA_PCR5 |= (0|PORT_PCR_ISF_MASK|      // Clear the interrupt flag

                      PORT_PCR_MUX(0x1)|      // PTA5 is configured as GPIO

                      PORT_PCR_IRQC(0xA));    // PTA5 is configured for falling edge interrupts

          

     //Enable PORTA interrupt on NVIC

     NVIC_ICPR |= 1 << ((INT_PORTA - 16) % 32);

     NVIC_ISER |= 1 << ((INT_PORTA - 16) % 32);

}


2. The FXLS8471Q uses the ‘Mode 0′ SPI protocol, which means that an inactive state of clock signal is low and data are captured on the leading edge of clock signal and changed on the falling edge.

 

The falling edge on the SA1/CS_B pin starts the SPI communication. A write operation is initiated by transmitting a 1 for the R/W bit. Then the 8-bit register address, ADDR[7:0] is encoded in the first and second serialized bytes. Data to be written starts in the third serialized byte. The order of the bits is as follows:

 

Byte 0: R/W, ADDR[6], ADDR[5], ADDR[4], ADDR[3], ADDR[2], ADDR[1], ADDR[0]

Byte 1: ADDR[7], X, X, X, X, X, X, X

Byte 2: DATA[7], DATA[6], DATA[5], DATA[4], DATA[3], DATA[2], DATA[1], DATA[0]

 

The rising edge on the SA1/CS_B pin stops the SPI communication.

 

Below is the write operation which writes the value 0x3D to the CTRL_REG1 (0x3A).


SPI Write.JPG.jpg


Similarly a read operation is initiated by transmitting a 0 for the R/W bit. Then the 8-bit register address, ADDR[7:0] is encoded in the first and second serialized bytes. The data is read from the MISO pin (MSB first).

 

The screenshot below shows the read operation which reads the correct value 0x6A from the WHO_AM_I register (0x0D).

 

SPI Read.JPG.jpg

 

Multiple read operations are performed similar to single read except bytes are read in multiples of eight SCLK cycles. The register address is auto incremented so that every eighth next clock edges will latch the MSB of the next register.

 

A burst read of 6 bytes from registers 0x01 to 0x06 is shown below. It also shows how the INT1 pin is automatically cleared by reading the acceleration output data.

 

SPI Burst.JPG.jpg

 

3. At the beginning of the initialization, all accelerometer registers should be reset to their default values by setting the RST bit of the CTRL_REG2 register. However, the software reset does not work properly in SPI mode as described in Appendix A of the FXLS8471Q data sheet. Therefore the following piece of the code performing the software reset should not be used. Instead, I have shortened R46 on the FRDM-FXS-MULTI-B board to activate a hardware reset.

 

The dynamic range is set to ±2g and to achieve the highest resolution, the LNOISE bit is set and the lowest ODR (1.56Hz) and the High Resolution mode are selected (more details in AN4075). The DRDY interrupt is enabled and routed to the INT1 interrupt pin that is configured to be a push-pull, active-low output.

 

void FXLS8471Q_Init (void)

{

     unsigned char reg_val = 0;

   

     /* The software reset does not work properly in SPI mode as described in Appendix A

        of the FXLS8471Q data sheet. Therefore the following piece of the code is not used.

        I have shortened R46 on the FRDM-FXS-MULTI-B board to activate a hardware reset. */

   

     /*FXLS8471Q_WriteRegister(CTRL_REG2, 0x40);     // Reset all registers to POR values

   

     Pause(0x631);     // ~1ms delay

          

     do       // Wait for the RST bit to clear

     {

          reg_val = FXLS8471Q_ReadRegister(CTRL_REG2) & 0x40;

     } while (reg_val); */

         

     FXLS8471Q_WriteRegister(XYZ_DATA_CFG_REG, 0x00);          // +/-2g range with ~0.244mg/LSB

     FXLS8471Q_WriteRegister(CTRL_REG2, 0x02);            // High Resolution mode

     FXLS8471Q_WriteRegister(CTRL_REG3, 0x00);            // Push-pull, active low interrupt

     FXLS8471Q_WriteRegister(CTRL_REG4, 0x01);            // Enable DRDY interrupt

     FXLS8471Q_WriteRegister(CTRL_REG5, 0x01);            // DRDY interrupt routed to INT1 - PTA5

      FXLS8471Q_WriteRegister(CTRL_REG1, 0x3D);            // ODR = 1.56Hz, Reduced noise, Active mode          

}

 

4. A simple offset calibration method is implemented according to the AN4069.

 

void FXLS8471Q_Calibration (void)

{

     char Xoffset, Yoffset, Zoffset;

     

     DataReady = 0;      

         while (!DataReady){}      // Is a first set of data ready?

     DataReady = 0;

     

     FXLS8471Q_WriteRegister(CTRL_REG1, 0x00);     // Standby mode

            

     FXLS8471Q_ReadMultiRegisters(OUT_X_MSB_REG, 6, AccData);     // Read data output registers 0x01-0x06 

                                              

     Xout_14_bit = ((short) (AccData[0]<<8 | AccData[1])) >> 2;     // Compute 14-bit X-axis output value

     Yout_14_bit = ((short) (AccData[2]<<8 | AccData[3])) >> 2;     // Compute 14-bit Y-axis output value

     Zout_14_bit = ((short) (AccData[4]<<8 | AccData[5])) >> 2;     // Compute 14-bit Z-axis output value

                                       

     Xoffset = Xout_14_bit / 8 * (-1);     // Compute X-axis offset correction value

     Yoffset = Yout_14_bit / 8 * (-1);     // Compute Y-axis offset correction value

     Zoffset = (Zout_14_bit - SENSITIVITY_2G) / 8 * (-1);     // Compute Z-axis offset correction value

                                       

     FXLS8471Q_WriteRegister(OFF_X_REG, Xoffset);          

     FXLS8471Q_WriteRegister(OFF_Y_REG, Yoffset);   

     FXLS8471Q_WriteRegister(OFF_Z_REG, Zoffset);

            

     FXLS8471Q_WriteRegister(CTRL_REG1, 0x3D);     // Active mode again

}     

 

5. In the ISR, only the interrupt flag is cleared and the DataReady variable is set to indicate the arrival of new data.


void PORTA_IRQHandler()

{

     PORTA_PCR5 |= PORT_PCR_ISF_MASK;     // Clear the interrupt flag

     DataReady = 1;    

}

 

6. The output values from accelerometer registers 0x01 – 0x06 are first converted to signed 14-bit values and afterwards to real values in g’s.

 

if (DataReady)     // Is a new set of data ready?

{            

     DataReady = 0;

                                                                                                                 

     FXLS8471Q_ReadMultiRegisters(OUT_X_MSB_REG, 6, AccData);     // Read data output registers 0x01-0x06

                                                 

     Xout_14_bit = ((short) (AccData[0]<<8 | AccData[1])) >> 2;     // Compute 14-bit X-axis output value

     Yout_14_bit = ((short) (AccData[2]<<8 | AccData[3])) >> 2;     // Compute 14-bit Y-axis output value

     Zout_14_bit = ((short) (AccData[4]<<8 | AccData[5])) >> 2;     // Compute 14-bit Z-axis output value

                                     

     Xout_g = ((float) Xout_14_bit) / SENSITIVITY_2G;     // Compute X-axis output value in g's

     Yout_g = ((float) Yout_14_bit) / SENSITIVITY_2G;     // Compute Y-axis output value in g's

     Zout_g = ((float) Zout_14_bit) / SENSITIVITY_2G;     // Compute Z-axis output value in g's

}


7. The calculated values can be watched in the "Variables" window on the top right of the Debug perspective or in the FreeMASTER application. To open and run the FreeMASTER project, install the FreeMASTER 1.4 application and FreeMASTER Communication Driver.

 

CW Variables.JPG.jpg

 

FreeMASTER Variables.JPG.jpg

 

Attached you can find the complete source code written in the CW for MCU's v10.5 including the FreeMASTER project.

 

If there are any questions regarding this simple application, please feel free to ask below. Your feedback or suggestions are also welcome.


Regards,

Tomas


Outcomes