Interrupt Arduino Uno rev2 wifi

hello everyone!

i am working with an arduino uno rev2 wifi board and i need to manage the reading of the imu integrated on the board.

What i need to do is the following: i need to read the values of the imu (accelerometer and gyroscope) with an interrupt every 100Hz.
This is the code I have done so far:

#include <Arduino_LSM6DS3.h>
#include <SPI.h>
#include <SD.h>
#include <TinyGPS.h>
#include <Wire.h>
#include <RTClib.h>
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <Arduino.h>

File file_imu, file_gps;
const int chipSelect = 4;

float gyro_x, gyro_y, gyro_z;
float acc_x, acc_y, acc_z;
char accX[7], accY[7], accZ[7]; 
char gyroX[8], gyroY[8], gyroZ[8]; 
int count = 0;
int stato = LOW;
int file_active = 0;


int lunghezza = 0;
long time_cpu_actual = 0,  delta_millis = 0, millis_last_utc = 0;
long time_cpu_arduino = millis();

#define N 11
String timestamp_str;
char utc[N];
char delta_millis_str[4];


// BUFFER PER LA RICEZIONE DATI
//volatile byte buf[32];
char myMsg[11];
volatile bool flag = false;

bool usingInterrupt = false;
//void useInterrupt(boolean); // Func prototype keeps Arduino 0023 happy

int delta_millis_old = 0;
long last_utc_old = 0, tmp = 0;
volatile bool interruptFlag = false;

// Timer 1 interrupt service routine (ISR)
ISR(TIMER0_COMPA_vect){
  Serial.print("INT");
  if (IMU.gyroscopeAvailable()) {
   IMU.readGyroscope(gyro_x, gyro_y, gyro_z);
   time_cpu_actual = millis();
  }
  if (IMU.accelerationAvailable()) {
    IMU.readAcceleration(acc_x, acc_y, acc_z);
    time_cpu_actual = millis();
  }
}

void setup() {

  // TIMER PER ACQUISIRE DATI OGNI 100 HZ
  //cli(); // disable interrupts during setup
  // // Configure Timer 1 interrupt
  // // F_clock = 16e6 Hz, prescaler = 64, Fs = 100 Hz
  // TCCR1A = 0;
  // TCCR1B = 1<<WGM12 | 0<<CS12 | 1<<CS11 | 1<<CS10;
  // TCNT1 = 0;          // reset Timer 1 counter
  // // OCR1A = ((F_clock / prescaler) / Fs) - 1 = 2499
  // OCR1A = 2499;       // Set sampling frequency Fs = 100 Hz
  // TIMSK1 = 1<<OCIE1A; // Enable Timer 1 interrupt
  
  // normal counting
  TCA0_SINGLE_CTRLB = 0;
  // enable overflow interrupt
  TCA0_SINGLE_INTCTRL = TCA_SINGLE_OVF_bm;
  // set TOP value
	TCA0_SINGLE_PER = 15999;
  // start timer at 15625 Hz
	TCA0_SINGLE_CTRLA = TCA_SINGLE_CLKSEL_DIV1024_gc | TCA_SINGLE_ENABLE_bm;

  //sei(); // re-enable interrupts

  // slave
  Wire.begin(8);


  Serial.begin(115200);
  SD.begin(chipSelect);
  pinMode(2, INPUT);


  while (!Serial);

  if (!IMU.begin()) {
    //Serial.println("Failed to initialize IMU!");
    while (1);
  }
  if (!SD.begin(chipSelect)) {
    //Serial.println("Errore inizializzazione scheda SD!");
    while (true); // Puoi anche gestire l'errore in modo diverso, ad esempio con un messaggio di errore e un loop.
  }

  if(SD.exists("IMU.csv")){
    SD.remove("IMU.csv");
    //Serial.println("Rimosso file già esistente!!");
  }
  if(SD.exists("gps.csv")){
    SD.remove("gps.csv");
    //Serial.println("Rimosso file già esistente!!");
  }

}

void receiveEvent(byte howMany) {
  for(byte i=0; i<howMany; i++) {
    myMsg[i] = Wire.read();
  }
  myMsg[howMany] = '\0';
  flag = true;

  millis_last_utc = millis();   
}


void loop(){
  Serial.print("LOOP"); // for debug!
  if(flag == true){
    //Serial.println(myMsg);
    flag = false;
  }
  //Serial.println();
  lunghezza = strlen(myMsg);
  char dato_ricevuto[lunghezza];
  strcpy(dato_ricevuto, myMsg);
  //Serial.println(dato_ricevuto);
  //delay(1000);

// ----------------- LAVORO SULLA STRINGA CHE RICEVO ------------------

  strcpy(utc, dato_ricevuto);

// ------------------------------ GESTIONE IMU -------------------------------
  if(file_active == 0){
    file_imu = SD.open("IMU.csv", FILE_WRITE);
    file_active = 1;
  }
  //IMU.getGyroOffsets();
  if (digitalRead(2) == HIGH){
    stato = !stato;
    //Serial.println(stato);
    count++;
    delay(300);
  }
  if(count == 2){
    Serial.println("CHIUSO DATALOG");
    file_imu.close();
  } else{
    if(count == 1){
      Serial.println("APERTO DATALOG");

      //read_data();
  
      delta_millis = time_cpu_actual - millis_last_utc;
      if(delta_millis > 0){
        last_utc_old = millis_last_utc;
      }
      else{
        tmp = last_utc_old;
        //millis_last_utc = last_utc_old;
        //delta_millis = time_cpu_actual - tmp;
        if(time_cpu_actual - tmp >= 1000){
          Serial.println("AAAAAAAAAAA");
          delta_millis = 999;
        }
      }

      snprintf(delta_millis_str, sizeof(delta_millis_str), "%ld", delta_millis);
      Serial.print("DELTA: ");
      Serial.println(delta_millis_str);
      char timestamp[11];
      int l_delta = strlen(delta_millis_str);
      strcpy(timestamp, utc);
      int startIndex = 6;
      customConcat(timestamp, delta_millis_str, startIndex);
      Serial.println(timestamp);
      int pos = 6;
      
      // scrivo su file...
      file_imu.print(acc_x);
      file_imu.print(";");
      file_imu.print(acc_y);
      file_imu.print(";");
      file_imu.print(acc_z);
      file_imu.print(";");
      file_imu.print(gyro_x);
      file_imu.print(";");
      file_imu.print(gyro_y);
      file_imu.print(";");
      file_imu.print(gyro_z);
      file_imu.print(";");
      file_imu.print(timestamp);
      file_imu.print(";");
      file_imu.print(millis());
      file_imu.print(";");
      file_imu.print(time_cpu_actual);
      file_imu.print(";");
      file_imu.print(millis_last_utc);

      file_imu.println();
    }
  }
  
}

void customConcat(char dest[11], const char src[4], int startIndex) {
    int destLen = strlen(dest);
    int srcLen = strlen(src);


    if (startIndex < 0 || startIndex >= destLen) {
        // Indice non valido
        printf("Indice non valido\n");
        return;
    }
    // Copia i caratteri dalla stringa di origine alla posizione desiderata nella stringa di destinazione
    for (int i = 0; i < srcLen; i++) {
      if(srcLen == 3){
        dest[startIndex + i + 1] = src[i];
      }
      else if(srcLen == 2){
        dest[startIndex + 1] = '0';
        dest[startIndex + 2 + i] = src[i];
      }
      else if(srcLen == 1){
        dest[startIndex + 1] = '0';
        dest[startIndex + 2] = '0';
        dest[startIndex + 3] = src[i];
      }
      //dest[startIndex + i +1] = src[i];
    }
    // Aggiungi il terminatore null per assicurarti che la stringa sia correttamente terminata
    dest[10] = '\0';
}

in the code you can find everything the application has to do, so there are extra things like the whole loop part.
The interrupt part is right at the beginning of the setup.

With this code the application doesn't go... the interrupt doesn't seem to work, it also doesn't seem to enter the loop either.
Can anyone help me or give me some advice?

thank you all very much in advance!

why do you want an interrupt to drive this?

it's likely that IMU.readGyroscope() or IMU.readAcceleration() use SPI and/or I2C (I don't have that board) and if you are within the ISR, interrupts are disabled and so the reading won't work.

i need to collect imu data to perform a path reconstruction using matlab, so i need the data with a certain frequency... not too high, not too low... it is, however, a design specification that i have to meet

OK...
so i, for example, could put a global variable inside the interrupt and when it goes 'high' (true), i have the imu read inside from the loop.
Could this be a solution?

it could but it's not a great idea as you'll sample at the speed of the loop anyway

you are better off bit using interrupts at all and just using millis or micros then

void loop() {
  static unsigned long lastSamplingTime =0;
  if (micros() - lastSamplingTime >= 10000) { // 100Hz = every 10ms = 10000µs
    float gyro_x, gyro_y, gyro_z;
    float acc_x, acc_y, acc_z;
    lastSamplingTime = micros();
    if (IMU.gyroscopeAvailable())    IMU.readGyroscope(gyro_x, gyro_y, gyro_z);
    if (IMU.accelerationAvailable()) IMU.readAcceleration(acc_x, acc_y, acc_z);
    // do something with the data
    •••
  }
}

For extra information on using millis (or micros) and examples look at

OK thank you very much.
i thought the interrupt was the best solution for this application.

I will try to implement it and let you know.

have you timed how long reading the IMU and processing the data takes?
does it fit in the 10ms budget you have before the next sample needs to be acquired?

yes, the code for reading the imu is about 2/3ms

so polling to check if it's time to do something should be good enough

Have you read the library documentation on github?

There appears to be a function to set sample rate(104Hz is default) and an .available( ) function when there is data.

I would try using the library functions for timing and reading the data.

https://github.com/arduino-libraries/Arduino_LSM6DS3/tree/master

I looked at the library but honestly I could not find the command to set the frequency

Yes, you're correct about the library not having a set frequency function.

If you look at data sheet for the imu device itself, you can see all the registers and the setting values, but unfortunately the sample rate is only at fixed values. The default is 104 and the next lower is 52 and higher is 208.

I think you can use the default 104 with .available() and it will be close to your 100Hz.

You can try using the timer interrupt flag or a millis() timer if you really want 100Hz, but the accuracy of the Arduino clock frequency will need to be tested.

I did some testing and thanks to your suggestion I fixed things.
Thank you very much!

yes, I saw that by default the frequency is 104Hz and I think that's already fine.
Anyway, for the moment, I think I've solved it.
I have to hand in my project in the next few days, I hope it's OK.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.