6

I've written a simple program - it generates signals over Port D at 4 MHz:

#include <Arduino.h>

int main(void) {

    DDRD = B11111111;
    PORTD = B00000000;

    while (true) {
        PORTD = 0;
        PORTD = 5;
        PORTD = 10;
        PORTD = 15;
        PORTD = 20;
        PORTD = 25;
        PORTD = 30;
        PORTD = 35;
        PORTD = 40;
    }
    return 0;
}

and this is the signal coming out on D4: Max Frequency

I've modified the program by inserting NOP after each assignment to POTRD:

#define NOP __asm__ __volatile__ ("nop\n\t")

int main(void) {

    DDRD = B11111111;
    PORTD = B00000000;

    while (true) {
        PORTD = 0;NOP;
        PORTD = 5;NOP;
        PORTD = 10;NOP;
        PORTD = 15;NOP;
        PORTD = 20;NOP;
        PORTD = 25;NOP;
        PORTD = 30;NOP;
        PORTD = 35;NOP;
        PORTD = 40;NOP;
    }
    return 0;
}

and now signal looks fine, but frequency is limited to 800 KHz: enter image description here

What is the reason for interference at 4 MHz? Is there a limitation to maximal frequency on digital out? I do not really need it for some particular project, just wanted to know it.

I've asked this question on stackoverflow, but then I've discovered this dedicated forum so... I've decided to try it out ;)

jfpoilpret
  • 9,132
  • 7
  • 37
  • 54
  • Set your scope mode to Single instead of Normal and the “interference” will magically disappear. – Edgar Bonet May 14 '15 at 09:24
  • This is correct... could you explain the reason for this? – Maciej Miklas May 14 '15 at 10:29
  • Your scope synchronizes on the rising edges, but since those are unequally spaced, it gets out of sync with the full period of the signal. By adding a few nops you reached a lucky synchronization in your second version of the code. In Single mode it only displays a single trace, so synchronization is not an issue. – Edgar Bonet May 14 '15 at 10:55
  • Could you paste your comment as an answer ? - thank you ! – Maciej Miklas May 14 '15 at 11:08
  • Try running avr-objdump -S /tmp/sketchname.elf and look at the generated assembler code. You'll see how many operations certain code requires. – Gerben May 14 '15 at 12:54
  • While not the cause of what you are seeing, you should also know that unless you disable it the Arduino has a timer interrupt running in the background which will slightly disturb operations like this. – Chris Stratton May 14 '15 at 13:19

2 Answers2

1

This is not a limitation of the Arduino: you can toggle a pin on every clock cycle. It's a synchronization problem between the generated signal and the triggering of the scope. Your scope displays several traces superimposed, and it synchronizes them on the rising edges, but since those are unequally spaced, it gets out of sync with the full period of the signal. By adding a few nops you reached a lucky synchronization in your second version of the code.

The simplest solution is to set the scope mode to Single instead of Normal. Then it only displays a single trace and synchronization is not an issue anymore.

Another option would be to use one of the bits of PORTD as a trigger signal. This bit should cycle only once inside the loop. PD5 should work in the current version of your code. Configure the scope for external trigger and feed this signal into its TRIG input.

Edgar Bonet
  • 43,033
  • 4
  • 38
  • 76
1

Thank you - correct trigger solves my problem: enter image description here