Delay using nop help

Hi all,

I need to implement a clock signal and I'd like to use the Arduino, however the clock signal has to be high frequency and variable.

I have generated an acceptable square wave using digitalWrite and delayMicrosecond but I need more than 1us resolution.

I attempted to use inline assembly and the "nop" command to get nanosecond resolution, but so far my code does not produce a squarewave. The pin just stays low according to the scope.

Here is the code (I am using digitalWriteFast to save programming time). There are no compile errors or anything to suggest something is wrong.

#include <digitalWriteFast.h>


void setup()
{
pinModeFast(13, OUTPUT);
cli();
}

void loop()
{
  digitalWriteFast(13, HIGH);
  asm("nop\n nop\n nop\n nop\n nop\n nop\n");
  digitalWriteFast(13, LOW);   
  asm("nop\n nop\n nop\n nop\n nop\n nop\n");
}

How can I fix this? Any pointers? This is my first time using inline assembly and my searches haven't turned up much I can use (or that makes sense to me.)

Thanks for the help, I can post pictures of the o-scope output if that will help.

Have you tried:

asm("nop; nop; nop; nop; nop; nop;");

//Or
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");

?

stop using digital write for high frequencies and use direct port manipulation instead - Arduino Reference - Arduino Reference -

void setup()
{
  DDRB = DDRB | B00100000;  // set outputmode for pin 13;
}

void loop()
{
  PORTB = PORTB | B00100000;   // set pin 13 high
  asm("nop\n nop\n nop\n nop\n nop\n nop\n");
  PORTB = PORTB & B11011111;  // set pin 13 low
  asm("nop\n nop\n ");
}

The number of nops is not equal as returning and calling loop() again and again takes also some instructions.

Hope this helps

You might also want to look into assembly language for this kind of code. There is some overhead in Arduino that you may be able to sidestep if you use assembly. There are other challenges, but it is an option where you are trying to push the envelope because you can work with a smaller envelope.

Maybe you should be using the timers instead?

Worked like a charm! robtillaart, your snippet worked like a charm! I'll pull up the port manipulation tutorials and do my homework.

Is there any way to avoid the extra overhead of loop() within arduino?

If you use the timers it'll be like pwm, working in the background with the hardware leaving the loop for your code

Is there any way to avoid the extra overhead of loop() within arduino?

investigate winner10920's advice ==> timer

There will allways be some jump in the SW code - you could do a while(1) { high wait low wait } - but even that has a jump to the start of the loop().

Check the command objdump.exe in your arduino distribution if you want to see the assembly generated.

I am looking into using timers now, I think I can find the flexibility I need in there. However, I'm still worried about the overhead.

If I wait for the overflow interrupt it will be too slow, even at system clock. what is the overhead for using the compare register? I think I could just set the interval in the compare register, and then clear the register after interrupt. Would that work? Does anyone know off the top of their head how many clock cycles that kind of compare would take?

However, I'm still worried about the overhead.

What overhead? You are using timers, these are hardware so there is no overhead.

Does anyone know off the top of their head how many clock cycles that kind of compare would take?

Again it is hardware the comparator works as fast as the clock works.

Okie day, I tried a timer implementation, and it seems pretty great except that I can't seem to get it to move faster than 250kHz. With a while(1) loop and assembly, I could get 2MHz. According to the scope and some fiddling, it takes 34 clock cycles to execute the register compare and the interrupt code.

Here is the code:

#include <avr/io.h>
#include <avr/interrupt.h>

ISR(TIMER1_COMPA_vect)
{
    PORTB = ~PORTB;   // Reverse all the damn pins  
}

void setup()
{
    pinMode(13, OUTPUT);
    cli();          // disable global interrupts
    TCCR1A = 0x00;     // set entire TCCR1A register to 0
    TCCR1B = 0x00;     // same for TCCR1B
 
    // set compare match register to 34 cycles:
    OCR1A = 0x22;
    
    // turn on CTC mode:, set TCCR1 prescaler to system clock 
    TCCR1B = B00001001;
   
    // enable timer compare interrupt
    TIMSK1 |= (1 << OCIE1A);

    // re-enable global interrupts:
    sei();
}

//avoiding linking errors 
void loop()
{
  
}

If this is all crazy talk, let me know. If you can think of anything to speed up the code, please tell me. I need 1.5 Mhz for timing/measuring purposes.

You guys are pretty awesome.

PORTB = ~PORTB;

should I think be

PORTB = ~PINB;

I'm not sure what you get when you read the port's output register so I don't know if that will affect what you are doing or not, but it certainly is what you intended I think.

There will be a large overhead with interrupts, I think the guys were suggesting you use the PWM abilities of the timer, that is totally hardware.


Rob