AnsweredAssumed Answered

8451 interrupts

Question asked by James Millard on Nov 13, 2016
Latest reply on Dec 3, 2016 by James Millard

I am trying to get tap detection working using an MMA8451QR1 and a Kinetis K22.  I have used this combination in a number of other products and haven't had any problems.  This is the first time I'm trying to get tap detection working.

 

I am running the MEMS at 200 Hz, trying to get interrupts for data and tap detection.  I get interrupts for data, and the first one for tap detection, but after that, nothing.

 

Unfortunately, I can't post all my code, so I'll try to show what is going on.

 

I have a number of structs which are unions of bit fields and "Byte" data.  Here is my configuration of the MEMS:

 

 

void mma8451qr1_configure_tap(void)

{

  MMA_CTRL_REG1 ctrl_reg1;

  MMA_CTRL_REG2 ctrl_reg2;

  MMA_CTRL_REG3 ctrl_reg3;

  MMA_CTRL_REG4 ctrl_reg4;

  MMA_CTRL_REG5 ctrl_reg5;

  MMA_XYZDATACFG ctrl_reg_xyz_data_cfg;

  MMA_PULSE_CFG pulse_cfg;

  MMA_PULSE_THSX pulse_thsx;

  MMA_PULSE_THSY pulse_thsy;

  MMA_PULSE_THSZ pulse_thsz;

  MMA_PULSE_TMLT pulse_tmlt;

  MMA_PULSE_LTCY pulse_ltcy;

  MMA_PULSE_WIND pulse_wind;

 

  ctrl_reg2.Bits.RST = true;

  mma8451qr1_set_register(MMA8451QR1_REG_CTRL_REG2, ctrl_reg2.Byte);

  do

  {

    ctrl_reg2.Byte = mma8451qr1_get_register(MMA8451QR1_REG_CTRL_REG2);

  } while (ctrl_reg2.Bits.RST);

 

  /* CTRL_REG1 */

  ctrl_reg1.Byte = mma8451qr1_get_register(MMA8451QR1_REG_CTRL_REG1);

  ctrl_reg1.Bits.DATA_RATE = MMA8451QR1_DATA_RATE_200;

  mma8451qr1_set_register(MMA8451QR1_REG_CTRL_REG1, ctrl_reg1.Byte);

 

  ctrl_reg_xyz_data_cfg.Bits.FS = MMA8451QR1_FSRANGE_2G;

  mma8451qr1_set_register(MMA8451QR1_REG_XYZ_DATA_CFG, ctrl_reg_xyz_data_cfg.Byte);

 

  /* CTRL_REG2 */

  ctrl_reg2.Byte = mma8451qr1_get_register(MMA8451QR1_REG_CTRL_REG2);

  ctrl_reg2.Bits.MODS = MMA8451QR1_OVS_MODE_HRES;

  mma8451qr1_set_register(MMA8451QR1_REG_CTRL_REG2, ctrl_reg2.Byte);

 

  /* CTRL_REG4 */

  ctrl_reg4.Byte = mma8451qr1_get_register(MMA8451QR1_REG_CTRL_REG4);

  ctrl_reg4.Bits.INT_EN_PULSE = true;

  ctrl_reg4.Bits.INT_EN_DRDY  = true;

  mma8451qr1_set_register(MMA8451QR1_REG_CTRL_REG4, ctrl_reg4.Byte);

 

  /* CTRL_REG5 */

  ctrl_reg5.Byte = mma8451qr1_get_register(MMA8451QR1_REG_CTRL_REG5);

  ctrl_reg5.Bits.INT_CFG_PULSE = false;   /* false == INT2 */

  ctrl_reg5.Bits.INT_CFG_DRDY  = false;

  mma8451qr1_set_register(MMA8451QR1_REG_CTRL_REG5, ctrl_reg5.Byte);

 

 

  pulse_cfg.Bits.XSPEFE = 1;

  pulse_cfg.Bits.XDPEFE = 0;

  pulse_cfg.Bits.YSPEFE = 1;

  pulse_cfg.Bits.YDPEFE = 0;

  pulse_cfg.Bits.ZSPEFE = 1;

  pulse_cfg.Bits.ZDPEFE = 0;

  pulse_cfg.Bits.ELE    = 1;

  pulse_cfg.Bits.DPA    = 0;

  mma8451qr1_set_register(MMA8451QR1_REG_PULSE_CFG, pulse_cfg.Byte);

  pulse_thsx.Byte = 0x20;

  mma8451qr1_set_register(MMA8451QR1_REG_PULSE_THSX, pulse_thsx.Byte);

  pulse_thsy.Byte = 0x20;

  mma8451qr1_set_register(MMA8451QR1_REG_PULSE_THSY, pulse_thsy.Byte);

  pulse_thsz.Byte = 0x2A;

  mma8451qr1_set_register(MMA8451QR1_REG_PULSE_THSZ, pulse_thsz.Byte);

  pulse_tmlt.Byte = 0x28;

  mma8451qr1_set_register(MMA8451QR1_REG_PULSE_TMLT, pulse_tmlt.Byte);

  pulse_ltcy.Byte = 0x28;

  mma8451qr1_set_register(MMA8451QR1_REG_PULSE_LTCY, pulse_ltcy.Byte);

  pulse_wind.Byte = 0x0F;

  mma8451qr1_set_register(MMA8451QR1_REG_PULSE_WIND, pulse_wind.Byte);

 

  mma8451qr1_set_active();

}

I have the INT1 and INT2 connected to two pins on the K22 and the interrupts work.   The pins on the K22 are configured as GPIO, with interrupts.  The handler is here:

void PORTD_IRQHandler(void)

{

  if (PORTD_PCR4 & PORT_PCR_ISF_MASK)

  {

    g_main_event_flags.bits.do_mems = true;

    PORTD_PCR4 |= PORT_PCR_ISF_MASK;

  }

 

  if (PORTD_PCR6 & PORT_PCR_ISF_MASK)

  {

    g_main_event_flags.bits.do_mems = true;

    PORTD_PCR6 |= PORT_PCR_ISF_MASK;

  }

}

The g_main_event_flags struct is also a union and declared globally.

In my main processing loop (main.c), I have the following:

 

 

    /*

     * Handle MEMS events

     */

    if (g_main_event_flags.bits.do_mems)

    {

      MMA_INT_SOURCE int_src;

      MMA_PULSE_SRC pulse_src;

 

      int_src.Byte = mma8451qr1_get_int_source();

 

      if (int_src.Bits.SRC_PULSE)

      {

        pulse_src.Byte = mma8451qr1_read_pulse();

        ports_led(true);

      }

 

      if (int_src.Bits.SRC_DRDY)

      {

        mma8451qr1_read_data();

      }

 

      int_src.Byte = mma8451qr1_get_int_source();

 

      g_main_event_flags.bits.do_mems = false;

    }

My understanding from reading the spec is that I should read the SRC_PULSE register to clear the interrupt and read the data from the MEMS to clear the SRC_DRDY interrupt.  All the routines appear to work, I just never get a second interrupt.  It makes me think I'm not clearing something I should.

 

ports_led() sets a GPIO to turn on an LED.  It also sets a clock counter to keep it on for about 200 ms (interrupt driven) so that I can see the taps and then the LED is turned off.

 

I have gotten as many as three taps before it stops working.  I can pause the debugger and it the K22 is not frozen (still executes my main event loop).

 

Thanks for the help.

Outcomes