Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[AVR] Arduino ADC driven by Timer interrupt Problem.

Status
Not open for further replies.

anj

Member level 3
Member level 3
Joined
Aug 16, 2012
Messages
66
Helped
7
Reputation
14
Reaction score
7
Trophy points
1,288
Location
Rajkot, Gujarat, India
Activity points
1,679
Hello.. :)
I am using Arduino Mega 2560. I am trying to sample 4 analog channels A5 to A8. But couldn't getting out of ISR once Logging is started. I have modified audio recording code for data logging.
please help me out to log data. it is supposed to log data in sd card..main problem is Stop button is not being detected once it is started.
checked hardware with audio recording code it is working fine. my code is :

Code:
#include <SdFat.h>

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))     // simplifying syntax of AVR methods.
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

SdFat sd;
SdFile rec;

const int chipSelect = 53;          // CS pin of microsd module. 
unsigned long recByteCount = 0L;    // total count of bytes saved to buffer
unsigned long recByteSaved = 0L;    //total count of bytes saved to sdcard
const int btnStart = 6;             // start button pin
const int btnStop = 5;              // stop button pin
const int ledStart = 3;             // start button LED (green)
const int ledStop = 2;             // stop button LED (red)
int recPressed = 0;                 // flag to check start is pressed or not
int stopPressed = 0;                // flag to check stop is pressed or not
byte buf00[510];                    // buffer array 1 for time
byte buf01[510];                    // buffer array 2 for time
//byte buf02[1020];                    // buffer array 2 to 15 for samples
//byte buf03[1020];
unsigned int bufByteCount=1;          // array index variable for buffers mentioned above
byte bufWrite,diff;                      // flag to state which buffer to write (will have only two values 0 or 1 since we are having only two buffers)
long t1,t0;
char name1[]= "audio_1.xls";


void setup() { // THIS RUNS ONCE

  Setup_timer2();       // timer config
  Setup_ADC();      // skipped to check timer function

  pinMode(10, OUTPUT);
  pinMode(ledStart, OUTPUT);
  pinMode(ledStop, OUTPUT);
  pinMode(btnStop, INPUT_PULLUP);
  pinMode(btnStart, INPUT_PULLUP);
  
  if (sd.begin(chipSelect, SPI_FULL_SPEED)) { // initialise card on SPI to 8MHz SPI bus speed
    for (int dloop = 0; dloop < 4; dloop++) {
      digitalWrite(ledStart,!digitalRead(ledStart));
      delay(50);
    }
  } else { // if error, flash LED twice per second, until reset
    while(1) {
      digitalWrite(ledStart,!digitalRead(ledStart));
      delay(50);
    }
  }
  for(int i=2;i<=510;i+=2)
  {
   if(i%10==0){buf00[i]='\n';buf01[i]='\n';}
   else{buf00[i]='\t'; buf01[i]='\t';}

  }
  
}
void loop() { // THIS RUNS CONTI.

  if (digitalRead(btnStart) == LOW && recPressed == 0) 
  {
    StartRec(); // launch StartRec method
  }
  
  if (digitalRead(btnStop) == LOW) 
  {
  cbi (TIMSK2, OCIE2A); 
  rec.close();
  recPressed = 0;
  digitalWrite(ledStart,LOW); // turn off recording LED
  digitalWrite(ledStop,HIGH); // light stop LED
  }
  
  if (recByteCount % 1020 == 510 && recPressed == 1) 
  {      
      rec.write(buf00,510);  
      recByteSaved+= 510; 
  } // save buf00 to card
  
  if (recByteCount % 1020 == 0 && recPressed == 1) 
  {   
       rec.write(buf01,510); 
       recByteSaved+= 510; 
  } // save buf01 to card


}

void StartRec() { // begin recording process

  digitalWrite(ledStart,HIGH);
  digitalWrite(ledStop,LOW);
  recByteCount = 0;
  recByteSaved = 0;
  recPressed = 1; // recording button has been pressed
  stopPressed = 0;
  
  rec.open(name1, O_CREAT | O_TRUNC | O_RDWR);

  sbi (TIMSK2, OCIE2A); // enable timer interrupt, start grabbing samples (here, time )

}

void Setup_timer2() {

  TCCR2B = _BV(CS21);  // Timer2 Clock Prescaler to : 8
  TCCR2A = _BV(WGM21); // Interupt frequency  = 16MHz / (8 x 90 + 1) = 22191Hz
  OCR2A = 221; // Compare Match register set to 221. to match 111uS requirement (i.e. 9.009kHz)

}

void Setup_ADC() {                

   // set ADC to read pin A5, ADLAR to 1 (left adjust)
  cbi(ADCSRA,ADPS2); // set prescaler to 8 / ADC clock = 2MHz
  sbi(ADCSRA,ADPS1);
  cbi(ADCSRA,ADPS0);
}

ISR(TIMER2_COMPA_vect) {            // timer interrupt function will be called automatically.
  t1=micros();      //catch the time when sample taken
 
  ADMUX = 0x65;     // set ADMUX to read analog channel 5.
  sbi(ADCSRA, ADSC); // start ADC sample
  while(bit_is_set(ADCSRA, ADSC));  // wait until ADSC bit goes low = new sample ready
  
  diff=t1-t0;
  t0=t1;

 if (bufByteCount == 510 && bufWrite == 0) { 
    bufByteCount = 0;
    bufWrite = 1;
  } else if (bufByteCount == 510 && bufWrite == 1) {
    bufByteCount = 0;
    bufWrite = 0;
  }
  
  if (bufWrite == 0) { buf00[bufByteCount] = diff;  buf00[bufByteCount+2] = ADCH;}    // we will read analog sensors here.
  if (bufWrite == 1) { buf01[bufByteCount] = diff;  buf01[bufByteCount+2] = ADCH;}    //here, difference between two sampled time is taken for timing purpose. 
  delayMicroseconds(10);
  
ADMUX = 0x66;       // set ADMUX to read analog channel 6.
  sbi(ADCSRA, ADSC); // start ADC sample
  while(bit_is_set(ADCSRA, ADSC));  // wait until ADSC bit goes low = new sample ready
  
  if (bufWrite == 0) {  buf00[bufByteCount+4] = ADCH;}
  if (bufWrite == 1) {  buf01[bufByteCount+4] = ADCH;}
  delayMicroseconds(10);

  ADMUX = 0x67;       // set ADMUX to read analog channel 7.
  sbi(ADCSRA, ADSC); // start ADC sample
  while(bit_is_set(ADCSRA, ADSC));  // wait until ADSC bit goes low = new sample ready
  
  if (bufWrite == 0) {  buf00[bufByteCount+6] = ADCH;}  
  if (bufWrite == 1) {  buf01[bufByteCount+6] = ADCH;}
  delayMicroseconds(10);

  ADMUX = 0x68;       // set ADMUX to read analog channel 7.
  sbi(ADCSRA, ADSC); // start ADC sample
  while(bit_is_set(ADCSRA, ADSC));

  if (bufWrite == 0) {  buf00[bufByteCount+8] = ADCH;}  
  if (bufWrite == 1) {  buf01[bufByteCount+8] = ADCH;}

  recByteCount+=10; // increment sample counter 
  bufByteCount+=10;
  delayMicroseconds(10);

}
please help.. :-|
 
Last edited:

You have a lot of things within ISR vector, such as a while() loop, as well a delay() command.
The only action you should do there is set/reset a flag informing the Timer2 event, and manage everithing at the loop() main function.
 

You have a lot of things within ISR vector, such as a while() loop, as well a delay() command.
The only action you should do there is set/reset a flag informing the Timer2 event, and manage everithing at the loop() main function.

Actually its not a very good aproach. In the embedded engineering we are looking even to do not have a main loop as it wastes energy.
But anyway.

1. Start first conversion in the timer interrupt. do not do any sei operations in the interrupt.
2. In ADC interrupt get the result for first channel (actually you should skip at least one result if you change the channel or the reference), start second channel etc etc.
 

You have a lot of things within ISR vector, such as a while() loop, as well a delay() command.
The only action you should do there is set/reset a flag informing the Timer2 event, and manage everithing at the loop() main function.

Actually its not a very good aproach. In the embedded engineering we are looking even to do not have a main loop as it wastes energy.
But anyway.

1. Start first conversion in the timer interrupt. do not do any sei operations in the interrupt.
2. In ADC interrupt get the result for first channel (actually you should skip at least one result if you change the channel or the reference), start second channel etc etc.

Thank you andre_teprom, franekz :smile: I will keep these suggestions in sight while programming, Actually I wanted to convert 4 channel analog data to a log file with sampling rate of 8Khz. since I am a new to ADC please suggest some idea to do this above code is my TRY to do that will it be possible ??
code has been debuged instead of :
Code:
 if (bufByteCount == 510 && bufWrite == 0) { 
    bufByteCount = 0;
    bufWrite = 1;
  } else if (bufByteCount == 510 && bufWrite == 1) {
    bufByteCount = 0;
    bufWrite = 0;
  }
it should be :
Code:
 if (bufByteCount >= 510 && bufWrite == 0) { 
    bufByteCount = 0;
    bufWrite = 1;
  } else if (bufByteCount >= 510 && bufWrite == 1) {
    bufByteCount = 0;
    bufWrite = 0;
  }
still just wanted to know feasibility of this task from you guys.
Thank You
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top