Registro de datos de múltiples sensores en la tarjeta SD al mismo tiempo: la escritura se cuelga

Estoy haciendo un proyecto de registrador de datos con 5 sensores diferentes que incluye un sensor de 3 ejes que funciona a 800 Hz. Mi requisito es registrar los datos en una tarjeta SD. Aquí tengo que registrar el sensor de 3 ejes a 800 Hz y todos los demás sensores a 1 Hz.

Dado que los sensores funcionan a diferentes frecuencias, utilicé interrupciones de ticker para cada sensor excepto el de 3 ejes. Hice 3 ejes para ejecutar el ciclo while. Ahora todo está bien. Debería poder iniciar sesión según mis requisitos. El problema es que después de iniciar sesión durante 10 minutos, a veces 30 minutos, el registro se detiene.

Un aspecto importante aquí: fopen y fclose se hacen afuera usando una interrupción. Eso significa que inicialmente abro la tarjeta SD y escribo los datos durante 2 minutos; más tarde, cierro ese archivo usando tickers y creo un nuevo archivo.

A continuación puede ver mi ejemplo de código.

// tickers used to create a new SD file at regular intervals.

 void onFileUpdate(void) 
    {    
        static int fileNumber = 0;
        if (logFile)
        fclose(logFile);
        char fileName[20];
        sprintf(fileName,"/sd/PCE-DL%03d.txt",fileNumber++);
        logFile = fopen(fileName,"w");
    }

// Ticker object for Light sensor which run at 1HZ by an inturrupt.

void onLight(void)
 {  
  LUX = max44009.getLUXReading();
   fprintf(logFile,"\r\n                                 %f  ",LUX);
 }

 // RTC ticker

 void onRtc(void)
 { 
    seconds = mktime(&t);
    rtc8564.get_time_rtc(&t);   // read RTC data
    strftime(buf, 40, "%I:%M:%S %p (%Y/%m/%d)", localtime(&seconds)); 
    fprintf(logFile,"\r\n %s", buf);
 } 

// my while loop

 while(1) { 
   accelerometer.getOutput(readings);
   fprintf(logFile,"\r\n%i,%i,%i", (int16_t)readings[0], (int16_t)readings[1], (int16_t)readings[2]); 

      }
  }

No sé por qué está colgando. Puede ser problema de tiempo...

Hay millones de MCU diferentes con tantas peculiaridades que pueden hacer que su programa se cuelgue. ¿Puedes aclararnos qué MCU estás usando?
¿Asignó un búfer lo suficientemente grande para manejar retrasos de, digamos, un par de cientos de ms?
Parece que estás escribiendo de forma asíncrona. Es posible que deba serializar todo. Tal vez sincronice la escritura con un mutex. Sería mejor registrar todo en un búfer en la memoria y luego volcarlo en el archivo a intervalos.

Respuestas (3)

Nunca, nunca, nunca ponga E/S de archivo en una rutina de interrupción, a menos que sea la única rutina para hacer E/S de archivo. ¡ Y aún así no lo hagas!

Una interrupción puede interrumpir cualquier cosa: incluida la E/S de archivos. ¡Y las interrupciones deben ser rápidas, rápidas, rápidas ! La E/S de archivos simplemente no lo es.

Debe usar los tickers para almacenar los datos en los búferes de memoria y luego escribir los datos dentro de loop().

Con ARMv6-M o ARMv7M, es bastante razonable tener todo el código funcional en las rutinas de interrupción y solo un wfibucle de hilo vacío ( ). Las interrupciones solo son interrumpidas por una nueva llegada que tiene mayor prioridad. Tiene razón en un sentido, es posible que el bucle de subprocesos no se vea si las interrupciones retroceden y se encadenan.
"es bastante razonable tener todo el código funcional en las rutinas de interrupción" - No estoy de acuerdo. Es posible si diseña para ello, pero no es razonable ni tiene la intención de hacerlo.
@JimmyB No me molestaré en preguntar, pero estoy bastante seguro de que es un modelo de uso previsto. Si observa los estados de suspensión diseñados, son compatibles con este modelo (suspensión al salir).
@SeanHoulihane, John y Jimmi están aquí: puedes hacerlo , pero el diseño general de INT es hacer lo menos posible en ellos; ya que a) interrumpir un INT es muy problemático, b) cada INT tiene que preservar el estado anterior de la CPU, lo que incurre en una penalización de tiempo de ejecución, c) el modelo de subprocesos (especialmente subprocesos de E/S) se vuelve más complicado una vez que introduce grandes datos mutables necesarios para manejadores de interrupciones complejos: es bastante imprudente hacer un trabajo pesado en INT. El idioma común de uC es solo establecer indicadores, contadores o hacer E/S ligeras en INT, por las mismas razones descritas anteriormente.

Su puntero de archivo se puede cambiar (mediante una interrupción) en el medio del archivo fprintf. Todas las demás rutinas de salida se encadenarán en lugar de interrumpirse (suponiendo que tengan la misma prioridad), pero su bucle while debe poder interrumpirse.

Como prueba, mueva la actualización del archivo para activar cada 48000 iteraciones de bucle, dentro del bucle (y no escriba para los otros sensores de este conteo en el valor final)

Debido a que otras respuestas ya explicaron el problema, solo describo mi solución.

Establecer banderas en las rutinas de interrupción. Verifique en la rutina principal si se establece una bandera (si es así: haga algo).