Trouble writing to SD card inside Interrupt Service Routine

I must admit to being quite new to Arduinos (been playing for about 6 weeks). One problem I have not been able to solve on my own or with previous forum posts:

I can't seem to write to the SD card within a Timer1 ISR(). Is this not possible? Or am I missing something? I am able to write to the card when inside the setup, so I don't believe it's my card or shield.

I'm using the Mega 2560 with the Adafruit Data Logger Shield. Here is the code that is refusing to work for me :slight_smile:

/*

Timer interrupt.  Using 16bit Timer/Counter 1 for mega 2560

*/
const int chipSelect = 10;

#include <avr/interrupt.h> 
#include <avr/io.h>
#include <SdFat.h>
 
unsigned int count = 0;

SdFat sd;
SdFile aFile;

//*****************************************************************
//   setup()
//*****************************************************************
void setup()  {
  
  Serial.begin(9600);    //testing
  pinMode(10, OUTPUT);   //SD card pin

  if (!sd.init(SPI_FULL_SPEED, chipSelect)) { 
     Serial.println("init error");
    sd.initErrorHalt();
  }
  //***************setting up Timer1******************
   DDRB = 0x01;    //PB0 aka pin 53
   PORTB = 0x00;  //start with all pins LOW   
  //setup Timer1 to fire every 250ms
//  TCCR1A = 0x00;    //disable Timer1 while we set it up
  TCCR1B = 0x00;    //disable Timer1 while we set it up
  //reset timer/counter1
  TCNT1  = 0x0000;        //set counter to 0, to count up to Output Compare Register     
  TCCR1A  = 0x00;   //Timer1 Control Reg A: Wave Gen Mode normal
  //TCCR1B bits 2:0 clock select bits, 011=clk(io)/64(from prescalar)
  TCCR1B  = 0x03;   //Timer1 Control Reg B: prescalar set to 64
  OCR1A = 0xF487;    //set Output Compare Reg to 62499     
  //turn on timer1  
  TIMSK1 = 0x02;        //enable output compare interrupt for OCR1A  
  sei();    //enables interrupts
}            //************** end setup()
   

//***************************************
//    main loop()
//***************************************

void loop()  
{
 
}            //*********************end main loop()


//*******************************************
//        logSD()
//*******************************************
void logSD()  
{
      if (!aFile.open("log.csv", O_RDWR | O_CREAT | O_APPEND))  
      {
         sd.errorHalt("opening log.csv for write failed in logSD()"); 
      }
      aFile.println("in loop");
      aFile.close();

}            //*************end logSD()

//********************************************************
//          ISR for Timer1
//**********************************************************
ISR(TIMER1_COMPA_vect)   {
     count++;   //testing
  
    PORTB= 0x01;   //switch pin 53 to HIGH, PB0
    logSD(); 
    PORTB = 0x00;    //switch to low   
    
    Serial.println(count, DEC);  //testing    
    OCR1A += 0xF487;      //set output compare to next value
}            //*******************end ISR for Timer1

I have tried simply writing to SD card inside the ISR without the subroutine logSD(), but the result is the same either way for me. Thanks in advance for any helpful suggestions or pointers to places I may have missed with my googling skills.

SdFat was not designed to be used in an interrupt routine. Writing to an SD with file I/O takes too long to be reasonable in an ISR.

If you need to log data in a timer ISR see the fastLogger examples here Google Code Archive - Long-term storage for Google Code Project Hosting..

No definite answer but...

ISR's must be kept short as possible, accessing SDcards might take too long, and you could get some reentry problem.

It might be that for the SPI IO which is used by the SDcard the timer is needed????

Thank you both. I think you are correct robtillaart, because it has worked before, but only for one or two writes. Thanks for the suggestion...I will try it out!

Hi, I also facing a same problem with sd card and timer1 interrupts. Any solution figure out ?

The standard solution is to buffer data in the interrupt routine and write to the SD card in the background.

The AnalogBinLogger example shows how to use a queue of buffers.

It is complex because it has a lot of other features but you can see the general idea for buffering in an interrupt routine.