I was wondering how well the timer capture would work, so I adapted the sketch linked above.
Input capture working for Arduino Due with input signal connected to pin 5.
Based on the example in this discussion thread: https://forum.arduino.cc/index.php?topic=158361.0
by Paul Dreik http://www.pauldreik.se/
Modified by Bob Cousins to measure positive going pulse width on TIOA6.
volatile uint32_t ra;
volatile uint32_t rb;
volatile uint32_t pulse_length; // pulse length in timer counts
* Interrupt function. TC6 = timer counter TC2, channel 0
* Note : this does not handle the overflow or other error cases
// reads the interrupt. necessary to clear the interrupt flag.
const uint32_t status=TC_GetStatus(TC2, 0);
// has the timer overflowed?
const bool overflowed=status & TC_SR_COVFS;
// input captures
const bool inputcaptureA=status & TC_SR_LDRAS;
const bool inputcaptureB=status & TC_SR_LDRBS;
// loading overrun?
const bool loadoverrun=status & TC_SR_LOVRS;
// read LDRA and store it. If we don't read RA, we will get overflow (TC_SR_LOVRS)
ra = TC2->TC_CHANNEL.TC_RA;
// read LDRB and calculate pulse len. If we don't read RB, we will get overflow (TC_SR_LOVRS)
rb = TC2->TC_CHANNEL.TC_RB;
pulse_length = rb-ra;
Tc *tc = TC2;
uint32_t channel = 0;
IRQn_Type irq = TC6_IRQn;
// We need to configure the pin to be controlled by the right peripheral.
// The TIOxx pins available depend on the Timer unit.
// The following is for timer unit TC6, pin TIOA6, Arduino pin 5.
// pin 5 is port C. PIOC_PDR is defined in hardware/arduino/sam/system/CMSIS/Device/ATMEL/sam3xa/include/instance/instance_pioc.h
// and PIO_PDR_P25 is defined in hardware/arduino/sam/system/CMSIS/Device/ATMEL/sam3xa/include/component/component_pio.h
// this disables the PIO from controlling the pin. see 32.7.2
REG_PIOC_PDR |= PIO_PDR_P25;
// next thing is to assign the IO line to the peripheral. See 32.7.24.
// we need to know which peripheral we should use. Read table 37-4 in section 37.5.1.
// TIOA6 is peripheral B, so we want to set that bit to 1.
// REG_PIOC_ABSR is defined in hardware/arduino/sam/system/CMSIS/Device/ATMEL/sam3xa/include/instance/instance_pioc.h
// PIO_ABSR_P25 is defined in hardware/arduino/sam/system/CMSIS/Device/ATMEL/sam3xa/include/component/component_pio.h
REG_PIOC_ABSR |= PIO_ABSR_P25;
//allow configuring the clock.
Every peripheral in the SAM3X is off by default (to save power) so must be turned on.
Configure the timer. All this is about setting TC_CMRx, see 37.7.10 in Atmel pdf.
We use CLOCK1 at 42 MHz to get the best possible resolution.
We want input capture on TIOA6 (pin 5). Nothing else should be necessary, BUT there is a caveat:
As mentioned in 37.6.8, we only get the value loaded in RA if not loaded since the last trigger,
or RB has been loaded. Since I do not want to trigger as that sets the timer value to 0, I
instead let register B be loaded when the pulse is going low.
TC_Configure(tc, channel, TC_CMR_TCCLKS_TIMER_CLOCK1 | TC_CMR_LDRA_RISING | TC_CMR_LDRB_FALLING);
// Set the interrupt flags. We want:
// interrupt on overflow
// TIOA6 (pin 5) going low
const uint32_t flags=TC_IER_COVFS | TC_IER_LDRBS;
//start the timer
digitalWrite (2, 0);
float ticks_per_us = F_CPU/2.0/1e6;
pulse_length = 0;
ra = 0;
rb = 0;
// create a short pulse
digitalWrite (2, 1);
digitalWrite (2, 0);
Some output :
For a pulse length of 2200 ns measured on my scope, the Due prints a value of 2190.48 ns to 2214.29 ns, which is about within 15 ns. The tick resolution is 1/42 MHz, about 24 ns, so it's accurate to the resolution of the timer clock.
The sketch can be extended to other timer channels, you will have to dig through the data sheet to see what TIO pins are available.