Asset Tracker Accelerometer + GPS problem


#61

I am also using timer tick interrupt to read from the GPS, which should be more reliable. If you want to do that you will need these:

// Interrupt driven GPS serial I/O
void handleSysTick(void* data) {
  char c = GPS.read();
}

void useInterrupt(boolean v) {
	if (v) {
    static HAL_InterruptCallback callback;
    static HAL_InterruptCallback previous;
    callback.handler = handleSysTick;
    HAL_Set_System_Interrupt_Handler(SysInterrupt_SysTick, &callback, &previous, nullptr);
	}
}

double gpsLat, gpsLon, gpsGeo, gpsAlt;
void initGPS() {
  pinMode(D6, OUTPUT);
  digitalWrite(D6, LOW);
  GPS.begin(9600);
  //# request a HOT RESTART, in case we were in standby mode before.
  GPS.sendCommand("$PMTK101*32");
  delay(250);
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_ALLDATA); // request everything!
  delay(250);
  GPS.sendCommand(PGCMD_NOANTENNA); // turn off antenna updates
  delay(250);
  gpsStartTime = millis();
	gpsLat = gpsLon = gpsGeo = gpsAlt = 0;
}

Add this to setup():

  initGPS();
  useInterrupt(true);

#62

@wbp I am able to read the INT1_SRC register just fine. I’m not sure what would be different for you.

However, I tried configuring the accelerator without latching the interrupt, and the interrupt is now only a pulse but it also auto-clears the INT1_SRC register so there is no way to use this to detect if you woke from motion.

Has anyone figured out a way, if possible, to not latch the interrupt AND not have the INT1_SRC register clear before reading it?


#63

@lancepitka , I can read the register, but when the device wakes up and I read INT1_SRC in Setup(), the value is always 255. The rest of the time (in loop()) it shows what caused the motion. Do you get something besides 255 if you read INT1_SRC in Setup()?

Have you tried my code yet? I may have a surprise for you. I did some testing with interrupt latched and I think I have it working now.


#64

I haven’t tried reading it in setup() yet. Glad to hear its working for you! I will have time to give your code a try tomorrow and let you know how it goes.


#65

I am not sure why the register is being cleared for you, at least if we are talking about in loop(). I check for WKP being on and if it is read INT1_SRC, and I see values that correspond to the motion that triggered WKP.

// if motion / woken by motion, flash LED and update motion timestamp
  bool hasMotion = digitalRead(WKP);
  if (hasMotion) {
    accel.readRegister8(LIS3DH_REG_REFERENCE);  // Reset LIS3DH reference to current position
    digitalWrite(LED, HIGH);
    inMotion = true;  // we are moving!
    publishInterval = MOTION_PUBLISH_INTERVAL;
    lastMotionTime = now;
    accel.read();
    accelMag = sqrt((accel.x*accel.x)+(accel.y*accel.y)+(accel.z*accel.z));
    Serial.printlnf("accel %x,%d,%d,%d,%d", lastINT1SRC, accelMag, accel.x, accel.y, accel.z);
    delay(100);  // make it easier to see LED flash
    digitalWrite(LED, LOW);
  }
  else {
    if ((now-lastMotionTime) > MOTION_DURATION) { // Still moving?
      inMotion = false;  // nope
      publishInterval = STATIC_PUBLISH_INTERVAL;
    }
  }

#66

I tried your code and it works the same as mine. I read the INT1_SRC register in my setup function and it read properly too. I’m not sure why that isn’t working for you.

I think out code works the same, but we have different objectives. I am trying to not latch the interrupt in the accelerometer, but still have a way of knowing if I woke from motion or from the timer. You proposed a solution with using the time from the GPS, but I am trying to find a different method since your method is less precise. I assumed I could do this by reading the IA bit from the INT1_SRC register, but this register seems to clear automatically if the interrupt isn’t latched.

It’s starting to look like I will have to accept the chance that the interrupt might occur when the Electron is going to sleep, and I won’t be able to catch it.


#67

It is very interesting to me that you are getting values in INT1_SRC at setup() and all I get is 255. In my testing I wake the device up with a single tap on the side of the case, that is the only vibration. I take it you are saying that if you do this the value of INT1_SRC as read by setup() is something other than 255?

I am also puzzled as to why you see INT1_SRC being cleared when I do not. Every time I tap or shake it while it is awake, the INT1_SRC register definitely has values from the acceleration, regardless if I set it to latching or not.

I may have something for you. I had stopped using latching before when I was using different code. With my newest version I tried setting it to latching interrupt and so far it has not failed. If you already have the code from the above examples, try this. In loop(), the block of code that tests for motion, add 2 lines to clear the interrupt:

  if (hasMotion) {
    lastINT1SRC = accel.readRegister8(LIS3DH_REG_INT1SRC);  // read INT1_SRC and clear interrupt
    accel.writeRegister8(LIS3DH_REG_INT1CFG, 0x2A);  // Enable all 3 axes, Zh, YH, XH

In the code at the end of loop() add the same 2 lines of code just before the sleep() call:

    lastINT1SRC = accel.readRegister8(LIS3DH_REG_INT1SRC);  // read INT1_SRC and clear interrupt
    accel.writeRegister8(LIS3DH_REG_INT1CFG, 0x2A);  // Enable all 3 axes, Zh, YH, XH
#endif
    System.sleep(SLEEP_MODE_DEEP, SLEEP_DURATION_SECONDS);  // deep sleep for lowest power consumption

in initAccelMotion() change the setting for register CTRL5 to latching:

  accel.writeRegister8(LIS3DH_REG_CTRL5, 0x08);   // latching, means interrupt must be cleared

I have been running with this for a few days now and so far no hangs or problems. With this you can check WKP in setup() and find out if an interrupt woke it up.