tdk-invn-oss / motion.arduino.ICM42670P

Arduino Driver for TDK InvenSense consumer motion sensor ICM42670P
https://invensense.tdk.com/smartmotion
BSD 3-Clause "New" or "Revised" License
30 stars 3 forks source link

Fifo not triggering callback #12

Closed kjs-eir closed 3 months ago

kjs-eir commented 4 months ago

Using the example "FIFO_interrupts" does not seems to ever trigger the callback function "event_cb". An interrupt occours and triggers

void irq_handler(void) { irq_received = 1; }

But using breakpoint, i never seem to enter void event_cb(inv_imu_sensor_event_t *evt) { // Format data for Serial Plotter if(IMU.isAccelDataValid(evt)&&IMU.isGyroDataValid(evt)) { Serial.print("AccelX:"); Serial.println(evt->accel[0]); Serial.print("AccelY:"); Serial.println(evt->accel[1]); Serial.print("AccelZ:"); Serial.println(evt->accel[2]); Serial.print("GyroX:"); Serial.println(evt->gyro[0]); Serial.print("GyroY:"); Serial.println(evt->gyro[1]); Serial.print("GyroZ:"); Serial.println(evt->gyro[2]); Serial.print("Temperature:"); Serial.println(evt->temperature); } }

Although i should say i have modified the code, to work with my psoc 6, but I only change how the interrupt is registeres for irq_handler, and how the print statements look.

rbuisson-invn commented 4 months ago

Hello kjs-eir,

Could you please check the interrupt INT1 line with a Logic analyzer? (CN1.3 on the ICM42670P eval board) If the line stay still, that means that the IMU interrupt configuration is not correct. If you observe a pulse on the line (0->1->0) that means that the IMU interrupt is correctly triggered but your MCU configuration does not correctly handle it.

Regards,

kjs-eir commented 4 months ago

Hi @rbuisson-invn

Thanks for the reply. I have a scope on both INT1 and INT2, and INT1 is firing, and correctly triggering irq_handler() according to FIFO_interupt.ino example. But the event callback function "event_cb" is never triggered, when running IMU.getDataFromFifo(event_cb);

From how I understand I, event_cb was suppose to be triggered every time inv_imu_get_data_from_fifo(&icm_driver); is executed in int ICM42670P::getDataFromFifo(ICM42670P_sensor_event_cb event_cb) { if(event_cb == NULL) { return -1; } icm_driver.sensor_event_cb = event_cb; return inv_imu_get_data_from_fifo(&icm_driver); }

Is that correct?

rbuisson-invn commented 4 months ago

Thanks for checking the interrupt lines. Your understanding is correct.

As interrupt line is correct, there must be an error occurring within the inv_imu_get_data_from_fifo function, probably due to the way the FIFO is read. How many samples do you expect to be in the FIFO? The number of bytes to be read might be greater than what your architecture supports. If so, we could split the read access into multiple smaller reads.

kjs-eir commented 4 months ago

Currently i have only been testing with very few samples. So I start the accelererometer and gyroscope at 12.5H, and then configure the fifo interrupts with enableFifoInterrupt() setting the watermark to 255, i have also tried with watermark set to 20, but that didn't change the outcome.

rbuisson-invn commented 4 months ago

1 FIFO sample is 16Bytes. For 255 samples, length is about 4kB, which is definitely bigger than the ICM42670P FIFO space. Are you using I2C or SPI interface? To read 20 samples, the I2C data buffer must be at least 320 bytes. Could you please try with just few samples in the FIFO to check if event_cb is correctly called? Meanwhile I'll provide a new version of the library defining a maximum number of samples in FIFO and splitting big read access into smaller ones.

Regards

kjs-eir commented 4 months ago

Thanks for the quick reply.

I changed my configuration, and tried with watermark = 1, 2 and 5, but that still didn't make event_cb trigger. The irq_handler, which trigger at every interrupt on my scope, and the "getDataFromFifo(event_cb)" function is triggered, event_cb is never executed.

kjs-eir commented 4 months ago

@rbuisson-invn i don't know if this i helpful, but I have been stepping through inv_imu_get_data_from_fifo(), and I am never able to reach: /* call sensor event callback */ if (s->sensor_event_cb) s->sensor_event_cb(&event); Which makes sense since the callback is never triggered, but the these for not reaching this far, is that the function fail to read fifo data in: `if (status |= inv_imu_read_reg(s, FIFO_DATA, packet_size packet_count, s->fifo_data)) { /

Here status is -5, everytime.

On the otherhand, if I in my main loop, run both getDataFromFifo(event_cb); and afterward getDataFromRegisters(inv_imu_sensor_event_t& evt) event_cb is triggered.

rbuisson-invn commented 4 months ago

Hi, thanks for stepping through and providing feedback. This is where I was expecting the issue to occur. -5 is INV_ERROR_SIZE, it happens when a read or a write exceed the maximum size defined at initialization: icm_serif.max_read = 2048; // maximum number of bytes allowed per serial read icm_serif.max_write = 2048; // maximum number of bytes allowed per serial write This corresponds to 128 samples. So you probably specified a higher watermark value. Could you please try debugging with following settings:

rbuisson-invn commented 4 months ago

And to make sure this is not an issue with I2C max data length, could you please replace i2c_read and i2c_write with the following code:

#define ARDUINO_I2C_BUFFER_LENGTH 32
static int i2c_read(inv_imu_serif* serif, uint8_t reg, uint8_t * rbuffer, uint32_t rlen)
{
  ICM42670P* obj = (ICM42670P*)serif->context;
  uint16_t offset = 0;

  obj->i2c->beginTransmission(obj->i2c_address);
  obj->i2c->write(reg);
  obj->i2c->endTransmission(false);
  while(offset < rlen)
  {
    uint16_t rx_bytes = 0;
    if(offset != 0)
      obj->i2c->beginTransmission(obj->i2c_address);
    uint16_t length = ((rlen - offset) > ARDUINO_I2C_BUFFER_LENGTH) ? ARDUINO_I2C_BUFFER_LENGTH : (rlen - offset) ;
    rx_bytes = obj->i2c->requestFrom(obj->i2c_address, length);
    if (rx_bytes == length) {
      for(uint8_t i = 0; i < length; i++) {
        rbuffer[offset+i] = obj->i2c->read();
      }
      offset += length;
      obj->i2c->endTransmission((offset == rlen));
    } else {
      obj->i2c->endTransmission((offset == rlen));
    }
  }
  if(offset == rlen)
  {
    return 0;
  } else {
    return -1;
  }
}

static int i2c_write(inv_imu_serif* serif, uint8_t reg, const uint8_t * wbuffer, uint32_t wlen) {
  ICM42670P* obj = (ICM42670P*)serif->context;
  obj->i2c->beginTransmission(obj->i2c_address);
  obj->i2c->write(reg);
  for(uint8_t i = 0; i < wlen; i++) {
    obj->i2c->write(wbuffer[i]);
  }
  obj->i2c->endTransmission();
  return 0;
}
kjs-eir commented 4 months ago

I am using spi, and have set the max read/write to 2048, ODR = 100, and watermark = 10, but when stepping through I can see the package length is 2336. But i cannot set my read/write to this. Should descreasing the watermark size, lower the package length, as the interrupt is triggered earlier? I have tried reducing the watermark to 5 and 2, but package lenght is the same.

rbuisson-invn commented 4 months ago

Thanks for your reply, it looks like the FIFO is far more filled than expected (almost full). It looks like the call to inv_imu_get_data_from_fifo has been too much delayed, either because of a previous breakpoint or long operations (such as printf) between the Interrupt and the call to inv_imu_get_data_from_fifo. To get 2336 bytes in FIFO, you need the delay of 146 samples so almost 1.5s @100Hz. Any idea that could explain so much delay ?

rbuisson-invn commented 4 months ago

@kjs-eir Do you have any update to share on this issue? Did you manage to get that API working on your side?

Regards,