FatFs f_write no funciona en LPC1788 Timer ISR

Estoy usando LPC1788 MCU con el compilador KeilV5.

Tengo un temporizador ISR en el que leo un valor de un canal ADC específico y lo escribo en una tarjeta SD usando la biblioteca FATFS.

Aquí está mi código ISR del temporizador:

void TIMER1_IRQHandler(void){
 if (TIM_GetIntStatus(LPC_TIM1, TIM_MR1_INT)== SET){
    ADC_Init(LPC_ADC,838);
    ADC_ChannelCmd (LPC_ADC,0,ENABLE);
    while (!(ADC_ChannelGetStatus(LPC_ADC,0, ADC_DATA_DONE)));
    ADCResult = ADC_ChannelGetData(LPC_ADC,0);
    sprintf(OutputSample,"%ld\r\n",ADCResultScaled);    
    f_lseek(&File1, f_size(&File1));
    //f_write(&File1,OutputSample,strlen(OutputSample), &FilePointer);              
    Counter++;
    TIM_ClearIntPending(LPC_TIM1, TIM_MR1_INT);
  }     
}

No hay ningún problema con el código anterior, pero cuando elimino el signo de comentario de la función f_write, el programa se detiene y nada se ejecuta exactamente después de que se habilita el temporizador 1. (referido a la depuración, después de ejecutar TIM_Cmd(LPC_TIM1, ENABLE) en la función principal)

Entonces no puedo escribir los datos en la tarjeta SD en el ISR de Timer.

Debo mencionar que la función f_write funciona bien fuera del Timer ISR.

¿Puedes adivinar dónde está el problema?

Gracias de antemano.

Tenga en cuenta que f_write() puede tomar un tiempo significativo en una tarjeta SD, del orden de unos pocos 100 ms hasta aproximadamente un segundo, aunque este último valor lo obtuve de una tarjeta sin nombre muy barata. Esto prohíbe el uso en una función de controlador de interrupciones en la mayoría de los casos.

Respuestas (2)

Por lo general, es una muy, muy mala idea usar FatFS de las interrupciones. El patrón más común es adquirir los datos en el ISR, almacenarlos en algún lugar y tener una tarea de ciclo principal que almacene los datos en cola en algún lugar.

Si su controlador SPI usa interrupciones y no habilita las interrupciones anidadas (tema avanzado), entonces sus interrupciones SPI no se ejecutarán hasta que finalice la interrupción del temporizador.

+1 para @filo, quien abordó correctamente el problema de las interrupciones anidadas que no están habilitadas (o tienen la misma prioridad, por lo tanto, no se activan).

Sin embargo, el problema no está en el SPI (que normalmente no se usa con la interrupción en FatFS, a menos que se realicen algunas modificaciones importantes en el código. El SPI se usa en el sondeo, con las funciones y xmit_spi()) xmit_spi_multi().

El problema radica en el disk_timerproc(), que debe llamarse (con una interrupción) cada ms, para tiempos de espera y para actualizar el estado de la tarjeta (tarjeta insertada, protegida contra escritura, etc.).

En el ejemplo LPC17xx, disk_timerproc()es llamado por SysTick_Handler().

Tienes por tanto dos caminos:

  1. Use un número de prioridad más alto (es decir, dé una prioridad más baja) para el TimerISR, que en realidad lee el ADC.
  2. O deje que Timer_ISR() establezca una variable global volátil "dataAvailable=1", y luego, en el ciclo principal, guarde los datos, cuando dataAvailable sea 1.

Por ejemplo

volatile dataAvailable = 0;
[...] other code[...]
void main (void)
{
   [...] other code [...]
   while (1)
   {
      [...] other code [...]
      if (dataAvailable)
      {
         dataAvailable = 0;
         saveData();
      }
   }
}
void TIMER1_IRQHandler(void)
{
   if (TIM_GetIntStatus(LPC_TIM1, TIM_MR1_INT)== SET)
   {
      [...] other code [...]
      dataAvailable = 1;
      TIM_ClearIntPending(LPC_TIM1, TIM_MR1_INT);
   }     
}