Pages: [1]   Go Down
Author Topic: [Solved!] Due code stalls while handling interrupts  (Read 770 times)
0 Members and 1 Guest are viewing this topic.
WI, USA
Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have a DS1077 programmable oscillator producing a 400kHz square wave (50% duty cycle, ~80 ns rise/fall time) which I will use as a master clock signal. I need to produce a pulse which both rises and falls during a high portion of the clock (though it may last many microseconds, or even milliseconds long). To accomplish this, I am monitoring the clock signal with an interrupt service routine on a Due.
Full code is below, but in short:
1. I set a boolean false
2. Attach the interrupt (I chose pin 26, as it serves no other function on the SAM3X)
3. Wait for the boolean to become false:
Code:
while(boolean){;}
4. On the next rising clock edge (within about 2 microseconds) the ISR simply sets the boolean true
5. When the ISR completes, the while loop should exit and start/end the pulse. Hopefully this can be done in few enough Due clock cycles that the DS1077 clock is still high. If not, then hopefully it is at least reproducible enough that I can catch the next (or nth future) high clock cycle.
6. Detach the interrupt when it is not needed to save CPU cycles. In the future I will be using several ISRs, so using noInterrupts() is not an option. Note that I've tried an alternate version of the code which attaches the interrupt once in setup and leaves it attached, but still had the same problem.

What I see is that ISR is triggered many times (I started incrementing an integer in the ISR), but my loop of code will not complete. If I pull out the wire, or re-insert it, the code seems to advance one loop (I see the Serial.println statements), but again hangs unless I pull it out/re-insert it again. I suppose this is because pulling it out will make the ISR stop being called, which fixes whatever problem I have. Re-inserting it will call the ISR which advances through the next while(!boolean).

One last point. The time to write a boolean seems to be only a little faster than the DS1077 period. This means that the ISR is triggered again right after it completes. With 12ns period for the Due, though, I would think that it would have enough time to detach the interrupt rather quickly.

Can anyone please teach me where my code is going wrong? Thank-you for reading my long post!
-Matt
(Code below)

Code:
/* Author: Matthew Rowley
   Date: 10/15/2013
  
   This program explores how to use built-in timers together with interrupts on the
   Arduino DUE.
   Connect the clock signal (via a voltage level converter) to pin 26 for
   interrupts. Monitor the clock and pin 4 on an oscilloscope to confirm that the
   pulse on 4 rises and falls wile the clock is high.
   Open a Serial monitor to check the debugging messages.
*/

volatile boolean interrupted = false;
unsigned long timer;
unsigned long integration_time=50;
volatile int interrupt_count=0;

int out_pin = 4;

void setup(){
  Serial.begin(9600);
  pinMode(out_pin,OUTPUT);
  digitalWrite(out_pin, LOW);
  pinMode(26,INPUT);
}

void loop(){
  // Avoid a problem with micros() overflow
  if(micros()>4294962295) delay(6); // within 5 milliseconds
  interrupted = false;
  
  // Proceed with creating a pulse
  attachInterrupt(26,setBool,RISING);
 // Serial.println("Interrupt Attached");
  while(!interrupted){;} // This will wait until a rising edge on 26
  detachInterrupt(26);
  digitalWrite(out_pin,HIGH);
  timer=micros()+integration_time;
  interrupted=false;
  while(micros()<timer){;}
  attachInterrupt(26,setBool,RISING);
  while(!interrupted){;} // This will wait until a rising edge on 26
  detachInterrupt(26);
  digitalWrite(out_pin,LOW);
  interrupted=false;
  
  delay(1);
  Serial.println(integration_time);
  Serial.println(interrupt_count);
  integration_time++;
}

void setBool(){
  interrupted = true;
  interrupt_count++;
}
« Last Edit: October 18, 2013, 02:16:32 pm by Matt_Chemist » Logged

New England
Offline Offline
Sr. Member
****
Karma: 7
Posts: 295
Natural Semiinductor
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I guess the problem is
while(micros()<timer){;}

It gets stuck there forever, change the logic to exit the while(1) mistake
Logged

I am going to get going.

WI, USA
Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank-you for your reply, but I don't see how my while(micros()<timer){;} statement is flawed.

timer is defined as micros()+integration_time at an earlier point in the code. Until the integration time has elapsed, then micros()<timer will evaluate as true and the program will wait. After the proper time has elapsed, micros() will be greater than timer, the condition will evaluate as false, and the while loop will exit. I don't see how this should get stuck forever.
Besides, if I pull out/re-insert the wire for the clock then the code advances (I immediately see the output on the serial monitor), so I think the hang-up must be tied to the use of an interrupt.
Logged

WI, USA
Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Solved!
This problem is clearly better solved with hardware. I just used a D-type flip-flop. The 400 kHz clock signal serves as the clock to the flip-flop, ensuring that the output will switch during the high phase of the clock. The long integration time pulse from the Due is connected to the flip-flop input, so it gets reproduced (with at most 1 clock-cycle error) with edges during the high phase of the clock.
Thanks to all readers!
Logged

Pages: [1]   Go Up
Jump to: