Arduino Uno not outputing the correct signal frequency

Hey guys,

I am trying to code a control system and i am currently having problems trying to get the correct output. What my code does is that it takes an input square wave of 1.6MHz and should turn it into a 100kHz square wave with a specific duty cycle. While i am getting the correct waveforms, the output frequency seems to be limited to 16.4kHz. I am guessing the problem is with my code, as the Uno has a CLK speed of 16Mhz. Note: I am meassuring the signals with a load of 1k ohms.

This picture shows the output signal with an input of 1.6MHz. If the input frequency is above 240kHz, the output signal will stay at a constant 16.4kHz.

The picture below shows the output signal with an input of 240kHz. Which gives the appropriate 15kHz output.

Here is the code:

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

//Input 1.6MHz squarewave onto pin 2 and output squarewaves with varying duty cycles at 100kHz

volatile int count = 0;

ISR (INT0_vect) // external interrupt 0
{  
  count++;

  switch(count){
    case 2:
    PORTD |= (1 << PORTD6); 
    PORTD &= ~(1 << PORTD4);
    break;  

    case 7:
    PORTD |= (1 << PORTD4);
    PORTD &= ~(1 << PORTD6);
    break; 

    case 10:
    PORTD |= (1 << PORTD5);
    PORTD &= ~(1 << PORTD7);
    break; 

    case 15:
    PORTD |= (1 << PORTD7);
    PORTD &= ~(1 << PORTD5);
    break; 

    case 16: count = 0; break;  
  }
}

void setup() {
  cli();
  
  DDRD &= ~(1 << DDD2); //PD2 input

  DDRD |= (1 << DDD4)|(1 << DDD5)|(1 << DDD6)|(1 << DDD7); //pin 4 to 7 is now output
  
  EICRA |= (1 << ISC00)|(1 << ISC01); // set INT0 to trigger on rising edge
  EIMSK |= (1 << INT0); // Turns on interrupt for INT0
  sei(); // turn on interrupts
}

void loop() {
  // put your main code here, to run repeatedly:
}

Interrupt overheads?

I dont understand. Do you mean that the interrupt code is taking too long to process and another interrupt occurs while it is processing?

Yes.

If your input frequency is 1.6MHz, then you only have 10 clock cycles to do everything your interrupt routine needs to do before the next pulse comes along.

Clearly this isn't happening.

Even if you had a bare interrupt preamble/postamble (stack/unstack only the return address), ten instruction cycles wouldn't be enough

I understand now, thanks for your help guys.

The ISR code as it is consumes between 4 and 8 useg (simulated in wokwi).
If the internal handling of the interrupt takes more than 2 usegs you are already in troubles.

You should consider using another faster micro.

You might be able to do what you want to do using the Arduino's timers/counters.

This tutorial from Nick Gammon is very useful:
www.gammon.com.au/timers

This but recognize, using a timer will not allow you to sample every waveform at 1.6Mhz. However you may be able to sample every 10th or 20th. I assume since you are down sampling it having every cycle of 1.6 Mhz will not be an issue.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.