センサの知識ベース

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 

Sensors Knowledge Base

ディスカッション

ソート順:
Hi Everyone, As I am frequently asked for a simple bare metal example code for the Xtrinsic MMA8451Q digital accelerometer, I would like to share here one of my examples I have created for this part while working with the Freescale FRDM-KL25Z platform. This example illustrates: 1. Initialization of the MKL25Z128 MCU (mainly I2C and PORT modules). 2. Initialization of the accelerometer to achieve the highest resolution. 3. Simple offset calibration based on the AN4069. 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. According to the schematic, the INT1 output of the MMA8451Q is connected to the PTA14 pin of the KL25Z MCU and both SCL and SDA lines are connected to the I2C0 module (PTE24 and PTE25 pins). The MCU is, therefore, configured as follows: void MCU_Init(void) {      //I2C0 module initialization      SIM_SCGC4 |= SIM_SCGC4_I2C0_MASK;        // Turn on clock to I2C0 module      SIM_SCGC5 |= SIM_SCGC5_PORTE_MASK;       // Turn on clock to Port E module      PORTE_PCR24 = PORT_PCR_MUX(5);           // PTE24 pin is I2C0 SCL line      PORTE_PCR25 = PORT_PCR_MUX(5);           // PTE25 pin is I2C0 SDA line      I2C0_F  = 0x14;                          // SDA hold time = 2.125us, SCL start hold time = 4.25us, SCL stop hold time = 5.125us *      I2C0_C1 = I2C_C1_IICEN_MASK;             // Enable I2C0 module           //Configure the PTA14 pin (connected to the INT1 of the MMA8451Q) for falling edge interrupts      SIM_SCGC5 |= SIM_SCGC5_PORTA_MASK;       // Turn on clock to Port A module      PORTA_PCR14 |= (0|PORT_PCR_ISF_MASK|     // Clear the interrupt flag                        PORT_PCR_MUX(0x1)|     // PTA14 is configured as GPIO                        PORT_PCR_IRQC(0xA));   // PTA14 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. At the beginning of the initialization, all accelerometer 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). void Accelerometer_Init (void) {      unsigned char reg_val = 0;        I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG2, 0x40);           // Reset all registers to POR values          do            // Wait for the RST bit to clear      {         reg_val = I2C_ReadRegister(MMA845x_I2C_ADDRESS, CTRL_REG2) & 0x40;      }  while (reg_val);        I2C_WriteRegister(MMA845x_I2C_ADDRESS, XYZ_DATA_CFG_REG, 0x00);    // +/-2g range -> 1g = 16384/4 = 4096 counts      I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG2, 0x02);           // High Resolution mode      I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG1, 0x3D);           // ODR = 1.56Hz, Reduced noise, Active mode   } 3. A simple offset calibration method is implemented according to the AN4069. At the end of the calibration routine, the DRDY interrupt is enabled and routed to the INT1 interrupt pin that is configured to be a push-pull, active-low output. void Calibrate (void) {      unsigned char reg_val = 0;            while (!reg_val)           // Wait for a first set of data               {         reg_val = I2C_ReadRegister(MMA845x_I2C_ADDRESS, STATUS_REG) & 0x08;      }               I2C_ReadMultiRegisters(MMA845x_I2C_ADDRESS, 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                                          I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG1, 0x00);             // Standby mode to allow writing to the offset registers       I2C_WriteRegister(MMA845x_I2C_ADDRESS, OFF_X_REG, Xoffset);              I2C_WriteRegister(MMA845x_I2C_ADDRESS, OFF_Y_REG, Yoffset);       I2C_WriteRegister(MMA845x_I2C_ADDRESS, OFF_Z_REG, Zoffset);       I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG3, 0x00);             // Push-pull, active low interrupt      I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG4, 0x01);             // Enable DRDY interrupt      I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG5, 0x01);             // DRDY interrupt routed to INT1 - PTA14      I2C_WriteRegister(MMA845x_I2C_ADDRESS, 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 PORTA_IRQHandler() {      PORTA_PCR14 |= PORT_PCR_ISF_MASK;            // Clear the interrupt flag      DataReady = 1;      } 5. 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;                                                                                                                      I2C_ReadMultiRegisters(MMA845x_I2C_ADDRESS, 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                                   } 6. The calculated values can be watched in the "Variables" window on the top right of the Debug perspective or in the FreeMASTER application. To view both the 14-bit and real values in the FreeMASTER application, some USBDM drivers need to be first installed on your computer. They are available for download from SourceForge. Erich Styger described their installation in this tutorial. In addition to that, the USBDM_OpenSDA application that provides both debugging and a virtual serial port needs to be loaded into the MK20 debugger chip on the FRDM-KL25Z board. This installation follows the usual FRDM-KL25Z bootloader process: Unplug the FRDM-KL25Z board. Whilst holding the SW1/RST switch depressed plug in the FRDM-KL25Z board. The green LED should start blinking at a rate of about 1Hz. Open a file explorer and locate the USB drive that has now appeared. It will have the drive name "BOOTLOADER". Drag the file USBDM_OpenSDA.sx to the USB drive and wait a short while. The OpenSDA firmware on the FRDM-KL25Z board will program the USBDM firmware into the MK20 debugger chip on the board. Remove and re-plug the FRDM-KL25Z board. The board will now appear as a USBDM device. Attached you can find the complete source code written in the CW for MCU's v10.5 as well as the FreeMASTER project. So make it, test it and keep in touch... Regards, Tomas
記事全体を表示
Hi Everyone,   As I am often asked for a simple bare metal example code for the Xtrinsic FXOS8700CQ 6-axis sensor, I would like to share here one of my examples I have created for this part while working with the Freescale FRDM-KL25Z platform and FRDM-FXS-MULTI(-B) sensor expansion board that features many of the Xtrinsic sensors including the FXOS8700CQ. The FreeMASTER tool is used to visualize both the acceleration and magnetic data that are read from the FXOS8700CQ using an interrupt technique through the I 2 C interface.   This example illustrates:   1. Initialization of the MKL25Z128 MCU (mainly I2C and PORT modules). 2. I 2 C data write and read operations. 3. Initialization of the FXOS8700CQ. 4. Simple accelerometer offset calibration based on the AN4069. 5. Simple magnetic hard-iron offset calibration. 6. Output data reading using an interrupt technique. 7. Conversion of the output values from registers 0x01 – 0x06 and 0x33 – 0x38 to real values in g’s and µT and simple heading angle calculation. 8. Visualization of the calculated values in the FreeMASTER tool.   1. As you can see in the FRDM-FXS-MULTI(-B)/FRDM-KL25Z schematics and the image below, I2C signals are routed to the I2C1 module (PTC1 and PTC2 pins) of the KL25Z MCU and the INT1 output is connected to the PTD4 pin (make sure that pins 1-2 of J3 on the sensor expansion board are connected together using a jumper). The INT1 output of the FXOS8700CQ is configured as a push-pull active-low output, so the corresponding PTD4 pin configuration is GPIO with an interrupt on falling edge.   The MCU is, therefore, configured as follows.   void MCU_Init(void) {      //I2C1 module initialization      SIM_SCGC4 |= SIM_SCGC4_I2C1_MASK;        // Turn on clock to I2C1 module      SIM_SCGC5 |= SIM_SCGC5_PORTC_MASK;       // Turn on clock to Port C module      PORTC_PCR1 |= PORT_PCR_MUX(0x2);         // PTC1 pin is I2C1 SCL line      PORTC_PCR2 |= PORT_PCR_MUX(0x2);         // PTC2 pin is I2C1 SDA line      I2C1_F  |= I2C_F_ICR(0x14);              // SDA hold time = 2.125us, SCL start hold time = 4.25us, SCL stop hold time = 5.125us      I2C1_C1 |= I2C_C1_IICEN_MASK;            // Enable I2C0 module               //Configure the PTD4 pin (connected to the INT1 of the FXOS8700CQ) for falling edge interrupts      SIM_SCGC5 |= SIM_SCGC5_PORTD_MASK;       // Turn on clock to Port A module      PORTD_PCR4 |= (0|PORT_PCR_ISF_MASK|      // Clear the interrupt flag                      PORT_PCR_MUX(0x1)|       // PTD4 is configured as GPIO                      PORT_PCR_IRQC(0xA));     // PTD4 is configured for falling edge interrupts                   //Enable PORTD interrupt on NVIC      NVIC_ICPR |= 1 << ((INT_PORTD - 16)%32);      NVIC_ISER |= 1 << ((INT_PORTD - 16)%32); }   2. The 7-bit I2C address of the FXOS8700CQ is 0x1E since both SA0 and SA1 lines are shorted to GND using jumpers J21 and J23 on the sensor board. As shown above, the SCL line is connected to the PTC1 pin and SDA line to the PTC2 pin. The I2C clock frequency is 125 kHz.   The screenshot below shows the write operation which writes the value 0x35 to the CTRL_REG1 (0x2A).     And here is the single byte read from the WHO_AM_I register 0x0D. As you can see, it returns the correct value 0xC7.     Multiple bytes of data can be read from sequential registers after each FXOS8700CQ acknowledgment (AK) is received until a no acknowledge (NAK) occurs from the KL25Z followed by a stop condition (SP) signaling an end of transmission. A burst read of 6 bytes from registers 0x33 to 0x38, that is performed in the calibration routine “FXOS8700CQ_Mag_Calibration()”, is shown below. It also shows when the INT1 pin is automatically cleared.     3. At the beginning of the initialization, all registers are reset to their default values by setting the RST bit of the CTRL_REG2 register. Then the FXOS8700CQ is initialized as shown below.   void FXOS8700CQ_Init (void) {      I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG2, 0x40);          // Reset all registers to POR values        Pause(0x631);        // ~1ms delay        I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, XYZ_DATA_CFG_REG, 0x00);   // +/-2g range with 0.244mg/LSB          I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, M_CTRL_REG1, 0x1F);        // Hybrid mode (accelerometer + magnetometer), max OSR      I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, M_CTRL_REG2, 0x20);        // M_OUT_X_MSB register 0x33 follows the OUT_Z_LSB register 0x06 (used for burst read)                   I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG2, 0x02);          // High Resolution mode      I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG3, 0x00);          // Push-pull, active low interrupt      I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG4, 0x01);          // Enable DRDY interrupt      I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG5, 0x01);          // DRDY interrupt routed to INT1 - PTD4      I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG1, 0x35);          // ODR = 3.125Hz, Reduced noise, Active mode   }   4. A simple accelerometer offset calibration method is implemented according to the AN4069.   void FXOS8700CQ_Accel_Calibration (void) {      char X_Accel_offset, Y_Accel_offset, Z_Accel_offset;        DataReady = 0;                while (!DataReady){}       // Is a first set of data ready?      DataReady = 0;        I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG1, 0x00);          // Standby mode             I2C_ReadMultiRegisters(FXOS8700CQ_I2C_ADDRESS, OUT_X_MSB_REG, 6, AccelMagData);          // Read data output registers 0x01-0x06                 Xout_Accel_14_bit = ((short) (AccelMagData[0]<<8 | AccelMagData[1])) >> 2;        // Compute 14-bit X-axis acceleration output value      Yout_Accel_14_bit = ((short) (AccelMagData[2]<<8 | AccelMagData[3])) >> 2;        // Compute 14-bit Y-axis acceleration output value      Zout_Accel_14_bit = ((short) (AccelMagData[4]<<8 | AccelMagData[5])) >> 2;        // Compute 14-bit Z-axis acceleration output value               X_Accel_offset = Xout_Accel_14_bit / 8 * (-1);         // Compute X-axis offset correction value      Y_Accel_offset = Yout_Accel_14_bit / 8 * (-1);         // Compute Y-axis offset correction value      Z_Accel_offset = (Zout_Accel_14_bit - SENSITIVITY_2G) / 8 * (-1);          // Compute Z-axis offset correction value               I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, OFF_X_REG, X_Accel_offset);                  I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, OFF_Y_REG, Y_Accel_offset);           I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, OFF_Z_REG, Z_Accel_offset);                    I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG1, 0x35);          // Active mode again }   5. A simple software calibration of magnetic hard-iron offset consists of recording the minimum and maximum magnetometer readings while rotating the board horizontally and vertically and then computing the calibration values from their average. The calibration time is defined by the number of samples taken during calibration (local variable “i” in the while loop) and selected ODR. In my example I use 94 samples at 3.125Hz, so the calibration routine takes 30s.   void FXOS8700CQ_Mag_Calibration (void) {      short Xout_Mag_16_bit_avg, Yout_Mag_16_bit_avg, Zout_Mag_16_bit_avg;          short Xout_Mag_16_bit_max, Yout_Mag_16_bit_max, Zout_Mag_16_bit_max;          short Xout_Mag_16_bit_min, Yout_Mag_16_bit_min, Zout_Mag_16_bit_min;      char i = 0;        DataReady = 0;            while (i < 94)             // This takes ~30s (94 samples * 1/3.125)      {               if (DataReady)             // Is a new set of data ready?         {                          DataReady = 0;                                                                                                                                                                I2C_ReadMultiRegisters(FXOS8700CQ_I2C_ADDRESS, MOUT_X_MSB_REG, 6, AccelMagData);         // Read data output registers 0x33 - 0x38                                   Xout_Mag_16_bit = (short) (AccelMagData[0]<<8 | AccelMagData[1]);        // Compute 16-bit X-axis magnetic output value              Yout_Mag_16_bit = (short) (AccelMagData[2]<<8 | AccelMagData[3]);        // Compute 16-bit Y-axis magnetic output value              Zout_Mag_16_bit = (short) (AccelMagData[4]<<8 | AccelMagData[5]);        // Compute 16-bit Z-axis magnetic output value                                            // Assign first sample to maximum and minimum values                        if (i == 0)              {                   Xout_Mag_16_bit_max = Xout_Mag_16_bit;                   Xout_Mag_16_bit_min = Xout_Mag_16_bit;                                                Yout_Mag_16_bit_max = Yout_Mag_16_bit;                   Yout_Mag_16_bit_min = Yout_Mag_16_bit;                                                Zout_Mag_16_bit_max = Zout_Mag_16_bit;                   Zout_Mag_16_bit_min = Zout_Mag_16_bit;              }                                       // Check to see if current sample is the maximum or minimum X-axis value                       if (Xout_Mag_16_bit > Xout_Mag_16_bit_max)    {Xout_Mag_16_bit_max = Xout_Mag_16_bit;}                       if (Xout_Mag_16_bit < Xout_Mag_16_bit_min)    {Xout_Mag_16_bit_min = Xout_Mag_16_bit;}                         // Check to see if current sample is the maximum or minimum Y-axis value                       if (Yout_Mag_16_bit > Yout_Mag_16_bit_max)    {Yout_Mag_16_bit_max = Yout_Mag_16_bit;}                       if (Yout_Mag_16_bit < Yout_Mag_16_bit_min)    {Yout_Mag_16_bit_min = Yout_Mag_16_bit;}                                       // Check to see if current sample is the maximum or minimum Z-axis value                       if (Zout_Mag_16_bit > Zout_Mag_16_bit_max)    {Zout_Mag_16_bit_max = Zout_Mag_16_bit;}                       if (Zout_Mag_16_bit < Zout_Mag_16_bit_min)    {Zout_Mag_16_bit_min = Zout_Mag_16_bit;}                              i++;          }           }        Xout_Mag_16_bit_avg = (Xout_Mag_16_bit_max + Xout_Mag_16_bit_min) / 2;            // X-axis hard-iron offset      Yout_Mag_16_bit_avg = (Yout_Mag_16_bit_max + Yout_Mag_16_bit_min) / 2;            // Y-axis hard-iron offset      Zout_Mag_16_bit_avg = (Zout_Mag_16_bit_max + Zout_Mag_16_bit_min) / 2;            // Z-axis hard-iron offset        // Left-shift by one as magnetometer offset registers are 15-bit only, left justified      Xout_Mag_16_bit_avg <<= 1;             Yout_Mag_16_bit_avg <<= 1;       Zout_Mag_16_bit_avg <<= 1;        I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG1, 0x00);          // Standby mode to allow writing to the offset registers        I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, MOFF_X_LSB_REG, (char) (Xout_Mag_16_bit_avg & 0xFF));             I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, MOFF_X_MSB_REG, (char) ((Xout_Mag_16_bit_avg >> 😎 & 0xFF));            I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, MOFF_Y_LSB_REG, (char) (Yout_Mag_16_bit_avg & 0xFF));      I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, MOFF_Y_MSB_REG, (char) ((Yout_Mag_16_bit_avg >> 😎 & 0xFF));                   I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, MOFF_Z_LSB_REG, (char) (Zout_Mag_16_bit_avg & 0xFF));      I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, MOFF_Z_MSB_REG, (char) ((Zout_Mag_16_bit_avg >> 😎 & 0xFF));              I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG1, 0x35);          // Active mode again       }   6. 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() {      PORTD_PCR4 |= PORT_PCR_ISF_MASK;                // Clear the interrupt flag      DataReady = 1;       }   7. The output values from accelerometer registers 0x01 – 0x06 are first converted to signed 14-bit integer values and afterwards to real values in g’s. Similarly, the output values from magnetometer registers 0x33 – 0x38 are first converted to signed 16-bit integer values and afterwards to real values in microtesla (µT).   If the board remains flat, then the compass heading can be simply computed from the arctangent of the ratio of the two horizontal magnetic field components. I have used the atan2 function which returns the result in radians (-π and π), so I multiply it by 180/π to end up with degrees.   If you are interested in more complex algorithms for a tilt-compensated e-compass with soft-iron calibration, please refer to our eCompass software.   if (DataReady)             // Is a new set of data ready? {                  DataReady = 0;                                                                                                                      I2C_ReadMultiRegisters(FXOS8700CQ_I2C_ADDRESS, OUT_X_MSB_REG, 12, AccelMagData);         // Read data output registers 0x01-0x06 and 0x33 - 0x38                 // 14-bit accelerometer data      Xout_Accel_14_bit = ((short) (AccelMagData[0]<<8 | AccelMagData[1])) >> 2;        // Compute 14-bit X-axis acceleration output value      Yout_Accel_14_bit = ((short) (AccelMagData[2]<<8 | AccelMagData[3])) >> 2;        // Compute 14-bit Y-axis acceleration output value      Zout_Accel_14_bit = ((short) (AccelMagData[4]<<8 | AccelMagData[5])) >> 2;        // Compute 14-bit Z-axis acceleration output value                          // Accelerometer data converted to g's      Xout_g = ((float) Xout_Accel_14_bit) / SENSITIVITY_2G;        // Compute X-axis output value in g's      Yout_g = ((float) Yout_Accel_14_bit) / SENSITIVITY_2G;        // Compute Y-axis output value in g's      Zout_g = ((float) Zout_Accel_14_bit) / SENSITIVITY_2G;        // Compute Z-axis output value in g's                           // 16-bit magnetometer data                   Xout_Mag_16_bit = (short) (AccelMagData[6]<<8 | AccelMagData[7]);          // Compute 16-bit X-axis magnetic output value      Yout_Mag_16_bit = (short) (AccelMagData[8]<<8 | AccelMagData[9]);          // Compute 16-bit Y-axis magnetic output value      Zout_Mag_16_bit = (short) (AccelMagData[10]<<8 | AccelMagData[11]);        // Compute 16-bit Z-axis magnetic output value                                                     // Magnetometer data converted to microteslas      Xout_uT = (float) (Xout_Mag_16_bit) / SENSITIVITY_MAG;        // Compute X-axis output magnetic value in uT      Yout_uT = (float) (Yout_Mag_16_bit) / SENSITIVITY_MAG;        // Compute Y-axis output magnetic value in uT      Zout_uT = (float) (Zout_Mag_16_bit) / SENSITIVITY_MAG;        // Compute Z-axis output magnetic value in uT                      Heading = atan2 (Yout_uT, Xout_uT) * 180 / PI;         // Compute Yaw angle }     8. 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.       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 Original Attachment has been moved to: FRDM-KL25Z-FXOS8700CQ-Basic-read-using-I2C-and-interrupt.zip Original Attachment has been moved to: FreeMASTER---FRDM-KL25Z-FXOS8700CQ-Basic-read-using-I2C-and-interrupt.zip
記事全体を表示
FRDM-STBC-AGM01: 9-Axis Inertial Measurement Sensor Board FRDM-KL25Z FRDM-STBC-AGM01 - Example project in KDS 3.0.0 using KSDK 1.2.0 and Processor Expert FRDM-STBC-AGM01 - Bare metal example project   FRDMSTBC-A8471: 3-Axis Accelerometer Sensor Toolbox Development Board FRDMSTBC-A8471 - Bare metal example project FRDMSTBC-A8471 - Example project in KDS 3.0.2 using KSDK 2.0 FXLS8471Q Auto-sleep with Transient threshold trigger    MPL3115A2: 20 to 110kPa, Absolute Digital (I 2 C) Pressure Sensor MPL3115A2 - Bare metal example project FRDMKL25-P3115 - Example project in KDS 3.0.2 using KSDK 2.0 https://community.nxp.com/docs/DOC-345632    MPL115A1: 50 to 115kPa, Absolute Digital (SPI) Pressure Sensor MPL115A1- Bare metal example project    FXOS8700CQ: Digital (I 2 C/SPI) Sensor - 3-Axis Accelerometer (±2g/±4g/±8g) + 3-Axis Magnetometer FXOS8700CQ - Bare metal example project FXOS8700CQ - Magnetic threshold detection function example code  FXOS8700CQ - Auto-sleep with Magnetic threshold trigger    FXLS8471Q: ±2g/±4g/±8g, 3-Axis, 14-Bit Digital (I 2 C/SPI) Accelerometer FXLS8471Q - Bare metal example project FXLS8471Q - FIFO Fill mode example code FXLS8471Q - Accelerometer vector-magnitude function example code FXLS8471Q - Accelerometer transient detection function example code FXLS8471Q - Accelerometer motion detection function example code  FXLS8471Q - Accelerometer orientation detection function example code    MMA8652FC: ±2g/±4g/±8g, 3-Axis, 12-Bit Digital (I 2 C) Accelerometer MMA8652FC - Bare metal example project MMA8652FC - Auto-WAKE/SLEEP mode   MMA8451Q: ±2g/±4g/±8g, 3-Axis, 14-bit Digital (I 2 C) Accelerometer MMA8451Q - Bare metal example project MMA8451Q - Single Tap Detection Bare metal example project FRDM-KL27Z MMA8451Q - How to build and run an ISSDK based example project    MMA8491Q: ±8g, 3-Axis, 14-bit Digital (I 2 C) Accelerometer/Tilt Sensor MMA8491Q - Acceleration data streaming using the PIT on the Kinetis KL25Z MCU   FXLN83xxQ: 3-Axis, Low-Power, Analog Accelerometer FXLN8371Q - Bare metal example project   FXAS21002C: 3-Axis Digital (I 2 C/SPI) Gyroscope FXAS21000 – Bare metal example project FXAS21002C - Angular rate threshold detection function example code   MAG3110FC: 3-Axis Digital (I 2 C) Magnetometer MAG3110FC – Bare metal example project   LM75A: Digital temperature sensor and thermal watchdog LM75A - Temperature data streaming using the PIT on the Kinetis KL25Z MCU
記事全体を表示
Hi Everyone,   I would like to share here another simple bare-metal example code/demo for the Xtrinsic MMA8652FC digital accelerometer that I have created while working with the Freescale FRDM-KL25Z development platform and FRDM-FXS-MULTI(-B) sensor expansion board. To visualize the acceleration data that are read from the MMA8652FC using an interrupt technique through the I 2 C interface, I have used the FreeMASTER tool.   This example illustrates:   1. Initialization of the MKL25Z128 MCU (mainly I 2 C and PORT modules). 2. I 2 C 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, I2C signals are routed to the I2C1 module (PTC1 and PTC2 pins) of the KL25Z MCU and the INT1 output is connected to the PTA5 pin (make sure that pin #3 of J4 and pin #2 of J6 connector on the sensor expansion board are connected together). The INT1 output of the MMA8652FC is configured as a push-pull active-low output, so the corresponding PTA5 pin configuration is GPIO with an interrupt on falling edge.     The MCU is, therefore, configured as follows. void MCU_Init(void) {      //I2C1 module initialization      SIM_SCGC4 |= SIM_SCGC4_I2C1_MASK;        // Turn on clock to I2C1 module      SIM_SCGC5 |= SIM_SCGC5_PORTC_MASK;       // Turn on clock to Port C module      PORTC_PCR1 |= PORT_PCR_MUX(0x2);         // PTC1 pin is I2C1 SCL line      PORTC_PCR2 |= PORT_PCR_MUX(0x2);         // PTC2 pin is I2C1 SDA line      I2C1_F  |= I2C_F_ICR(0x14);              // SDA hold time = 2.125us, SCL start hold time = 4.25us, SCL stop hold time = 5.125us      I2C1_C1 |= I2C_C1_IICEN_MASK;            // Enable I2C1 module                      //Configure the PTA5 pin (connected to the INT1 of the MMA8652FC) 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 7-bit I 2 C address of the MMA8652FC is fixed value 0x1D. As shown above, the SCL line is connected to the PTC1 pin and SDA line to the PTC2 pin. The I2C clock frequency is 125 kHz. The screenshot below shows the write operation which writes the value 0x39 to the CTRL_REG1 (0x2A).     And here is the single byte read from the WHO_AM_I register 0x0D. As you can see, it returns the correct value 0x4A.     Multiple bytes of data can be read from sequential registers after each MMA8652FC acknowledgment (AK) is received until a no acknowledge (NAK) occurs from the KL25Z followed by a stop condition (SP) signaling an end of transmission. A burst read of 6 bytes from registers 0x01 to 0x06 is shown below. It also shows how the INT1 pin is automatically deasserted by reading the acceleration output data.       3. At the beginning of the initialization, all 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 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 MMA8652FC_Init (void) {      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, CTRL_REG2, 0x40);          // Reset all registers to POR values           Pause(0x631);          // ~1ms delay           I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, XYZ_DATA_CFG_REG, 0x00);   // +/-2g range with ~0.977mg/LSB       I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, CTRL_REG2, 0x02);          // High Resolution mode      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, CTRL_REG3, 0x00);          // Push-pull, active low interrupt      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, CTRL_REG4, 0x01);          // Enable DRDY interrupt      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, CTRL_REG5, 0x01);          // DRDY interrupt routed to INT1 - PTA5      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, CTRL_REG1, 0x39);          // ODR = 1.56Hz, Active mode       }   4. A simple offset calibration method is implemented according to the AN4069.   void MMA8652FC_Calibration (void) {      char X_offset, Y_offset, Z_offset;           DataReady = 0;                while (!DataReady){}          // Is a first set of data ready?      DataReady = 0;           I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, CTRL_REG1, 0x00);          // Standby mode                I2C_ReadMultiRegisters(MMA8652FC_I2C_ADDRESS, OUT_X_MSB_REG, 6, AccelData);          // Read data output registers 0x01-0x06                         Xout_12_bit = ((short) (AccelData[0]<<8 | AccelData[1])) >> 4;             // Compute 12-bit X-axis acceleration output value      Yout_12_bit = ((short) (AccelData[2]<<8 | AccelData[3])) >> 4;             // Compute 12-bit Y-axis acceleration output value      Zout_12_bit = ((short) (AccelData[4]<<8 | AccelData[5])) >> 4;             // Compute 12-bit Z-axis acceleration output value                  X_offset = Xout_12_bit / 2 * (-1);          // Compute X-axis offset correction value      Y_offset = Yout_12_bit / 2 * (-1);          // Compute Y-axis offset correction value      Z_offset = (Zout_12_bit - SENSITIVITY_2G) / 2 * (-1);         // Compute Z-axis offset correction value                  I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, OFF_X_REG, X_offset);                  I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, OFF_Y_REG, Y_offset);            I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, OFF_Z_REG, Z_offset);                        I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, CTRL_REG1, 0x39);          // 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 12-bit values and afterwards to real values in g’s.   if (DataReady)             // Is a new set of data ready? {                  DataReady = 0;                                                                                                                         I2C_ReadMultiRegisters(MMA8652FC_I2C_ADDRESS, OUT_X_MSB_REG, 6, AccelData);          // Read data output registers 0x01-0x06                    // 12-bit accelerometer data      Xout_12_bit = ((short) (AccelData[0]<<8 | AccelData[1])) >> 4;             // Compute 12-bit X-axis acceleration output value      Yout_12_bit = ((short) (AccelData[2]<<8 | AccelData[3])) >> 4;             // Compute 12-bit Y-axis acceleration output value      Zout_12_bit = ((short) (AccelData[4]<<8 | AccelData[5])) >> 4;             // Compute 12-bit Z-axis acceleration output value                             // Accelerometer data converted to g's      Xout_g = ((float) Xout_12_bit) / SENSITIVITY_2G;              // Compute X-axis output value in g's      Yout_g = ((float) Yout_12_bit) / SENSITIVITY_2G;              // Compute Y-axis output value in g's      Zout_g = ((float) Zout_12_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 application and FreeMASTER Communication Driver.       Attached you can find the complete source code written in the CW for MCU's (Eclipse IDE) 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.   Regards, Tomas
記事全体を表示
Hi Everyone,   To complete the collection of simple bare-metal examples for the Xtrinsic sensors on the FRDM-FXS-MULTI(-B) sensor expansion board, I would like to share here another example code/demo I have created for the MPL3115A2 pressure sensor.   This example illustrates: 1. Initialization of the MKL25Z128 MCU (mainly I2C and PORT modules). 2. I2C data write and read operations. 3. Initialization of the MPL3115A2. 4. Output data reading using an interrupt technique. 5. Conversion of the output values from registers 0x01 – 0x05 to real values in Pascals and °C. 6. 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, I2C signals are routed to the I2C1 module (PTC1 and PTC2 pins) of the KL25Z MCU and the INT1 output (INT_PED) is connected to the PTA13 pin (make sure that pins 2-3 of J5 on the sensor board are connected together using a jumper). The INT1 output of the MPL3115A2 is configured as a push-pull active-low output, so the corresponding PTA13 pin configuration is GPIO with an interrupt on falling edge.     The MCU is, therefore, configured as follows. void MCU_Init(void) {      //I2C1 module initialization      SIM_SCGC4 |= SIM_SCGC4_I2C1_MASK;        // Turn on clock to I2C1 module      SIM_SCGC5 |= SIM_SCGC5_PORTC_MASK;       // Turn on clock to Port C module      PORTC_PCR1 |= PORT_PCR_MUX(0x2);         // PTC1 pin is I2C1 SCL line      PORTC_PCR2 |= PORT_PCR_MUX(0x2);         // PTC2 pin is I2C1 SDA line      I2C1_F  |= I2C_F_ICR(0x14);              // SDA hold time = 2.125us, SCL start hold time = 4.25us, SCL stop hold time = 5.125us      I2C1_C1 |= I2C_C1_IICEN_MASK;            // Enable I2C1 module                    //Configure the PTA13 pin (connected to the INT1 of the MPL3115A2) for falling edge interrupts      SIM_SCGC5 |= SIM_SCGC5_PORTA_MASK;       // Turn on clock to Port A module      PORTA_PCR13 |= (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 7-bit I 2 C address of the MPL3115A2 is fixed value 0x60 which translates to 0xC0 for a write and 0xC1 for a read. As shown above, the SCL line is connected to the PTC1 pin and SDA line to the PTC2 pin. The I2C clock frequency is 125 kHz. The screenshot below shows the write operation which writes the value 0x39 to the CTRL_REG1 register (0x26).     And here is the single byte read from the WHO_AM_I register (0x0C). As you can see, it returns the correct device ID 0xC4.     Multiple bytes of data can be read from sequential registers after each MPL3115A2 acknowledgment (AK) is received until a no acknowledge (NAK) occurs from the KL25Z followed by a stop condition (SP) signaling an end of transmission. A burst read of 5 bytes from registers 0x01 to 0x05 is shown below. It also shows how the INT1 pin is automatically deasserted by reading the output registers.       3. At the beginning of the initialization, all MPL3115A2 registers are reset to their default values by setting the RST bit of the CTRL_REG1 register. The DRDY interrupt is enabled and routed to the INT1 pin that is configured to be a push-pull, active-low output. Further, the OSR ratio of 128 is selected and finally the part goes into Active barometer (eventually altimeter) mode.   void MPL3115A2_Init (void) {      I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, CTRL_REG1, 0x04);          // Reset all registers to POR values           Pause(0x631);          // ~1ms delay           I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, PT_DATA_CFG_REG, 0x07);    // Enable data flags      I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, CTRL_REG3, 0x00);          // Push-pull, active low interrupt      I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, CTRL_REG4, 0x80);          // Enable DRDY interrupt      I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, CTRL_REG5, 0x80);          // DRDY interrupt routed to INT1 - PTA13      I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, CTRL_REG1, 0x39);          // Active barometer mode, OSR = 128              //I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, CTRL_REG1, 0xB9);        // Active altimeter mode, OSR = 128 }   4. 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_PCR13 |= PORT_PCR_ISF_MASK;          // Clear the interrupt flag      DataReady = 1;   }   5. In the main loop, the DataReady variable is periodically checked and if it is set, both pressure (eventually altitude) and temperature data are read and then calculated.  if (DataReady)          // Is a new set of data ready? {      DataReady = 0;                                                                                                                         I2C_ReadMultiRegisters(MPL3115A2_I2C_ADDRESS, OUT_P_MSB_REG, 5, RawData);          // Read data output registers 0x01-0x05                    /* Get pressure, the 20-bit measurement in Pascals is comprised of an unsigned integer component and a fractional component.      The unsigned 18-bit integer component is located in RawData[0], RawData[1] and bits 7-6 of RawData[2].      The fractional component is located in bits 5-4 of RawData[2]. Bits 3-0 of RawData[2] are not used.*/                                             Pressure = (float) (((RawData[0] << 16) | (RawData[1] << 😎 | (RawData[2] & 0xC0)) >> 6) + (float) ((RawData[2] & 0x30) >> 4) * 0.25;                                                 /* Get temperature, the 12-bit temperature measurement in °C is comprised of a signed integer component and a fractional component.      The signed 8-bit integer component is located in RawData[3].      The fractional component is located in bits 7-4 of RawData[4]. Bits 3-0 of OUT_T_LSB are not used. */                         Temperature = (float) ((short)((RawData[3] << 😎 | (RawData[4] & 0xF0)) >> 4) * 0.0625;                             /* Get altitude, the 20-bit measurement in meters is comprised of a signed integer component and a fractional component.      The signed 16-bit integer component is located in RawData[0] and RawData[1].      The fraction component is located in bits 7-4 of RawData[2]. Bits 3-0 of RawData[2] are not used */                                       //Altitude = (float) ((short) ((RawData[0] << 😎 | RawData[1])) + (float) (RawData[2] >> 4) * 0.0625; }   6. 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.      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, do not hesitate to ask below. Your feedback or suggestions are also welcome.   Regards, Tomas Original Attachment has been moved to: FreeMASTER---FRDM-KL25Z-MPL3115A2-Pressure-and-temperature-reading-using-I2C-and-interrupt.zip Original Attachment has been moved to: FRDM-KL25Z-MPL3115A2-Pressure-and-temperature-reading-using-I2C-and-interrupt.zip
記事全体を表示
Hi Everyone,   I would like to share a simple example code/demo that reads both the altitude and temperature data from the Xtrinsic MPL3115A2 pressure sensor and visualizes them using the FreeMASTER tool via USBDM interface. I have used recently released Xtrinsic MEMS sensors board that features three types of Xtrinsic sensors including the MPL3115A2 and is fully compatible with the Freescale FRDM-KL25Z platform.   According to the User Manual, both interrupt pins of the MPL3115A2 are connected to the PTD3 pin of KL25Z MCU through a 4.7K pull-up resistor as well as both SCL and SDA lines that are connected to the I2C1 module (PTE1 and PTE0 pins) on the KL25Z. The MCU is, therefore, configured as follows: void MCU_Init(void) {        //I2C1 module initialization            SIM_SCGC4 |= SIM_SCGC4_I2C1_MASK;        // Turn on clock to I2C1 module        SIM_SCGC5 |= SIM_SCGC5_PORTE_MASK;       // Turn on clock to Port E module        PORTE_PCR1 = PORT_PCR_MUX(6);            // PTE1 pin is I2C1 SCL line        PORTE_PCR0 = PORT_PCR_MUX(6);            // PTE0 pin is I2C1 SDA line        I2C1_F  = 0x14;                          // SDA hold time = 2.125us, SCL start hold time = 4.25us, SCL stop hold time = 5.125us        I2C1_C1 = I2C_C1_IICEN_MASK;             // Enable I2C1 module          //Configure the PTD3 pin (connected to the INT2 of the MPL3115A2) for falling edge interrupt          SIM_SCGC5 |= SIM_SCGC5_PORTD_MASK;       // Turn on clock to Port D module        PORTD_PCR3 |= (0|PORT_PCR_ISF_MASK|      // Clear the interrupt flag        PORT_PCR_MUX(0x1)|                       // PTD3 is configured as GPIO        PORT_PCR_IRQC(0xA));                     // PTD3 is configured for falling edge interrupts                     //Enable PORTD interrupt on NVIC        NVIC_ICPR |= 1 << ((INT_PORTD - 16)%32);        NVIC_ISER |= 1 << ((INT_PORTD - 16)%32); }   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() {        PORTD_PCR3 |= PORT_PCR_ISF_MASK;         // Clear the interrupt flag        DataReady = 1; } At the beginning of the initialization, all MPL3115A2 registers are reset to their default values by setting the RST bit of the CTRL_REG1 register.The DRDY interrupt is enabled and routed to the INT2 pin that is configured to be an open-drain, active-low output. During the initialization of the MPL3115A2, the OSR ratio of 128 is selected and finally the part goes into Active Altimeter mode.   void MPL3115A2_Init (void) {        unsigned char reg_val = 0;                    I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, CTRL_REG1, 0x04);                        // Reset all registers to POR values             do            // Wait for the RST bit to clear        {           reg_val = I2C_ReadRegister(MPL3115A2_I2C_ADDRESS, CTRL_REG1) & 0x04;        }  while (reg_val);        I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, PT_DATA_CFG_REG, 0x07);                  // Enable data flags        I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, CTRL_REG3, 0x11);                        // Open drain, active low interrupts        I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, CTRL_REG4, 0x80);                        // Enable DRDY interrupt        I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, CTRL_REG5, 0x00);                        // DRDY interrupt routed to INT2 - PTD3        I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, CTRL_REG1, 0xB9);                        // Active altimeter mode, OSR = 128 }   In the main loop, the DataReady variable is periodically checked and if it is set, both altitude and temperature data are read and then calculated.   if (DataReady)          // Is a new set of data ready? {                   DataReady = 0;                  OUT_P_MSB = I2C_ReadRegister(MPL3115A2_I2C_ADDRESS, OUT_P_MSB_REG);        // High byte of integer part of altitude,        OUT_P_CSB = I2C_ReadRegister(MPL3115A2_I2C_ADDRESS, OUT_P_CSB_REG);        // Low byte of integer part of altitude        OUT_P_LSB = I2C_ReadRegister(MPL3115A2_I2C_ADDRESS, OUT_P_LSB_REG);        // Decimal part of altitude in bits 7-4        OUT_T_MSB = I2C_ReadRegister(MPL3115A2_I2C_ADDRESS, OUT_T_MSB_REG);        // Integer part of temperature        OUT_T_LSB = I2C_ReadRegister(MPL3115A2_I2C_ADDRESS, OUT_T_LSB_REG);        // Decimal part of temperature in bits 7-4                           /* Get altitude, the 20-bit measurement in meters is comprised of a signed integer component and        a fractional component. The signed 16-bit integer component is located in OUT_P_MSB and OUT_P_CSB.        The fraction component is located in bits 7-4 of OUT_P_LSB. Bits 3-0 of OUT_P_LSB are not used */                       Altitude = (float) ((short) ((OUT_P_MSB << 😎 | OUT_P_CSB)) + (float) (OUT_P_LSB >> 4) * 0.0625;                     /* Get temperature, the 12-bit temperature measurement in °C is comprised of a signed integer component and        a fractional component. The signed 8-bit integer component is located in OUT_T_MSB. The fractional component        is located in bits 7-4 of OUT_T_LSB. Bits 3-0 of OUT_T_LSB are not used. */                           Temperature = (float) ((signed char) OUT_T_MSB) + (float) (OUT_T_LSB >> 4) * 0.0625;                                                              }   The calculated values can be watched in the "Variables" window on the top right of the Debug perspective or in the FreeMASTER application. Attached you can find the complete source code written in the CW 10.3 as well as 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 Original Attachment has been moved to: FreeMASTER---XTRINSIC-SENSORS-EVK_MPL3115A2_BasicReadUsingInterrupt.zip Original Attachment has been moved to: XTRINSIC-SENSORS-EVK_MPL3115A2_BasicReadUsingInterrupt.zip
記事全体を表示
Hi Everyone, This tutorial is a guide on how to create a simple application in the Kinetis Design Studio that reads the data from both sensors on the FRDM-STBC-AGM01 board​ using an interrupt technique through the I 2 C interface. The Processor Expert is used to configure the I 2 C interface and GPIO on the MKL25Z128 MCU. I will not cover the Sensor Fusion libraryand the ISF​. Before you begin please make sure that both the Kinetis Design Studio (Eclipse based) and the Kinetis SDK are setup and you can already compile and debug code. If not, please refer to Erich's blog: Tutorial: Adafruit WS2812B NeoPixels with the Freescale FRDM-K64F Board – Part 2: Software Tools | MCU on Eclipse http://centaurian.co.uk/2015/05/22/toolchain-ksdk-1-2-0-with-eclipse-4-4-luna-and-gnu-arm-plugin/ 1. Create a new project in KDS Within KDS, click on "File" menu item and select "New" > "Kinetis Project" Name and set location of your project. I use the default location under the workspace area. Click Next. Select the development board used (in my case it is the FRDM-KL25Z) and click Next. Select “KSDK 1.2.0”. Set location to KSDK path, I use an absolute path. The location of my KSDK is in the default location where KSDK would install to. Ensure “Processor Expert” checkbox is checked. Press Next. Make sure that “GNU C Compiler” is selected. Click the "Finish" button. 2. Open Processor Expert Open the Processor Expert perspective, this should be a button on the top right hand side of Eclipse. If it is not there, try clicking on the “Open Perspective” button and then selecting “Processor Expert” in the form that appears. 3. Add I2C component Click on the “Components Library” tab, search for the component “fsl_i2c” and double click on it. Select the "i2cCom1:fsl_i2c" in the Components window. In the "Component Inspector" tab configure the I2C component. As you can see in the FRDM-STBC-AGM01 schematic, with jumpers J6 and J7 in their default position (2-3), the I 2 C signals are routed to the I2C1 module (PTC1 and PTC2 pins) of the KL25Z MCU. The 7-bit I 2 C slave address of the FXOS8700CQ is 0x1E (to enter hex values, switch the format to the ‘H’ mode) since both SA0 and SA1 pins are shorted to GND. The address of the FXAS21002C is 0x20 since SA0 pin is also shorted to GND. The I2C bus clock frequency is set to 400 kHz. 4. Add GPIO component Click on the “Components Library” tab, search for the component “fsl_gpio” and double click on it. Select the "gpio1:fsl_gpio" in the Components window. In the "Component Inspector" tab configure the GPIO component. The INT1_8700 output is connected to the PTD4 pin and the INT1_21002 pin to the PTA5 pin of the KL25Z MCU. These both interrupt pins are configured as push-pull active-low outputs, so the corresponding PTD4/PTA5 pin configuration is GPIO with an interrupt on falling edge. To enable both the PORTA and PORTD interrupts, select the “Events” tab and then select “generate code” next to PORTA IRQ and PORTD IRQ handlers. 5. Add Wait component​ Click on the “Components Library” tab, search for the component “Wait” and double click on it. At this point we have done all we can within Processor Expert. Make sure you save all on the project at this point then on the Components window, click on the "Generate code" button. 6. Add your code Here is the initialization of the FXOS8700CQ and FXAS21002C. /****************************************************************************** * FXOS8700CQ initialization function ******************************************************************************/ void FXOS8700CQ_Init (void) {   FXOS8700CQ_WriteRegister(CTRL_REG2, 0x40); // Reset all registers to POR values   WAIT1_Waitms(1);   FXOS8700CQ_WriteRegister(XYZ_DATA_CFG_REG, 0x00); // +/-2g range with 0.244mg/LSB   FXOS8700CQ_WriteRegister(M_CTRL_REG1, 0x1F); // Hybrid mode (accelerometer + magnetometer), max OSR   FXOS8700CQ_WriteRegister(M_CTRL_REG2, 0x20); // M_OUT_X_MSB register 0x33 follows the OUT_Z_LSB register 0x06 (used for burst read)   FXOS8700CQ_WriteRegister(CTRL_REG2, 0x02); // High Resolution mode   FXOS8700CQ_WriteRegister(CTRL_REG3, 0x00); // Push-pull, active low interrupt   FXOS8700CQ_WriteRegister(CTRL_REG4, 0x01); // Enable DRDY interrupt   FXOS8700CQ_WriteRegister(CTRL_REG5, 0x01); // DRDY interrupt routed to INT1 - PTD4   FXOS8700CQ_WriteRegister(CTRL_REG1, 0x25); // ODR = 25Hz, Reduced noise, Active mode } /****************************************************************************** * FXAS21002C initialization function ******************************************************************************/ void FXAS21002C_Init (void) {   FXAS21002C_WriteRegister(GYRO_CTRL_REG1, 0x40); // Reset all registers to POR values   WAIT1_Waitms(1);   FXAS21002C_WriteRegister(GYRO_CTRL_REG0, 0x03); // High-pass filter disabled, +/-250 dps range -> 7.8125 mdps/LSB = 128 LSB/dps   FXAS21002C_WriteRegister(GYRO_CTRL_REG2, 0x0C); // Enable DRDY interrupt, mapped to INT1 - PTA5, push-pull, active low interrupt   FXAS21002C_WriteRegister(GYRO_CTRL_REG1, 0x16); // ODR = 25Hz, Active mode } In the ISRs (look for the file Events.c), only the interrupt flags are cleared and the DataReady variables are set to indicate the arrival of new data. void PORTA_IRQHandler(void) {   /* Clear interrupt flag.*/   PORT_HAL_ClearPortIntFlag(PORTA_BASE_PTR);   /* Write your code here ... */   FXAS21002C_DataReady = 1; } void PORTD_IRQHandler(void) {   /* Clear interrupt flag.*/   PORT_HAL_ClearPortIntFlag(PORTD_BASE_PTR);   /* Write your code here ... */   FXOS8700CQ_DataReady = 1; } The output values from accelerometer registers 0x01 – 0x06 are first converted to signed 14-bit integer values and afterwards to real values in g’s. Similarly, the output values from magnetometer registers 0x33 – 0x38 are first converted to signed 16-bit integer values and afterwards to real values in microtesla (µT). if (FXOS8700CQ_DataReady)         // Is a new set of accel+mag data ready? {    FXOS8700CQ_DataReady = 0;       FXOS8700CQ_ReadRegisters(OUT_X_MSB_REG, 12, AccelMagData);         // Read FXOS8700CQ data output registers 0x01-0x06 and 0x33 - 0x38       // 14-bit accelerometer data    Xout_Accel_14_bit = ((int16_t) (AccelMagData[0]<<8 | AccelMagData[1])) >> 2;             // Compute 14-bit X-axis acceleration output value    Yout_Accel_14_bit = ((int16_t) (AccelMagData[2]<<8 | AccelMagData[3])) >> 2;             // Compute 14-bit Y-axis acceleration output value    Zout_Accel_14_bit = ((int16_t) (AccelMagData[4]<<8 | AccelMagData[5])) >> 2;             // Compute 14-bit Z-axis acceleration output value       // Accelerometer data converted to g's    Xout_g = ((float) Xout_Accel_14_bit) / SENSITIVITY_2G;         // Compute X-axis output value in g's    Yout_g = ((float) Yout_Accel_14_bit) / SENSITIVITY_2G;         // Compute Y-axis output value in g's    Zout_g = ((float) Zout_Accel_14_bit) / SENSITIVITY_2G;         // Compute Z-axis output value in g's    // 16-bit magnetometer data    Xout_Mag_16_bit = (int16_t) (AccelMagData[6]<<8 | AccelMagData[7]);        // Compute 16-bit X-axis magnetic output value    Yout_Mag_16_bit = (int16_t) (AccelMagData[8]<<8 | AccelMagData[9]);        // Compute 16-bit Y-axis magnetic output value    Zout_Mag_16_bit = (int16_t) (AccelMagData[10]<<8 | AccelMagData[11]);      // Compute 16-bit Z-axis magnetic output value    // Magnetometer data converted to microteslas    Xout_uT = (float) (Xout_Mag_16_bit) / SENSITIVITY_MAG;             // Compute X-axis output magnetic value in uT    Yout_uT = (float) (Yout_Mag_16_bit) / SENSITIVITY_MAG;             // Compute Y-axis output magnetic value in uT    Zout_uT = (float) (Zout_Mag_16_bit) / SENSITIVITY_MAG;             // Compute Z-axis output magnetic value in uT } Similarly, the output values from gyroscope registers 0x01 – 0x06 are first converted to signed 16-bit integer values and afterwards to real values in degrees per second. Temperature is also read out from the 0x12 register. if (FXAS21002C_DataReady)         // Is a new set of gyro data ready? {    FXAS21002C_DataReady = 0;    FXAS21002C_ReadRegisters(GYRO_OUT_X_MSB_REG, 6, GyroData);         // Read FXAS21002C data output registers 0x01-0x06    // 16-bit gyro data    Xout_Gyro_16_bit = (int16_t) (GyroData[0]<<8 | GyroData[1]);         // Compute 16-bit X-axis output value    Yout_Gyro_16_bit = (int16_t) (GyroData[2]<<8 | GyroData[3]);         // Compute 16-bit Y-axis output value    Zout_Gyro_16_bit = (int16_t) (GyroData[4]<<8 | GyroData[5]);         // Compute 16-bit Z-axis output value    // Gyro data converted to dps    Roll = (float) (Xout_Gyro_16_bit) / SENSITIVITY_250;               // Compute X-axis output value in dps    Pitch = (float) (Yout_Gyro_16_bit) / SENSITIVITY_250;              // Compute Y-axis output value in dps    Yaw = (float) (Zout_Gyro_16_bit) / SENSITIVITY_250;                // Compute Z-axis output value in dps    // Temperature data    FXAS21002C_ReadRegisters(GYRO_TEMP_REG, 1, GyroData);    Temp = (int8_t) (GyroData[0]); } The complete project including the I2C communication routines and sensor's header files is attached. 6. Build and debug the project To build the project, select the root folder of the project in the Project Explorer view and click the "Hammer" icon to build it. If everything goes well, no errors are shown in the "Problems" view: The .elf (binary) file has been created inside the "Debug" folder: Connect the SDA port on the FRDM-KL25Z board to a USB port on your computer. To debug the project for the first time, select the root folder of the project in the Project Explorer view and open the "Debug Configurations" window. Select the ""GDB PEMicro Interface Debugging" and click the "New launch configuration" icon. In the "Debugger" tab, select the "OpenSDA Embedded Debug - USB Port" interface and the KL25Z128M4 as a target device. Click the "Debug" button. Click the "Resume" button to run the project. You can pause the execution and look at the data using the "Suspend" button. Now you can edit, build and debug the project again. As we used a debug configuration, it is listed under the "Debug" icon, so you can start it from there. Well done if you managed to follow along and get it all working. As a bonus I have attached the FreeMASTER project that will allow you to visualize the gathered data. If there are any questions regarding this simple project, do not hesitate to ask below. Your feedback or suggestions are also welcome. Regards, Tomas
記事全体を表示
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. 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). 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 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. 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
記事全体を表示
Hello community, This time, I would like to share a simple bare metal example code using the MAG3110 , the digital Magnetometer from NXP. I created this example code with the FRDM-KL25Z  platform and the FRDM-FXS-MULT2-B sensor expansion board. The complete source code is written in the Kinetis Design Studio V3.2.0  in collaboration with the FreeMASTER  tool in order to visualize the magnetic data. This document guides you through the initialization process and how to appreciate the demonstration. Section 1: Initialization of the MKL25Z128 MCU. Section 2: Initialization of the MAG3110. Section 3: Simple magnetic hard-iron offset calibration. Section 4: Output data reading using an interrupt technique. Section 5: Conversion of the output values. Section 6: FreeMASTER tool. 1. Initialization of the MKL25Z128 MCU Based on the figure below, the SCL and SDA signals, from the I2C Module, are connected to the PTC1 and PTC2 pins respectively. The INT1 output of the MAG3110 is connected to the PTD4 pin of the KL25Z. Please make sure the 2&3 pins of the J3 are connected together using a jumper at the FRDM-FXS-MULT2-B. The RGB LED from the FRDM-KL25Z is also set using the PTB18 and PTB19 pins as GPIOs. //I2C1 module initialization SIM_SCGC4 |= SIM_SCGC4_I2C1_MASK;         // Turn on clock to I2C0 module SIM_SCGC5 |= SIM_SCGC5_PORTC_MASK;        // Turn on clock to Port C module PORTC_PCR1 = PORT_PCR_MUX(2);             // PTC1 pin is I2C0 SCL line PORTC_PCR2 = PORT_PCR_MUX(2);             // PTC2 pin is I2C0 SDA line I2C1_F  = 0x14;                           // SDA hold time = 2.125us, SCL start hold time = 4.25us, SCL stop hold time = 5.125us I2C1_C1 = I2C_C1_IICEN_MASK;              // Enable I2C0 module //Configure the PTD4 pin (connected to the INT1 of the MAG3110) for rising edge interrupts SIM_SCGC5 |= SIM_SCGC5_PORTD_MASK;        // Turn on clock to Port D module PORTD_PCR4  |= (0|PORT_PCR_ISF_MASK|      // Clear the interrupt flag                   PORT_PCR_MUX(0x1)|      // PTD4 is configured as GPIO                   PORT_PCR_IRQC(0x09));   // PTD4 is configured for rising edge interrupts (MAG3110 generates low to high signal) //Configure RGB LED SIM_SCGC5 |= SIM_SCGC5_PORTB_MASK;        // Turn on clock to Port B module PORTB_PCR19 = PORT_PCR_MUX(1);            // PTB19 is configured as GPIO GPIOB_PDDR |= (1 << 19);                  // Configure pin as output GPIOB_PSOR |= (1 << 19);                  // Turn OFF GREEN LED PORTB_PCR18 = PORT_PCR_MUX(1);            // PTB18 is configured as GPIO GPIOB_PDDR |= (1 << 18);                  // Configure pin as output GPIOB_PCOR |= (1 << 18);                  // Turn ON RED LED //Enable PORTD interrupt on NVIC NVIC_EnableIRQ(PORTD_IRQn);               // Enable interrupts NVIC_ClearPendingIRQ(PORTD_IRQn);         // Clear pending interrupts ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ 2. Initialization of the MAG3110 The MAG3110 is capable of measuring magnetic fields with an output data rate (ODR) up to 80 Hz. In this case, the ODR of the MAG3110 is set at 20Hz. The automatic resets are enabled. When new measurement data is available, the INT1 pin triggers a software interrupt. The WHO_AM_I register is read in order to verify the correct communication with the magnetometer. I2C_WriteRegister(MAG3110_I2C_ADDRESS, CTRL_REG2, 0x80);  // Enable automatic resets WhoAmI = I2C_ReadRegister(MAG3110_I2C_ADDRESS, WHO_AM_I); // Read WHO_AM_I Register I2C_WriteRegister(MAG3110_I2C_ADDRESS, CTRL_REG1, 0x11);  // ODR 20Hz (0.05s), Active mode ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ 3. Simple magnetic hard-iron offset calibration. Please note that the magnetometer readings must be corrected for Hard-Iron and Soft-Iron effects. If you are interested in more complex algorithms you may refer to the NXP E-Compass Software. As an alternative, a method to calibrate the hard iron offset is rotating the MAG3110 in a figure of eight twisting motions for a few seconds, record the minimum and maximum magnetometer readings, compute the corresponding offset values by using the min/max averaging and then either subtract these offset values from the current magnetometer measurements or write them in the user offset registers with CTRL_REG2[RAW] = 0. The hard iron offset calibration is done as follow: short Xout_16_bit_avg, Yout_16_bit_avg, Zout_16_bit_avg; short Xout_16_bit_max, Yout_16_bit_max, Zout_16_bit_max; short Xout_16_bit_min, Yout_16_bit_min, Zout_16_bit_min; short i=0; while (i < 200) // Calibration process ~10s (200 samples * 1/20Hz) {     if (DataReady)         {             DataReady= 0;             I2C_ReadMultiRegisters(MAG3110_I2C_ADDRESS, OUT_X_MSB, 6, MagData);        // Read data output registers 0x01-0x06             Xout_16_bit = ((short) (MagData[0]<<8 | MagData[1]));        // Compute 16-bit X-axis output value             Yout_16_bit = ((short) (MagData[2]<<8 | MagData[3]));        // Compute 16-bit Y-axis output value             Zout_16_bit = ((short) (MagData[4]<<8 | MagData[5]));        // Compute 16-bit Z-axis output value             if (i == 0)             {                 Xout_16_bit_max = Xout_16_bit;                 Xout_16_bit_min = Xout_16_bit;                 Yout_16_bit_max = Yout_16_bit;                 Yout_16_bit_min = Yout_16_bit;                 Zout_16_bit_max = Zout_16_bit;                 Zout_16_bit_min = Zout_16_bit;             }             // Check to see if current sample is the maximum or minimum X-axis value             if (Xout_16_bit > Xout_16_bit_max) {Xout_16_bit_max = Xout_16_bit;}             if (Xout_16_bit < Xout_16_bit_min) {Xout_16_bit_min = Xout_16_bit;}             // Check to see if current sample is the maximum or minimum X-axis value             if (Yout_16_bit > Yout_16_bit_max) {Yout_16_bit_max = Yout_16_bit;}             if (Yout_16_bit < Yout_16_bit_min) {Yout_16_bit_min = Yout_16_bit;}             // Check to see if current sample is the maximum or minimum X-axis value             if (Zout_16_bit > Zout_16_bit_max) {Zout_16_bit_max = Zout_16_bit;}             if (Zout_16_bit < Zout_16_bit_min) {Zout_16_bit_min = Zout_16_bit;}             i++;         } } Xout_16_bit_avg = (Xout_16_bit_max + Xout_16_bit_min) / 2;    // X-axis hard-iron offset Yout_16_bit_avg = (Yout_16_bit_max + Yout_16_bit_min) / 2;    // Y-axis hard-iron offset Zout_16_bit_avg = (Zout_16_bit_max + Zout_16_bit_min) / 2;    // Z-axis hard-iron offset // Left-shift by one as magnetometer offset registers are 15-bit only, left justified Xout_16_bit_avg <<= 1; Yout_16_bit_avg <<= 1; Zout_16_bit_avg <<= 1; I2C_WriteRegister(MAG3110_I2C_ADDRESS, CTRL_REG1, 0x00);  // Standby mode // Set Offset I2C_WriteRegister(MAG3110_I2C_ADDRESS, OFF_X_LSB, (char)(Xout_16_bit_avg & 0xFF)); I2C_WriteRegister(MAG3110_I2C_ADDRESS, OFF_X_MSB, (char)((Xout_16_bit_avg >>8) & 0xFF)); I2C_WriteRegister(MAG3110_I2C_ADDRESS, OFF_Y_LSB, (char)(Yout_16_bit_avg & 0xFF)); I2C_WriteRegister(MAG3110_I2C_ADDRESS, OFF_Y_MSB, (char)((Yout_16_bit_avg >>8) & 0xFF)); I2C_WriteRegister(MAG3110_I2C_ADDRESS, OFF_Z_LSB, (char)(Zout_16_bit_avg & 0xFF)); I2C_WriteRegister(MAG3110_I2C_ADDRESS, OFF_Z_MSB, (char)((Zout_16_bit_avg >>8) & 0xFF)); I2C_WriteRegister(MAG3110_I2C_ADDRESS, CTRL_REG1, 0x11);  //  Active mode again ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ 4. Output data reading using an interrupt technique. At the ISR, the interrupt flag is clear and the DataReady variable is set in order to know that a new magnetic measurement is ready. void PORTD_IRQHandler() {     PORTD_PCR4 |= PORT_PCR_ISF_MASK;            // Clear the interrupt flag     DataReady= 1; } ‍‍‍‍‍‍‍‍‍‍‍ 5. Conversion of the output values The output values from magnetometer are converted to signed 16-bit integer values and afterwards to real values in microtesla (µT). for(;;){    if (DataReady)    {            DataReady= 0;            I2C_ReadMultiRegisters(MAG3110_I2C_ADDRESS, OUT_X_MSB, 6, MagData);        // Read data output registers 0x01-0x06            // 16-bit magnetometer data            Xout_16_bit = ((short) (MagData[0]<<8 | MagData[1]));        // Compute 16-bit X-axis output value            Yout_16_bit = ((short) (MagData[2]<<8 | MagData[3]));        // Compute 16-bit Y-axis output value            Zout_16_bit = ((short) (MagData[4]<<8 | MagData[5]));        // Compute 16-bit Z-axis output value            // Magnetometer data converted to microteslas           Xout_uT = (float)Xout_16_bit / SENSITIVITY;     // Compute X-axis output magnetic value in uT            Yout_uT = (float)Yout_16_bit / SENSITIVITY;     // Compute Y-axis output magnetic value in uT           Zout_uT = (float)Zout_16_bit / SENSITIVITY;     // Compute Z-axis output magnetic value in uT    } }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ 6. FreeMASTER FreeMASTER is a user-friendly real-time debug monitor and data visualization tool that you can use for any application development and information management. In this case, it is used in order to visualize the magnetic data. In case you have problems with the communication port, please go to Project / Options… Select Plug-in Module and choose the FreeMASTER BDM Communication Plug-in option. Select configure and make sure the P&E Kinetis is selected. Select OK and Start the communication. Please find attached the complete source code, including the FreeMASTER project. You are invited to take part of the NXP community where you can post all your questions and you may find useful material for your projects. I hope you find useful and funny this sample project. Any suggestion will be appreciated. Best Regards, David
記事全体を表示
Hello Community,   One of the main features of the NXP accelerometers is the Auto-WAKE/SLEEP mode.   I would like to share this project in order to demonstrate the feasibility of using the Low-power and auto-WAKE/SLEEP modes for reducing current consumption in the different NXP accelerometers such as the MMA845x and MMA865x series.   I created this project using the FRDM-KL25Z platform and the MMA8652FC accelerometer (You may find the breakout board files here). The complete source code is written in CodeWarrior v10.x IDE.   This document gives you an introduction of the MMA8652FC accelerometer as well as the different power consumptions and guides you through the initialization process and how to appreciate the demonstration:   Initialization of the MKL25Z128 MCU. Initialization of the MMA8652FC. Auto-WAKE/SLEEP mode. MMA8652FC Embedded functions. Interrupt handlers. Evaluation of the interrupt source. Summarizing the application and Macros definition. Visualization of the current consumption.   1. As you can see in the FRDM-KL25Z schematic and the image below, the I2C signals are routed to the I2C1 module (PTC1 and PTC2 pins) of the KL25Z MCU and the INT1 and INT2 outputs are connected to the PTD5 and PTA5 pins. The INT1 and INT2 outputs of the MMA8652FC are configured as a push-pull active-low outputs, so the corresponding PTD5 and PTA5 pins configuration are GPIOs with an interrupt on falling edge.   The MCU is, therefore, configured as follows:          /* I2C1 module initialization */      SIM_SCGC4 |= SIM_SCGC4_I2C1_MASK;        // Turn on clock to I2C1 module      SIM_SCGC5 |= SIM_SCGC5_PORTC_MASK;       // Turn on clock to Port C module      PORTC_PCR1 |= PORT_PCR_MUX(0x2);         // PTC1 pin is I2C1 SCL line      PORTC_PCR2 |= PORT_PCR_MUX(0x2);         // PTC2 pin is I2C1 SDA line      I2C1_F  |= I2C_F_ICR(0x14);              // SDA hold time = 2.125us, SCL start hold time = 4.25us, SCL stop hold time = 5.125us      I2C1_C1 |= I2C_C1_IICEN_MASK;            // Enable I2C1 module        /*Configure the PTD5 and PTA5 pin (connected to the INT1 and INT2 of the MMA8652FC) for falling edge interrupts */      SIM_SCGC5 |= SIM_SCGC5_PORTD_MASK;       // Turn on clock to Port D module      PORTD_PCR5 |= (0|PORT_PCR_ISF_MASK|      // Clear the interrupt flag                           PORT_PCR_MUX(0x1)|  // PTD5 is configured as GPIO                           PORT_PCR_IRQC(0xA));// PTD5 is configured 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 PORTD interrupt on NVIC */      NVIC_ICPR |= 1 << ((INT_PORTD - 16)%32);      NVIC_ISER |= 1 << ((INT_PORTD - 16)%32);      /* Enable PORTA interrupt on NVIC */      NVIC_ICPR |= 1 << ((INT_PORTA - 16)%32);      NVIC_ISER |= 1 << ((INT_PORTA - 16)%32);     2. The MMA8652FC is an intelligent, low-power, three-axis, capacitive micromachined accelerometer with 12 bits of resolution.   At the beginning of the initialization, all registers are reset to their default values by setting the RST bit of the CTRL_REG2 register. The Normal and Low Power modes are set in the same register. The MODS[1:0] bits select which Oversampling mode is to be used. The Oversampling modes are available in both WAKE Mode MOD[1:0] and also in the SLEEP Mode SMOD[1:0].   Then the MMA8652FC is initialized as shown below:        I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, CTRL_REG2, 0x40);        // Reset all registers to POR values      Pause(0x631);        // ~1ms delay      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, XYZ_DATA_CFG_REG, 0x00); // +/-2g range with ~0.977mg/LSB              /* Power Mode Configuration */      If LOW power mode is selected:      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, CTRL_REG2, 0x1B);        // Low Power mode        If NORMAL power mode is selected:      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, CTRL_REG2, 0x00);        // Normal mode     3. As I mentioned, one of the main features of the MMA8652FC is the Auto-WAKE/SLEEP mode.   The advantage of using the Auto-WAKE/SLEEP is that the system can automatically transition to a higher sample rate (higher current consumption) when needed, but spends the majority of the time in the SLEEP mode (lower current) when the device does not require higher sampling rates.   • Auto-WAKE refers to the device being triggered by one of the interrupt functions to transition to a higher sample rate. This may also interrupt the processor to transition from a SLEEP mode to a higher power mode. • SLEEP mode occurs after the accelerometer has not detected an interrupt for longer than the user-definable timeout period.       At the ASLP_COUNT register, you can set the minimum time period of inactivity required to switch the part between Wake and Sleep status, in this case, 5 seconds.   The Auto-WAKE/SLEEP mode, therefore, is configured as follow:        read_reg = I2C_ReadRegister(MMA8652FC_I2C_ADDRESS, CTRL_REG2);      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, CTRL_REG2, read_reg|0x04);  // Auto-SLEEP enable      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, ASLP_COUNT_REG, 0x10);      // 5 seconds (16 * 320ms)      read_reg = I2C_ReadRegister(MMA8652FC_I2C_ADDRESS, CTRL_REG4);      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, CTRL_REG4, read_reg|0x80);  // Enable AutoSleep interrupt, INT2 - PTD5      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, CTRL_REG1, 0xC1);           // ODR=800Hz and Sleep mode ODR=1.56Hz, Active mode     4. The device can be configured to generate inertial wake-up interrupt signals from any combination of the configurable embedded functions, enabling the MMA8652FC to monitor inertial events while remaining in a low-power mode during periods of inactivity.   The Interrupts that can WAKE the device from SLEEP are: Tap Detection, Orientation Detection, Motion/Freefall, and Transient Detection.       In this project, the TAP (Pulse) or Transient interrupts are used to wake up the device from the SLEEP. In order to get more information about the TAP detection, please click here.   The MMA8652FC is configured as below:        If Transient interrupt is selected:      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, TRANSIENT_THS_REG, 0x84);         // Set threshold to 252mg (4 x 63mg )      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, TRANSIENT_COUNT_REG, 0x02);       // Set debounce timer period to 40ms (low power mode) / 2.5ms (normal mode)-Table 66      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, TRANSIENT_CFG_REG, 0x17);         // Enable transient detection for X and Y axis, latch enabled         I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, CTRL_REG3, 0x40);                 // Wake from Transient interrupt, Push-pull, active low interrupt      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, CTRL_REG4, 0x20);                 // Enable Transient detection interrupt      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, CTRL_REG5, 0x20);                 // Transient interrupt routed to INT1 - PTA5          If TAP interrupt is selected:      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, PULSE_CFG_REG, 0x15);             // Enable X, Y and Z Single Pulse      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, PULSE_THSX_REG, 0x20);            // Set X Threshold to 2.016g      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, PULSE_THSY_REG, 0x20);            // Set Y Threshold to 2.016g      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, PULSE_THSZ_REG, 0x2A);            // Set Z Threshold to 2.646g      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, PULSE_TMLT_REG, 0x28);            // Set Time Limit for Tap Detection to 25 ms      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, PULSE_LTCY_REG, 0x28);            // Set Latency Time to 50 ms. During this time interval, all pulses are ignored          I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, CTRL_REG3, 0x10);                 // Wake from Pulse interrupt, Push-pull, active low interrupt      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, CTRL_REG4, 0x08);                 // Pulse detection interrupt enabled      I2C_WriteRegister(MMA8652FC_I2C_ADDRESS, CTRL_REG5, 0x08);                 // Pulse interrupt routed to INT1 - PTA5     5. As I mentioned above, the TAP (Pulse) or Transient interrupts are used to wake up the device from the SLEEP. Besides, if Auto-SLEEP interrupt is enabled, then transitioning from ACTIVE mode to Auto-SLEEP mode (or vice versa) generates an interrupt.   In this project, the Auto-SLEEP, the TAP (Pulse) or the Transient interrupts are enable. The MKL25Z128 responds to these interrupts reading the INT_SOURCE (0x0C) register, in order to determine the appropriate sources of the interrupt.   Every source of interrupt has its own way to clear the interrupt flag. Please refer to the comments of each ISR:        Transient interrupt handler      void PORTA_IRQHandler()      {         PORTA_PCR5 |= PORT_PCR_ISF_MASK;                // Clear the PTC interrupt         int_source = I2C_ReadRegister(MMA8652FC_I2C_ADDRESS, INT_SOURCE_REG); // Clear interrupt Source Register           if(int_source&0x20)  // Transient interrupt ?         {            i = I2C_ReadRegister(MMA8652FC_I2C_ADDRESS, TRANSIENT_SRC_REG); // Read the TRANSIENT_SRC register to clear the SRC_TRANS flag in the INT_SOURCE register             transient_int = 1;         }      }        TAP interrupt handler      void PORTA_IRQHandler()      {         PORTA_PCR5 |= PORT_PCR_ISF_MASK;                // Clear the PTC interrupt flag         int_source = I2C_ReadRegister(MMA8652FC_I2C_ADDRESS, INT_SOURCE_REG); // Clear interrupt Source Register            if(int_source&0x08)  // Pulse interrupt ?         {            i = I2C_ReadRegister(MMA8652FC_I2C_ADDRESS, PULSE_SRC_REG); // Read the PULSE_SRC register to clear the SRC_TRANS flag in the INT_SOURCE register             pulse_int = 1;         }      }        Auto WAKE/SLEEP interrupt handler      void PORTD_IRQHandler()      {          PORTD_PCR5 |= PORT_PCR_ISF_MASK;                // Clear the PTD interrupt flag             int_source = I2C_ReadRegister(MMA8652FC_I2C_ADDRESS, INT_SOURCE_REG); // Clear interrupt Source Register             if (int_source&0x80) // Auto Sleep/Wake interrupt ?          {             i = I2C_ReadRegister(MMA8652FC_I2C_ADDRESS, SYSMOD_REG);      // Read the SYSMOD register to clear the SRC_ASLP flag in the INT_SOURCE register             sleep_int = 1;          }      }     6. At this point, the configuration of the MCU and the accelerometer is done. The RGB LED contained on the FRDM-KL25Z board is configured in order to help showing the behavior of the application. This behavior is configured as follow:        #if TRANSIENT_DETECTION                    if (transient_int){                             transient_int = 0;                 TURN_BLUE_ON(); TURN_RED_OFF();}      #elif TAP_DETECTION                    if (pulse_int){                 pulse_int = 0;                 TURN_BLUE_ON(); TURN_RED_OFF();}      #endif                    if (sleep_int){                  sleep_int = 0;                  TURN_RED_ON(); TURN_BLUE_OFF();}     7. In summary, the FRDM-KL25Z will be interfacing with the MMA8652FC. The power mode will be set and the interrupts will be enabled. The macros at the top of the source code will allow us to select between the different power modes, the different embedded functions and to select the Auto-WAKE/SLEEP function.   If the Auto-WAKE/SLEEP function is enabled, the MMA8652FC will go into the SLEEP mode (ODR=1.56Hz) after 5 seconds of inactivity. The RED LED will be set. When an interrupt from the embedded functions is generated, the MMA8652FC will be awakened (ODR=800Hz) and so on. The BLUE LED will be set.        /* Select the Power Mode - Table 101 from datasheet */      #define NORMAL_MODE        1      #define LOW_POWER_MODE     0         /* Select the Embedded Function */      #define TRANSIENT_DETECTION       1      #define TAP_DETECTION             0        /* Auto-WAKE/SLEEP Function */      #define AUTO_SLEEP   1     8. The Table 5 from the datasheet shows the expected current consumption in regard with the power mode and ODR selected:   As I mentioned before, the Sleep mode allow us to change between different Output Data Rates (ODR) dynamically so we can reduce the current consumption.   In order to verify if the accelerometer is consuming the current mentioned on the datasheet, I measured the MMA8652FC current consumption using the project mentioned.   Please refer to the results below:           9. The advantage of using the Auto-WAKE/SLEEP mode is that the system can automatically transition to a higher sample rate (higher current consumption) when needed, but spends the majority of the time in the SLEEP mode (lower current) when the device does not require higher sampling rates.   In the manner we have come to expect of the MMA8652FC, the current consumption decreases when the ODR is changed from 800Hz to 1.56Hz, in both normal and low power mode.   The information mentioned on the datasheet is now confirmed.     Please find attached the complete source code.   I hope you find useful and funny this sample project. Any suggestion will be appreciated.   You are invited to take part of the NXP community where you can post all your questions and you may find useful material for your projects.   Best Regards, David
記事全体を表示
Hello community, As we know, The MMA8451Q has embedded single/double and directional tap detection. This post describes an example project using the Single Tap detection for the MMA8451Q included on the FRDM-KL25Z. Figure 1. Depending on the tapping direction, positive or negative of each axis, the RGB LED will turn into a different color. For more detailed information on how to configure the device for tap detection please refer to NXP application note, AN4072. Configuring the MCU Enable the I2C module of the KL25Z MCU and turn on all the corresponding clocks. In this case, the INT1 output of the MMA8451Q is connected to the PTA14 pin and both SCL and SDA lines are connected to the I2C0 module (PTE24 and PTE25 pins). Please review the FRDM-KL25Z schematic.      //I2C0 module initialization        SIM_SCGC4 |= SIM_SCGC4_I2C0_MASK;        // Turn on clock to I2C0 module        SIM_SCGC5 |= SIM_SCGC5_PORTE_MASK;       // Turn on clock to Port E module        PORTE_PCR24 = PORT_PCR_MUX(5);           // PTE24 pin is I2C0 SCL line        PORTE_PCR25 = PORT_PCR_MUX(5);           // PTE25 pin is I2C0 SDA line        I2C0_F = 0x14;                           // SDA hold time = 2.125us, SCL start hold time = 4.25us, SCL stop hold time = 5.125us *        I2C0_C1 = I2C_C1_IICEN_MASK;             // Enable I2C0 module                   //Configure the PTA14 pin (connected to the INT1 of the MMA8451Q) for falling edge interrupts        SIM_SCGC5 |= SIM_SCGC5_PORTA_MASK;       // Turn on clock to Port A module        PORTA_PCR14 |= (0|PORT_PCR_ISF_MASK|     // Clear the interrupt flag        PORT_PCR_MUX(0x1)|           // PTA14 is configured as GPIO        PORT_PCR_IRQC(0xA));         // PTA14 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); Configure the RBG LED of the FRDM-KL25Z Based on FRDM-KL25Z User's Manual , the RGB LED signals are connected as follow: The pins mentioned, are configured as output.      //Configure PTB18, PTB19 and PTD1 as output for the RGB LED        SIM_SCGC5 |= SIM_SCGC5_PORTB_MASK;    // Turn on clock to Port B module        SIM_SCGC5 |= SIM_SCGC5_PORTD_MASK;    // Turn on clock to Port D module                   PORTB_PCR18 |= PORT_PCR_MUX(0x1);     // PTB18 is configured as GPIO        PORTB_PCR19 |= PORT_PCR_MUX(0x1);     // PTB19 is configured as GPIO        PORTD_PCR1 |= PORT_PCR_MUX(0x1);      // PTD1 is configured as GPIO                   GPIOB_PDDR |= (1 << 18);              //Port Data Direction Register (GPIOx_PDDR)        GPIOB_PDDR |= (1 << 19);              //Set GPIO direction set bit corresponding bit on the direction        GPIOD_PDDR |= (1 << 1);               //register for each port, set the bit means OUTPUT Initialize and configure the MMA8451Q for Tap Detection To utilize the single and/or double tap detection the following eight (8) registers must be configured. Register 0x21: PULSE_CFG Pulse Configuration Register Register 0x22: PULSE_SRC Pulse Source Register Register 0x23 - 0x25: PULSE_THSX,Y,Z Pulse Threshold for X, Y and Z Registers Register 0x26: PULSE_TMLT Pulse Time Window 1 Register Register 0x27: PULSE_LTCY Pulse Latency Timer Register Register 0x28: PULSE_WIND Second Pulse Time Window Register Please review the MMA8451Q datasheet in order to get more information about the registers mentioned. For a single tap event, the PULSE_TMLT, PULSE_THSX/Y/Z and PULSE_LTCY registers are key parameters to consider. Note in condition (a) the interrupt is asserted since the acceleration due to a pulse exceeds the specified acceleration threshold (value set in the PULSE_THSX) and crosses up and down before the specified Pulse Time Limit (value set in PULSE_TMLT) expires. Note that in condition (b) the acceleration due to a pulse exceeds the specified acceleration threshold limit, but does not go below the threshold before the specified Pulse Time Limit expires. Therefore, this is an invalid pulse and the interrupt will not be triggered. Also note that the Latency is not shown for this example.              unsigned char reg_val = 0, CTRL_REG1_val = 0;            I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG2, 0x40);             // Reset all registers to POR values                 do            // Wait for the RST bit to clear        {               reg_val = I2C_ReadRegister(MMA845x_I2C_ADDRESS, CTRL_REG2) & 0x40;        }      while (reg_val);            I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG1, 0x0C);             // ODR = 400Hz, Reduced noise, Standby mode        I2C_WriteRegister(MMA845x_I2C_ADDRESS, XYZ_DATA_CFG_REG, 0x00);      // +/-2g range -> 1g = 16384/4 = 4096 counts        I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG2, 0x02);             // High Resolution mode            I2C_WriteRegister(MMA845x_I2C_ADDRESS, PULSE_CFG_REG, 0x15);         //Enable X, Y and Z Single Pulse        I2C_WriteRegister(MMA845x_I2C_ADDRESS, PULSE_THSX_REG, 0x20);        //Set X Threshold to 2.016g        I2C_WriteRegister(MMA845x_I2C_ADDRESS, PULSE_THSY_REG, 0x20);        //Set Y Threshold to 2.016g        I2C_WriteRegister(MMA845x_I2C_ADDRESS, PULSE_THSZ_REG, 0x2A);        //Set Z Threshold to 2.646g        I2C_WriteRegister(MMA845x_I2C_ADDRESS, PULSE_TMLT_REG, 0x28);        //Set Time Limit for Tap Detection to 25 ms        I2C_WriteRegister(MMA845x_I2C_ADDRESS, PULSE_LTCY_REG, 0x28);        //Set Latency Time to 50 ms        I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG4, 0x08);             //Pulse detection interrupt enabled        I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG5, 0x08);             //Route INT1 to system interrupt            CTRL_REG1_val = I2C_ReadRegister(MMA845x_I2C_ADDRESS, CTRL_REG1);   //Active Mode        CTRL_REG1_val |= 0x01;        I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG1, CTRL_REG1_val); Handle the Interrupt The PULSE_SRC register indicates a double or single pulse event has occurred and also which direction. In this case the value of the register mentioned is passed to the PULSE_SRC_val variable and evaluated. Reading the PULSE_SRC register clears all bits. Reading the source register will clear the interrupt.      void PORTA_IRQHandler()      {             PORTA_PCR14 |= PORT_PCR_ISF_MASK;               // Clear the interrupt flag              PULSE_SRC_val = I2C_ReadRegister(MMA845x_I2C_ADDRESS, PULSE_SRC_REG); //Read Pulse Source Register      } Please find attached the complete source code written in the CodeWarrior for Microcontrollers-Eclipse IDE|NXP . As I mentioned before, you can find more detailed information at application note AN4072. Useful information about handling the MMA8451 can be founded in MMA8451Q - Bare metal example project. I hope you find useful and funny this sample project. Regards, David
記事全体を表示
    Objective: Getting Started guide for MPL3115 using i.MXRT1020 EVK and FRDMSTBC-P3115. This guide help enable you to: Get familiarity with NXP’s sensor toolbox ecosystem: a complete ecosystem for product development with NXP’s motion and pressure sensors targeted toward IoT, Industrial, Medical applications. Try hands-on IoT (Industrial/medical) sensor applications using NXP’s IoT sensors and IoT Sensing SDK framework (ISSDK, available as middleware component in MCUXpresso SDK). Leverage FRDMSTBC-P3115 sensor development board with i.MXRT1020 EVK to create and run example sensor applications for: NXP’s absolute pressure sensor MPL3115A2 designed for industrial applications.   Prerequisites: This Getting Started guide assumes following prior prerequisites actions to be completed: Availability of Windows 10 development PC. Availability of MIMXRT1020-EVK evaluation kit with Arduino I/O headers populated Availability of FRDMSTBC-P3115 sensor development boards. NXP’s MCUXpresso IDE v11.3.0 in installed on the development PC. mbed windows serial drivers are installed on development PC.  MIMXRT1020-EVK evaluation kit is pre-programmed with the latest OpenSDA bootloader and firmware application. Generate and download EVK-MIMXRT1020 SDK package from web based MCUXpresso SDK builder. Any serial terminal application (e.g. RealTerm) is installed on the training PC to view sensor output of ISSDK example applications.   Introduction to Sensors Developers Ecosystem: Sensor Development Toolbox is the complete ecosystem for product development with NXP’s motion and pressure sensors targeted toward IoT, Industrial, Medical applications. It encompasses a wide spectrum of sensor evaluation hardware and software tools making our sensors easy to use. Sensor Evaluation Boards Sensor evaluation boards provide a wide spectrum of enablement hardware for quick sensor evaluation and development. It includes a demonstration kit, shield development board and breakout board for motion and pressure sensors targeted toward IoT, Industrial, Medical applications. IoT Sensing SDK The IoT Sensing Software Development Kit (ISSDK) is the embedded software framework for the Sensor Toolbox ecosystem enabling NXP's digital and analog sensors platforms for IoT applications. Following are key features and benefits provided by ISSDK framework: ISSDK provides a unified set of sensor support models that target NXP’s portfolio of sensors across a broad range of NXP’s Arm ® Cortex ® -M core-based microcontrollers including NXP’s LPC, Kinetis and i.MX RT crossover platforms. ISSDK leverages latest version of MCUXpresso SDK (Kinetis, LPC and i.MX SDK) drivers and release infrastructure through MCUXpresso web. ISSDK combines a set of robust sensor drivers and algorithms along with out-of-box example applications to allow users to get started with using NXP sensors. Enables easy porting across broad range of NXP’s Arm Cortex M based Microcontrollers by using Arm CMSIS Driver APIs. Provides NXP’s sensor register definitions, register access interfaces and sensor level multiple register read/write interfaces. For more information on list of ISSDK supported sensors and development kits, refer to ISSDK Release Notes. Executing out-of-box MPL3115 examples: The out-of-box sensors (MPL3115) example projects ("evkmimxrt1020_mpl3115_examples.zip") are made available through this sensor knowledge base community page. These example projects are based on ISSDK framework using MPL3115 sensor drivers. Please refer to next sections on steps to run these out-of-box examples on MIMXRT1020-EVK attached with FRDMSTBC-P3115 sensor development board. Refer to attached "NXP_Hackathon_Sensors_GS_MPL3115.pdf" section#4, to execute out-of-box MPL3115 sensor examples using i.MXRT1020 EVK and FRDMSTBC-P3115 sensor development board. License and Copyright Information: Note: Please refer to the SW-Content-Register.txt file to get more details on the example project SW package components and applicable licenses. The example project sources are released under "LA_OPT_NXP_Software_License", users downloading this SW should carefully read the license agreements and comply.
記事全体を表示
Hello Freescale Community, Most of the new Freescale Sensors in our portfolio come in very small packages, some of them as small as 2x2x1mm, which is awesome! However, one of the problems that we detected last year is that many customers struggle in the evaluation stage of the project due to the small packages. They should either, buy an evaluation board or spend valuable time designing and manufacturing a PCB just for testing our devices. Our goal with this project is to share with our community the Freescale Sensors Breakout Boards we designed for this specific purpose, so you can easily manufacture your own sensor boards or modify our designs to fit  your specific application. This way you can easily evaluate Freescale sensors. The boards were designed to be used in a prototype board (DIP style pins) and they can communicate to any MCU thru IIC or SPI (depending on the sensor). These designs were made using Eagle Layout 6.5, if you want to modify the designs you can do it with the free version of Eagle CAD (for non-commercial purposes), or you can send the gerber files (included in the zip files) to your preferred PCB manufacturer. The following designs are available: + Altimeter: MPL3115A2 Breakout Board + Accelerometer: MMA845x Breakout Board MMA865x Breakout Board MMA8491 Breakout Board FXLN83xx Breakout Board FXLS8471 Breakout Board MMA690x Breakout Board + Accelerometer + Magnetometer (6-DOF): FXOS8700 Breakout Board + Gyroscope: FXAS2100x Breakout Board The above .ZIP files, contains the following design information: - Schematic Source File (.SCH) - Schematic (.PDF) - Layout Source File (.BRD) - Layout Images (.jpg) - Gerber Files (GTL, GBL, GTS, GBS, GTO, GBO, GKO, XLN). - PCB Render Image (.png created in OSH park) - BOM (.xls) Additional content: If you want to modify our designs, please download the attached library file "Freescale_Sensors_v2.lbr" and add it to your Eagle Library repository. We'll be more than glad to respond to your questions and please, let us know what you think. -Freescale Sensor's Support team.
記事全体を表示
The Freescale Freedom KL26Z hardware (FRDM-KL26Z) is a capable and cost-effective design featuring a Kinetis L series microcontroller, the industry’s first microcontroller built on the ARM® Cortex™-M0+ core. It features a KL26Z128VLH4 (KL26Z), a device boasting a maximum operating frequency of 48MHz, 128KB of flash. The FRDM-KL26Z features the Freescale open standard embedded serial and debug adapter known as OpenSDA. You can find more information at following link: FRDM-KL26Z: Freescale Freedom Development Platform for Kinetis KL16 and KL26 MCUs (up to 128 KB Flash) The second required board for this example is the Freescale's Freedom Development Platform for Multiple Xtrinsic Sensors, the FRDM-FXS-MULTI. It is a sensor expansion board that contains 7 sensors among which is the FXAS21000 Xtrinsic 3-axis gyroscopic sensors. This example is using above mentioned tools to create data acquisition system (DAQ) for acquiring angular rate data measured in deg/s from the FXAS21000 Xtrinsic 3-axis gyroscopic sensors (Gyro). For data logging and visualization of acquired data FreeMASTER tool is used. The output is in 3 directions of rotation. Around X direction is for the Roll (around longitudinal axis), around Y direction is for the Pitch (around the lateral axis) and around Z direction for the Yaw (around the vertical axis). The Gyro embedded registers are accessed through an I 2 C serial interface and routed to KL26Z I 2 C 1 module with following pin association. Precisely the 7-bit I 2 C slave address is 0x20 (SA0=0) and SCL1, SDA1 lines are routed to port C of the I 2 C 1 module at KL26Z board pins PTC1 and PTC2: Proper interrupt INT1_GYRO at J1-6 needs to be routed via jumper on J6 to INT_GYRO as shown in following block diagram since the interrupts are shared with other sensors: This is then handled as GPIO port A: PTA at the KL26Z board and configured for the falling edge interrupts. For more details see the schematics of the FRDM-FXS-MULTI block diagram. This example illustrates:    1.  Initialization of the KL26Z MCU (I 2 C and PORT modules).    2. Initialization of the Gyro to achieve the resolution 0.025 dsp/LSB with +/-200 dps range and a high-pass filter on.    3. Output data reading using an interrupt technique.    4. Conversion of the output values from registers 0x01 – 0x06 to real values in deg/s.    5. Visualization of the output values in the FreeMASTER tool. 1. According to the schematic, the INT1_GYRO output of the FXAS21000 is connected to the PTA5 pin of the KL26Z MCU and both SCL and SDA lines are connected to the I2C1 module (PTC1 and PTC2 pins). The MCU is, therefore, configured as follows:      void MCU_Init(void){              //I2C1 module initialisation         SIM_SCGC4 |= SIM_SCGC4_I2C1_MASK;       // Turn on clock to I2C1 module         SIM_SCGC5 |= SIM_SCGC5_PORTC_MASK;      // Turn on clock to Port C module         PORTC_PCR1 = PORT_PCR_MUX(2);           // PTC1 pin is I2C1 SCL1 line pin alternative         PORTC_PCR2 = PORT_PCR_MUX(2);           // PTC2 pin is I2C1 SDA1 line pin alternative         I2C1_F = 0x14; // SDA hold time = 2.125us, SCL start hold time = 4.25us, SCL stop hold time = 5.125us         I2C1_C1 = I2C_C1_IICEN_MASK;                    // Enable I2C1 module              //Configure the PTA5 pin (connected to the INT_GYRO of the FXAS21000) 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. At the beginning of the initialization, all Gyro registers are reset to their default values by setting the RST bit of the CTRL_REG1 register. Also the ZR_cond in CTRL_REG1 to trigger the offset compensation is enabled and hold till ZR_cond offset compensation is accomplished. This is meant to be used only when the IC is in zero rate condition on all axes. Writing a '1' to this bit initiates the internal zero-rate offset calibration. The ZR_cond bit self-clears after the zero-rate offset calculation, and it can only be used once after a hard or soft reset has occurred. The measuring range of Gyro is set to ±200 dps and to achieve the highest resolution the ODR = 1.5625Hz (640ms) and the High-pass filter is enabled with H-P filter cutoff frq.:0.047 Hz.      void Gyro_Init (void){              unsigned char reg_val = 0;          I2C_WriteRegister(FXAS21_I2C_ADDRESS, CTRL_REG1, 0x40); // Reset all registers to POR values              do              // Wait for the RST bit to clear              {                 reg_val = I2C_ReadRegister(FXAS21_I2C_ADDRESS, CTRL_REG1) & 0x40;              } while (reg_val);         // Zero values initialisation ------------------------------------------------------------             //      I2C_WriteRegister(FXAS21_I2C_ADDRESS, CTRL_REG1, 0x80); // ZR_cond to trigger offset compensation             do      // wait till ZR_cond to trigger offset compensation accomplished          {           reg_val = I2C_ReadRegister(FXAS21_I2C_ADDRESS, CTRL_REG1) & 0x80;               } while (reg_val);             //----------------------------------------------------------------------------------------         I2C_WriteRegister(FXAS21_I2C_ADDRESS, CTRL_REG2, 0x0C); // Enable DRDY interrupt, DRDY interrupt routed to INT1 - PTA5, Push-pull, active low interrupt         I2C_WriteRegister(FXAS21_I2C_ADDRESS, CTRL_REG0, 0x17); // High-pass filter enabled, H-P filter cutoff frq.:0.047 Hz, +/-200 dps range -> 0.025 dsp/LSB = 40 LSB/dps         I2C_WriteRegister(FXAS21_I2C_ADDRESS, CTRL_REG1, 0x1E); // ODR = 1.5625Hz(640ms), Active mode      }      Below are the snap shots of write and read section of the registers from the instructions above.           3. 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;       }      4. The output values from Gyro registers 0x01 – 0x06 are first converted to signed 14-bit values and afterwards to real values in deg/s.      while(1){              if (DataReady){                 // Is a new set of data ready?                               DataReady = 0;                                                                                                I2C_ReadMultiRegisters(FXAS21_I2C_ADDRESS, OUT_X_MSB_REG, 6, GyrData);  // Read data output registers 0x01-0x06              Xout_14_bit = ((short) (GyrData[0]<<8 | GyrData[1])) >> 2;// Compute 14-bit X-axis output value      Yout_14_bit = ((short) (GyrData[2]<<8 | GyrData[3])) >> 2;// Compute 14-bit Y-axis output value              Zout_14_bit = ((short) (GyrData[4]<<8 | GyrData[5])) >> 2;// Compute 14-bit Z-axis output value                                        Roll = ((float) (Xout_14_bit)) / SENGYR_025D;   // Compute X-axis output value in dps              Pitch = ((float) (Yout_14_bit)) / SENGYR_025D;  // Compute Y-axis output value in dps              Yaw = ((float) (Zout_14_bit)) / SENGYR_025D;    // Compute Z-axis output value in dps                                    Temperature on the Gyro is also read out from the TEMP register of the Gyro              Temp = (signed char) I2C_ReadRegister(FXAS21_I2C_ADDRESS, TEMP_REG);  // temperature on Gyro      5. The calculated values can be watched in the "(x)= Variables" window on the top right of the Debug perspective of the CodeWarrior IDE or in the FreeMASTER application.      To open and run the FreeMASTER project, install the FreeMASTER 1.4 application and FreeMASTER Communication Driver that can be downloaded from following link:      FREEMASTER: FreeMASTER Run-Time Debugging Tool      User Guide for FreeMASTER is available within the installation.      For board communication in FreeMASTER following Options of Plug-in Module needs to be selected and configured for the BDM P&E Kinetis cable settings:             FreeMASTER in action screenshot: Enjoy the Freescale Gyro.
記事全体を表示
Hi Folks, If you are planning to design an application where a pressure sensor is needed but you are not sure about which kind of Pressure Measurement and Level of Integration is needed, or you even doesn’t know what does that means (like me before start working with pressure sensors), then this document can be useful. First, for a better understanding about what I’m talking about in this document and how pressure sensors and measurement works I’m adding below an image that shows a cross-section of a standard pressure sensor which basically shows the Physical Internal structure of a pressure sensor: What I’m trying to show in this image is the position of the Ports P1 and P2, you will see the importance of these ports and its position for the pressure measurement. Also in this image you can see that the die and the wire bonds are protected with a Silicone Gel, this gel can get damaged leaving the die and the wire bonds exposed to the media if it’s used with different media than dry clean air. Pressure Measurements can be divided into three different categories: Absolute pressure, Gage (Gauge) pressure and Differential pressure. Let’s learn something about these categories: + Absolute pressure refers to the absolute value of the force per-unit-area exerted on a surface. Therefore the absolute pressure is the difference between the pressure at a given point and the absolute zero of pressure or a perfect vacuum. In other words: Pressure is applied on Port P1 of the sensor while the Port P2 of the sensor is a vacuum sealed reference. + Gage (Gauge) pressure is the measurement of the difference between the absolute pressure and the Local atmospheric pressure. In other words: Port P2 of the sensor is exposed to the local atmosphere while Port P1 is where pressure is applied. *Local atmospheric pressure can vary depending on ambient temperature, altitude and local weather conditions. A gage pressure by convention is always positive. A 'negative' gage pressure is defined as vacuum. Vacuum is the measurement of the amount by which the local atmospheric pressure exceeds the absolute pressure. A perfect vacuum is zero absolute pressure. + Differential pressure is simply the measurement of one unknown pressure with reference to another unknown pressure. The pressure measured is the difference between the two unknown pressures. In other words: The difference in pressure between two points is measured where pressure is applied to both sides (Port P1 and Port P2) of sensor. Since a differential pressure is a measure of one pressure referenced to another, it is not necessary to specify a pressure reference. Figure below shows the relationship between Absolute, Gage pressure and Vacuum. Freescale Pressure Sensors can also be divided into three different categories according to the Level of Integration: Uncompensated, Temperature Compensated and Integrated, now let’s learn the difference between these categories: + Uncompensated Pressure Sensors are the most basic pressure sensors according to the level of integration; this type of sensor gives a differential output in the range of millivolts, this output will need to be temperature compensated and amplified with external circuitry before sending it to the MCU’s ADC.   + Compensated Pressure Sensors is the following step according to the level of integration; although this type of sensor also gives you a differential output in the range of millivolts, the given output it’s already internally temperature compensated, so externally you only need to add the amplification circuit before sending the sensor’s signal to the MCU’s ADC. + Integrated Pressure Sensor (IPS) gives you the complete solution embedded into the same package, the output signal of the integrated pressure sensors it’s already internally temperature compensated and amplified (the output range can be from 0 to ~3V or from 0 to ~5V depending on the part number), so you do not have to worry about adding external circuitry (just probably some decoupling capacitors), the sensor signal can be sent directly to the MCU’s ADC. Additional to the mentioned types of Pressure Sensors, we also have some Digital Output Pressure Sensors which can be communicated with the MCU via SPI (MPL115A1 Digital Pressure Sensor) or I2C (MPL115A2 and MPL3115A2 Digital Pressure Sensor). Now that you know about Pressure Measurement and Level of Integration, you can jump into my Community Guideline to select the best Freescale Pressure Sensor Part Number for your application. If there are any questions regarding this document, please feel free to ask below. Your feedback or suggestions are also welcome. Regards, Jose
記事全体を表示
Hi Everyone, In this tutorial I intend to run through my simple bare metal example code I created for the Freescale FRDM-KL25Z platform and the FRDM-STBC-AGM01 board containing a three axis accelerometer + magnetometer (FXOS8700CQ) and a three axis gyroscope (FXAS21002C). I will not cover the Sensor Fusion library and the ISF which also support this board. The FreeMASTER tool is used to visualize all the data that are read from both sensors using an interrupt technique through the I 2 C interface. This example illustrates: 1. Initialization of the MKL25Z128 MCU (mainly I 2 C and PORT modules). 2. I 2 C data write and read operations. 3. Initialization of the FXOS8700CQ and FXAS21002C. 4. Simple accelerometer offset calibration based on the AN4069. 5. Output data reading using an interrupt technique. 6. Conversion of the output raw values to real values in g’s, µT, dps and °C. 7. Visualization of the calculated values in the FreeMASTER tool. 1. As you can see in the FRDM-STBC-AGM01 schematic, both sensors are controlled via I 2 C by default. With jumpers J6 and J7 in their default position (2-3), the I 2 C signals are routed to the I2C1 module (PTC1 and PTC2 pins) of the KL25Z MCU. The INT1_8700 output is connected to the PTD4 pin and the INT1_21002 pin to the PTA5 pin of the KL25Z MCU. These both interrupt pins are configured as push-pull active-low outputs, so the corresponding PTD4/PTA5 pin configuration is GPIO with an interrupt on falling edge. The MCU is, therefore, configured as follows. void MCU_Init(void) {      //I2C1 module initialization      SIM_SCGC4 |= SIM_SCGC4_I2C1_MASK;        // Turn on clock to I2C1 module      SIM_SCGC5 |= SIM_SCGC5_PORTC_MASK;       // Turn on clock to Port C module      PORTC_PCR1 |= PORT_PCR_MUX(0x2);         // PTC1 pin is I2C1 SCL line      PORTC_PCR2 |= PORT_PCR_MUX(0x2);         // PTC2 pin is I2C1 SDA line      I2C1_F  |= I2C_F_ICR(0x14);              // SDA hold time = 2.125us, SCL start hold time = 4.25us, SCL stop hold time = 5.125us      I2C1_C1 |= I2C_C1_IICEN_MASK;            // Enable I2C1 module                       //Configure the PTD4 pin (connected to the INT1 of the FXOS8700CQ) for falling edge interrupts      SIM_SCGC5 |= SIM_SCGC5_PORTD_MASK;       // Turn on clock to Port D module      PORTD_PCR4 |= (0|PORT_PCR_ISF_MASK|      // Clear the interrupt flag                       PORT_PCR_MUX(0x1)|      // PTD4 is configured as GPIO                       PORT_PCR_IRQC(0xA));    // PTD4 is configured for falling edge interrupts                   //Configure the PTA5 pin (connected to the INT1 of the FXAS21002) 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 PORTD interrupt on NVIC      NVIC_ICPR |= 1 << ((INT_PORTD - 16)%32);      NVIC_ISER |= 1 << ((INT_PORTD - 16)%32);                //Enable PORTA interrupt on NVIC      NVIC_ICPR |= 1 << ((INT_PORTA - 16)%32);      NVIC_ISER |= 1 << ((INT_PORTA - 16)%32); } 2. The 7-bit I 2 C slave address of the FXOS8700CQ is 0x1E since both SA0 and SA1 pins are shorted to GND. The address of the FXAS21002C is 0x20 since SA0 pin is also shorted to GND. The two screenshots below show the write operation which writes the value 0x25 to the CTRL_REG1 (0x2A) of the FXOS8700CQ and 0x16 to the CTRL_REG1 (0x13) of the FXAS21002C. Here is the single byte read from the WHO_AM_I register. As you can see, it returns the correct value 0xC7 for the FXOS8700CQ and 0xD7 for the FXAS21002C. Finally, a burst read of 12 bytes from the FXOS8700CQ output data registers (0x01 – 0x06 and 0x33 – 0x38) and 6 bytes from the FXAS21002C output data registers (0x01 – 0x06) is shown below. 3. At the beginning of the initialization, all registers are reset to their default values by setting the RST bit of the CTRL_REG2 register. Then the FXOS8700CQ is initialized as shown below. void FXOS8700CQ_Init (void) {      I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG2, 0x40);          // Reset all registers to POR values      Pause(0x631);          // ~1ms delay            I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, XYZ_DATA_CFG_REG, 0x00);   // +/-2g range with 0.244mg/LSB              I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, M_CTRL_REG1, 0x1F);        // Hybrid mode (accelerometer + magnetometer), max OSR      I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, M_CTRL_REG2, 0x20);        // M_OUT_X_MSB register 0x33 follows the OUT_Z_LSB register 0x06 (burst read)                       I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG2, 0x02);          // High Resolution mode      I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG3, 0x00);          // Push-pull, active low interrupt      I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG4, 0x01);          // Enable DRDY interrupt      I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG5, 0x01);          // DRDY interrupt routed to INT1 - PTD4      I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG1, 0x25);          // ODR = 25Hz, Reduced noise, Active mode   } And here is the initialization of the FXAS21002C. void FXAS21002C_Init (void) {      I2C_WriteRegister(FXAS21002C_I2C_ADDRESS, GYRO_CTRL_REG1, 0x40);     // Reset all registers to POR values      Pause(0x631);        // ~1ms delay            I2C_WriteRegister(FXAS21002C_I2C_ADDRESS, GYRO_CTRL_REG0, 0x03);     // High-pass filter disabled, +/-250 dps range -> 7.8125 mdps/LSB = 128 LSB/dps      I2C_WriteRegister(FXAS21002C_I2C_ADDRESS, GYRO_CTRL_REG2, 0x0C);     // Enable DRDY interrupt, routed to INT1 - PTA5, push-pull, active low interrupt      I2C_WriteRegister(FXAS21002C_I2C_ADDRESS, GYRO_CTRL_REG1, 0x16);     // ODR = 25Hz, Active mode        } 4. A simple accelerometer offset calibration method is implemented according to the AN4069. void FXOS8700CQ_Accel_Calibration (void) {      char X_Accel_offset, Y_Accel_offset, Z_Accel_offset;            FXOS8700CQ_DataReady = 0;           while (!FXOS8700CQ_DataReady){}           // Is a first set of data ready?      FXOS8700CQ_DataReady = 0;            I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG1, 0x00);          // Standby mode                 I2C_ReadMultiRegisters(FXOS8700CQ_I2C_ADDRESS, OUT_X_MSB_REG, 6, AccelMagData);          // Read data output registers 0x01-0x06                     Xout_Accel_14_bit = ((short) (AccelMagData[0]<<8 | AccelMagData[1])) >> 2;          // Compute 14-bit X-axis acceleration output value      Yout_Accel_14_bit = ((short) (AccelMagData[2]<<8 | AccelMagData[3])) >> 2;          // Compute 14-bit Y-axis acceleration output value      Zout_Accel_14_bit = ((short) (AccelMagData[4]<<8 | AccelMagData[5])) >> 2;          // Compute 14-bit Z-axis acceleration output value                   X_Accel_offset = Xout_Accel_14_bit / 8 * (-1);          // Compute X-axis offset correction value      Y_Accel_offset = Yout_Accel_14_bit / 8 * (-1);          // Compute Y-axis offset correction value      Z_Accel_offset = (Zout_Accel_14_bit - SENSITIVITY_2G) / 8 * (-1);          // Compute Z-axis offset correction value                   I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, OFF_X_REG, X_Accel_offset);                  I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, OFF_Y_REG, Y_Accel_offset);           I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, OFF_Z_REG, Z_Accel_offset);                        I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG1, 0x25);          // Active mode again } 5. In the ISRs, only the interrupt flags are cleared and the DataReady variables are set to indicate the arrival of new data. void PORTD_IRQHandler() {      PORTD_PCR4 |= PORT_PCR_ISF_MASK;          // Clear the interrupt flag      FXOS8700CQ_DataReady = 1;  } void PORTA_IRQHandler() {      PORTA_PCR5 |= PORT_PCR_ISF_MASK;          // Clear the interrupt flag      FXAS21002C_DataReady = 1;  } 6. The output values from accelerometer registers 0x01 – 0x06 are first converted to signed 14-bit integer values and afterwards to real values in g’s. Similarly, the output values from magnetometer registers 0x33 – 0x38 are first converted to signed 16-bit integer values and afterwards to real values in microtesla (µT). if (FXOS8700CQ_DataReady)          // Is a new set of accel + mag data ready? {                  FXOS8700CQ_DataReady = 0;                                                                                                                          I2C_ReadMultiRegisters(FXOS8700CQ_I2C_ADDRESS, OUT_X_MSB_REG, 12, AccelMagData);         // Read FXOS8700CQ data output registers 0x01-0x06 and 0x33 - 0x38                     // 14-bit accelerometer data      Xout_Accel_14_bit = ((short) (AccelMagData[0]<<8 | AccelMagData[1])) >> 2;        // Compute 14-bit X-axis acceleration output value      Yout_Accel_14_bit = ((short) (AccelMagData[2]<<8 | AccelMagData[3])) >> 2;        // Compute 14-bit Y-axis acceleration output value      Zout_Accel_14_bit = ((short) (AccelMagData[4]<<8 | AccelMagData[5])) >> 2;        // Compute 14-bit Z-axis acceleration output value                              // Accelerometer data converted to g's      Xout_g = ((float) Xout_Accel_14_bit) / SENSITIVITY_2G;        // Compute X-axis output value in g's      Yout_g = ((float) Yout_Accel_14_bit) / SENSITIVITY_2G;        // Compute Y-axis output value in g's      Zout_g = ((float) Zout_Accel_14_bit) / SENSITIVITY_2G;        // Compute Z-axis output value in g's                               // 16-bit magnetometer data                   Xout_Mag_16_bit = (short) (AccelMagData[6]<<8 | AccelMagData[7]);          // Compute 16-bit X-axis magnetic output value      Yout_Mag_16_bit = (short) (AccelMagData[8]<<8 | AccelMagData[9]);          // Compute 16-bit Y-axis magnetic output value      Zout_Mag_16_bit = (short) (AccelMagData[10]<<8 | AccelMagData[11]);        // Compute 16-bit Z-axis magnetic output value                                                         // Magnetometer data converted to microteslas      Xout_uT = (float) (Xout_Mag_16_bit) / SENSITIVITY_MAG;        // Compute X-axis output magnetic value in uT      Yout_uT = (float) (Yout_Mag_16_bit) / SENSITIVITY_MAG;        // Compute Y-axis output magnetic value in uT      Zout_uT = (float) (Zout_Mag_16_bit) / SENSITIVITY_MAG;        // Compute Z-axis output magnetic value in uT              } Similarly, the output values from gyroscope registers 0x01 – 0x06 are first converted to signed 16-bit integer values and afterwards to real values in degrees per second. Temperature is also read out from the 0x12 register. if (FXAS21002C_DataReady)         // Is a new set of gyro data ready? {                  FXAS21002C_DataReady = 0;                                                                                                                                       I2C_ReadMultiRegisters(FXAS21002C_I2C_ADDRESS, GYRO_OUT_X_MSB_REG, 6, GyroData);         // Read FXAS21002C data output registers 0x01-0x06                                   // 16-bit gyro data      Xout_Gyro_16_bit = (short) (GyroData[0]<<8 | GyroData[1]);           // Compute 16-bit X-axis output value      Yout_Gyro_16_bit = (short) (GyroData[2]<<8 | GyroData[3]);           // Compute 16-bit Y-axis output value      Zout_Gyro_16_bit = (short) (GyroData[4]<<8 | GyroData[5]);           // Compute 16-bit Z-axis output value                                           // Gyro data converted to dps      Roll = (float) (Xout_Gyro_16_bit) / SENSITIVITY_250;          // Compute X-axis output value in dps      Pitch = (float) (Yout_Gyro_16_bit) / SENSITIVITY_250;         // Compute Y-axis output value in dps      Yaw = (float) (Zout_Gyro_16_bit) / SENSITIVITY_250;           // Compute Z-axis output value in dps                               // Temperature data      Temp = I2C_ReadRegister(FXAS21002C_I2C_ADDRESS, GYRO_TEMP_REG);                   }   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 application​ and FreeMASTER Communication Driver. I guess this is enough to let you start experimenting with the FRDM-STBC-AGM01 board. Attached you can find the complete source code written in the CW for MCU's v10.6 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. Regards, Tomas
記事全体を表示
         The FXTH87XXX is a sensor for use in applications that monitor tire pressure and temperature. It contains the pressure and temperature sensors, an X-axis and a Z-axis accelerometer, a microcontroller, an LF receiver and an RF transmitter all within a single package.          NCK2912 is a fully integrated single-chip receiver for use in an automotive environment. The device incorporated several commonly used building blocks including a crystal stabilized oscillator, a fractional-N based Phase Locked Loop(PLL) for a accurate frequency selection, Low Noise Amplifier(LNA), attenuator for Automatic Gain Control(AGC), I/Q down-mixer and two high resolution Analog to Digital Converters(ADC). By transforming signals in the digital domain in an early phase, one highly configurable RX channel is available including channel filter, ASK/FSK demodulator, clock-data recovery, bit processor and a micro-controller memory interface(DMA) allowing the micro-controller to complete the data handling and handshaking. NCK2912 has an embedded RISC micro-controller optimized for high performance and low power as well as an EROM for customer application.         
記事全体を表示
     The MC12311 is a highly-integrated, cost-effective, system-in-package (SIP), sub-1GHz wireless node solution with an FSK, GFSK, MSK, or OOK modulation-capable transceiver and low-power HCS08 8-bit microcontroller. The highly integrated RF transceiver operates over a wide frequency range including 315 MHz, 433 MHz, 470 MHz, 868 MHz, 915 MHz, 928 MHz, and 955 MHz in the license-free Industrial, Scientific and Medical (ISM) frequency bands.      The MPXY8600 is a sensor for use in applications that monitor tire pressure and temperature. It contains the pressure and temperature sensors, an X-axis and a Z-axis accelerometer, a microcontroller, an LF receiver and an RF transmitter all within a single package.      This document offer customers to utilize Freescale MPXY8600 as transmitter and MC12311 as receiver to form 315MHz, 433.92MHz TPMS transmitter and receiver solution.
記事全体を表示
Hi Everyone,   I would like to present another example code/demo that reads acceleration data from the Xtrinsic MMA8491Q digital accelerometer and visualizes them using the FreeMASTER tool via USBDM interface. I have used recently released Xtrinsic MEMS sensors board that features three types of Xtrinsic sensors including the MMA8491Q and is fully compatible with the Freescale FRDM-KL25Z platform.   In comparison with other Xtrinsic accelerometers, the MMA8491Q is turned on at the rising edge on the EN pin and acquires only one sample for each of the three axes. It does not have any interrupt pins, instead there are three push-pull logic outputs which provide tilt detection at 45 degrees as the original target application was tamper detection. However, it is possible to read the 14-bit output values through the I2C port as demonstrated in my example below.   According to the User Manual, both SCL and SDA lines are connected through the 4.7K pull-up resistors to the I2C1 module (PTE1 and PTE0 pins) on the KL25Z128 MCU and the EN pin is connected to the PTA13 pin. The EN input needs to be kept high until a new data is ready (max. 900us) and read. In my code I use the PIT module to wait 1ms before reading the output values. This timer is also used to read the output data periodically at a fixed rate. The timeout period of the PIT is set to 500us. The MCU is, therefore, configured as follows:   void MCU_Init(void) {             //I2C1 module initialization             SIM_SCGC4 |= SIM_SCGC4_I2C1_MASK;        // Turn on clock to I2C1 module         SIM_SCGC5 |= SIM_SCGC5_PORTE_MASK;       // Turn on clock to Port E module        PORTE_PCR1 = PORT_PCR_MUX(6);            // PTE1 pin is I2C1 SCL line        PORTE_PCR0 = PORT_PCR_MUX(6);            // PTE0 pin is I2C1 SDA line        I2C1_F  = 0x14;                          // SDA hold time = 2.125us, SCL start hold time = 4.25us, SCL stop hold time = 5.125us         I2C1_C1 = I2C_C1_IICEN_MASK;             // Enable I2C1 module                //Configure the PTA13 pin as an output to drive the EN input of the MMA8491Q        SIM_SCGC5 |= SIM_SCGC5_PORTA_MASK;       // Turn on clock to Port A module        PORTA_PCR13 = PORT_PCR_MUX(1);           // PTA13 is configured as GPIO        GPIOA_PCOR |= 1<<13;                     // Set PTA13 pin low        GPIOA_PDDR |= 1<<13;                     // PTA13 pin is an output                //PIT initialization        SIM_SCGC6 |= SIM_SCGC6_PIT_MASK;         // Turn on clock to to the PIT module        PIT_LDVAL0 = 5240;                       // Timeout period = 500us        PIT_MCR = PIT_MCR_FRZ_MASK;              // Enable clock for PIT, freeze PIT in debug mode        PIT_TCTRL0 = PIT_TCTRL_TIE_MASK |        // Enable PIT interrupt                    PIT_TCTRL_TEN_MASK;          // and PIT                //Enable PIT interrupt on NVIC           NVIC_ICPR |= 1 << ((INT_PIT - 16) % 32);        NVIC_ISER |= 1 << ((INT_PIT - 16) % 32); }   In the PIT interrupt service routine (ISR), there is a variable Counter that is increased by one on every PIT interrupt (500us) and its value is then compared with two preset values. The first preset value EN_HIGH_TIME determines how long the EN pin will remain high to ensure a valid reading of a new set of output data. The second preset value DATA_UPDATE_PERIOD corresponds to the desired output data rate. At the end of the ISR, the PIT interrupt flag is cleared.   void PIT_IRQHandler() {        static int Counter = 0;        Counter++;                                   // Each increment represents 500us        switch (Counter)     {             case 1:             GPIOA_PSOR |= 1<<13;                 // Set EN pin high                      break;             caseEN_HIGH_TIME:                        // 1ms passed             DataReady = 1;                       // Data is ready                      break;             caseDATA_UPDATE_PERIOD:                  // 100ms passed             Counter = 0;                         // Clear Counter at the end of the sample period                      break;             default:                      break;     }        PIT_TFLG0 |= PIT_TFLG_TIF_MASK;              // Clear PIT interrupt flag }   In the main loop, the DataReady variable is periodically checked and if it is set, the accelerometer data registers 0x01 - 0x06 are read and then the acceleration in units of g is calculated. Finally the EN pin is set low to reduce the current consumption and the DataReady variable is cleared.   if (DataReady)                                                                  // Is a new set of data ready? {                  AccData[0] = I2C_ReadRegister(MMA8491Q_I2C_ADDRESS, OUT_X_MSB_REG);         // [7:0] are 8 MSBs of the 14-bit X-axis sample      AccData[1] = I2C_ReadRegister(MMA8491Q_I2C_ADDRESS, OUT_X_LSB_REG);         // [7:2] are the 6 LSB of 14-bit X-axis sample      AccData[2] = I2C_ReadRegister(MMA8491Q_I2C_ADDRESS, OUT_Y_MSB_REG);         // [7:0] are 8 MSBs of the 14-bit Y-axis sample      AccData[3] = I2C_ReadRegister(MMA8491Q_I2C_ADDRESS, OUT_Y_LSB_REG);         // [7:2] are the 6 LSB of 14-bit Y-axis sample      AccData[4] = I2C_ReadRegister(MMA8491Q_I2C_ADDRESS, OUT_Z_MSB_REG);         // [7:0] are 8 MSBs of the 14-bit Z-axis sample      AccData[5] = I2C_ReadRegister(MMA8491Q_I2C_ADDRESS, OUT_Z_LSB_REG);         // [7:2] are the 6 LSB of 14-bit Z-axis sample        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;          // Compute X-axis output value in g's      Yout_g = ((float) Yout_14_bit) / SENSITIVITY;          // Compute Y-axis output value in g's      Zout_g = ((float) Zout_14_bit) / SENSITIVITY;          // Compute Z-axis output value in g's                                              GPIOA_PCOR |= 1<<13;       // Set EN pin low      DataReady = 0;                                                                                                                                 }                       The calculated values can be watched in the "Variables" window on the top right of the Debug perspective or in the FreeMASTER application.       Attached you can find the complete source code written in the CW 10.3 as well as 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.   Regards, Tomas  
記事全体を表示
Hi Everyone,   In this document I would like to present a very simple bare-metal example code I created for the LM75A. This I 2 C digital temperature sensor offers an improved resolution of 0.125°C with an accuracy of ±2°C from –25°C to 100°C and ±3°C over –55°C to 125°C. It operates with a single supply from 2.8V to 5.5V and has three address pins, allowing up to eight LM75A devices to operate on a single I 2 C bus without address collisions. The device also includes an open-drain output (OS) which becomes active when the temperature exceeds the programmed limits.   NXP offers the OM13257 temperature sensor daughter card for easy evaluation of most NXP’s temperature sensors including the LM75ADP in a small 8-pin TSSOP8 package. The daughter card is shipped with no temperature sensors soldered to the board, so the LM75ADP needs to be purchased and soldered separately. The daughter board is designed to connect directly to the OM13320 Fm+ Development kit, but I have decided to pair it with one of the most popular Freedom development boards – FRDM-KL25Z.   The wiring is very straightforward as shown on the picture below. Both SCL (JP4-2) and SDA (JP3-2) lines are connected through the on-board 10K pull-up resistors to the I2C1 module (PTE1 and PTE0 pins) on the KL25Z128 MCU. The Vcc pin (JP2-2) is connected to the 3.3V supply voltage and the GND pin to common ground. The address select pins A2, A1 and A0 are connected to GND using jumpers between pins 1 and 2 of JP12, JP11 and JP10, resulting in a 7-bit I 2 C slave address of 0x48.       The LM75A does not have a data ready interrupt, so the PIT (Periodic Interrupt Timer) module is used to read the Temp register periodically at a fixed rate of about 10Hz since the temp-to-digital conversion is executed every 100 ms. The MCU is configured as follows.   /************* MCU initialization function ******/   void MCU_Init(void) {   //I2C1 module initialization SIM_SCGC4 |= SIM_SCGC4_I2C1_MASK; // Turn on clock to I2C1 module  SIM_SCGC5 |= SIM_SCGC5_PORTE_MASK; // Turn on clock to Port E module  PORTE_PCR1 |= PORT_PCR_MUX(6); // PTE1 pin is I2C1 SCL line PORTE_PCR0 |= PORT_PCR_MUX(6); // PTE0 pin is I2C1 SDA line I2C1_F  |= I2C_F_ICR(0x14); // SDA hold time = 2.125us, SCL start hold time = 4.25us, SCL stop hold time = 5.125us   I2C1_C1 |= I2C_C1_IICEN_MASK; // Enable I2C1 module     //PIT initialization    SIM_SCGC6 |= SIM_SCGC6_PIT_MASK; // Turn on clock to to the PIT module   PIT_LDVAL0 = 1048000; // Timeout period = 100 ms   PIT_MCR = PIT_MCR_FRZ_MASK; // Enable clock for PIT, freeze PIT in debug mode PIT_TCTRL0 = PIT_TCTRL_TIE_MASK | // Enable PIT interrupt   PIT_TCTRL_TEN_MASK; // and PIT     //Enable PIT interrupt on NVIC NVIC_ICPR |= 1 << ((INT_PIT - 16) % 32); NVIC_ISER |= 1 << ((INT_PIT - 16) % 32); }       In the PIT ISR, the Temp register is read and then the real temperature in °C is calculated as shown below. For more information on how to convert the raw values from the Temp register to real values in °C, please refer to the LM75A data sheet (chapter 7.4.3).   /******** Interrupt handler for PIT ************/   void PIT_IRQHandler() {   PIT_TFLG0 |= PIT_TFLG_TIF_MASK; // Clear the PIT interrupt flag I2C_ReadMultiRegisters(LM75A_I2C_ADDRESS, TEMP_REG, 2, TemperatureData); // Read LM75A Temperature register (MSB + LSB)    Temperature_11_bit = ((short) (TemperatureData[0]<<8 | TemperatureData[1])) >> 5; // Compute 11-bit temperature output value   Temperature = ((float) Temperature_11_bit) * 0.125; // Compute temperature in °C }       The screenshot below shows the two bytes read of the Temp register. It also illustrates how the OS output is activated in interrupt mode by crossing the Tos threshold value stored in the Tos register. The threshold value was set to 26°C, which corresponds to 16-bit value of 0x1A00 read out of the Temp register.       The calculated temperature 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 2.0 application and FreeMASTER Communication Driver. You can try touching your finger to the sensor to see the temperature rise.         Attached you can find the complete source code written in the CW for MCU's v10.6 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 Original Attachment has been moved to: FreeMASTER---FRDM-KL25Z-LM75A-Temperature-reading-using-I2C.rar Original Attachment has been moved to: FRDM-KL25Z-LM75A-Temperature-reading-using-I2C.rar
記事全体を表示
clicktaleID