I did the following:
#include <WProgram.h>
#include <string.h>
#include <pins_arduino.h>
// will initialize output pin with 1, then measure time for input pin go to high
typedef int32_t micros_type;
// output pin
const uint8_t c_output_pin = 13; // internal LED is connected to digital pin 13
const uint8_t c_output_pin__bit = 5; // lookup in pins_arduino.c
// attention: input pin and break pin must use the same port !!!
const uint8_t c_input_pin = 19; // used as primary trigger pin
const uint8_t c_input_pin__bit = 5;
int32_t measure_lag_micros;
int32_t measure_lag() {
pinMode(c_input_pin, INPUT);
digitalWrite(c_input_pin, HIGH);
// output to low because we want to trigger with high
// because the opto coupler will turn this to low again
pinMode(c_output_pin, OUTPUT);
digitalWrite(c_output_pin, HIGH);
// compute pin ports and bit masks in advance
volatile uint8_t* in_port = portInputRegister(digitalPinToPort(c_input_pin));
volatile uint8_t* out_port = portInputRegister(digitalPinToPort(c_output_pin));
//volatile uint8_t* break_port = portInputRegister(digitalPinToPort(c_break_pin));
uint8_t in_bit = 1 << c_input_pin__bit;
uint8_t out_bit = 1 << c_output_pin__bit;
// ensure that we will never see 0 microseconds in the assembler part
// this is because it would wrap around and give way to long delays
// impact is that latency will never be below 1 microsecodns
const micros_type timeout = 99999999;
measure_lag_micros = timeout;
uint8_t tmp = 0;
cli();
// the inline assembler loop will burn 16 cycles or 1 microsecond at 16 MHz
// for details:
// http://www.rn-wissen.de/index.php/Inline-Assembler_in_avr-gcc
// http://www.avr-asm-tutorial.net/avr_de/beginner/register.html
// http://www.avr-asm-tutorial.net/avr_en/beginner/PDETAIL.html#IOPORTS
__asm__ __volatile__ (
// activate output
" eor %[tmp], %[tmp]" "\n\t" // set output to low
" st %a[out_port], %[tmp]" "\n\t" // now
// the loop below will take exactly 16 cycles per pass = 1us at 16 MHz
"1: nop" "\n\t"
" nop" "\n\t"
" nop" "\n\t"
" nop" "\n\t"
" nop" "\n\t"
" ld %[tmp], %a[in_port]" "\n\t" // 2 cycles
" and %[tmp], %[in_bit]" "\n\t" // 1 cycle
" cp %[tmp], %[in_bit]" "\n\t" // 1 cycle
" breq 2f" "\n\t" // 1 cycle // stop timing once we see a high
" subi %A[micros],1" "\n\t" // subtract immediate, 1 cycle
" sbci %B[micros],0" "\n\t" // subtract with carry, 1 cycle
" sbci %C[micros],0" "\n\t" // subtract with carry, 1 cycle
" sbci %D[micros],0" "\n\t" // subtract with carry, 1 cycle
" brne 1b" "\n\t" // 2 cycles (1 in the last pass)
"2: nop" "\n\t"
: [micros] "+a" (measure_lag_micros) // constraint: simple upper register
: "0" (measure_lag_micros), // constraint: use same register as [micros]
[in_port] "e" (in_port), // constraint: pointer register
[in_bit] "a" (in_bit), // constraint: simple upper register
[out_port] "e" (out_port), // constraint: pointer register
[out_bit] "a" (out_bit), // constraint: simple upper register
[tmp] "a" (tmp) // constraint: simple upper register
:
);
digitalWrite(c_output_pin, HIGH);
measure_lag_micros = timeout - measure_lag_micros;
sei();
return measure_lag_micros;
}
int main(){
Serial.begin(115200);
Serial.println("ready");
for (;;) {
micros_type rv;
rv = measure_lag();
if (rv>0) {
Serial.println(rv ,DEC); }
}
}
(Sorry for the messed up tabs).
The issue is: if I code a digitalWrite(13,LOW) it will set pin 13 to low. But if I do not it will not.
However I would expect that
" eor %[tmp], %[tmp]" "\n\t" // set output to low
" st %a[out_port], %[tmp]" "\n\t" // now
would set pin 13 to low. But it fails to do so. Can anyone hit me with a cluebat?
Cheers, Udo