Pages: [1] 2   Go Down
Author Topic: Pin output toggling error.......signal tearing?  (Read 802 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Jr. Member
**
Karma: 0
Posts: 55
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,
I'm trying to just toggle the output pin several times to get desired timing signal. However I'm getting some errors in output.
Few signals/toggles get missing on random interval. Is this called Signal Tearing?
How to fix it?
Please advice.
Code:
#define NOP  __asm__ __volatile__("nop\n\t")
void setup()
 {
   DDRB = DDRB | B00111111; // sets Arduino pins 8 to 13 as outputs, pins GND & AREF are unchanged
   PORTB = 0;
 }
 void loop()
 {
   while(1)
   {
    for(int j=0;j <5; j++)
     {
      for(int i=0;i<24; i++)
       {
        PORTB = 1;
        NOP;
        NOP;
        NOP;
        NOP;
        PORTB = 0;  
        NOP;
        NOP;
        NOP;
        NOP;
      }
   }
   PORTB = 0;
   delayMicroseconds(200);
 }
}

Output where you can see some signals missing for about 6.4uSec


http://i49.tinypic.com/6zwps4.jpg

Thanks
« Last Edit: November 18, 2012, 03:26:05 pm by DirtyBits » Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 503
Posts: 19092
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

The timer interrupt fires every 1.024 mS which would stop your loop temporarily. If you want a proper signal use the hardware timers, not a timed loop. Examples here:

http://www.gammon.com.au/forum/?id=11504
Logged


Global Moderator
Offline Offline
Brattain Member
*****
Karma: 503
Posts: 19092
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

There is also a small gap just after where you have 40 uS on the screenshot (which is after 24 pulses) which would be where the loop of 24 ends.
Logged


Offline Offline
Jr. Member
**
Karma: 0
Posts: 55
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

There is also a small gap just after where you have 40 uS on the screenshot (which is after 24 pulses) which would be where the loop of 24 ends.

true
..1st let me refer to the link you send...brb
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 55
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The timer interrupt fires every 1.024 mS which would stop your loop temporarily. If you want a proper signal use the hardware timers, not a timed loop. Examples here:

http://www.gammon.com.au/forum/?id=11504


Thanks a lott Nick..you are a super star!!
I tried to scan through the whole Timer and Interrupt topics...understood few bits and pieces but finally found out that
cli (); is needed to Disable Interrupt flag. I put that after "While" in the loop and it works!!
Code:
while(1)
   {
cli ();
    for(int j=0;j <5; j++)
     {

But the question is would that affect any other Interrupt routine in the "While" loop?? i.e. if I'm using  Serial.read function then??
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 503
Posts: 19092
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

If you turn off interrupts you won't be getting any serial reads (or writes) and the timer functions will return incorrect time.

You are better off generating pulses in hardware.
Logged


UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12630
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

would that affect any other Interrupt routine ...

If you disable interrupts then you disable all interrupts.

Nick's suggestion to use a hardware timer to do the fixed frequency output did not rely on disabling interrupts and seems like a much better approach to take.
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Offline Offline
Edison Member
*
Karma: 116
Posts: 2205
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
cli (); is needed to Disable Interrupt flag.

It doesn't disable interrupt flags: it disable interrupt execution. The flags will be set as they otherwise would be, except that they don't trigger isrs anymore.

Before you disable it, think hard if you have to. If your pulses needs to be generated absolutely as you had written, without interruption, you then have no choice but to disable interrupts.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 503
Posts: 19092
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Before you disable it, think hard if you have to. If your pulses needs to be generated absolutely as you had written, without interruption, you then have no choice but to disable interrupts.

Even then there will be glitches at the end of loops, as I pointed out above. He has "no choice" but to use the hardware timers if he wants glitch-free pulses.

What frequency are you after? 1 MHz? This sketch does that, nice and simple:

Code:
const byte LED = 3;  // Timer 2 "B" output: OC2B

const long frequency = 1000000;  // 1 MHz

void setup()
 {
  pinMode (LED, OUTPUT);

  TCCR2A = _BV (WGM20) | _BV (WGM21) | _BV (COM2B1); // fast PWM, clear OC2A on compare
  TCCR2B = _BV (WGM22) | _BV (CS20);         // fast PWM, no prescaler
  OCR2A =  (F_CPU / frequency) - 1;          // zero relative 
  OCR2B = ((OCR2A + 1) / 2) - 1;             // 50% duty cycle
  }  // end of setup

void loop()
  {
  // do other stuff here
  }

Glitch-free output:



Plus you are free to do whatever you want in the main loop, interrupts, serial send/receive, whatever.
Logged


Offline Offline
Edison Member
*
Karma: 116
Posts: 2205
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If you have to protect the transmission, you may want to think what it is that you are trying to protect: you can protect the pulse width (high or low, or high and low); you can protect every 8 pulses; or you can protect all 24 pulses.

That will determine where / when  you disable / re-enable the interrupts.

The key is to minimize the duration of disabling them.
Logged

UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12630
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That will determine where / when  you disable / re-enable the interrupts.

I disagree. Nick Gammon has already demonstrated a far better approach which does not require or rely on disabling interrupts. A general rule I try to follow is to use interrupts only where necessary, and when using interrupts disable them only where necessary. In this case, neither the use of interrupt nor the disabling of interrupts are necessary.
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17303
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nick;

 That's a very impressive application of a timer. I have a few questions:

1. Can the OCR2A&B registers be changed 'on the fly' to other values without having to do anything else?
2. What would the max and min frequencies be on a standard 16 Mhz board with retaining @ 50% duty cycle?
3. What would be the commands to stop the timer at any time, and to restart it at any time.

Sure seems like this could be made into a nice simple general purpose function clock generator?

Lefty
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 503
Posts: 19092
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Can the OCR2A&B registers be changed 'on the fly' to other values without having to do anything else?

Yes they can. They would take effect next cycle. If you are going smaller it might be best to stop the clock in case it overshoots the new limit, and then start it again.

Quote
What would the max and min frequencies be on a standard 16 Mhz board with retaining @ 50% duty cycle?

With no prescaler:  62.5 KHz to 4 MHz. 
With a prescaler of 8: 7813 Hz to 1 MHz.
And so on. (With no prescaler it should go to 8 MHz but I got artifacts doing that).

Quote
What would be the commands to stop the timer at any time, and to restart it at any time.

You would turn off the clock source, eg.

Off:

Code:
  TCCR2B = 0;         // clock stopped

On:

Code:
  TCCR2B = _BV (WGM22) | _BV (CS20);         // fast PWM, no prescaler


If you just want a 50% duty cycle some of the other modes (like CTC) might be better. This one uses both "sides" of the timer. I did a bit of copy/paste on that one. <grin>
Logged


Offline Offline
Jr. Member
**
Karma: 0
Posts: 55
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Before you disable it, think hard if you have to. If your pulses needs to be generated absolutely as you had written, without interruption, you then have no choice but to disable interrupts.

Even then there will be glitches at the end of loops, as I pointed out above. He has "no choice" but to use the hardware timers if he wants glitch-free pulses.

What frequency are you after? 1 MHz? This sketch does that, nice and simple:

Code:
const byte LED = 3;  // Timer 2 "B" output: OC2B

const long frequency = 1000000;  // 1 MHz

void setup()
 {
  pinMode (LED, OUTPUT);

  TCCR2A = _BV (WGM20) | _BV (WGM21) | _BV (COM2B1); // fast PWM, clear OC2A on compare
  TCCR2B = _BV (WGM22) | _BV (CS20);         // fast PWM, no prescaler
  OCR2A =  (F_CPU / frequency) - 1;          // zero relative 
  OCR2B = ((OCR2A + 1) / 2) - 1;             // 50% duty cycle
  }  // end of setup

void loop()
  {
  // do other stuff here
  }

Glitch-free output:



Plus you are free to do whatever you want in the main loop, interrupts, serial send/receive, whatever.
Thanks Nick!
Just woke up  smiley-wink

I need pulses of min 250nS or max 400ns. I need to learn how to use your approach though.


Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 55
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
cli (); is needed to Disable Interrupt flag.

It doesn't disable interrupt flags: it disable interrupt execution. The flags will be set as they otherwise would be, except that they don't trigger isrs anymore.

Before you disable it, think hard if you have to. If your pulses needs to be generated absolutely as you had written, without interruption, you then have no choice but to disable interrupts.


yes it disables all Interrupts...
Logged

Pages: [1] 2   Go Up
Jump to: