Hi Everyone, In this document I would like to go through a simple example code I created for the FRDMKL25-A8471 kit using the KDS 3.0.2 and KSDK 2.0. I will not cover the Sensor Toolbox – CE and Intelligent Sensing Framework (ISF) which primarily support this kit. 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 PORT and SPI modules). 2. SPI data write and read operations. 3. Initialization of the FXLS8471Q to achieve the highest resolution. 4. Output data reading using an interrupt technique. 5. Conversion of the output values from registers 0x01 – 0x06 to real acceleration values in g’s. 6. Visualization of the output values in the FreeMASTER tool. 1. As you can see in the FRDMSTBC-A8471/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 PTD4 pin. 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 PTD4 pin configuration is GPIO with an interrupt on falling edge. The configuration is done in the BOARD_InitPins() function using the NXP Pins Tool for Kinetis MCUs. void BOARD_InitPins(void) { CLOCK_EnableClock(kCLOCK_PortD); /* Port D Clock Gate Control: Clock enabled */ CLOCK_EnableClock(kCLOCK_Spi0); /* SPI0 Clock Gate Control: Clock enabled */ PORT_SetPinMux(PORTD, PIN1_IDX, kPORT_MuxAlt2); /* PORTD1 (pin 74) is configured as SPI0_SCK */ PORT_SetPinMux(PORTD, PIN2_IDX, kPORT_MuxAlt2); /* PORTD2 (pin 75) is configured as SPI0_MOSI */ PORT_SetPinMux(PORTD, PIN3_IDX, kPORT_MuxAlt2); /* PORTD3 (pin 76) is configured as SPI0_MISO */ PORT_SetPinMux(PORTD, PIN0_IDX, kPORT_MuxAsGpio); /* PORTD0 (pin 73) is configured as PTD0 */ GPIO_PinInit(GPIOD, PIN0_IDX, &CS_config); /* PTD0 = 1 (Chip Select inactive) */ PORT_SetPinMux(PORTD, PIN4_IDX , kPORT_MuxAsGpio); /* PORTD4 (pin 77) is configured as PTD4 */ PORT_SetPinInterruptConfig(PORTD, PIN4_IDX, kPORT_InterruptFallingEdge); /* PTD4 is configured for falling edge interrupts */ NVIC_EnableIRQ(PORTD_IRQn); /* Enable PORTD interrupt on NVIC */ } The SPI_INIT() function is used to enable and configure the SPI0 module. 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 SPI clock is 500 kHz. void SPI_Init(void) { uint32_t sourceClock = 0U; sourceClock = CLOCK_GetFreq(kCLOCK_BusClk); spi_master_config_t masterConfig = { .enableMaster = true, .enableStopInWaitMode = false, .polarity = kSPI_ClockPolarityActiveHigh, .phase = kSPI_ClockPhaseFirstEdge, .direction = kSPI_MsbFirst, .outputMode = kSPI_SlaveSelectAsGpio, .pinMode = kSPI_PinModeNormal, .baudRate_Bps = 500000U }; SPI_MasterInit(SPI0, &masterConfig, sourceClock); } 2. The falling edge on the CS 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 CS pin stops the SPI communication. Below is the write operation which writes the value 0x3D to the CTRL_REG1 (0x3A). 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). 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. 3. At the beginning of the initialization, all FXLS8471Q registers are reset to their default values by setting the RST bit of the CTRL_REG2 register. 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) { FXLS8471Q_WriteRegister(CTRL_REG2, 0x40); /* Reset all registers to POR values */ Pause(0xC62); /* ~1ms delay */ 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 - PTD4 */ FXLS8471Q_WriteRegister(CTRL_REG1, 0x3D); /* ODR = 1.56Hz, Reduced noise, Active mode */ } 4. In the ISR, only the interrupt flag is cleared and the DataReady variable is set to indicate the arrival of new data. void PORTD_IRQHandler(void) { PORT_ClearPinsInterruptFlags(PORTD, 1<<4); /* Clear the interrupt flag */ DataReady = 1; } 5. In the main loop, the DataReady variable is periodically checked and if it is set, the accelerometer registers 0x01 – 0x06 are read and then converted to signed 14-bit values and 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 = ((int16_t) (AccData[0]<<8 | AccData[1])) >> 2; /* Compute 14-bit X-axis output value */ Yout_14_bit = ((int16_t) (AccData[2]<<8 | AccData[3])) >> 2; /* Compute 14-bit Y-axis output value */ Zout_14_bit = ((int16_t) (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 */ } 6. The calculated values can be watched in the Debug perspective or in the FreeMASTER application. To open and run the FreeMASTER project, install the FreeMASTER 2.0 application and FreeMASTER Communication Driver. Attached you can find the complete source code written in the KDS 3.0.2 including the FreeMASTER project. If there are any questions regarding this simple application, do not hesitate to ask below. Your feedback or suggestions are also welcome. Best regards, Tomas
記事全体を表示