Arduino R4 WiFi pulse measurement

Hi,

I am generating an on-off keyed square wave of varying pulse widths (all quite short!) to encode a signal. I've used an Arduino R3 Uno to measure the pulse widths (in number of clock cycles), however it struggles below pulse widths of approximately 8us. My thought is to try it on the R4, which has a 48MHz clock and should provide a better resolution (I need to measure pulse widths down to approx 4us). However, I am unfamiliar with the code on the new microcontroller, and struggling to find sufficient resources to learn. Could anyone help, either below or by providing links, on how to implement a similar system as to the R3 code I have attached?

// === CONFIGURATION ===
#define MAX_EDGES 30  // Number of edges we will store
#define THRESH_LONG 10000

// === GLOBAL VARIABLES ===
volatile uint16_t timing[MAX_EDGES];  // Array to store time differences
volatile uint16_t sequence[MAX_EDGES];  // Array to store time differences
volatile uint16_t i_glob = 0, i_thresh = 0;         // Index in timing array
volatile uint16_t last_capture = 0;   // Stores the last captured time
int goThresh = 0;

void setup() {
  // Start serial for debugging (you won't use it yet)
  Serial.begin(2000000);

  // === TIMER1 SETUP ===
  TCCR1A = 0;  // Normal mode
  TCCR1B = (0 << ICES1) | (1 << CS10);  // Rising edge, no prescaler
  TIMSK1 |= (1 << ICIE1);  // Enable input capture interrupt
  DDRD |= (1 << PD5);  // Set pin 5 as output
}

void loop() {
  if (i_glob >= MAX_EDGES) {
    cli(); // Pause interrupts
    uint16_t local_timing[MAX_EDGES];
    for (uint16_t j = 0; j < MAX_EDGES; j++) {
      local_timing[j] = timing[j];
      Serial.println(local_timing[j]);
    }
    i_glob = 0;
    memset(timing, 0, sizeof(timing)); // Reset answer
    sei(); // Enable interrupts
  }
}

// === INPUT CAPTURE INTERRUPT ===
// This runs every time there's a rising (or falling) edge on pin 8
ISR(TIMER1_CAPT_vect) {
  uint16_t current_capture = ICR1;               // Read current timer value
  uint16_t time_diff = current_capture - last_capture;
  last_capture = current_capture;
  
  if (time_diff > THRESH_LONG){
    goThresh = 1;
    i_thresh = i_glob;
    i_glob = 0;
  }

  // Store the timing if there's room and the long threshold has been detected!
  if (i_glob < MAX_EDGES && goThresh == 1) {
    timing[i_glob] = time_diff;
    i_glob = i_glob + 1;
  }

  // Toggle edge detection: rising <-> falling
  TCCR1B ^= (1 << ICES1);
  
}

The code above works by detecting rising/falling edges on pin 8, measuring the pulse widths in clock cycles, and if a long cycle has occurred ( > 10,000 cycles), it will record a buffer of the next cycles. This is because the input signal is duty cycled and has a long low between data.

Many thanks.

That code was specifically written for Arduino using ATmega328. The R4 uses a completely different chip and the code will need to be almost completely re-written by someone with high level of expertise in both the ATmega and the Renesas chips.

Have you considered using the pulseIn() Arduino function? I don't know for sure but would expect that should work on R4 and have a higher timing resolution than it does on R3.

Thanks, yes I understand it needs a totally different codebase and I am looking for some resources which may help me understand/implement this. Unfortunately the pulseIn() function supposedly works on pulses from 10us to 3minutes (https://docs.arduino.cc/language-reference/en/functions/advanced-io/pulseIn/)

Have you tried it?

Works down to 1µs on an Arduino R4 Minima.

int pin = 7;
unsigned long duration;

void setup() {
  Serial.begin(9600);
  pinMode(pin, INPUT);
}

void loop() {
  duration = pulseIn(pin, HIGH);
  Serial.print(" Pulse width: ");
  Serial.print(duration);
  Serial.println(" µs");
}

2 Likes

I guess that documentation hasn't been updated for more modern Arduino such as R4.

It's often better to avoid using code that's limited to any particular model of chip. Unfortunately, AVR ATmega chips were the only ones used in Arduinos for so many years that much chip-specific code got written for them.

1 Like

Maybe all you need to use on R4 is attach_interrupt() and micros() ?

I would hope/expect micros() to be accurate to 1us on R4, given @JohnLincoln 's comments.

1 Like

Thanks all for the comments. That works pretty well on the R4 actually! Only downside is that it is to 1us accuracy, but probably is workable.

Thanks for the help.

1us is 4x better than 4us!

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