2

I’m using LPC1788 MCU with KeilV5 compiler.

I Have a Timer ISR in which I read a value form specific ADC channel and write it into a SD-Card using FATFS library.

Here is my Timer ISR code:

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);
  }     
}

There is no problem with above code but when I remove the comment sign from the f_write function, program stops and nothing executes exactly after Timer1 is enabled. (referred to debug, after TIM_Cmd(LPC_TIM1, ENABLE) is executed in main function)

So I can’t write the data into the SD-Card in Timer's ISR.

I should mention that f_write function works fine outside the Timer ISR.

Can you guess where is the problem?

Thanks in advance.

Nima
  • 166
  • 11
  • 2
    Note that f_write() can take significant time on a SD card, in the order of a few 100ms up to about one second - though the latter value I got from a very cheap no-name card. This forbids usage in an interrupt handler function in most cases. – Turbo J Oct 08 '17 at 12:19

2 Answers2

4

It is usually a very, very bad idea to use FatFS from interrupts. The most common pattern is to acquire the data in the ISR, store is somewhere and have a main loop task that stores that queued data somewhere.

If your SPI driver uses interrupts and you don't enable nested interrupts (advanced topic), then your SPI interrupts won't run until the timer interrupt is done.

filo
  • 8,801
  • 1
  • 25
  • 46
3

+1 for @filo, who correctly addressed the problem of nested interrupts either not enabled (or having the same priority, therefore not being triggered).

However the problem is not with the SPI (which typically is not used with interrupt on the FatFS, unless some heavy modifications are done in the code. The SPI is used in polling, with the xmit_spi() and xmit_spi_multi() functions).

The problem lies on the disk_timerproc() , which must be called (with an interrupt) each ms, for timeouts and for updating card's state (card inserted, write protected, etc).

In the LPC17xx example, disk_timerproc() is called by SysTick_Handler().

You have therefore two ways:

  1. Use a higher priority number (i.e. give a lower priority) for the TimerISR, which actually reads the ADC.
  2. Or let the Timer_ISR() set a volatile global variable "dataAvailable=1", and then in the main loop, save the data, when dataAvailable is 1.

For instance

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);
   }     
}
next-hack
  • 5,297
  • 15
  • 33